feat(templates): compose the real daily page in the editor #35

Merged
TJC merged 9 commits from feat/m8-daily-page into main 2026-08-18 19:56:28 +01:00
Collaborator

Summary

  • compose the real daily page from the five built-in widgets by driving the
    shipped insert menu, outline and inspector
  • templates/daily-page.json is byte-for-byte what Export JSON writes, so the
    committed file is provably editor-built
  • A4 portrait, 10mm margins; date area and day circles across the top, an
    07:00-24:00 hourly timeline down the left, 10 todo rows over ruled notes
    on the right
  • then the five findings composing it turned up: closes #36, #37, #38, #39,
    #40
  • #24 stays open until the printed page has been written on for a day

Test plan

  • pnpm test - 601 passing; tsc --noEmit, eslint . and prettier --check .
    all clean
  • the composition test asserts no layout errors, no overflow, A4 page box,
    content inside all four margins, and seven day circles at seven distinct x
    positions
  • PDF taken off the Download PDF button; MediaBox is 595.2756 x 841.8898pt and
    spot-checked coordinates match the primitives in mm
  • the page is unchanged by the five fixes: same 118 primitives, no overflow
  • print on A4 and write on it for a day
## Summary - compose the real daily page from the five built-in widgets by driving the shipped insert menu, outline and inspector - templates/daily-page.json is byte-for-byte what Export JSON writes, so the committed file is provably editor-built - A4 portrait, 10mm margins; date area and day circles across the top, an 07:00-24:00 hourly timeline down the left, 10 todo rows over ruled notes on the right - then the five findings composing it turned up: closes #36, #37, #38, #39, #40 - #24 stays open until the printed page has been written on for a day ## Test plan - `pnpm test` - 601 passing; `tsc --noEmit`, `eslint .` and `prettier --check .` all clean - the composition test asserts no layout errors, no overflow, A4 page box, content inside all four margins, and seven day circles at seven distinct x positions - PDF taken off the Download PDF button; MediaBox is 595.2756 x 841.8898pt and spot-checked coordinates match the primitives in mm - the page is unchanged by the five fixes: same 118 primitives, no overflow - [ ] print on A4 and write on it for a day
- driven through the insert menu, outline and inspector, so the file is
  what those controls build rather than a fixture
- templates/daily-page.json is byte-for-byte what Export JSON writes,
  which is why prettier ignores it
- a container measured off its children has no leftover to share, so a
  grow child contributed nothing and its contents drew anyway
- day circles landed on one point 6mm past the right margin at the width
  the insert menu hands them
- the distribution base is unchanged: grow still starts at nothing and
  takes its whole extent from the share

closes #36
- a widget measured too narrow printed off the side of the paper as
  quietly as a tall one printed off the end of it
- one overflow entry per edge, each with its own band and label; a side
  band labels on the paper because it is millimetres wide
- the export warning names every margin rather than the deepest alone

closes #37
- the badge lands on the widget per decision 21, which is never the node
  whose size has to change
- definiteness now carries the outermost ancestor that broke the chain,
  and the message says to set that one
- outermost rather than innermost, because grow only works on a node
  whose own parent is definite

closes #38
- paper, orientation, margin, the three strokes, the three inks and the
  four font sizes had no control outside the raw JSON editor
- generated from an inputs schema like every other panel, so no
  hand-written property panel appears
- ink is coverage in percent, since decision 9 bans a hex escape hatch
  and already writes the greys down as coverage
- text with no ink of its own now takes the theme's rather than a black
  nailed into the renderer, so the control reaches inside a widget

closes #39
- PLAN.md says row height is a readout in the inspector, and there was
  no readout: the inspector showed declared inputs and nothing else
- a readout is a declared input like any other, so a custom widget can
  say the same thing about itself
- evaluated after layout against the box the node was given, which is
  the only place $boxWidth and $boxHeight are bound
- adds count, so a repeat over a generated list can say how many rows it
  will run to

closes #40
- decision 6 listed the function table without count
- decision 11 listed the control types without readout, and said nothing
  about the page and theme declaring the same kind of schema
- decision 16 said the bottom margin where the check is now all four
- widgetScope evaluates every prop, so building the readout scope threw
  where only the readout expression was caught
- resolve props against the template scope, not a bare theme scope
- widgetScope and instanceValues walk valueInputs, so a readout name
  validated clean and was then dropped
Author
Collaborator

Review fixes, one commit each:

  • cfcb492 - readoutFields built its scope with widgetScope, which evaluates every prop, but only the readout expression was inside a try/catch. Selecting a widget whose prop cannot resolve (e.g. a Day timeline under a repeat with start: $item) threw out of the Inspector render. The scope build is now caught and the fields read empty. It also resolves against templateScope rather than a bare theme scope, so a prop naming a template input works.
  • 12f9275 - undeclaredProps walked all of spec.inputs, but widgetScope and instanceValues walk valueInputs only, so props: { rowHeight: ... } on the day timeline validated clean and was then silently dropped. Readout names now get their own message.

Regression tests for both. 603 tests, tsc --noEmit and eslint pass.

Not addressed, all low:

  • theme-inputs.ts:46 - margin stepper has no max; a margin of 200 on A4 gives a negative content box and puts the overflow bands mid-sheet.
  • Control.tsx:133 - a failed readout renders the unit with no value, so the field reads a bare "mm".
  • theme-inputs.ts:79 + layout-inputs.ts:88 - two controls labelled "Ink" in the same aside when a text node is selected.
Review fixes, one commit each: - `cfcb492` - `readoutFields` built its scope with `widgetScope`, which evaluates every prop, but only the readout expression was inside a try/catch. Selecting a widget whose prop cannot resolve (e.g. a Day timeline under a repeat with `start: $item`) threw out of the Inspector render. The scope build is now caught and the fields read empty. It also resolves against `templateScope` rather than a bare theme scope, so a prop naming a template input works. - `12f9275` - `undeclaredProps` walked all of `spec.inputs`, but `widgetScope` and `instanceValues` walk `valueInputs` only, so `props: { rowHeight: ... }` on the day timeline validated clean and was then silently dropped. Readout names now get their own message. Regression tests for both. 603 tests, `tsc --noEmit` and `eslint` pass. Not addressed, all low: - `theme-inputs.ts:46` - margin stepper has no `max`; a margin of 200 on A4 gives a negative content box and puts the overflow bands mid-sheet. - `Control.tsx:133` - a failed readout renders the unit with no value, so the field reads a bare "mm". - `theme-inputs.ts:79` + `layout-inputs.ts:88` - two controls labelled "Ink" in the same aside when a text node is selected.
TJC merged commit 62d3cd2dbc into main 2026-08-18 19:56:28 +01:00
Sign in to join this conversation.
No reviewers
No labels
chore
core
render
ui
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
TJC/daily-planner-template!35
No description provided.