Commit Graph
3 Commits
Author SHA1 Message Date
ekklesiaandClaude Opus 5.5 89ef4b5ff6 feat(shell): Settings hierarchy, Discover, and /settings/<module-id>
CI / verify (pull_request) Successful in 1m12s
CI / infrastructure-smoke (pull_request) Successful in 37s
CI / package-release (pull_request) Successful in 51s
CI / migration-smoke (pull_request) Successful in 2m29s
CI / image-build (pull_request) Successful in 1m4s
CI / deploy-smoke (same-origin) (pull_request) Successful in 54s
CI / package-publication (pull_request) Successful in 58s
CI / deploy-smoke (split) (pull_request) Successful in 2m56s
The Settings foundation (ADR 0061):

- URL model. /settings is a real landing page. The platform sections
  are /settings/general, /branding, /displays, and /system. Module
  lifecycle is Discover: /settings/discover/browse, /installed, and
  /updates. /settings/discover is respelled in place to Browse's one
  canonical address. A module's settings are /settings/<module-id>,
  never nested under Discover. Deeper Settings addresses are
  reserved. "Modules" stays the user-facing word: "Discover modules",
  "Installed modules", "Module updates".
- Collisions. Core's one reserved list gains the Settings section
  names (branding, discover, displays, general, system) as a second
  documented group, so no module id can shadow a section; `modules` is
  an ordinary id. apps/api tests hold it equal to the shell's sections.
- Navigation. One Settings item in the same sidebar expands in place
  into Platform and Modules (and Discover's three views) while in
  Settings, and the phone drawer has the same hierarchy. The rest of
  the navigation stays.
- Permissions. GET /api/v1/dashboard/settings evaluates, through
  Core's evaluator, which destinations the viewer may see:
  - Displays: core.devices.manage
  - Discover: core.modules.lifecycle.manage
  - a module's settings: core.modules.configuration.manage, for each
    module that declares configuration (ADR 0029)
  - General, Branding, System: the platform owner, until each has its
    own permission
  These are presentation hints; every data route keeps its own
  enforcement. With nothing visible, there is no Settings link.
- Pages are honest placeholders with Back to Settings. A disabled
  module's settings say it is turned off; a section or module the
  person cannot see says so without detail; an unknown name is not
  found; a failed load withholds the link and offers Retry.
- The deploy smoke opens Settings by deep link, refreshes a section,
  enters Discover, opens the module's settings, uses the phone
  drawer, and returns to the Dashboard.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 22:22:50 -05:00
ekklesiaandClaude Opus 5.5 d42b64a093 feat(theme): Light/Dark/System, reduced motion, and one radius scale
CI / verify (pull_request) Successful in 1m10s
CI / infrastructure-smoke (pull_request) Successful in 34s
CI / package-release (pull_request) Successful in 52s
CI / migration-smoke (pull_request) Successful in 2m20s
CI / image-build (pull_request) Successful in 1m5s
CI / deploy-smoke (same-origin) (pull_request) Successful in 50s
CI / package-publication (pull_request) Successful in 58s
CI / deploy-smoke (split) (pull_request) Successful in 2m38s
The theme foundation DESIGN.md requires (ADR 0060):

- A design token may carry a `dark` value and a `reduced` value. The
  token stylesheet selects them in CSS alone: dark under
  prefers-color-scheme unless the host chose light, or when it chose
  dark; motion durations zero under prefers-reduced-motion unless it
  allowed motion, or when it chose reduce. `color-scheme` travels with
  the tokens. System is live, an explicit choice wins, and every module
  root follows through custom-property inheritance, with no module
  contract change.
- @ekklesia/design-tokens adds a small appearance API: system/light/dark
  and system/reduce/allow, parsers for untrusted stored values,
  resolvers, and a controller that applies the attributes immediately.
  The shell applies it before React renders. That is the hook the
  account preferences work will feed; nothing is persisted. The
  Dashboard page declares `color-scheme: light dark` so a dark system
  never flashes white. Displays stay light.
- A designed dark theme: teal-tinted charcoal, never pure black or
  white, the same teal accent.
- WCAG AA contrast is tested for 41 element pairings in both schemes.
  Two light pairings failed and are fixed visibly: text.muted darkens,
  and form controls get a new border.control (3:1).
  background.placeholder keeps skeletons visible in dark.
- Motion tokens (duration-short, duration-ambient) replace literal
  durations and every per-element reduced-motion rule. radius.scale
  multiplies sm/md/lg, unchanged at its default of 1.
- The sign-in card and module loading/error text move from literal
  colours to tokens. Guards keep raw colours and literal radii out of
  Dashboard product source and @ekklesia/ui.
- Fixes ConfirmationDialog's phrase input, which used a class that
  does not exist (`ek-input`) and so was unstyled.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 20:00:39 -05:00
ekklesiaandClaude Opus 5.5 af31724cb4 feat(shell): collapsible sidebar, account menu, and phone drawer
CI / verify (pull_request) Failing after 57s
CI / infrastructure-smoke (pull_request) Skipped
CI / migration-smoke (pull_request) Skipped
CI / package-release (pull_request) Skipped
CI / package-publication (pull_request) Skipped
CI / image-build (pull_request) Skipped
CI / deploy-smoke (same-origin) (pull_request) Skipped
CI / deploy-smoke (split) (pull_request) Skipped
The Dashboard's shell now follows DESIGN.md §4 (ADR 0058):

- A collapsible left sidebar replaces the header-and-column layout. It
  is icons and labels when expanded and icons only when collapsed; each
  collapsed item keeps its name, visually hidden, and shows a tooltip
  on hover and on keyboard focus (WCAG 2.2 §1.4.13). The Overview comes
  first, then the server's groups and modules. There is no top bar.
- The expanded/collapsed choice is remembered in this browser's
  localStorage, behind a SidebarPreference interface that a synced
  store can replace later.
- An account menu at the bottom of the sidebar follows the WAI-ARIA menu
  button pattern and offers only Sign out, which now lives there rather
  than in the header.
- On phones (below 48em) the same navigation opens in a modal drawer:
  the page behind it is inert and focus is trapped inside it. Escape,
  its close button, and the backdrop close it and return focus to the
  menu button. Choosing a page closes it and focuses the page. Changing
  layout keeps the route, the desktop mode, and the mounted module.
- Lucide (lucide-react 1.48.0, shell only) is Ekklesia's icon
  vocabulary. Every module shows one generic icon until manifest v9
  lets modules declare their own; there is no per-module icon map.
- The identity slot is a neutral placeholder with no inputs, waiting
  for branding (#101).

The tooltip, menu, and drawer stay shell-local until a second consumer
needs them (ADR 0039). The deploy smoke now signs out through the
account menu, and drives the drawer at phone size in a real browser.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 17:49:56 -05:00