editor: element cards show a served children digest instead of nested cards and image-only thumbnails #260

Closed
opened 2026-10-13 11:34:01 +02:00 by dominik.polakovics · 0 comments

Summary

The page overview's element card shows one server-served digest of the element's children — count, the first three row summaries, thumbnails where a summary is an image — for every kind of child, and never nests cards. This replaces today's two inconsistent treatments: container children as nested cards, and item rows as image-only thumbnails (or nothing). With #259 landed, every child is managed in the owner's form, so the overview no longer needs to reach them.

Mockup (private artifact, decided with the maintainer; the "Page overview" tab with its "Show today's layout for comparison" switch is this issue): https://claude.ai/artifact/7TnAN5rACaDYNv6iZPsak5

Current behavior

  • A card (web/src/components/ElementCard.tsx) shows label, #uid, badges, the served summary line and, through elementImageRefs (web/src/elementcard.ts), up to three thumbnails of its item rows' image-typed params. Item rows without an image (cards → card) show nothing, although card declares summary: heading.
  • A container's children are nested as cards under the parent (hasSubList, LayoutGrid's sub-list with its own insert rows), draggable into and out of the container.
  • gridCardCount counts nested cards; the translation grid (web/src/translationgrid.ts) walks into translated containers to place placeholders for untranslated nested children.

Desired behavior

  • Every card with children shows, under its summary line, a children digest: the count with the collection's label ("3 cards", "5 images", "4 items" — the items label or the child element's label), then the first three rows' summaries separated by a dot, then "+n" for the rest. A row whose summary came from an image-typed param shows a thumbnail in place of its text (so the image card keeps its thumbnails). Disabled rows count and show, dimmed like the form shows them. A card with no children shows nothing extra.
  • The digest is served with the tree: the server's per-node verdict (content.Verdict, elemops.Verdicts) carries it, exactly as role and summary are served today, so the client assembles the line from served data and derives no summary, role or field-type rule itself (CLAUDE.md "Every rule has exactly one owner"; elemops.ElementSummary is the one summary rule).
  • No card carries a nested sub-list or nested insert rows any more; hasSubList, the sub-list rendering and nested drag targets go. Clicking the card opens the owner's form, where #259 put the children. Inserting into a container happens from its form's Add, or by cut and paste (the ⋮ menu / ⌘X ⌘V still paste into a container as a target? — see Decisions).
  • The Content tab's card count (gridCardCount) counts top-level cards only; the translation grid shows a translated container as one card with its digest and no nested placeholders (an untranslated nested child is reached from the translated container's form, which #259 shows read-only with the pencil).
  • The same digest serves the link picker's rows and any other place the served summary is shown beside the element, where that is useful; at minimum the overview and the unused-content dense list.

Decisions

  • One digest rule for every child kind — the maintainer's call: "it should be just in the element shown itself"; rows as cards on the overview are too large.
  • Digest content is count + first three summaries + thumbnails for image summaries — enough to recognise the element, small enough for twelve cards to stay one line.
  • Server-served, never client-derived — the rule already exists in elemops.ElementSummary; the client gets a verdict, not a recipe.
  • Nested cards and nested insert rows are removed, not collapsed — with the form managing children there is no second place to keep consistent.
  • Cut and paste remains the way to move an element across containers — the overview loses in-container drop targets; paste "into" a container as the ⋮ menu offers it today stays, since it goes through the same move/transfer operation.
  • No sidecar syntax — dropped by the maintainer.

Key interfaces

  • content.Verdict / shortcodeJSON (internal/content/json.go): a new optional children digest beside role and summary, present only for a node with children of role item or element; shape: count, label, and up to three entries each either {text} or {image: <media ref>}; built in internal/elemops from ChildRole and ElementSummary (which already knows whether the summary came from a basename/image param — expose that, do not re-derive it).
  • web/src/api/content.ts node types; web/src/elementcard.ts (elementImageRefs, hasSubList, gridCardCount); web/src/components/ElementCard.tsx, LayoutGrid.tsx (the sub-list and nested InsertRow), web/src/translationgrid.ts, web/src/dragReorder.ts / dropzone.ts for nested drop targets.
  • Vitest fixtures pinned from Go where the client needs the digest shape (the internal/pagepath/testdata pattern) if any client logic depends on it beyond rendering.
  • Docs and skills: scaffold/site/AGENTS.md wherever it describes the Content tab's cards, nested elements and thumbnails; scaffold/site/.claude/skills/add-element/SKILL.md (verification of a container or items element on the overview), verify-site, preview-site and edit-content where they mention nested cards; scaffold/skills_test.go and internal/element/agentsdoc_test.go must stay green.

