SettingsSection now carries titleKey/descriptionKey instead of title/description, and the sidebar and content pane resolve them. The section arrays are module-level consts holding JSX content, so they cannot call a hook — the data holds keys and the renderers translate. Sidebar search matches the RESOLVED words, so it works in the language on screen. Capital K in titleKey is load-bearing: docs-check-settings.ts greps key:\s*'…' for route segments, and a lowercase title_key would have fed it twenty bogus paths. Verified 0 bogus, 26 declared, 20 offered, 0 missing. Section titles now share one key with the Spotlight rows that name the same section, per 'one key per meaning'. Two casings had to converge, so Settings shows Spotlight's: 'Change Password' now reads 'Change password'. Settings sidebar search placeholder was 'Search...'; it is now 'Search settings…', which is what the skeleton catalog already said and what distinguishes it from the global Spotlight.
99 lines
3.0 KiB
TypeScript
99 lines
3.0 KiB
TypeScript
import { useMemo } from 'react';
|
|
import { User, Lock, Globe, KeyRound, LayoutGrid, Volume2 } from 'lucide-react';
|
|
import type { LayoutNode, PanelComponents } from 'officerdev';
|
|
import { WorkspaceLayout } from 'officerdev';
|
|
|
|
import { SettingsRoute, createSettingsPanelComponents, type SettingsSection } from '../SettingsPanel';
|
|
import { UserData } from './UserData';
|
|
import { ChangePassword } from './ChangePassword';
|
|
import { ApiKeys } from './ApiKeys';
|
|
import { Languages } from './Languages';
|
|
import { DockSettings } from './DockSettings';
|
|
import { VoicePreference } from './VoicePreference';
|
|
|
|
const BASE_PATH = '/settings/profile';
|
|
|
|
const sections: SettingsSection[] = [
|
|
{
|
|
key: 'profile',
|
|
icon: User,
|
|
titleKey: 'settings.sections.profile.label',
|
|
descriptionKey: 'settings.sections.profile.description',
|
|
content: <UserData />,
|
|
},
|
|
{
|
|
key: 'change-password',
|
|
icon: Lock,
|
|
titleKey: 'settings.sections.changePassword.label',
|
|
descriptionKey: 'settings.sections.changePassword.description',
|
|
content: <ChangePassword />,
|
|
},
|
|
// Beside the password rather than under Integrations, where it was until 2026-08-21. A key is not an
|
|
// integration with anything — it is a second way to present the authority this account already has, and
|
|
// the permission registry says so: `/api-keys` is `core`, sitting with `/user` and `/dock`. Somebody
|
|
// looking for it went to user management and then to profile, which is where it should have been.
|
|
{
|
|
key: 'api-keys',
|
|
icon: KeyRound,
|
|
titleKey: 'settings.sections.apiKeys.label',
|
|
descriptionKey: 'settings.sections.apiKeys.description',
|
|
content: <ApiKeys />,
|
|
},
|
|
{
|
|
key: 'languages',
|
|
icon: Globe,
|
|
titleKey: 'settings.sections.languages.label',
|
|
descriptionKey: 'settings.sections.languages.description',
|
|
content: <Languages />,
|
|
},
|
|
{
|
|
key: 'voice',
|
|
icon: Volume2,
|
|
titleKey: 'settings.sections.voice.label',
|
|
descriptionKey: 'settings.sections.voice.description',
|
|
content: <VoicePreference />,
|
|
},
|
|
{
|
|
key: 'dock',
|
|
icon: LayoutGrid,
|
|
titleKey: 'settings.sections.dock.label',
|
|
descriptionKey: 'settings.sections.dock.description',
|
|
content: <DockSettings />,
|
|
},
|
|
];
|
|
|
|
const { Sidebar, Content } = createSettingsPanelComponents({
|
|
basePath: BASE_PATH,
|
|
sidebarIcon: User,
|
|
sidebarLabelKey: 'settings.nav.profile',
|
|
sections,
|
|
});
|
|
|
|
const layout: LayoutNode = {
|
|
type: 'group',
|
|
id: 'profile-root',
|
|
direction: 'horizontal',
|
|
children: [
|
|
{ node: { type: 'panel', id: 'profile-left', appType: null }, size: 20 },
|
|
{ node: { type: 'panel', id: 'profile-right', appType: null }, size: 80 },
|
|
],
|
|
};
|
|
|
|
export const ProfileSettings = () => {
|
|
const panelComponents: PanelComponents = useMemo(
|
|
() => ({
|
|
'profile-left': Sidebar,
|
|
'profile-right': Content,
|
|
}),
|
|
[],
|
|
);
|
|
|
|
return (
|
|
<SettingsRoute basePath={BASE_PATH} sections={sections}>
|
|
<div className="h-full w-full pt-2">
|
|
<WorkspaceLayout layout={layout} onLayoutChange={() => {}} components={panelComponents} />
|
|
</div>
|
|
</SettingsRoute>
|
|
);
|
|
};
|