Add a static images manager and polish dashboard layout and fonts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-16 23:56:17 +03:30
co-authored by Cursor
parent e79211e3cd
commit b9024ad77a
57 changed files with 2025 additions and 122 deletions
+128
View File
@@ -69,6 +69,7 @@ const en = {
'nav.instructions.settings': 'Settings',
'nav.website': 'Website',
'nav.website.overview': 'Overview',
'nav.website.staticImages': 'Static Images',
'nav.website.sliders': 'Sliders',
'nav.website.specialCategories': 'Special Categories',
'nav.website.specialBrands': 'Special Brands',
@@ -82,6 +83,7 @@ const en = {
'nav.logout': 'Logout',
'header.toggleMenu': 'Toggle menu',
'header.closeMenu': 'Close menu',
'header.title': 'Admin Dashboard',
'header.messages': 'Messages',
'header.notifications': 'Notifications',
@@ -1252,6 +1254,9 @@ const en = {
'portfolio.details.galleryImage': 'View gallery image {index}',
'website.page.subtitle': 'Manage public website content, forms, and customer-facing settings.',
'website.card.staticImages.desc':
'Replace named website images (heroes, banners, galleries) without a deploy.',
'website.card.staticImages.link': 'Manage images',
'website.card.sliders.desc': 'Manage homepage banner sliders and promotional image carousels.',
'website.card.sliders.link': 'Manage sliders',
'website.card.specialCategories.desc':
@@ -1325,6 +1330,63 @@ const en = {
'website.sliders.modal.linkOptional': 'Link URL (optional)',
'website.sliders.modal.addSlide': 'Add slide',
'website.staticImages.subtitle':
'Websites load these by key from GET /tenants/{domain}/website/static-images',
'website.staticImages.loading': 'Loading static images...',
'website.staticImages.empty': 'No image slots yet for this website.',
'website.staticImages.emptyPage': 'No static images on this page yet.',
'website.staticImages.errorLoad': 'Unable to load static images.',
'website.staticImages.errorCreate': 'Unable to create image slot.',
'website.staticImages.errorUpdate': 'Unable to update image slot.',
'website.staticImages.errorDelete': 'Unable to delete image slot.',
'website.staticImages.errorUpload': 'Unable to upload image.',
'website.staticImages.errorAddImage': 'Unable to save image.',
'website.staticImages.errorRemoveImage': 'Unable to remove image.',
'website.staticImages.toastCreated': 'Image slot created.',
'website.staticImages.toastUpdated': 'Image slot updated.',
'website.staticImages.toastDeleted': 'Image slot deleted.',
'website.staticImages.toastImageSaved': 'Image saved.',
'website.staticImages.toastImageRemoved': 'Image removed.',
'website.staticImages.addSlot': 'Add image slot',
'website.staticImages.createTitle': 'Add image slot',
'website.staticImages.editTitle': 'Edit image slot',
'website.staticImages.deleteTitle': 'Delete image slot',
'website.staticImages.deleteMessage':
'Delete slot {label}? The website placeholder will have no image until you add one again.',
'website.staticImages.addImage': 'Add image',
'website.staticImages.replaceImage': 'Replace image',
'website.staticImages.removeImage': 'Remove image',
'website.staticImages.removeImageTitle': 'Remove image',
'website.staticImages.removeImageMessage': 'Remove this image from the slot?',
'website.staticImages.slotLabel': 'Label',
'website.staticImages.slotLabelPlaceholder': 'e.g. Home hero',
'website.staticImages.slotKey': 'Key (matches website placeholder)',
'website.staticImages.kind': 'Type',
'website.staticImages.page': 'Page',
'website.staticImages.pageHome': 'Home',
'website.staticImages.pageProducts': 'Products',
'website.staticImages.pageProduct': 'Product',
'website.staticImages.pageCategories': 'Categories',
'website.staticImages.pageBrands': 'Brands',
'website.staticImages.pageBlog': 'Blog',
'website.staticImages.pageAbout': 'About',
'website.staticImages.pageContact': 'Contact',
'website.staticImages.kindSingle': 'Single image',
'website.staticImages.kindList': 'List (add more)',
'website.staticImages.kindFixed': '{count} images',
'website.staticImages.itemCount': 'Number of images',
'website.staticImages.itemCountPlaceholder': 'Empty = add more freely',
'website.staticImages.itemCountHint': 'e.g. 2 for a two-banner row. Leave empty for an unlimited list.',
'website.staticImages.aspectRatio': 'Aspect ratio',
'website.staticImages.recommendedWidth': 'Recommended width (px)',
'website.staticImages.cropHint': '{ratio} recommended',
'website.staticImages.titleFa': 'Title (FA)',
'website.staticImages.titleEn': 'Title (EN)',
'website.staticImages.titleFaPlaceholder': 'Persian title',
'website.staticImages.titleEnPlaceholder': 'English title',
'website.staticImages.subtext': 'Subtext',
'website.staticImages.subtextPlaceholder': 'Optional caption under the title',
'website.specialCategories.subtitle':
'Curate featured product categories into groups for your website homepage.',
'website.specialCategories.loading': 'Loading special category groups...',
@@ -1542,6 +1604,7 @@ const en = {
'title.editPortfolio': 'Edit Portfolio',
'title.portfolioDetails': 'Portfolio Details',
'title.website': 'Website',
'title.staticImages': 'Static Images',
'title.sliders': 'Sliders',
'title.specialCategories': 'Special Categories',
'title.specialBrands': 'Special Brands',
@@ -1922,6 +1985,7 @@ const fa: Record<MessageKey, string> = {
'nav.instructions.settings': 'تنظیمات',
'nav.website': 'وب‌سایت',
'nav.website.overview': 'نمای کلی',
'nav.website.staticImages': 'تصاویر ثابت',
'nav.website.sliders': 'اسلایدرها',
'nav.website.specialCategories': 'دسته‌های ویژه',
'nav.website.specialBrands': 'برندهای ویژه',
@@ -1935,6 +1999,7 @@ const fa: Record<MessageKey, string> = {
'nav.logout': 'خروج',
'header.toggleMenu': 'باز و بسته کردن منو',
'header.closeMenu': 'بستن منو',
'header.title': 'پنل مدیریت',
'header.messages': 'پیام‌ها',
'header.notifications': 'اعلان‌ها',
@@ -3105,6 +3170,9 @@ const fa: Record<MessageKey, string> = {
'website.page.subtitle':
'محتوای عمومی وب‌سایت، فرم‌ها و تنظیمات مشتری‌محور را مدیریت کنید.',
'website.card.staticImages.desc':
'تصاویر نام‌گذاری‌شده وب‌سایت (هیرو، بنر، گالری) را بدون دیپلوی عوض کنید.',
'website.card.staticImages.link': 'مدیریت تصاویر',
'website.card.sliders.desc': 'اسلایدرهای بنر صفحه اصلی و کاروسل‌های تبلیغاتی را مدیریت کنید.',
'website.card.sliders.link': 'مدیریت اسلایدرها',
'website.card.specialCategories.desc':
@@ -3177,6 +3245,63 @@ const fa: Record<MessageKey, string> = {
'website.sliders.modal.linkOptional': 'آدرس لینک (اختیاری)',
'website.sliders.modal.addSlide': 'افزودن اسلاید',
'website.staticImages.subtitle':
'وب‌سایت‌ها این تصاویر را با کلید از GET /tenants/{domain}/website/static-images می‌خوانند',
'website.staticImages.loading': 'در حال بارگذاری تصاویر ثابت...',
'website.staticImages.empty': 'هنوز اسلاتی برای این وب‌سایت نیست.',
'website.staticImages.emptyPage': 'در این صفحه هنوز تصویر ثابتی نیست.',
'website.staticImages.errorLoad': 'بارگذاری تصاویر ثابت ممکن نشد.',
'website.staticImages.errorCreate': 'ساخت اسلات تصویر ممکن نشد.',
'website.staticImages.errorUpdate': 'به‌روزرسانی اسلات ممکن نشد.',
'website.staticImages.errorDelete': 'حذف اسلات ممکن نشد.',
'website.staticImages.errorUpload': 'آپلود تصویر ممکن نشد.',
'website.staticImages.errorAddImage': 'ذخیره تصویر ممکن نشد.',
'website.staticImages.errorRemoveImage': 'حذف تصویر ممکن نشد.',
'website.staticImages.toastCreated': 'اسلات تصویر ساخته شد.',
'website.staticImages.toastUpdated': 'اسلات تصویر به‌روز شد.',
'website.staticImages.toastDeleted': 'اسلات تصویر حذف شد.',
'website.staticImages.toastImageSaved': 'تصویر ذخیره شد.',
'website.staticImages.toastImageRemoved': 'تصویر حذف شد.',
'website.staticImages.addSlot': 'افزودن اسلات تصویر',
'website.staticImages.createTitle': 'افزودن اسلات تصویر',
'website.staticImages.editTitle': 'ویرایش اسلات تصویر',
'website.staticImages.deleteTitle': 'حذف اسلات تصویر',
'website.staticImages.deleteMessage':
'اسلات {label} حذف شود؟ تا وقتی تصویر جدیدی نگذارید، جای‌نگهدار وب‌سایت خالی می‌ماند.',
'website.staticImages.addImage': 'افزودن تصویر',
'website.staticImages.replaceImage': 'جایگزینی تصویر',
'website.staticImages.removeImage': 'حذف تصویر',
'website.staticImages.removeImageTitle': 'حذف تصویر',
'website.staticImages.removeImageMessage': 'این تصویر از اسلات حذف شود؟',
'website.staticImages.slotLabel': 'برچسب',
'website.staticImages.slotLabelPlaceholder': 'مثلاً: هیرو صفحه اصلی',
'website.staticImages.slotKey': 'کلید (مطابق جای‌نگهدار وب‌سایت)',
'website.staticImages.kind': 'نوع',
'website.staticImages.page': 'صفحه',
'website.staticImages.pageHome': 'خانه',
'website.staticImages.pageProducts': 'محصولات',
'website.staticImages.pageProduct': 'محصول',
'website.staticImages.pageCategories': 'دسته‌بندی‌ها',
'website.staticImages.pageBrands': 'برندها',
'website.staticImages.pageBlog': 'بلاگ',
'website.staticImages.pageAbout': 'درباره ما',
'website.staticImages.pageContact': 'تماس',
'website.staticImages.kindSingle': 'یک تصویر',
'website.staticImages.kindList': 'فهرست (قابل افزودن)',
'website.staticImages.kindFixed': '{count} تصویر',
'website.staticImages.itemCount': 'تعداد تصویر',
'website.staticImages.itemCountPlaceholder': 'خالی = افزودن آزاد',
'website.staticImages.itemCountHint': 'مثلاً ۲ برای ردیف دو بنر. خالی بگذارید تا فهرست نامحدود باشد.',
'website.staticImages.aspectRatio': 'نسبت تصویر',
'website.staticImages.recommendedWidth': 'عرض پیشنهادی (پیکسل)',
'website.staticImages.cropHint': 'نسبت {ratio} توصیه می‌شود',
'website.staticImages.titleFa': 'عنوان (فارسی)',
'website.staticImages.titleEn': 'عنوان (انگلیسی)',
'website.staticImages.titleFaPlaceholder': 'عنوان فارسی',
'website.staticImages.titleEnPlaceholder': 'English title',
'website.staticImages.subtext': 'متن فرعی',
'website.staticImages.subtextPlaceholder': 'متن کوتاه زیر عنوان (اختیاری)',
'website.specialCategories.subtitle':
'دسته‌بندی‌های ویژه محصول را برای صفحه اصلی وب‌سایت در گروه‌ها گردآوری کنید.',
'website.specialCategories.loading': 'در حال بارگذاری گروه‌های دسته ویژه...',
@@ -3394,6 +3519,7 @@ const fa: Record<MessageKey, string> = {
'title.editPortfolio': 'ویرایش نمونه کار',
'title.portfolioDetails': 'جزئیات نمونه کار',
'title.website': 'وب‌سایت',
'title.staticImages': 'تصاویر ثابت',
'title.sliders': 'اسلایدرها',
'title.specialCategories': 'دسته‌های ویژه',
'title.specialBrands': 'برندهای ویژه',
@@ -3754,6 +3880,7 @@ const BREADCRUMB_LABEL_KEYS: Record<string, MessageKey> = {
'Edit Video': 'bc.editVideo',
'Video Details': 'bc.videoDetails',
Website: 'nav.website',
'Static Images': 'nav.website.staticImages',
Sliders: 'nav.website.sliders',
'Special Categories': 'nav.website.specialCategories',
'Special Brands': 'nav.website.specialBrands',
@@ -3867,6 +3994,7 @@ export function getBusinessRouteTitleRules(locale: DashboardLocale): RouteTitleR
{ match: '/portfolios/categories', labels: [t('title.portfolios'), t('title.categories')] },
{ match: '/portfolios/settings', labels: [t('title.portfolios'), t('title.settings')] },
{ match: '/portfolios', labels: [t('title.portfolios')] },
{ match: '/website/static-images', labels: [t('title.website'), t('title.staticImages')] },
{ match: '/website/sliders', labels: [t('title.website'), t('title.sliders')] },
{
match: '/website/special-categories',