diff --git a/frontend/src/pages/admin/SettingsPage.tsx b/frontend/src/pages/admin/SettingsPage.tsx index ac035f2d..6c751d64 100644 --- a/frontend/src/pages/admin/SettingsPage.tsx +++ b/frontend/src/pages/admin/SettingsPage.tsx @@ -1,5 +1,21 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { + Sliders, + CalendarPlus, + Activity, + Lock, + Shield, + Image as ImageIcon, + Search, + Tags, + BarChart3, + Flag, + Code, + KeyRound, + Webhook, + type LucideIcon, +} from 'lucide-react'; import { Loading } from '../../components/common'; import { useSettingsState, @@ -20,6 +36,17 @@ import { type TabType = 'general' | 'events' | 'status' | 'security' | 'imageSecurity' | 'thumbnails' | 'categories' | 'seo' | 'analytics' | 'moderation' | 'styling' | 'apiTokens' | 'webhooks'; +interface NavItem { + key: TabType; + label: string; + icon: LucideIcon; +} + +interface NavGroup { + label: string; + items: NavItem[]; +} + export const SettingsPage: React.FC = () => { const [activeTab, setActiveTab] = useState('general'); const { t } = useTranslation(); @@ -71,22 +98,54 @@ export const SettingsPage: React.FC = () => { ); } - const tabs: { key: TabType; label: string }[] = [ - { key: 'general', label: t('settings.general.title') }, - { key: 'events', label: t('settings.events.title', 'Event Creation') }, - { key: 'status', label: t('settings.systemStatus.title') }, - { key: 'security', label: t('settings.security.title') }, - { key: 'imageSecurity', label: t('settings.imageSecurity.title', 'Image Protection') }, - { key: 'thumbnails', label: t('settings.thumbnails.title', 'Thumbnails') }, - { key: 'seo', label: t('settings.seo.title', 'SEO & Robots') }, - { key: 'categories', label: t('settings.categories.title') }, - { key: 'analytics', label: t('settings.analytics.title') }, - { key: 'moderation', label: t('settings.moderation.title', 'Moderation') }, - { key: 'styling', label: t('settings.styling.title', 'Custom CSS') }, - { key: 'apiTokens', label: t('settings.apiTokens.title', 'API Tokens') }, - { key: 'webhooks', label: t('settings.webhooks.title', 'Webhooks') }, + // Grouped nav: replaces the previous flat 13-tab horizontal bar that + // overflowed even on 1440px viewports. Categories follow the macOS + // System Settings / Stripe / GitHub pattern — scales to N tabs without + // horizontal scroll, gives visual taxonomy, and surfaces every option. + const navGroups: NavGroup[] = [ + { + label: t('settings.groups.general', 'General'), + items: [ + { key: 'general', label: t('settings.general.title'), icon: Sliders }, + { key: 'events', label: t('settings.events.title', 'Event Creation'), icon: CalendarPlus }, + ], + }, + { + label: t('settings.groups.display', 'Display'), + items: [ + { key: 'categories', label: t('settings.categories.title'), icon: Tags }, + { key: 'thumbnails', label: t('settings.thumbnails.title', 'Thumbnails'), icon: ImageIcon }, + { key: 'styling', label: t('settings.styling.title', 'Custom CSS'), icon: Code }, + ], + }, + { + label: t('settings.groups.privacySecurity', 'Privacy & Security'), + items: [ + { key: 'security', label: t('settings.security.title'), icon: Lock }, + { key: 'imageSecurity', label: t('settings.imageSecurity.title', 'Image Protection'), icon: Shield }, + { key: 'seo', label: t('settings.seo.title', 'SEO & Robots'), icon: Search }, + { key: 'moderation', label: t('settings.moderation.title', 'Moderation'), icon: Flag }, + ], + }, + { + label: t('settings.groups.integrations', 'Integrations'), + items: [ + { key: 'apiTokens', label: t('settings.apiTokens.title', 'API Tokens'), icon: KeyRound }, + { key: 'webhooks', label: t('settings.webhooks.title', 'Webhooks'), icon: Webhook }, + ], + }, + { + label: t('settings.groups.system', 'System'), + items: [ + { key: 'status', label: t('settings.systemStatus.title'), icon: Activity }, + { key: 'analytics', label: t('settings.analytics.title'), icon: BarChart3 }, + ], + }, ]; + const allItems = navGroups.flatMap((g) => g.items); + const activeItem = allItems.find((i) => i.key === activeTab) ?? allItems[0]; + return (
@@ -94,26 +153,90 @@ export const SettingsPage: React.FC = () => {

{t('settings.subtitle')}

- {/* Tab Navigation */} -
- -
+
+ {/* Mobile: native select dropdown — keeps every option reachable + in one tap on touch devices, no horizontal scroll. */} +
+ + +
- {/* Tab Content */} + {/* Desktop: grouped left rail. Sticky so the nav stays visible + while the right pane scrolls through long forms. */} + + +
+ {/* Section heading echoes the active nav item — anchors the user + after they switch, especially after a mobile select change. */} +
+
+ +

+ {activeItem.label} +

+
+
+ + {/* Tab Content */} {activeTab === 'general' && ( { {activeTab === 'apiTokens' && } {activeTab === 'webhooks' && } +
+
); };