mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 14:32:03 +00:00
Merge v1.25.3: channels into notifications + Darstellung appearance hub
This commit is contained in:
commit
7eca388f56
18 files changed
+347
-188
No files matched your search
@@ -63,7 +63,10 @@ export function VorsorgeSettings() {
|
||||
// `<section>` blocks with `text-sm` headings.
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<SettingsCard>
|
||||
{/* v1.25.3 — `id="vorsorge-view"` + `scroll-mt-28` so the Appearance hub
|
||||
deep-link (`/settings/vorsorge#vorsorge-view`) lands on this card
|
||||
below the sticky page header, mirroring the labs/illness anchors. */}
|
||||
<SettingsCard id="vorsorge-view" className="scroll-mt-28">
|
||||
<SettingsCardHeader
|
||||
icon={LayoutGrid}
|
||||
title={t("moduleList.viewHeading")}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
/**
|
||||
* v1.17.1 (F-2) — the "Layout & Personalization" hub.
|
||||
* v1.17.1 (F-2) — the "Appearance" hub (slug stays `layout`).
|
||||
*
|
||||
* The hub is the single front door for the four personalization editors.
|
||||
* It must link to each of them with consistent framing so the concept
|
||||
* reads as one home rather than four scattered settings sections.
|
||||
* The hub is the single front door for every view/arrangement surface. It must
|
||||
* link to each with consistent framing so "how my app looks" reads as one home
|
||||
* rather than scattered settings sections.
|
||||
*
|
||||
* v1.25.3 — the hub widened from 2 links (dashboard + insights) to 6: it now
|
||||
* also deep-links to the view/sort/order cards of medications, labs, the
|
||||
* illness journal, and checkups. Those cards stay on their own module pages;
|
||||
* the hub only indexes them via anchor deep-links.
|
||||
*/
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
@@ -20,26 +25,34 @@ function render(locale: "en" | "de" = "en") {
|
||||
}
|
||||
|
||||
describe("<LayoutSection>", () => {
|
||||
it("links to the arrangement editors it still hosts", () => {
|
||||
it("links to every view surface it indexes (anchor deep-links)", () => {
|
||||
const html = render();
|
||||
for (const href of ["/settings/dashboard", "/settings/insights"]) {
|
||||
for (const href of [
|
||||
"/settings/dashboard",
|
||||
"/settings/insights",
|
||||
"/settings/medications#medications-view",
|
||||
"/settings/labs#labs-view",
|
||||
"/settings/illness#illness-view",
|
||||
"/settings/vorsorge#vorsorge-view",
|
||||
]) {
|
||||
expect(html).toContain(`href="${href}"`);
|
||||
}
|
||||
// v1.18.0 (S5) — Medications (Medikamente) and Mood (Stimmung)
|
||||
// graduated to their own nav entries and are no longer linked here.
|
||||
expect(html).not.toContain('href="/settings/medications"');
|
||||
expect(html).not.toContain('href="/settings/mood"');
|
||||
});
|
||||
|
||||
it("renders the hub heading and a card per editor", () => {
|
||||
it("renders one card per indexed surface (6 links)", () => {
|
||||
const html = render();
|
||||
// Pin the link count: every hub card is an `<a href="/settings/…">`.
|
||||
const links = html.match(/href="\/settings\//g) ?? [];
|
||||
expect(links.length).toBe(6);
|
||||
expect(html).toContain("Dashboard");
|
||||
expect(html).toContain("Insights");
|
||||
});
|
||||
|
||||
it("resolves its copy in German too", () => {
|
||||
const html = render("de");
|
||||
expect(html).toContain("Layout");
|
||||
// The hub body is the link list; the German module labels resolve.
|
||||
expect(html).toContain("Medikamente");
|
||||
expect(html).toContain("Labor");
|
||||
expect(html).not.toContain("settings.sections.layout.");
|
||||
});
|
||||
});
|
||||
@@ -188,19 +188,25 @@ describe("settings sections — SSR smoke", () => {
|
||||
expect(html).toContain("Withings");
|
||||
});
|
||||
|
||||
it("<NotificationsSection> renders the single reminder-types home", () => {
|
||||
it("<NotificationsSection> renders the reminders + delivery-channels groups", () => {
|
||||
const html = renderFramed("notifications", <NotificationsSection />);
|
||||
// v1.18.6 (W9) — the visible heading comes from the frame; the proactive
|
||||
// Coach nudge moved to Settings → Coach, so it no longer renders here.
|
||||
expect(html).toContain("settings-section-notifications-title");
|
||||
expect(html).not.toContain("Notification channels");
|
||||
expect(html).not.toContain('data-slot="notifications-channels-cross-link"');
|
||||
expect(html).not.toContain('data-slot="notifications-inbox-cross-link"');
|
||||
// The mood card fails OPEN (mock user carries no module map), so both
|
||||
// remaining reminder-type cards render. The coach-nudge card is gone.
|
||||
// reminder-type cards render under the Reminders group. The coach-nudge
|
||||
// card is gone.
|
||||
expect(html).toContain('id="mood-reminder"');
|
||||
expect(html).toContain('id="low-stock"');
|
||||
expect(html).not.toContain('id="coach-nudge"');
|
||||
// v1.25.3 — the delivery-channels group is now part of this surface: the
|
||||
// `#channels` anchor and the embedded channels panel both render.
|
||||
expect(html).toContain('id="channels"');
|
||||
expect(html).toContain('data-slot="notification-channels-panel"');
|
||||
expect(html).toContain("Reminders");
|
||||
expect(html).toContain("Delivery channels");
|
||||
// No raw i18n key leaks past the provider.
|
||||
expect(html).not.toContain("settings.sections.notifications.");
|
||||
});
|
||||
|
||||
@@ -91,6 +91,9 @@ describe("SETTINGS_SECTION_SLUGS", () => {
|
||||
// sits right after `ai`.
|
||||
// v1.18.1 (D4) — `channels` + `sources` split out of the Integrations
|
||||
// sub-tabs into their own left-side entries, right after `integrations`.
|
||||
// v1.25.3 — `channels` folded back into Notifications as an in-page group;
|
||||
// `/settings/channels` 301-redirects to `/settings/notifications#channels`.
|
||||
// `sources` keeps its own entry.
|
||||
// v1.18.7 — `labs`, `illness`, `vorsorge` move into the shell as
|
||||
// first-class sections, right after `mood` (the three were standalone
|
||||
// `ModuleSettingsFrame` pages).
|
||||
@@ -102,7 +105,6 @@ describe("SETTINGS_SECTION_SLUGS", () => {
|
||||
"security",
|
||||
"modules",
|
||||
"integrations",
|
||||
"channels",
|
||||
"sources",
|
||||
"notifications",
|
||||
"layout",
|
||||
@@ -293,14 +295,15 @@ describe("<SettingsShell>", () => {
|
||||
// (single-line; the longer "Notification channels" wrapped). The
|
||||
// `/notifications` inbox now shares the "Notifications" label.
|
||||
expect(html).toContain("Notifications");
|
||||
// v1.17.1 (F-2) — the dashboard + insights arrangement editors are
|
||||
// reached through one hub entry (route stays `/settings/layout`).
|
||||
// v1.19.1 (S3) — the nav label now reads "Dashboard" to match where
|
||||
// it leads; the route is unchanged.
|
||||
// v1.17.1 (F-2) — the view/arrangement editors are reached through one hub
|
||||
// entry (route stays `/settings/layout`). v1.25.3 — the hub is renamed
|
||||
// "Appearance" (DE "Darstellung") and indexes every module's view surface;
|
||||
// the route is unchanged.
|
||||
expect(html).toContain('href="/settings/layout"');
|
||||
expect(html).toContain(">Dashboard</a>");
|
||||
// v1.18.1 (D4) — Channels + Sources are their own left-side entries.
|
||||
expect(html).toContain('href="/settings/channels"');
|
||||
expect(html).toContain(">Appearance</a>");
|
||||
// v1.25.3 — Channels folded into Notifications, so it is no longer a
|
||||
// left-side entry; Sources keeps its own.
|
||||
expect(html).not.toContain('href="/settings/channels"');
|
||||
expect(html).toContain('href="/settings/sources"');
|
||||
// v1.18.0 (S5) — Medications (Medikamente) and Mood (Stimmung, gated;
|
||||
// fail-open mock shows both) are their own nav entries now.
|
||||
@@ -334,15 +337,14 @@ describe("<SettingsShell>", () => {
|
||||
// compound "Benachrichtigungs-Kanäle" wrapped). The `/notifications`
|
||||
// inbox now shares the "Benachrichtigungen" label.
|
||||
expect(html).toContain("Benachrichtigungen");
|
||||
// v1.17.1 (F-2) — the arrangement editors are reached through one hub
|
||||
// entry (route stays `/settings/layout`). v1.19.1 (S3) — the nav label
|
||||
// reads "Dashboard" in every locale to match where it leads.
|
||||
// v1.17.1 (F-2) — the view editors are reached through one hub entry
|
||||
// (route stays `/settings/layout`). v1.25.3 — the German nav label reads
|
||||
// "Darstellung" (Appearance) to match the renamed hub.
|
||||
expect(html).toContain('href="/settings/layout"');
|
||||
expect(html).toContain(">Dashboard</a>");
|
||||
// v1.18.1 (D4) — Channels ("Kanäle") + Sources ("Quellen-Priorität")
|
||||
// are their own left-side entries.
|
||||
expect(html).toContain('href="/settings/channels"');
|
||||
expect(html).toContain("Kanäle");
|
||||
expect(html).toContain(">Darstellung</a>");
|
||||
// v1.25.3 — Channels ("Kanäle") folded into Notifications; Sources keeps
|
||||
// its own left-side entry.
|
||||
expect(html).not.toContain('href="/settings/channels"');
|
||||
// v1.18.0 (S5) — Medications + Mood are their own nav entries now.
|
||||
expect(html).toContain('href="/settings/medications"');
|
||||
expect(html).toContain('href="/settings/mood"');
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* `<ChannelsSection>` — Settings → Kanäle (notification delivery channels).
|
||||
*
|
||||
* v1.18.1 (D4) — split out of the Integrations sub-tabs into its own left-side
|
||||
* entry. A channel (Telegram / ntfy / Web Push / Webhook / Email) is a
|
||||
* delivery provider — the same family as a connected device — and now reads as
|
||||
* a first-class settings home rather than a tab hidden behind Integrationen.
|
||||
*
|
||||
* The content is the existing `<NotificationChannelsPanel>`. v1.18.6 (W9) —
|
||||
* the visible heading + subtitle now come from the shared
|
||||
* `<SettingsSectionFrame>` in the route; this wrapper is the panel only.
|
||||
*/
|
||||
|
||||
import { NotificationChannelsPanel } from "@/components/settings/integrations/notification-channels-panel";
|
||||
|
||||
export function ChannelsSection() {
|
||||
return <NotificationChannelsPanel />;
|
||||
}
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
import Link from "next/link";
|
||||
import {
|
||||
CalendarCheck,
|
||||
ChevronRight,
|
||||
FlaskConical,
|
||||
LayoutDashboard,
|
||||
Pill,
|
||||
Thermometer,
|
||||
TrendingUp,
|
||||
type LucideIcon,
|
||||
} from "lucide-react";
|
||||
@@ -12,17 +16,23 @@ import { useTranslations } from "@/lib/i18n/context";
|
||||
import { SettingsCard } from "./settings-card";
|
||||
|
||||
/**
|
||||
* v1.17.1 (F-2) — the one "Layout & Personalization" home.
|
||||
* v1.17.1 (F-2) — the "Appearance" home (slug stays `layout`).
|
||||
*
|
||||
* Before this section, "how my app is laid out" was scattered across
|
||||
* several unrelated settings sections with no shared framing. This
|
||||
* section is the single front door for the arrangement editors: it
|
||||
* presents them as one consistent set of cards and links to each editor,
|
||||
* which keep their own routes and mutation flows intact.
|
||||
* "How my app looks and is arranged" was scattered across several unrelated
|
||||
* settings sections with no shared framing. This section is the single front
|
||||
* door: it presents the view/arrangement surfaces as one consistent set of
|
||||
* cards and links to each editor, which keep their own routes, their own
|
||||
* cards, and their mutation flows intact — the hub indexes them, it does not
|
||||
* own them.
|
||||
*
|
||||
* v1.18.0 (S5) — Medications (Medikamente) and Mood (Stimmung) graduated
|
||||
* to their own top-level nav entries, so the hub now hosts only the
|
||||
* dashboard + insights arrangement editors.
|
||||
* v1.25.3 — the hub widens from the dashboard + insights arrangement editors
|
||||
* to the full set of view surfaces: it now also deep-links to the view/sort/
|
||||
* order cards of medications, labs, the illness journal, and checkups. Each
|
||||
* of those modules keeps its view cards on its own settings page; the links
|
||||
* land on the existing card anchors (`#medications-view`, `#labs-view`,
|
||||
* `#illness-view`, `#vorsorge-view`). Data/behaviour settings (biomarker
|
||||
* catalog, local OCR, injection-site exclusions, per-reminder toggles, the
|
||||
* mood tag/group catalog) stay on their module pages and are NOT indexed here.
|
||||
*/
|
||||
interface LayoutLink {
|
||||
href: string;
|
||||
@@ -44,10 +54,34 @@ const LAYOUT_LINKS: ReadonlyArray<LayoutLink> = [
|
||||
titleKey: "settings.sections.layout.insights.title",
|
||||
descriptionKey: "settings.sections.layout.insights.description",
|
||||
},
|
||||
// v1.18.0 (S5) — Medications (Medikamente) and Mood (Stimmung) graduated
|
||||
// to their own top-level nav entries, so they are no longer linked from
|
||||
// the Layout hub. Only the dashboard + insights arrangement editors
|
||||
// remain here.
|
||||
// v1.25.3 — view/sort/order surfaces of the tracking modules. Each link
|
||||
// deep-links to the module's existing view card anchor; the cards stay on
|
||||
// their own settings page. The module routes resolve regardless of the
|
||||
// module's enabled state, so the link never dead-ends.
|
||||
{
|
||||
href: "/settings/medications#medications-view",
|
||||
icon: Pill,
|
||||
titleKey: "settings.sections.layout.medications.title",
|
||||
descriptionKey: "settings.sections.layout.medications.description",
|
||||
},
|
||||
{
|
||||
href: "/settings/labs#labs-view",
|
||||
icon: FlaskConical,
|
||||
titleKey: "settings.sections.layout.labs.title",
|
||||
descriptionKey: "settings.sections.layout.labs.description",
|
||||
},
|
||||
{
|
||||
href: "/settings/illness#illness-view",
|
||||
icon: Thermometer,
|
||||
titleKey: "settings.sections.layout.illness.title",
|
||||
descriptionKey: "settings.sections.layout.illness.description",
|
||||
},
|
||||
{
|
||||
href: "/settings/vorsorge#vorsorge-view",
|
||||
icon: CalendarCheck,
|
||||
titleKey: "settings.sections.layout.vorsorge.title",
|
||||
descriptionKey: "settings.sections.layout.vorsorge.description",
|
||||
},
|
||||
];
|
||||
|
||||
export function LayoutSection() {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { LowStockCard } from "@/components/settings/low-stock-card";
|
||||
import { MoodReminderCard } from "@/components/settings/mood-reminder-card";
|
||||
import { NotificationChannelsPanel } from "@/components/settings/integrations/notification-channels-panel";
|
||||
|
||||
/**
|
||||
* `<NotificationsSection>` — Settings → Notifications ("Benachrichtigungen").
|
||||
@@ -19,41 +21,77 @@ import { MoodReminderCard } from "@/components/settings/mood-reminder-card";
|
||||
* (a toggleable fail-open module since D3, so a missing key reads as enabled
|
||||
* and a stale `/me` payload never blanks a card).
|
||||
*
|
||||
* v1.18.1 (D5) — the page is intentionally lean: the section blurb, the
|
||||
* channels / inbox cross-links, and the embedded Vorsorge (preventive-care)
|
||||
* editor were all removed. Vorsorge has its own `/vorsorge` page, so embedding
|
||||
* it here was a duplicate. Delivery CHANNELS (Telegram / ntfy / Web Push /
|
||||
* Webhook / Email) live under Settings → Integrations → Channels.
|
||||
* v1.25.3 — the standalone "Channels" entry folds back in here. The page is
|
||||
* now one Notifications surface with two sequential, labelled groups, ordered
|
||||
* the way a user reasons about it: **Reminders** ("what you receive") first,
|
||||
* then **Delivery channels** ("where it's delivered") = the existing
|
||||
* `<NotificationChannelsPanel>`. This is two distinct-but-related concepts
|
||||
* sequenced under one roof, not one concept split top/bottom — the
|
||||
* channels group carries `id="channels"` so `/settings/channels` can
|
||||
* 301-redirect to `/settings/notifications#channels`, and the per-channel
|
||||
* anchors (`#telegram`, `#ntfy`, …) inside the panel keep working.
|
||||
*
|
||||
* v1.18.6 (W9) — the visible heading + subtitle now come from the shared
|
||||
* `<SettingsSectionFrame>`. The proactive-Coach nudge card moved to Settings →
|
||||
* Coach (it is a Coach setting, not a generic notification), so this screen
|
||||
* carries the mood + low-stock reminder cards only.
|
||||
* v1.18.6 (W9) — the page heading + subtitle come from the shared
|
||||
* `<SettingsSectionFrame>`. The proactive-Coach nudge card lives under
|
||||
* Settings → Coach (it is a Coach setting, not a generic notification).
|
||||
*/
|
||||
export function NotificationsSection() {
|
||||
const { isAuthenticated, user } = useAuth();
|
||||
const { t } = useTranslations();
|
||||
|
||||
// v1.18.0 (S4) — module-gated per-type visibility. Fail OPEN (`!== false`)
|
||||
// so a stale `/me` payload without the module map keeps every card visible.
|
||||
const moodEnabled = user?.modules?.mood !== false;
|
||||
const medsEnabled = user?.modules?.medications !== false;
|
||||
const anyReminder = moodEnabled || medsEnabled;
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Mood check-in reminder — only when the mood module is enabled. */}
|
||||
{moodEnabled ? (
|
||||
<div id="mood-reminder" className="scroll-mt-28">
|
||||
<MoodReminderCard isAuthenticated={isAuthenticated} />
|
||||
</div>
|
||||
<div className="space-y-10">
|
||||
{/* Group 1 — Reminders ("what you receive"). Rendered only when at
|
||||
least one reminder-type card is visible, so a fully-disabled
|
||||
account never shows an empty heading. */}
|
||||
{anyReminder ? (
|
||||
<section className="space-y-4">
|
||||
<div className="space-y-0.5">
|
||||
<h2 className="text-foreground text-lg font-semibold">
|
||||
{t("settings.sections.notifications.remindersHeading")}
|
||||
</h2>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("settings.sections.notifications.remindersDescription")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Mood check-in reminder — only when the mood module is enabled. */}
|
||||
{moodEnabled ? (
|
||||
<div id="mood-reminder" className="scroll-mt-28">
|
||||
<MoodReminderCard isAuthenticated={isAuthenticated} />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{/* Medication low-stock runway — only when the medications module
|
||||
is enabled (toggleable, fail-open, since D3). */}
|
||||
{medsEnabled ? (
|
||||
<div id="low-stock" className="scroll-mt-28">
|
||||
<LowStockCard isAuthenticated={isAuthenticated} />
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
{/* Medication low-stock runway — only when the medications module is
|
||||
enabled (toggleable, fail-open, since D3). */}
|
||||
{medsEnabled ? (
|
||||
<div id="low-stock" className="scroll-mt-28">
|
||||
<LowStockCard isAuthenticated={isAuthenticated} />
|
||||
{/* Group 2 — Delivery channels ("where it's delivered"). The existing
|
||||
channels panel, unchanged. `id="channels"` anchors the group for the
|
||||
`/settings/channels` redirect. */}
|
||||
<section id="channels" className="scroll-mt-28 space-y-4">
|
||||
<div className="space-y-0.5">
|
||||
<h2 className="text-foreground text-lg font-semibold">
|
||||
{t("settings.sections.notifications.channelsHeading")}
|
||||
</h2>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("settings.sections.notifications.channelsDescription")}
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
<NotificationChannelsPanel />
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import {
|
||||
Link2,
|
||||
Lock,
|
||||
Pill,
|
||||
Radio,
|
||||
Settings2,
|
||||
Share2,
|
||||
ShieldCheck,
|
||||
@@ -51,7 +50,6 @@ const SLUG_ICON: Record<SettingsSectionSlug, LucideIcon> = {
|
||||
security: ShieldCheck,
|
||||
modules: Blocks,
|
||||
integrations: Link2,
|
||||
channels: Radio,
|
||||
sources: Layers,
|
||||
notifications: Bell,
|
||||
layout: LayoutDashboard,
|
||||
|
||||
@@ -57,9 +57,10 @@ export const SETTINGS_SECTION_SLUGS = [
|
||||
// single front door for enabling/disabling secondary tracking domains.
|
||||
"modules",
|
||||
"integrations",
|
||||
// v1.18.1 (D4) — Kanäle (delivery channels) + Quellen (source weighting)
|
||||
// split out of the Integrations tabs into their own left-side entries.
|
||||
"channels",
|
||||
// v1.18.1 (D4) — Quellen (source weighting) split out of the Integrations
|
||||
// tabs into its own left-side entry. v1.25.3 — Kanäle (delivery channels)
|
||||
// folded back into Notifications as an in-page group; `/settings/channels`
|
||||
// 301-redirects to `/settings/notifications#channels` (next.config.ts).
|
||||
"sources",
|
||||
"notifications",
|
||||
"layout",
|
||||
|
||||
@@ -30,12 +30,11 @@ import {
|
||||
Info,
|
||||
KeyRound,
|
||||
Plug,
|
||||
LayoutDashboard,
|
||||
Layers,
|
||||
Link2,
|
||||
Lock,
|
||||
Palette,
|
||||
Pill,
|
||||
Radio,
|
||||
Settings2,
|
||||
Share2,
|
||||
ShieldCheck,
|
||||
@@ -123,13 +122,9 @@ export const SETTINGS_SECTIONS: readonly SettingsSection[] = [
|
||||
titleKey: "settings.sections.integrations.title",
|
||||
icon: Link2,
|
||||
},
|
||||
// v1.18.1 (D4) — Kanäle (delivery channels) split out of the Integrations
|
||||
// sub-tabs into its own entry. A channel is a delivery provider.
|
||||
{
|
||||
slug: "channels",
|
||||
titleKey: "settings.sections.channels.title",
|
||||
icon: Radio,
|
||||
},
|
||||
// v1.25.3 — the standalone Kanäle (delivery channels) entry folded back
|
||||
// into Notifications as a labelled in-page group; `/settings/channels`
|
||||
// 301-redirects to `/settings/notifications#channels`.
|
||||
// v1.18.1 (D4) — Quellen (source weighting) split out into its own entry:
|
||||
// which connection wins when two report the same metric.
|
||||
{
|
||||
@@ -145,15 +140,17 @@ export const SETTINGS_SECTIONS: readonly SettingsSection[] = [
|
||||
titleKey: "settings.sections.notifications.title",
|
||||
icon: Bell,
|
||||
},
|
||||
// v1.17.1 (F-2) — one "Layout & Personalization" nav entry replaces the
|
||||
// four scattered Dashboard / Insights / Medications / Mood "arrange"
|
||||
// entries. Those routes still resolve (deep links, page-header cogs, and
|
||||
// the hub's own links all work); they are simply reached through the
|
||||
// Layout hub now, so "how my app is laid out" reads as one home.
|
||||
// v1.17.1 (F-2) — one nav entry replaces the four scattered Dashboard /
|
||||
// Insights / Medications / Mood "arrange" entries. Those routes still
|
||||
// resolve (deep links, page-header cogs, and the hub's own links all work);
|
||||
// they are reached through this hub now, so "how my app looks" reads as one
|
||||
// home. v1.25.3 — renamed to "Appearance"/"Darstellung" and widened into the
|
||||
// index for every module's view/sort/order surface. The slug stays `layout`
|
||||
// so every route + deep link is untouched.
|
||||
{
|
||||
slug: "layout",
|
||||
titleKey: "settings.sections.layout.title",
|
||||
icon: LayoutDashboard,
|
||||
icon: Palette,
|
||||
},
|
||||
// v1.18.0 (S5) — Medikamente: medication-specific settings (list view +
|
||||
// order + injection sites). Was a hidden child of the Layout hub.
|
||||
|
||||
Reference in new issue
Block a user