Feature modules: the list on item rows, and tree: pages | hidden with auto-open, container tabs and a prompt that is a screen #347

Closed
opened 2026-10-24 10:36:10 +02:00 by dominik.polakovics · 0 comments

Mockups (definitions agreed 2026-10-24):

Depends on #346 (the shared item row). Second of three.

What changes

The module list (ModuleScreen.tsx)

  • The docheader is the page head: module icon + title (section role) on the left of the context row, " " on the right; no container badge in any module (decision C). One primary: "New " as .btn .btn--primary, sentence case; disabled in a non-default language with the reason in a .note--info above the panel, not a tooltip.
  • The body is a .page (960px, centred) holding one .panel: head with the module's title and one descriptive line, panel__tools with the search field, the filters, and the sort menu for every layout (column-header sorting goes; the URL's sort and the server are unchanged); body: the entries as item rows stacked on the sunken ground; foot: the shared .pager (count left, Previous/Next small bordered, page numbers).
  • Columns map onto the item row: title → .item__label (a real link, heading ink); status → badges in the head (ok Published, info+dot Modified, dashed Unpublished, warn Disabled; two badges when two facts hold); the page's slug as .item__id; every other declared column → the summary line in column order, drawn by the existing FieldValueView rules (dateTime short, tags as chips, bool Yes/No, image as thumb). The cards layout keeps its grid and card roles; both layouts remain valid YAML (decision E, H).
  • Row actions as on a content element and in that order: Edit (pencil, the entry link), Enable/Disable (eye / eye-off) and ⋮. Enable/Disable and the ⋮'s Rename… and Delete… come from pageactions.ts (the entry editor's items; the list calls, never re-derives). The ⋮ keeps the translation items (Translate to …, Delete translation…). An untranslated row in a non-default language has no actions; its title is italic with the default language's code tag and the Translation state (the language switch's dot + words, Translate… ghost button) sits in the head.
  • States: empty (.empty: "No yet." + what to do + a bordered New button), no match (.empty + ghost "Clear search"), loading and error on the shared recipes. No .pane__hint opacity anywhere on this screen.
  • CSS retired: .list-table*, .module-toolbar*, .module-pager*, .module-empty*, .module-tag(s), .module-lang-tag, .module-l10n*, .module-card* (the cards layout draws .item + image), the .docheader__btn recipe on this screen.

