refactor(frontend): each module defines itself in its folder; rails load lazily and keep their own state
A page used to be listed three times (lib/modules for its label, icon and gate; shell/moduleRegistry for its page and rail; lib/pageMeta for its title), and App held every rail's layout and collapse flag. Now each module's `module.ts` says it all — label, icon, gate, its lazy page and rail, its width — handed out through its index.ts, and features/navigation/moduleRegistry lists them in nav order for the rail, the palette, the tab title, the reachable set and the shell's render. A contract test holds the registry to the page ids and each definition to its own folder, with no static import of a page. Every rail is lazy now, loaded together with its page so a pinned rail never arrives after it and shoves the content aside; the feed's and the playlists' rails took @dnd-kit off the boot path (boot 428.5 → 393.9 KiB gzip, the App chunk 122 → 32 KiB). A rail reads its own layout and collapse flag (lib/useRail) and writes a layout change to the `me` cache too, since it now mounts anew on each visit. App's session effects, its one-shot entry-URL handlers and the admin nudge move into shell hooks; App is layout. The registry's three layer suppressions are gone: none is left.
This commit is contained in:
@@ -21,7 +21,11 @@ vi.mock("react-i18next", async (importOriginal) => {
|
||||
useTranslation: () => ({ t: (key: string) => key, i18n: { language: "en" } }),
|
||||
};
|
||||
});
|
||||
vi.mock("../../lib/api", () => ({ api: h }));
|
||||
// Partial: the module graph reaches the feed's store, which reads its defaults here.
|
||||
vi.mock("../../lib/api", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../../lib/api")>()),
|
||||
api: h,
|
||||
}));
|
||||
// Partial mock: SettingsPanel's module graph (PrefsProvider) also pulls getNotifSettings from here.
|
||||
vi.mock("../../lib/notifications", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../../lib/notifications")>();
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
// The settings page's public face: how the shell and the navigation know it.
|
||||
export { settingsModule } from "./module";
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Settings } from "lucide-react";
|
||||
import { lazyWithPreload } from "../../lib/lazyWithPreload";
|
||||
import type { ModuleDef } from "../../lib/moduleDef";
|
||||
|
||||
// This page as the shell and the navigation know it (lib/moduleDef). Its page load lazily.
|
||||
export const settingsModule: ModuleDef = {
|
||||
id: "settings",
|
||||
labelKey: "header.account.settings",
|
||||
railKey: "nav.rail.settings",
|
||||
titleKey: "settings.title",
|
||||
icon: Settings,
|
||||
Page: lazyWithPreload(() => import("./SettingsPanel")),
|
||||
};
|
||||
Reference in New Issue
Block a user