import { useT } from '@app/i18n' import { type Icon, IconExternalLink as SquareArrowOutUpRight, IconX as X } from '@tabler/icons-react' import { Fragment, type ReactNode, useEffect, useRef, useState } from 'react' import { Link } from 'react-router-dom' export interface SettingsSection { id: string label: string /** Row glyph, mirroring the reference settings dialog. */ icon?: Icon /** Rows sharing a group sit under one small caption. */ group?: string /** Rows that leave the dialog for a full page instead of switching panes. */ href?: string } export interface SettingsModalShellProps { /** Nav heading, e.g. 用户设置 / 社区设置. Also the dialog's accessible name. */ title: string sections: SettingsSection[] active: string onSelect: (id: string) => void onClose: () => void children: ReactNode /** Replaces the section list while a section runs its own sub-navigation. */ navOverride?: ReactNode /** Swap key for the content pane (defaults to the active section id). */ contentToken?: string } /** * The large two-column settings overlay shared by every settings surface, so a * community's settings cannot drift away from the user's own in size or spacing. * * The backdrop deliberately does NOT close: these forms hold unsaved edits * across many sections, and click-away is far too lossy to be the dismiss path. */ export function SettingsModalShell({ title, sections, active, onSelect, onClose, children, navOverride, contentToken, }: SettingsModalShellProps) { const { t } = useT() useEffect(() => { const onKey = (event: KeyboardEvent) => { if (event.key === 'Escape') onClose() } window.addEventListener('keydown', onKey) return () => window.removeEventListener('keydown', onKey) }, [onClose]) const activeSection = sections.find((item) => item.id === active && !item.href) ?? sections.find((item) => !item.href) ?? sections[0] return (