fix(settings): fold the About section into the user-card dropdown

Eleven sections on the settings sidebar was one over the comfort
line. About is three small cards (identity, links, update check) that
collectively get read once or twice a year and didn't earn a top-level
slot. Hide it from the in-shell nav and surface it as "About HealthLog"
in the sidebar user-card dropdown (mobile dropdown mirrors). The
`/settings/about` route stays alive so direct links, the public
`/about` permalink, and the dropdown entry continue to resolve.
This commit is contained in:
Marc-André Bombeck committed 2026-05-16 17:59:52 +02:00
1 parent bececda630
commit 0de1e2ebe7
10 files changed
+59 -9

No files matched your search

+1
View File
@@ -169,6 +169,7 @@
"admin": "Admin-Konsole",
"logout": "Abmelden",
"login": "Anmelden",
"about": "Über HealthLog",
"notifications": "Benachrichtigungs-Center",
"theme": "Darstellung",
"themeSystem": "System",
+1
View File
@@ -169,6 +169,7 @@
"admin": "Admin Console",
"logout": "Sign out",
"login": "Sign in",
"about": "About HealthLog",
"notifications": "Notification Center",
"theme": "Appearance",
"themeSystem": "System",
+1
View File
@@ -169,6 +169,7 @@
"admin": "Admin Console",
"logout": "Sign out",
"login": "Iniciar sesión",
"about": "Acerca de HealthLog",
"notifications": "Centro de notificaciones",
"theme": "Apariencia",
"themeSystem": "Sistema",
+1
View File
@@ -169,6 +169,7 @@
"admin": "Admin Console",
"logout": "Sign out",
"login": "Se connecter",
"about": "À propos de HealthLog",
"notifications": "Centre de notifications",
"theme": "Apparence",
"themeSystem": "Système",
+1
View File
@@ -169,6 +169,7 @@
"admin": "Admin Console",
"logout": "Sign out",
"login": "Accedi",
"about": "Informazioni su HealthLog",
"notifications": "Centro notifiche",
"theme": "Aspetto",
"themeSystem": "Sistema",
+1
View File
@@ -169,6 +169,7 @@
"admin": "Admin Console",
"logout": "Sign out",
"login": "Zaloguj się",
"about": "O HealthLog",
"notifications": "Centrum powiadomień",
"theme": "Wygląd",
"themeSystem": "Systemowy",
+12
View File
@@ -8,6 +8,7 @@ import {
ChevronsLeft,
ChevronsRight,
Home,
Info,
Lightbulb,
LogOut,
Monitor,
@@ -143,6 +144,17 @@ function SidebarUserSection({ collapsed }: { collapsed: boolean }) {
{t("nav.notifications")}
</Link>
</DropdownMenuItem>
{/* v1.4.33 IW7 — "About" used to live as its own Settings
section but the three small cards inside (identity / links /
update check) collectively get read once or twice a year, so
the top-level slot has been collapsed into this dropdown. The
route stays alive at `/settings/about`. */}
<DropdownMenuItem asChild>
<Link href="/settings/about" className="cursor-pointer">
<Info className="mr-2 h-4 w-4" />
{t("nav.about")}
</Link>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
{themeIcon}
+10
View File
@@ -3,6 +3,7 @@
import {
Bell,
ChevronDown,
Info,
LogIn,
LogOut,
Monitor,
@@ -82,6 +83,15 @@ export function TopBar() {
{t("nav.notifications")}
</Link>
</DropdownMenuItem>
{/* v1.4.33 IW7 — "About" folded out of Settings into the
user-card dropdown; mobile dropdown mirrors the
desktop sidebar so the entry shows up here too. */}
<DropdownMenuItem asChild>
<Link href="/settings/about" className="cursor-pointer">
<Info className="mr-2 h-4 w-4" />
{t("nav.about")}
</Link>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
{themeIcon}
@@ -80,9 +80,16 @@ describe("SETTINGS_SECTION_SLUGS", () => {
});
describe("<SettingsShell>", () => {
it("renders every section link — once for the mobile strip and once for the desktop sidebar", () => {
it("renders every navigable section link — once for the mobile strip and once for the desktop sidebar", () => {
const html = renderShell({ active: "account" });
for (const slug of SETTINGS_SECTION_SLUGS) {
// v1.4.33 IW7 — the `about` slug is alive as a route
// (`/settings/about` still resolves and `generateStaticParams()`
// still emits the page) but it is hidden from the in-shell nav.
// The user-card dropdown owns the link now. Iterate the visible
// sections list, not the slug list, when asserting on rendered
// markup.
const navigableSlugs = SETTINGS_SECTIONS.map((section) => section.slug);
for (const slug of navigableSlugs) {
const matches = html.match(new RegExp(`href="/settings/${slug}"`, "g"));
// Two renders — mobile strip + desktop sidebar — guarantee the link
// exists in both layouts. Tablet/desktop hide the strip with `md:`,
@@ -90,6 +97,8 @@ describe("<SettingsShell>", () => {
// before media queries resolve.
expect(matches?.length ?? 0).toBe(2);
}
// The hidden `about` slug must NOT appear in the in-shell nav.
expect(html).not.toContain('href="/settings/about"');
});
it("links use the correct `/settings/<slug>` href — regression guard against typos", () => {
@@ -149,7 +158,10 @@ describe("<SettingsShell>", () => {
// entry in the sidebar; the link must be present in both locales.
expect(html).toContain('href="/settings/export"');
expect(html).toContain("Advanced");
expect(html).toContain("About");
// v1.4.33 IW7 — About is no longer in the settings nav; it lives
// in the sidebar user-card dropdown. Route `/settings/about` is
// still alive for direct links.
expect(html).not.toContain('href="/settings/about"');
});
it("resolves every section title via the i18n provider — German", () => {
@@ -172,7 +184,9 @@ describe("<SettingsShell>", () => {
// API & Tokens is identical in both locales (proper noun + ampersand)
expect(html).toContain("API &amp; Tokens");
expect(html).toContain("Erweitert");
expect(html).toContain("Über");
// v1.4.33 IW7 — "Über" (About) section removed from the in-shell
// nav, folded into the sidebar user-card dropdown ("Über HealthLog").
expect(html).not.toContain('href="/settings/about"');
});
it("does NOT surface the raw key when a translation resolves — guards against missing JSON entries", () => {
+13 -5
View File
@@ -20,7 +20,6 @@ import { usePathname } from "next/navigation";
import {
Bell,
Download,
Info,
KeyRound,
Layers,
LayoutDashboard,
@@ -61,9 +60,19 @@ interface SettingsSection {
}
/**
* Source of truth for the section list. Order matches the in-app navigation
* order so the sidebar, mobile strip, and `generateStaticParams()` all line
* up. Don't reorder without updating tests.
* Source of truth for the section list that the settings shell renders
* in its sidebar + mobile chip-strip. Order matches the in-app
* navigation order. Don't reorder without updating tests.
*
* v1.4.33 IW7 — "About" was folded into the sidebar user-card
* dropdown (sidebar-nav.tsx -> "Über HealthLog" / "About HealthLog")
* because its three small cards (identity / links / update check)
* collectively read once or twice a year and didn't earn a top-level
* settings slot. The route `/settings/about` is still alive — the
* slug stays in `SETTINGS_SECTION_SLUGS` so `generateStaticParams()`
* keeps emitting the page — but it no longer appears in the in-page
* navigation. Direct links (the user-card dropdown, the public
* `/about` permalink) continue to resolve to the same component.
*/
export const SETTINGS_SECTIONS: readonly SettingsSection[] = [
{ slug: "account", titleKey: "settings.sections.account.title", icon: User },
@@ -104,7 +113,6 @@ export const SETTINGS_SECTIONS: readonly SettingsSection[] = [
titleKey: "settings.sections.advanced.title",
icon: Settings2,
},
{ slug: "about", titleKey: "settings.sections.about.title", icon: Info },
] as const;
export interface SettingsShellProps {