tree: pages | hidden (new module key)

  • Server: the module loader decodes tree (default pages, hidden; anything else a load error named in the schema banner); harness migrate's canonical form writes the key only when hidden (existing files stay byte-identical); GET /api/modules carries it. docs/api.md GET /api/modules; AGENTS.md "Editor modules": the key in the reference YAML and the "In the editor" paragraph rewritten (see below). The canonical-form and unknown-key tests cover it.
  • Client: featureModuleDef sets nav: PAGE_TREE_NAV only for pages. With hidden the shell already drops the column and the rail toggle (ModuleDef.nav optional).
  • One new rule, one owner (FeatureModule mode + routerepair): what a tree-hidden module shows when the URL names no container of its own —
    • exactly one container in the tree: repair the URL to it and show the list (issue #33 narrowed to "where a choice exists"; record this in a new docs/adr/ entry and state the behaviour in AGENTS.md);
    • several: one tab per container in the docheader's tab row (no counts this round), the active tab being the URL's container and the body its list; when the URL names none of them, no tab is active and the body is the prompt panel (one row per container with a bordered Open), so nothing is chosen on the author's behalf where a choice exists;
    • none: the docheader stays, New disabled, an .empty naming the container page type and pointing at the Page module.
    • An open entry goes back through the docheader ("All " ghost button, crumbs " › "); return semantics unchanged.
  • Modules that keep the tree (Proposal B, every tree: pages module): the prompt mode mounts the docheader and shows a .panel listing the containers with a bordered "Open" each; TreePane's rejected rows take --chrome-text-muted instead of opacity (.tree-row__label--disabled), chevrons stay live; the container's row is drawn normally with the module's icon.
  • Bundles: scaffold/features/forms/editor/modules/forms.yaml and scaffold/features/categories/editor/modules/categories.yaml gain tree: hidden; both feature.yaml versions bump; forms' hint "Build each form in the Forms module by selecting the Forms page in its tree and pressing New" is rewritten. docs/features.md "The forms bundle" / categories follow. An installed site keeps its files (harness add does not upgrade a receipted bundle): the skills say the key is a one-line edit.

Documents, skills, owners (CLAUDE.md inventory)

  • Documents: scaffold/site/AGENTS.md "Editor modules" (key, "In the editor": tree beside the module or not, the prompt, auto-open, tabs, the sort menu, the list anatomy, no container badge); docs/api.md GET /api/modules; docs/features.md; a new ADR; docs/architecture.md where it narrates the module shell; docs/styleguide/styleguide.html only if a sample is missing. The README gains nothing.
  • Skills: create-feature (the module YAML it writes incl. tree, the screen it produces), setup-site (walking a customer through Forms), edit-content where it names the tree-selection step, migrate-site if it lists module limits.
  • Rule owners: entry status words/tone Badge.tsx gitBadgeState; translation dots/words stores/translationState; page actions pageactions.ts; containers/entries the server's containerFor/managedBy; the module key's validity the server's loader; the new "which container" rule FeatureModule+routerepair. No client re-derivation; no "same as" comments.
  • i18n: module.*, feature.selectPage/selectTypedPage replaced by the new copy, EN and DE.

Acceptance

  • Forms module on a fresh harness add forms site: clicking the rail entry shows the list at once, no tree column, no rail toggle; News still shows the tree with muted non-container rows and the prompt panel.
  • Every state in the mockup's switcher (5 forms, empty, no match, viewing in German; one/several/no container; entry open) renders as drawn, on today's payload.
  • Drift tests: web/ styles test (no literal, opacity only disabled), scaffold/skills_test.go, scaffold canonical-form test, module decoder unknown-key test, docs/docs_test.go, the internal/server route test (unchanged routes), agentsdoc_test if touched.
  • grep -rn "list-table\|module-toolbar\|module-pager\|module-empty\|pane__hint" web/src/components/ModuleScreen.tsx finds nothing.
Mockups (definitions agreed 2026-10-24): - the list: https://claude.ai/artifact/VKDHiP5SA6Nxdx5Ery762Q — "Proposal", "Row menu and statuses", "Decisions" A–I, "What changes where" - opening the module: https://claude.ai/artifact/XC9KeADJfRrjD428fZFMdj — "Proposal A", "Does the code allow it?", "Proposal B", "Decisions" A–G, "What changes where" Depends on #346 (the shared item row). Second of three. ## What changes ### The module list (`ModuleScreen.tsx`) - The docheader is the page head: module icon + title (section role) on the left of the context row, "<n> <entries>" on the right; **no container badge** in any module (decision C). One primary: "New <type>" as `.btn .btn--primary`, sentence case; disabled in a non-default language with the reason in a `.note--info` above the panel, not a tooltip. - The body is a `.page` (960px, centred) holding one `.panel`: head with the module's title and one descriptive line, `panel__tools` with the search field, the filters, and **the sort menu for every layout** (column-header sorting goes; the URL's `sort` and the server are unchanged); body: the entries as **item rows** stacked on the sunken ground; foot: the shared `.pager` (count left, Previous/Next small bordered, page numbers). - **Columns map onto the item row**: `title` → `.item__label` (a real link, heading ink); `status` → badges in the head (`ok` Published, `info`+dot Modified, `dashed` Unpublished, `warn` Disabled; two badges when two facts hold); the page's slug as `.item__id`; every other declared column → the summary line in column order, drawn by the existing `FieldValueView` rules (dateTime short, tags as chips, bool Yes/No, image as thumb). The `cards` layout keeps its grid and `card` roles; both layouts remain valid YAML (decision E, H). - **Row actions** as on a content element and in that order: Edit (pencil, the entry link), Enable/Disable (eye / eye-off) and ⋮. Enable/Disable and the ⋮'s **Rename…** and **Delete…** come from `pageactions.ts` (the entry editor's items; the list calls, never re-derives). The ⋮ keeps the translation items (Translate to <lang>…, Delete <lang> translation…). An untranslated row in a non-default language has no actions; its title is italic with the default language's code tag and the Translation state (the language switch's dot + words, Translate… ghost button) sits in the head. - States: empty (`.empty`: "No <entries> yet." + what to do + a bordered New button), no match (`.empty` + ghost "Clear search"), loading and error on the shared recipes. No `.pane__hint` opacity anywhere on this screen. - CSS retired: `.list-table*`, `.module-toolbar*`, `.module-pager*`, `.module-empty*`, `.module-tag(s)`, `.module-lang-tag`, `.module-l10n*`, `.module-card*` (the cards layout draws `.item` + image), the `.docheader__btn` recipe on this screen. ### `tree: pages | hidden` (new module key) - **Server**: the module loader decodes `tree` (default `pages`, `hidden`; anything else a load error named in the schema banner); `harness migrate`'s canonical form writes the key only when `hidden` (existing files stay byte-identical); GET /api/modules carries it. `docs/api.md` GET /api/modules; `AGENTS.md` "Editor modules": the key in the reference YAML and the "In the editor" paragraph rewritten (see below). The canonical-form and unknown-key tests cover it. - **Client**: `featureModuleDef` sets `nav: PAGE_TREE_NAV` only for `pages`. With `hidden` the shell already drops the column and the rail toggle (`ModuleDef.nav` optional). - **One new rule, one owner** (`FeatureModule` mode + `routerepair`): what a tree-hidden module shows when the URL names no container of its own — - exactly one container in the tree: repair the URL to it and show the list (issue #33 narrowed to "where a choice exists"; record this in a new `docs/adr/` entry and state the behaviour in AGENTS.md); - several: **one tab per container in the docheader's tab row** (no counts this round), the active tab being the URL's container and the body its list; when the URL names none of them, no tab is active and the body is the prompt panel (one row per container with a bordered Open), so nothing is chosen on the author's behalf where a choice exists; - none: the docheader stays, New disabled, an `.empty` naming the container page type and pointing at the Page module. - An open entry goes back through the docheader ("All <entries>" ghost button, crumbs "<Module> › <entry>"); `return` semantics unchanged. - **Modules that keep the tree** (Proposal B, every `tree: pages` module): the prompt mode mounts the docheader and shows a `.panel` listing the containers with a bordered "Open" each; `TreePane`'s rejected rows take `--chrome-text-muted` instead of opacity (`.tree-row__label--disabled`), chevrons stay live; the container's row is drawn normally with the module's icon. - **Bundles**: `scaffold/features/forms/editor/modules/forms.yaml` and `scaffold/features/categories/editor/modules/categories.yaml` gain `tree: hidden`; both `feature.yaml` versions bump; forms' hint "Build each form in the Forms module by selecting the Forms page in its tree and pressing New" is rewritten. `docs/features.md` "The forms bundle" / categories follow. An installed site keeps its files (`harness add` does not upgrade a receipted bundle): the skills say the key is a one-line edit. ### Documents, skills, owners (CLAUDE.md inventory) - Documents: `scaffold/site/AGENTS.md` "Editor modules" (key, "In the editor": tree beside the module or not, the prompt, auto-open, tabs, the sort menu, the list anatomy, no container badge); `docs/api.md` GET /api/modules; `docs/features.md`; a new ADR; `docs/architecture.md` where it narrates the module shell; `docs/styleguide/styleguide.html` only if a sample is missing. The README gains nothing. - Skills: `create-feature` (the module YAML it writes incl. `tree`, the screen it produces), `setup-site` (walking a customer through Forms), `edit-content` where it names the tree-selection step, `migrate-site` if it lists module limits. - Rule owners: entry status words/tone `Badge.tsx gitBadgeState`; translation dots/words `stores/translationState`; page actions `pageactions.ts`; containers/entries the server's `containerFor`/`managedBy`; the module key's validity the server's loader; the new "which container" rule `FeatureModule`+`routerepair`. No client re-derivation; no "same as" comments. - i18n: `module.*`, `feature.selectPage`/`selectTypedPage` replaced by the new copy, EN and DE. ## Acceptance - Forms module on a fresh `harness add forms` site: clicking the rail entry shows the list at once, no tree column, no rail toggle; News still shows the tree with muted non-container rows and the prompt panel. - Every state in the mockup's switcher (5 forms, empty, no match, viewing in German; one/several/no container; entry open) renders as drawn, on today's payload. - Drift tests: `web/` styles test (no literal, opacity only disabled), `scaffold/skills_test.go`, `scaffold` canonical-form test, module decoder unknown-key test, `docs/docs_test.go`, the `internal/server` route test (unchanged routes), `agentsdoc_test` if touched. - `grep -rn "list-table\|module-toolbar\|module-pager\|module-empty\|pane__hint" web/src/components/ModuleScreen.tsx` finds nothing.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/deckle#347
No description provided.