feat: integrate section sub-links into UserSettings sidebar

This commit is contained in:
Jannis Braun
2026-03-22 03:18:28 +01:00
parent 537f489432
commit f94958354a
@@ -8,9 +8,43 @@ import { VoicePanel } from './settingsPanels/VoicePanel';
import { PrivacyPanel } from './settingsPanels/PrivacyPanel'; import { PrivacyPanel } from './settingsPanels/PrivacyPanel';
import { ConnectionsPanel } from './settingsPanels/ConnectionsPanel'; import { ConnectionsPanel } from './settingsPanels/ConnectionsPanel';
import { InstancePanel } from './settingsPanels/InstancePanel'; import { InstancePanel } from './settingsPanels/InstancePanel';
import { SettingsSectionsProvider, useSettingsSectionsContext } from './SettingsSectionsContext';
type SettingsTab = 'account' | 'voice' | 'privacy' | 'connections' | 'instance'; type SettingsTab = 'account' | 'voice' | 'privacy' | 'connections' | 'instance';
function SidebarSubLinks() {
const ctx = useSettingsSectionsContext();
if (!ctx || ctx.sections.length === 0) return null;
return (
<div className="overflow-hidden">
{ctx.sections.map((section) => (
<button
key={section.id}
onClick={() => ctx.scrollToSection(section.id)}
className={`w-full text-left pl-6 py-1 text-xs rounded-md transition-colors ${
ctx.activeSection === section.id
? 'text-txt-primary'
: 'text-txt-tertiary hover:text-txt-secondary'
}`}
aria-current={ctx.activeSection === section.id ? 'true' : undefined}
>
{section.label}
</button>
))}
</div>
);
}
function SettingsScrollContainer({ children }: { children: React.ReactNode }) {
const ctx = useSettingsSectionsContext();
return (
<div ref={ctx?.scrollContainerRef} className="flex-1 min-w-0 overflow-y-auto scrollbar-thin py-6">
{children}
</div>
);
}
export function UserSettingsModal() { export function UserSettingsModal() {
const activeModal = useUIStore((s) => s.activeModal); const activeModal = useUIStore((s) => s.activeModal);
const modalData = useUIStore((s) => s.modalData); const modalData = useUIStore((s) => s.modalData);
@@ -61,6 +95,7 @@ export function UserSettingsModal() {
return ( return (
<Modal isOpen={isOpen} onClose={closeModal} size="settings" mobileStyle="fullscreen"> <Modal isOpen={isOpen} onClose={closeModal} size="settings" mobileStyle="fullscreen">
<SettingsSectionsProvider>
<div className="flex h-full"> <div className="flex h-full">
{/* Desktop Sidebar */} {/* Desktop Sidebar */}
<div className="hidden md:flex w-52 flex-shrink-0 flex-col p-4 gap-3"> <div className="hidden md:flex w-52 flex-shrink-0 flex-col p-4 gap-3">
@@ -94,6 +129,7 @@ export function UserSettingsModal() {
<div className="border-t border-white/[0.04] my-2 mx-2" /> <div className="border-t border-white/[0.04] my-2 mx-2" />
<div className="text-[10px] font-semibold text-txt-tertiary uppercase tracking-wider px-3 py-1">Administration</div> <div className="text-[10px] font-semibold text-txt-tertiary uppercase tracking-wider px-3 py-1">Administration</div>
<button onClick={() => handleTabClick('instance')} className={tabClass('instance')}>Instance</button> <button onClick={() => handleTabClick('instance')} className={tabClass('instance')}>Instance</button>
{tab === 'instance' && <SidebarSubLinks />}
</> </>
)} )}
@@ -157,7 +193,7 @@ export function UserSettingsModal() {
{/* Content area (desktop always, mobile only when viewing content) */} {/* Content area (desktop always, mobile only when viewing content) */}
{(!isMobile || mobileView === 'content') && ( {(!isMobile || mobileView === 'content') && (
<div className="flex-1 min-w-0 overflow-y-auto scrollbar-thin py-6"> <SettingsScrollContainer>
<div className="px-6 max-w-[640px] mx-auto"> <div className="px-6 max-w-[640px] mx-auto">
{/* Mobile back button */} {/* Mobile back button */}
{isMobile && ( {isMobile && (
@@ -178,9 +214,10 @@ export function UserSettingsModal() {
{tab === 'connections' && <ConnectionsPanel />} {tab === 'connections' && <ConnectionsPanel />}
{tab === 'instance' && isAdmin && <InstancePanel />} {tab === 'instance' && isAdmin && <InstancePanel />}
</div> </div>
</div> </SettingsScrollContainer>
)} )}
</div> </div>
</SettingsSectionsProvider>
</Modal> </Modal>
); );
} }