mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 22:50:51 +00:00
feat(settings): standardize settings and admin section framing
Introduce a shared SettingsSectionFrame (the settings twin of the admin renderer's SectionFrame) that emits the canonical visible heading + subheading, and route all 19 settings sections through it. Every settings page now shows a real h1 + subtitle in the reference Übersicht style instead of an invisible sr-only title; the section bodies drop their own headings and off-style intro paragraphs (the explanatory copy folds into the frame subtitle). - Route the admin About page through SectionFrame so it carries the same visible heading as every other admin section. - Rename the AI settings section from KI-Auswertung to KI-Anbieter across six locales: the page configures the provider and key, not an analysis. - Add a heading-block spacer to the settings and admin sidebars so the first menu item lines up with the top of the first card. - Remove the always-on core-domains card from Module: a tracking area that can't be turned off doesn't need listing. - Move the proactive-coach control out of Benachrichtigungen into Coach. - Move admin module availability out of the Coach section into its own page: it gates every module, not just the coach. - Give the Layout Insights editor a proper Insights heading. Adds settings.sections.<slug>.subtitle and the new admin keys across all six locales; removes the now-unused module core-domain strings.
This commit is contained in:
1 parent
ae3091df9e
commit
33d7d103da
42 files changed
+822
-802
No files matched your search
@@ -94,18 +94,32 @@ export function AdminSectionRenderer({
|
||||
// v1.18.1 — the former ai-quality, assistant, and coach-feedback
|
||||
// sections fold into one Coach area: surface toggles + operator
|
||||
// config first, then the two feedback-quality tables.
|
||||
// v1.18.6 (W9) — server-wide module availability moved out to its own
|
||||
// `module-availability` section: it gates EVERY module, not just the
|
||||
// coach, so it no longer belongs stacked under Coach.
|
||||
return (
|
||||
<SectionFrame
|
||||
title={t("admin.section.coach.title")}
|
||||
subtitle={t("admin.section.coach.subtitle")}
|
||||
>
|
||||
<AssistantSection />
|
||||
<ModuleAvailabilitySection />
|
||||
<AiServerKeySection />
|
||||
<CoachFeedbackSection />
|
||||
<AiQualitySection />
|
||||
</SectionFrame>
|
||||
);
|
||||
case "module-availability":
|
||||
// v1.18.6 (W9) — operator-side server-wide module on/off, its own
|
||||
// admin section (was stacked under Coach). Reconciled name: the
|
||||
// user-facing "Module" settings pick from what is available here.
|
||||
return (
|
||||
<SectionFrame
|
||||
title={t("admin.section.module-availability.title")}
|
||||
subtitle={t("admin.section.module-availability.subtitle")}
|
||||
>
|
||||
<ModuleAvailabilitySection />
|
||||
</SectionFrame>
|
||||
);
|
||||
case "feedback":
|
||||
return (
|
||||
<SectionFrame
|
||||
@@ -191,12 +205,18 @@ export function AdminSectionRenderer({
|
||||
</SectionFrame>
|
||||
);
|
||||
case "about":
|
||||
// v1.4.36 W4e — About section reused as-is from the settings
|
||||
// surface. The component owns its own heading + cards layout
|
||||
// so no SectionFrame wrapper.
|
||||
// v1.18.6 — the About surface no longer carries the tour-replay card
|
||||
// (consolidated onto Settings → Advanced), so there's nothing to hide.
|
||||
return <AboutSection />;
|
||||
// v1.4.36 W4e — About section reused as-is from the settings surface.
|
||||
// v1.18.6 (W9) — route it through `SectionFrame` like every other admin
|
||||
// section so it gets the same visible heading + subtitle (the one admin
|
||||
// page that was bypassing the frame and showing no heading).
|
||||
return (
|
||||
<SectionFrame
|
||||
title={t("admin.section.about.title")}
|
||||
subtitle={t("admin.section.about.subtitle")}
|
||||
>
|
||||
<AboutSection />
|
||||
</SectionFrame>
|
||||
);
|
||||
default:
|
||||
slug satisfies never;
|
||||
return null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import type { JSX } from "react";
|
||||
import type { JSX, ReactNode } from "react";
|
||||
|
||||
import { AccountSection } from "@/components/settings/account-section";
|
||||
import { AboutSection } from "@/components/settings/about-section";
|
||||
@@ -29,6 +29,9 @@ import {
|
||||
type SettingsSectionSlug,
|
||||
} from "@/components/settings/section-slugs";
|
||||
import { SettingsShell } from "@/components/settings/settings-shell";
|
||||
import { SettingsSectionFrame } from "@/components/settings/settings-section-frame";
|
||||
import { SettingsHubBackLink } from "@/components/settings/settings-hub-back-link";
|
||||
import { ModuleTourTrigger } from "@/components/onboarding/module-tour-trigger";
|
||||
|
||||
/**
|
||||
* Dynamic settings section route. Each of the `SETTINGS_SECTION_SLUGS`
|
||||
@@ -71,6 +74,50 @@ const SECTION_COMPONENTS: Record<
|
||||
advanced: AdvancedSection,
|
||||
};
|
||||
|
||||
// v1.18.6 (W9) — the two Layout-hub child editors render a "← back to hub"
|
||||
// link above their heading. The shared `<SettingsSectionFrame>` exposes a
|
||||
// `topSlot` for exactly this; the link lives here so the section bodies stay
|
||||
// pure card content.
|
||||
const HUB_CHILD_SLUGS: ReadonlySet<SettingsSectionSlug> = new Set([
|
||||
"dashboard",
|
||||
"insights",
|
||||
]);
|
||||
|
||||
/** Optional content rendered above the canonical heading, per slug. */
|
||||
function frameTopSlot(slug: SettingsSectionSlug): ReactNode {
|
||||
if (HUB_CHILD_SLUGS.has(slug)) {
|
||||
return (
|
||||
<SettingsHubBackLink
|
||||
href="/settings/layout"
|
||||
labelKey="settings.sections.layout.backToHub"
|
||||
/>
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Optional inline content rendered at the top-right of the heading row. */
|
||||
function frameHeadingAccessory(slug: SettingsSectionSlug): ReactNode {
|
||||
// v1.18.6 (W9) — the module guided-tour re-entry triggers used to live in
|
||||
// a `justify-end` header inside the section body; they move to the frame's
|
||||
// heading row so the heading itself is the spotlight anchor.
|
||||
if (slug === "gesundheitsakte") {
|
||||
return (
|
||||
<span data-tour-id="export-hero">
|
||||
<ModuleTourTrigger stopId="export" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (slug === "integrations") {
|
||||
return (
|
||||
<span data-tour-id="integrations-hero">
|
||||
<ModuleTourTrigger stopId="integrations" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
interface PageProps {
|
||||
// Next.js 16 made route `params` an async Promise. We `await` it before use.
|
||||
params: Promise<{ section: string }>;
|
||||
@@ -91,8 +138,17 @@ export default async function SettingsSectionPage({ params }: PageProps) {
|
||||
// guards the slug, but a future slug added to `SETTINGS_SECTION_SLUGS`
|
||||
// without a wired component would otherwise crash silently — placeholder
|
||||
// surfaces the gap visually instead.
|
||||
// v1.18.6 (W9) — every section now renders inside the shared
|
||||
// `<SettingsSectionFrame>`, which emits the one visible heading + subtitle
|
||||
// each page must show (the section bodies no longer carry their own).
|
||||
const body = SectionComponent ? (
|
||||
<SectionComponent />
|
||||
<SettingsSectionFrame
|
||||
slug={section}
|
||||
topSlot={frameTopSlot(section)}
|
||||
headingAccessory={frameHeadingAccessory(section)}
|
||||
>
|
||||
<SectionComponent />
|
||||
</SettingsSectionFrame>
|
||||
) : (
|
||||
<SectionPlaceholder slug={section} />
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user