The single 12-card SettingsPage is replaced by a hub at /settings linking
to three thematic sub-pages mounted via a shared SettingsLayout (Outlet):
/settings SettingsHomePage (3 cards-cluster + PageHelp)
/settings/users UsersSettingsPage (Account, License, DocsContent)
/settings/data DataSettingsPage (Categories, DataManagement,
PriceFetchConsentToggle)
/settings/systems SystemsSettingsPage (Version, UpdateCard,
ChangelogContent, LogViewer)
DocsPage and ChangelogPage are extracted into reusable DocsContent /
ChangelogContent components and the standalone /docs and /changelog
routes become Navigate redirects to preserve external bookmarks and
release-note links. UpdateCard is extracted from the inline updater
block for symmetry and testability.
TokenStoreFallbackBanner is mounted once in SettingsLayout, surfacing
the OS-keychain-fallback warning across the four main routes only.
The two existing /settings/categories/{standard,migrate} sub-routes
stay flat (siblings of SettingsLayout) to keep their focused flows
free of the banner — their internal back-links now point to
/settings/data.
i18n FR/EN gain settings.{home, users, data, systems, backToHome};
docs/architecture.md and CHANGELOG{,.fr}.md updated. Pure refactor of
presentation: no new business logic, no Tauri commands, no SQL
migrations.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
106 lines
3.4 KiB
TypeScript
106 lines
3.4 KiB
TypeScript
import { useTranslation } from "react-i18next";
|
|
import { Link } from "react-router-dom";
|
|
import { Users, Database, Cpu, ChevronRight } from "lucide-react";
|
|
import { PageHelp } from "../../components/shared/PageHelp";
|
|
|
|
interface SectionCard {
|
|
to: string;
|
|
titleKey: string;
|
|
descriptionKey: string;
|
|
Icon: React.ComponentType<{ size?: number }>;
|
|
itemKeys: string[];
|
|
}
|
|
|
|
const SECTIONS: SectionCard[] = [
|
|
{
|
|
to: "/settings/users",
|
|
titleKey: "settings.users.title",
|
|
descriptionKey: "settings.users.description",
|
|
Icon: Users,
|
|
itemKeys: [
|
|
"settings.users.sections.accounts",
|
|
"settings.users.sections.licenses",
|
|
"settings.users.sections.userGuide",
|
|
],
|
|
},
|
|
{
|
|
to: "/settings/data",
|
|
titleKey: "settings.data.title",
|
|
descriptionKey: "settings.data.description",
|
|
Icon: Database,
|
|
itemKeys: [
|
|
"settings.data.sections.categories",
|
|
"settings.data.sections.backup",
|
|
"settings.data.sections.priceFetch",
|
|
],
|
|
},
|
|
{
|
|
to: "/settings/systems",
|
|
titleKey: "settings.systems.title",
|
|
descriptionKey: "settings.systems.description",
|
|
Icon: Cpu,
|
|
itemKeys: [
|
|
"settings.systems.sections.version",
|
|
"settings.systems.sections.update",
|
|
"settings.systems.sections.changelog",
|
|
"settings.systems.sections.logs",
|
|
],
|
|
},
|
|
];
|
|
|
|
export default function SettingsHomePage() {
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="relative flex items-center gap-3">
|
|
<h1 className="text-2xl font-bold">{t("settings.title")}</h1>
|
|
<PageHelp helpKey="settings" />
|
|
</div>
|
|
|
|
<p className="text-sm text-[var(--muted-foreground)]">
|
|
{t("settings.home.intro")}
|
|
</p>
|
|
|
|
<div className="space-y-4">
|
|
{SECTIONS.map(({ to, titleKey, descriptionKey, Icon, itemKeys }) => (
|
|
<Link
|
|
key={to}
|
|
to={to}
|
|
className="block bg-[var(--card)] border border-[var(--border)] rounded-xl p-6 hover:border-[var(--primary)] transition-colors group"
|
|
>
|
|
<div className="flex items-center justify-between gap-4">
|
|
<div className="flex items-start gap-4 flex-1">
|
|
<div className="w-12 h-12 rounded-xl bg-[var(--primary)]/10 flex items-center justify-center text-[var(--primary)] shrink-0">
|
|
<Icon size={22} />
|
|
</div>
|
|
<div className="flex-1 space-y-2">
|
|
<div>
|
|
<h2 className="text-lg font-semibold">{t(titleKey)}</h2>
|
|
<p className="text-sm text-[var(--muted-foreground)]">
|
|
{t(descriptionKey)}
|
|
</p>
|
|
</div>
|
|
<ul className="flex flex-wrap gap-2 text-xs text-[var(--muted-foreground)]">
|
|
{itemKeys.map((key) => (
|
|
<li
|
|
key={key}
|
|
className="px-2 py-0.5 rounded-full bg-[var(--background)] border border-[var(--border)]"
|
|
>
|
|
{t(key)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<ChevronRight
|
|
size={18}
|
|
className="text-[var(--muted-foreground)] group-hover:text-[var(--primary)] transition-colors shrink-0"
|
|
/>
|
|
</div>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|