Layout & Navigation

Layout system

A pluggable module that aggregates navigation from all frontend modules and provides an Admin Layout Manager for toggling visibility.

Overview

  • Frontend module contributes a route for an Admin Layout Manager page.
  • Aggregates navItems from all loaded frontend modules via FrontendModuleLoader.
  • Supports role-based visibility through each item's visible predicate.
  • Non-invasive: does not alter existing app behavior; simply adds layout tooling.

Backend

  • src/modules/layout/index.ts: declares EnvSpec and installs a small health endpoint.
  • Health check: GET /api/layout/health{ ok: true, module: "layout", version: "1.0.0" }

Environment variables (backend)

  • FEATURE_LAYOUT: Enable/disable the Layout module (default: enabled).
  • LAYOUT_DEFAULT: Default preset (e.g., drawer-left, drawer-right, topbar-only).
  • LAYOUT_SHOW_FOOTER: Whether to render a footer in the app shell (default: true).

Frontend

  • client/src/modules/layout/index.ts: registers route /admin/layout (rendered under the app base) and contributes a topbar nav item to /app/admin/layout.
  • Requires admin/owner: wrapped with RequireAdmin and uses isAuthenticatedWithSomeRole(["admin","owner"]).
  • client/src/modules/layout/pages/AdminLayoutManager.tsx: loads modules, aggregates navItems, and lets admins toggle item visibility.

Navigation item contract

// client/src/modules/types.ts
export type FrontendModuleNavItem = {
  to: string;              // e.g. "/app/admin/layout"
  label: string;           // UI label
  area?: string;           // e.g. "topbar"
  icon?: React.ReactNode;  // optional icon
  visible?: boolean | (() => boolean); // RBAC or custom conditions
};

Admin Layout Manager

Page component: client/src/modules/layout/pages/AdminLayoutManager.tsx

  • Persists hidden items in localStorage under key "layout.hiddenNavItems".
  • Emits a window event "layout:nav.changed" after changes so consumers can re-render navigation.
  • Respects each item's visible predicate before presenting toggles.
// Toggle handler excerpt
function saveHidden(set: Set<string>) {
  localStorage.setItem("layout.hiddenNavItems", JSON.stringify(Array.from(set)));
  window.dispatchEvent(new Event("layout:nav.changed"));
}

Enable the module

# Backend/Frontend modules loader
MODULES_ENABLED=layout
# Optional (default is enabled)
FEATURE_LAYOUT=true

# Optional layout preferences
LAYOUT_DEFAULT=drawer-left
LAYOUT_SHOW_FOOTER=true

Restart the server. The backend exposes the health endpoint; the frontend adds the admin page and topbar item for admins.

Troubleshooting

  • If the admin page doesn't show, ensure your user has admin or owner role.
  • Verify MODULES_ENABLED contains layout and FEATURE_LAYOUT is not false.
  • Check console logs: [frontend-modules][layout] and [modules][layout] in development.

Related