From 5ed082631e85107e5db2c9935ce4ad0b45fe8c30 Mon Sep 17 00:00:00 2001 From: MMD Date: Sun, 6 Sep 2026 21:57:26 +0330 Subject: [PATCH] =?UTF-8?q?=D9=81=D8=B1=D8=A7=D9=86=D8=AA=E2=80=8C=D8=A7?= =?UTF-8?q?=D9=86=D8=AF:=20=D9=88=DB=8C=D8=B1=D8=A7=DB=8C=D8=B4=20=D8=B2?= =?UTF-8?q?=D9=86=D8=AF=D9=87=20=D8=AF=D8=B1=D8=AC=D8=A7=20=E2=80=94=20?= =?UTF-8?q?=D8=AF=D9=88=D9=82=D9=84=D9=88=DB=8C=20=D8=AF=DB=8C=D8=AC=DB=8C?= =?UTF-8?q?=D8=AA=D8=A7=D9=84=20=D8=B3=D8=A7=DB=8C=D8=AA=20=D8=A8=D8=B1?= =?UTF-8?q?=D8=A7=DB=8C=20=D8=A7=D8=AF=D9=85=DB=8C=D9=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit لایه ویرایش بصری روی سایت واقعی (بدون داشبورد جدا): - ورود ادمین از مسیر پنهان /admin/login با توکن JWT (localStorage) و AdminContext شامل isEditMode و وضعیت ذخیره (همگام/در حال ذخیره/خطا) - AdminBar شناور پایین صفحه (فقط برای کاربر واردشده): کلید حالت ویرایش، وضعیت ذخیره، خروج — حالت ویرایش در sessionStorage می‌ماند - InlineEdit: در حالت عادی دقیقاً همان HTML قبلی (بدون تغییر چیدمان)؛ در حالت ویرایش کادرخط‌چین + contentEditable با ذخیره خودکار در blur (Enter ذخیره، Esc لغو) — وایرایش‌شده روی همه متن‌های سایت: هیرو، تیتر بخش‌ها، هیرو صفحات، داستان، فرم تماس، خبرنامه، فوتر، منو، برچسب‌های وضعیت پروژه و... - کشوی عمومی EntityDrawer با پیکربندی متمرکز برای ۱۴ مجموعه (خدمات، پروژه‌ها، مقالات، نظرات، سوالات، تیم، تایم‌لاین، آمار، چرا آرامش، مدل‌های سرمایه‌گذاری، مراحل کار، دفاتر، گالری، منو): ویرایش چندفیلدی، افزودن، حذف و جابه‌جایی ترتیب (▲▼) با ذخیره خودکار هر فیلد - دکمه‌های شناور ویرایش/حذف/ترتیب فقط در حالت ویرایش روی آیتم‌ها - کشوهای یگانه: برند و لوگو، تنظیمات هیرو، فرم تماس، خبرنامه، فوتر، قبل/بعد و نقل‌قول داستان — آپلود تصویر به MinIO از همان‌جا - به‌روزرسانی خوش‌بینانه SiteContext (updateSite) پس از هر PATCH؛ مسیرها در حالت ویرایش کلیک نمی‌شوند؛ breadcrumb محافظ beforeunload --- .gitignore | 3 + frontend/src/App.tsx | 31 ++- frontend/src/admin/AdminBar.tsx | 64 +++++ frontend/src/admin/AdminContext.tsx | 157 +++++++++++ frontend/src/admin/AdminLoginPage.tsx | 85 ++++++ frontend/src/admin/Editable.tsx | 208 +++++++++++++++ frontend/src/admin/EntityDrawer.tsx | 250 ++++++++++++++++++ frontend/src/admin/adminClient.ts | 86 ++++++ frontend/src/admin/entities.ts | 187 +++++++++++++ frontend/src/api.tsx | 24 +- frontend/src/components/ContactSection.tsx | 67 +++-- frontend/src/components/Footer.tsx | 59 ++++- frontend/src/components/Header.tsx | 31 ++- frontend/src/components/PageHero.tsx | 56 +++- frontend/src/components/SectionHeading.tsx | 45 +++- frontend/src/components/admin/ImageField.tsx | 81 ++++++ frontend/src/components/admin/InlineEdit.tsx | 87 ++++++ frontend/src/components/home/Articles.tsx | 32 ++- frontend/src/components/home/BeforeAfter.tsx | 5 + frontend/src/components/home/Faq.tsx | 82 +++--- .../src/components/home/FeaturedProjects.tsx | 48 +++- frontend/src/components/home/Gallery.tsx | 40 +-- frontend/src/components/home/Hero.tsx | 37 ++- frontend/src/components/home/Newsletter.tsx | 22 +- frontend/src/components/home/Services.tsx | 42 ++- frontend/src/components/home/Stats.tsx | 31 ++- frontend/src/components/home/Story.tsx | 49 +++- frontend/src/components/home/Team.tsx | 36 +-- frontend/src/components/home/Testimonials.tsx | 33 +-- frontend/src/components/home/Timeline.tsx | 28 +- frontend/src/components/home/WhyUs.tsx | 38 ++- frontend/src/data/site.ts | 3 + frontend/src/pages/About.tsx | 6 +- frontend/src/pages/Blog.tsx | 17 +- frontend/src/pages/ContactPage.tsx | 11 +- frontend/src/pages/FaqPage.tsx | 6 +- frontend/src/pages/Investment.tsx | 11 +- frontend/src/pages/Projects.tsx | 33 ++- frontend/src/pages/ServicesPage.tsx | 11 +- 39 files changed, 1882 insertions(+), 260 deletions(-) create mode 100644 frontend/src/admin/AdminBar.tsx create mode 100644 frontend/src/admin/AdminContext.tsx create mode 100644 frontend/src/admin/AdminLoginPage.tsx create mode 100644 frontend/src/admin/Editable.tsx create mode 100644 frontend/src/admin/EntityDrawer.tsx create mode 100644 frontend/src/admin/adminClient.ts create mode 100644 frontend/src/admin/entities.ts create mode 100644 frontend/src/components/admin/ImageField.tsx create mode 100644 frontend/src/components/admin/InlineEdit.tsx diff --git a/.gitignore b/.gitignore index 073ce1d..892a7d0 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ Thumbs.db # Database *.sqlite3 *.db + +# تصاویر محلی — از پنل/کنسول MinIO مدیریت می‌شوند +frontend/public/images/ diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index dce1d9a..f7e4a50 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -16,6 +16,9 @@ import { ArticleDetail } from './pages/ArticleDetail'; import { FaqPage } from './pages/FaqPage'; import { ContactPage } from './pages/ContactPage'; import { SiteProvider, useSiteData } from './api'; +import { AdminProvider, useAdmin } from './admin/AdminContext'; +import { AdminBar } from './admin/AdminBar'; +import { AdminLoginPage } from './admin/AdminLoginPage'; function ScrollToTop() { const { pathname } = useLocation(); @@ -35,8 +38,9 @@ function AnimatedRoutes() { animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.28, ease: [0.23, 1, 0.32, 1] }}> - + + } /> } /> } /> } /> @@ -54,6 +58,22 @@ function AnimatedRoutes() { } +function AppChrome() { + const { pathname } = useLocation(); + const { isAuthenticated } = useAdmin(); + const isLoginPage = pathname === '/admin/login'; + + return ( + <> + {!isLoginPage &&
} + + {!isLoginPage &&