Refactor theme settings with two collapsible sections

- Quick Presets: collapsible section with 8 theme presets
- Custom Colors: collapsible section with all color pickers
- Added translations for quickPresets, customColors in all locales (ru, en, zh, fa)
- Chevron icon rotates when section is expanded
- Preview section moved inside Custom Colors
This commit is contained in:
PEDZEO
2026-01-21 02:11:39 +03:00
parent bf0a43384b
commit 215a65dbae
5 changed files with 213 additions and 198 deletions

View File

@@ -1221,6 +1221,10 @@
"theme": { "theme": {
"colors": "Theme Colors", "colors": "Theme Colors",
"reset": "Reset", "reset": "Reset",
"quickPresets": "Quick Presets",
"quickPresetsDescription": "Choose a ready-made color scheme",
"customColors": "Custom Colors",
"customColorsDescription": "Customize each color individually",
"accent": "Accent Color", "accent": "Accent Color",
"accentDescription": "Main brand color for buttons, links and interactive elements", "accentDescription": "Main brand color for buttons, links and interactive elements",
"darkTheme": "Dark Theme", "darkTheme": "Dark Theme",

View File

@@ -700,6 +700,10 @@
"theme": { "theme": {
"colors": "رنگ‌های تم", "colors": "رنگ‌های تم",
"reset": "بازنشانی", "reset": "بازنشانی",
"quickPresets": "پیش‌تنظیمات سریع",
"quickPresetsDescription": "یک طرح رنگی آماده انتخاب کنید",
"customColors": "رنگ‌های سفارشی",
"customColorsDescription": "هر رنگ را جداگانه سفارشی کنید",
"accent": "رنگ تأکیدی", "accent": "رنگ تأکیدی",
"accentDescription": "رنگ اصلی برند برای دکمه‌ها، لینک‌ها و عناصر تعاملی", "accentDescription": "رنگ اصلی برند برای دکمه‌ها، لینک‌ها و عناصر تعاملی",
"darkTheme": "تم تیره", "darkTheme": "تم تیره",

View File

@@ -1379,6 +1379,10 @@
"theme": { "theme": {
"colors": "Цвета темы", "colors": "Цвета темы",
"reset": "Сбросить", "reset": "Сбросить",
"quickPresets": "Быстрые пресеты",
"quickPresetsDescription": "Выберите готовую цветовую схему",
"customColors": "Ручная настройка",
"customColorsDescription": "Настройте каждый цвет отдельно",
"accent": "Акцентный цвет", "accent": "Акцентный цвет",
"accentDescription": "Основной цвет бренда для кнопок, ссылок и интерактивных элементов", "accentDescription": "Основной цвет бренда для кнопок, ссылок и интерактивных элементов",
"darkTheme": "Тёмная тема", "darkTheme": "Тёмная тема",

View File

@@ -701,6 +701,10 @@
"theme": { "theme": {
"colors": "主题颜色", "colors": "主题颜色",
"reset": "重置", "reset": "重置",
"quickPresets": "快速预设",
"quickPresetsDescription": "选择现成的配色方案",
"customColors": "自定义颜色",
"customColorsDescription": "单独自定义每种颜色",
"accent": "主题色", "accent": "主题色",
"accentDescription": "用于按钮、链接和交互元素的主品牌颜色", "accentDescription": "用于按钮、链接和交互元素的主品牌颜色",
"darkTheme": "深色主题", "darkTheme": "深色主题",

View File

@@ -1496,9 +1496,33 @@ export default function AdminSettings() {
</p> </p>
</div> </div>
{/* Quick Presets */} {/* Quick Presets - Collapsible */}
<div className="pb-6 border-b border-dark-700/50"> <div className="border-b border-dark-700/50">
<label className="label mb-3">Быстрые пресеты</label> <button
onClick={() => toggleThemeSection('presets')}
className="w-full flex items-center justify-between py-3 text-left"
>
<div className="flex items-center gap-3">
<div className="flex gap-0.5">
{THEME_PRESETS.slice(0, 4).map((preset) => (
<div
key={preset.name}
className="w-3 h-3 rounded-full"
style={{ backgroundColor: preset.colors.accent }}
/>
))}
</div>
<div>
<span className="text-sm font-medium text-dark-200">{t('theme.quickPresets')}</span>
<p className="text-xs text-dark-500">{t('theme.quickPresetsDescription')}</p>
</div>
</div>
<div className={`transition-transform ${expandedThemeSections.has('presets') ? 'rotate-180' : ''}`}>
<ChevronDownIcon />
</div>
</button>
{expandedThemeSections.has('presets') && (
<div className="pb-4">
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2"> <div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
{THEME_PRESETS.map((preset) => ( {THEME_PRESETS.map((preset) => (
<button <button
@@ -1524,49 +1548,54 @@ export default function AdminSettings() {
<div <div
className="w-3 h-3 rounded" className="w-3 h-3 rounded"
style={{ backgroundColor: preset.colors.darkSurface }} style={{ backgroundColor: preset.colors.darkSurface }}
title="Surface"
/> />
<div <div
className="w-3 h-3 rounded" className="w-3 h-3 rounded"
style={{ backgroundColor: preset.colors.success }} style={{ backgroundColor: preset.colors.success }}
title="Success"
/> />
<div <div
className="w-3 h-3 rounded" className="w-3 h-3 rounded"
style={{ backgroundColor: preset.colors.warning }} style={{ backgroundColor: preset.colors.warning }}
title="Warning"
/> />
<div <div
className="w-3 h-3 rounded" className="w-3 h-3 rounded"
style={{ backgroundColor: preset.colors.error }} style={{ backgroundColor: preset.colors.error }}
title="Error"
/> />
</div> </div>
</button> </button>
))} ))}
</div> </div>
<p className="text-xs text-dark-500 mt-2"> </div>
Выберите готовую цветовую схему. Изменения сохраняются автоматически. )}
</p>
</div> </div>
{/* Accent Color - Collapsible */} {/* Custom Colors - Collapsible */}
<div className="border-b border-dark-700/50 pb-4"> <div className="border-b border-dark-700/50">
<button <button
onClick={() => toggleThemeSection('accent')} onClick={() => toggleThemeSection('custom')}
className="w-full flex items-center justify-between py-2 text-left" className="w-full flex items-center justify-between py-3 text-left"
> >
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div <div className="flex gap-0.5">
className="w-5 h-5 rounded-full border-2 border-dark-600" <div className="w-3 h-3 rounded-full" style={{ backgroundColor: themeColors?.accent || DEFAULT_THEME_COLORS.accent }} />
style={{ backgroundColor: themeColors?.accent || DEFAULT_THEME_COLORS.accent }} <div className="w-3 h-3 rounded-full" style={{ backgroundColor: themeColors?.darkBackground || DEFAULT_THEME_COLORS.darkBackground }} />
/> <div className="w-3 h-3 rounded-full" style={{ backgroundColor: themeColors?.success || DEFAULT_THEME_COLORS.success }} />
<span className="text-sm font-medium text-dark-200">{t('theme.accent')}</span> <div className="w-3 h-3 rounded-full" style={{ backgroundColor: themeColors?.error || DEFAULT_THEME_COLORS.error }} />
</div> </div>
<div>
<span className="text-sm font-medium text-dark-200">{t('theme.customColors')}</span>
<p className="text-xs text-dark-500">{t('theme.customColorsDescription')}</p>
</div>
</div>
<div className={`transition-transform ${expandedThemeSections.has('custom') ? 'rotate-180' : ''}`}>
<ChevronDownIcon /> <ChevronDownIcon />
</div>
</button> </button>
{expandedThemeSections.has('accent') && ( {expandedThemeSections.has('custom') && (
<div className="mt-3"> <div className="pb-4 space-y-6">
{/* Accent Color */}
<div>
<h4 className="text-sm font-medium text-dark-300 mb-3">{t('theme.accent')}</h4>
<ColorPicker <ColorPicker
label={t('theme.accent')} label={t('theme.accent')}
description={t('theme.accentDescription')} description={t('theme.accentDescription')}
@@ -1575,23 +1604,14 @@ export default function AdminSettings() {
disabled={updateColorsMutation.isPending} disabled={updateColorsMutation.isPending}
/> />
</div> </div>
)}
</div>
{/* Dark Theme Section - Collapsible */} {/* Dark Theme */}
<div className="border-b border-dark-700/50 pb-4"> <div>
<button <h4 className="text-sm font-medium text-dark-300 mb-3 flex items-center gap-2">
onClick={() => toggleThemeSection('dark')}
className="w-full flex items-center justify-between py-2 text-left"
>
<div className="flex items-center gap-3">
<MoonIcon /> <MoonIcon />
<span className="text-sm font-medium text-dark-200">{t('theme.darkTheme')}</span> {t('theme.darkTheme')}
</div> </h4>
<ChevronDownIcon /> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
</button>
{expandedThemeSections.has('dark') && (
<div className="mt-3 grid grid-cols-1 sm:grid-cols-2 gap-4">
<ColorPicker <ColorPicker
label={t('theme.background')} label={t('theme.background')}
value={themeColors?.darkBackground || DEFAULT_THEME_COLORS.darkBackground} value={themeColors?.darkBackground || DEFAULT_THEME_COLORS.darkBackground}
@@ -1617,23 +1637,15 @@ export default function AdminSettings() {
disabled={updateColorsMutation.isPending} disabled={updateColorsMutation.isPending}
/> />
</div> </div>
)}
</div> </div>
{/* Light Theme Section - Collapsible */} {/* Light Theme */}
<div className="border-b border-dark-700/50 pb-4"> <div>
<button <h4 className="text-sm font-medium text-dark-300 mb-3 flex items-center gap-2">
onClick={() => toggleThemeSection('light')}
className="w-full flex items-center justify-between py-2 text-left"
>
<div className="flex items-center gap-3">
<SunIcon /> <SunIcon />
<span className="text-sm font-medium text-dark-200">{t('theme.lightTheme')}</span> {t('theme.lightTheme')}
</div> </h4>
<ChevronDownIcon /> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
</button>
{expandedThemeSections.has('light') && (
<div className="mt-3 grid grid-cols-1 sm:grid-cols-2 gap-4">
<ColorPicker <ColorPicker
label={t('theme.background')} label={t('theme.background')}
value={themeColors?.lightBackground || DEFAULT_THEME_COLORS.lightBackground} value={themeColors?.lightBackground || DEFAULT_THEME_COLORS.lightBackground}
@@ -1659,27 +1671,12 @@ export default function AdminSettings() {
disabled={updateColorsMutation.isPending} disabled={updateColorsMutation.isPending}
/> />
</div> </div>
)}
</div> </div>
{/* Status Colors - Collapsible */} {/* Status Colors */}
<div className="border-b border-dark-700/50 pb-4"> <div>
<button <h4 className="text-sm font-medium text-dark-300 mb-3">{t('theme.statusColors')}</h4>
onClick={() => toggleThemeSection('status')} <div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
className="w-full flex items-center justify-between py-2 text-left"
>
<div className="flex items-center gap-3">
<div className="flex gap-1">
<div className="w-3 h-3 rounded-full" style={{ backgroundColor: themeColors?.success || DEFAULT_THEME_COLORS.success }} />
<div className="w-3 h-3 rounded-full" style={{ backgroundColor: themeColors?.warning || DEFAULT_THEME_COLORS.warning }} />
<div className="w-3 h-3 rounded-full" style={{ backgroundColor: themeColors?.error || DEFAULT_THEME_COLORS.error }} />
</div>
<span className="text-sm font-medium text-dark-200">{t('theme.statusColors')}</span>
</div>
<ChevronDownIcon />
</button>
{expandedThemeSections.has('status') && (
<div className="mt-3 grid grid-cols-1 sm:grid-cols-3 gap-4">
<ColorPicker <ColorPicker
label={t('theme.success')} label={t('theme.success')}
value={themeColors?.success || DEFAULT_THEME_COLORS.success} value={themeColors?.success || DEFAULT_THEME_COLORS.success}
@@ -1699,7 +1696,6 @@ export default function AdminSettings() {
disabled={updateColorsMutation.isPending} disabled={updateColorsMutation.isPending}
/> />
</div> </div>
)}
</div> </div>
{/* Preview */} {/* Preview */}
@@ -1714,6 +1710,9 @@ export default function AdminSettings() {
</div> </div>
</div> </div>
</div> </div>
)}
</div>
</div>
</div> </div>
{/* Search */} {/* Search */}