Acceptance criteria

  • On the scaffold showcase page, the Cards card shows "3 cards · · · ", the Image card shows the count and up to three thumbnails plus "+n", the Accordion card shows the count and its first three item summaries; a text-media with images shows thumbnails; an element without children shows no digest.
  • The digest comes from the tree payload; go test pins the verdict for an items owner, a container, an element with a disabled child, and one with more than three children; no client code reads a schema's params or field types to build it.
  • No card nests cards or insert rows; a container's children are not draggable on the overview; the card count on the Content tab counts top-level cards only.
  • Clicking a container card opens its form, where its children are listed (#259).
  • The translation grid shows a translated container as one card; untranslated nested children produce no placeholders on the overview.
  • Cut/copy and paste into a container still work through the ⋮ menu.
  • scaffold/site/AGENTS.md and the affected skills describe the digest and no longer describe nested cards; drift tests pass.

How to verify

  • go test ./... (needs web/dist), cd web && npm test, harness check on the scaffolded site.
  • harness serve the scaffold site, open the showcase page's Content tab and compare against the mockup's "Page overview" tab.

Assumptions to check

  • That elemops.ElementSummary can report which step produced the summary without a second evaluation (refactor it to return the origin rather than mirroring its precedence elsewhere).
  • Where the link picker (internal/server/linktargets.go) composes " — ": decide whether the digest belongs there too, or leave it on the element summary alone.
  • The unused-content dense list (ElementCard dense) — whether it should show the digest or stay one line.

Out of scope

  • The children section in the owner's form — #259.
  • Any sidecar key controlling the digest.
  • Changing what the form's items rows show.

Blocked by

## Summary The page overview's element card shows one server-served digest of the element's children — count, the first three row summaries, thumbnails where a summary is an image — for every kind of child, and never nests cards. This replaces today's two inconsistent treatments: container children as nested cards, and item rows as image-only thumbnails (or nothing). With #259 landed, every child is managed in the owner's form, so the overview no longer needs to reach them. Mockup (private artifact, decided with the maintainer; the "Page overview" tab with its "Show today's layout for comparison" switch is this issue): https://claude.ai/artifact/7TnAN5rACaDYNv6iZPsak5 ## Current behavior - A card (`web/src/components/ElementCard.tsx`) shows label, `#uid`, badges, the served `summary` line and, through `elementImageRefs` (`web/src/elementcard.ts`), up to three thumbnails of its item rows' `image`-typed params. Item rows without an image (`cards` → `card`) show nothing, although `card` declares `summary: heading`. - A container's children are nested as cards under the parent (`hasSubList`, `LayoutGrid`'s sub-list with its own insert rows), draggable into and out of the container. - `gridCardCount` counts nested cards; the translation grid (`web/src/translationgrid.ts`) walks into translated containers to place placeholders for untranslated nested children. ## Desired behavior - Every card with children shows, under its summary line, a **children digest**: the count with the collection's label ("3 cards", "5 images", "4 items" — the items `label` or the child element's label), then the first three rows' summaries separated by a dot, then "+n" for the rest. A row whose summary came from an image-typed param shows a thumbnail in place of its text (so the image card keeps its thumbnails). Disabled rows count and show, dimmed like the form shows them. A card with no children shows nothing extra. - The digest is **served with the tree**: the server's per-node verdict (`content.Verdict`, `elemops.Verdicts`) carries it, exactly as `role` and `summary` are served today, so the client assembles the line from served data and derives no summary, role or field-type rule itself (CLAUDE.md "Every rule has exactly one owner"; `elemops.ElementSummary` is the one summary rule). - No card carries a nested sub-list or nested insert rows any more; `hasSubList`, the sub-list rendering and nested drag targets go. Clicking the card opens the owner's form, where #259 put the children. Inserting into a container happens from its form's Add, or by cut and paste (the ⋮ menu / ⌘X ⌘V still paste into a container as a target? — see Decisions). - The Content tab's card count (`gridCardCount`) counts top-level cards only; the translation grid shows a translated container as one card with its digest and no nested placeholders (an untranslated nested child is reached from the translated container's form, which #259 shows read-only with the pencil). - The same digest serves the link picker's rows and any other place the served `summary` is shown beside the element, where that is useful; at minimum the overview and the unused-content dense list. ## Decisions - One digest rule for every child kind — the maintainer's call: "it should be just in the element shown itself"; rows as cards on the overview are too large. - Digest content is count + first three summaries + thumbnails for image summaries — enough to recognise the element, small enough for twelve cards to stay one line. - Server-served, never client-derived — the rule already exists in `elemops.ElementSummary`; the client gets a verdict, not a recipe. - Nested cards and nested insert rows are removed, not collapsed — with the form managing children there is no second place to keep consistent. - Cut and paste remains the way to move an element across containers — the overview loses in-container drop targets; paste "into" a container as the ⋮ menu offers it today stays, since it goes through the same move/transfer operation. - No sidecar syntax — dropped by the maintainer. ## Key interfaces - `content.Verdict` / `shortcodeJSON` (`internal/content/json.go`): a new optional children digest beside `role` and `summary`, present only for a node with children of role item or element; shape: count, label, and up to three entries each either `{text}` or `{image: <media ref>}`; built in `internal/elemops` from `ChildRole` and `ElementSummary` (which already knows whether the summary came from a basename/image param — expose that, do not re-derive it). - `web/src/api/content.ts` node types; `web/src/elementcard.ts` (`elementImageRefs`, `hasSubList`, `gridCardCount`); `web/src/components/ElementCard.tsx`, `LayoutGrid.tsx` (the sub-list and nested `InsertRow`), `web/src/translationgrid.ts`, `web/src/dragReorder.ts` / `dropzone.ts` for nested drop targets. - Vitest fixtures pinned from Go where the client needs the digest shape (the `internal/pagepath/testdata` pattern) if any client logic depends on it beyond rendering. - Docs and skills: `scaffold/site/AGENTS.md` wherever it describes the Content tab's cards, nested elements and thumbnails; `scaffold/site/.claude/skills/add-element/SKILL.md` (verification of a container or items element on the overview), `verify-site`, `preview-site` and `edit-content` where they mention nested cards; `scaffold/skills_test.go` and `internal/element/agentsdoc_test.go` must stay green. ## Acceptance criteria - [ ] On the scaffold showcase page, the Cards card shows "3 cards · <heading> · <heading> · <heading>", the Image card shows the count and up to three thumbnails plus "+n", the Accordion card shows the count and its first three item summaries; a `text-media` with images shows thumbnails; an element without children shows no digest. - [ ] The digest comes from the tree payload; `go test` pins the verdict for an items owner, a container, an element with a disabled child, and one with more than three children; no client code reads a schema's params or field types to build it. - [ ] No card nests cards or insert rows; a container's children are not draggable on the overview; the card count on the Content tab counts top-level cards only. - [ ] Clicking a container card opens its form, where its children are listed (#259). - [ ] The translation grid shows a translated container as one card; untranslated nested children produce no placeholders on the overview. - [ ] Cut/copy and paste into a container still work through the ⋮ menu. - [ ] `scaffold/site/AGENTS.md` and the affected skills describe the digest and no longer describe nested cards; drift tests pass. ## How to verify - `go test ./...` (needs `web/dist`), `cd web && npm test`, `harness check` on the scaffolded site. - `harness serve` the scaffold site, open the showcase page's Content tab and compare against the mockup's "Page overview" tab. ## Assumptions to check - That `elemops.ElementSummary` can report which step produced the summary without a second evaluation (refactor it to return the origin rather than mirroring its precedence elsewhere). - Where the link picker (`internal/server/linktargets.go`) composes "<summary> — <page>": decide whether the digest belongs there too, or leave it on the element summary alone. - The unused-content dense list (`ElementCard` `dense`) — whether it should show the digest or stay one line. ## Out of scope - The children section in the owner's form — #259. - Any sidecar key controlling the digest. - Changing what the form's items rows show. ## Blocked by - #259
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#260
No description provided.