Calendar: month view, desktop grid and phone dots #190

Closed
opened 2026-08-23 22:54:06 +00:00 by nalum · 2 comments
Owner

Part of the calendar redesign. The design handoff (design_handoff_calendar, held outside the repo) is the source; the facts it depends on are repeated here so this issue stands alone.

Desktop is a hairline grid, not floating cards. The shipped 8px gutters between rounded cells break the column reading a month grid exists for, and cost roughly a line of text per cell.

  • Rows size to their fullest day: an empty week collapses to 74px, a busy one takes 132px. Same month, about 200px shorter, no scroll on a laptop.
  • No time column in cells. Rows sort by time; the clock face belongs to the day sheet, week and agenda. A time that fits only as 15:0... is worse than none. Where the time is the point, it rides in the title.
  • Weekend columns tinted, out-of-month days dimmed, today a tinted cell with the word Today.
  • Overflow reads 3 more and opens the day sheet.
  • Birthdays are the one tinted row — the only all-day item nobody attends.

Phone is the only genuinely new visual language in this bundle. At 390px a week column is 47px, so the grid stops pretending to hold content: a date and up to three dots.

  • A dot is a person with something on, not an item. A family generates a dozen items on a Saturday and there is no honest way to draw twelve dots in 47px. "Who has something on" is bounded by the household and answers what a parent actually asks.
  • Past three, the third slot becomes a split-colour lozenge meaning "and others" — a dot-shaped object, never a numeral at 8px.
  • Order is fixed: you first, then household order, so your own colour is never merged away.
  • Filtered to one person the dots count items instead, because colour is then carrying nothing.
  • Dots stay round. A squircle and a circle are the same object at 5px, so type reappears at the first size that can draw a mark.
  • Day content lives in a sheet below the grid, full width, 48px rows.

Two requirements added after #213 shipped

The job sheet went out to the family's cluster three times before it was right.
Seven visual defects, none caught by a suite: pickers that unfolded forms
instead of opening, three Save buttons on a commit-on-blur screen, (optional)
labels, a reward's name used as a field label, an unstyled add row, checkboxes
with a ghosted tick, and a create form with a browser spinner. Every one had to
be found by a person looking at a screen.

1. Screenshot goldens are part of this ticket

Record gallery (Playwright) and Roborazzi cases for every surface this ticket
builds or visibly changes, and treat them as a deliverable rather than a
follow-up. Three of #213's defects — the unstyled add row, the ghosted
checkboxes, the spinner in the create form — were pixel faults that a golden
would have caught before a deploy did.

#172 deferred its goldens on the reasoning that later tickets would re-record
them. That reasoning was sound then and is not now: the row grammar and the
pickers are settled, so an image recorded here stays valid.

Mechanics, from AGENTS.md: a new case rides in the same commit as the code
that adds it — a commit that adds a gallery or Roborazzi case without its image
is red on its own, because check / web runs npm run test:screens and
android / build runs verifyRoborazziDebug. A re-recorded existing case
goes in its own commit, so the reviewable diff stays code.

2. Check for leaked form styling before you finish

Every visual defect on #213 came from one place: the shipped app's form
fragments reused inside the new row grammar. They pass every test, because the
tests assert the pieces exist rather than that the screen reads right.

Before you call this done, grep the surfaces you touched and report what you
found and what you did about each:

  • a raw <input> / OutlinedTextField / BasicTextField outside the row and
    picker components — a form field dropped into a list of rows
  • type="number", which renders browser spinner arrows
  • btn, link-btn, btn-quiet or TextButton where a row or a quiet row
    verb belongs — underlined links reading as broken text
  • (optional) in any label — §8 names that pattern as the form admitting it
    should not have asked
  • any Save button on a surface that commits on blur, including Save changes and Save the points
  • a disabled-and-grey control where law 5 wants it absent
  • a record's title used as a field row's label — that column is for a
    field's name (Who, When, Worth), and a long title wraps in it

If your ticket is the first to land after this was written, add the check to
AGENTS.md beside the goldens rule, so it stops being a thing I remember to say.


Update — the locked demo supersedes the per-row heights (2026-08-25)

calendar-demo.dc.html is now the design to build from, and it changes one rule above: every week row in the month is the same height, sized to the busiest day in the month (the demo tiers it — 96px when the month is empty, 112px light, 132px busy), and the date sits in the same top-left spot in every cell. Today's date is a filled accent pill in that spot with the word Today beside it, not an extra line above the content. The "empty weeks collapse to 74px" sentence above is stale; the handoff's acceptance checklist and the demo agree on uniform rows.

Phone month, from the demo: a birthday takes a dot slot with the cake (the cap beside it drops to two); unowned jobs draw the hollow dot; soloed to one person the dots count that person's items with fading opacity; past the cap the last slot is the split-colour lozenge. Day content below the grid, full-width rows, unchanged.

Part of the calendar redesign. The design handoff (`design_handoff_calendar`, held outside the repo) is the source; the facts it depends on are repeated here so this issue stands alone. **Desktop** is a hairline grid, not floating cards. The shipped 8px gutters between rounded cells break the column reading a month grid exists for, and cost roughly a line of text per cell. - Rows size to their fullest day: an empty week collapses to 74px, a busy one takes 132px. Same month, about 200px shorter, no scroll on a laptop. - No time column in cells. Rows sort by time; the clock face belongs to the day sheet, week and agenda. A time that fits only as `15:0...` is worse than none. Where the time is the point, it rides in the title. - Weekend columns tinted, out-of-month days dimmed, today a tinted cell with the word *Today*. - Overflow reads `3 more` and opens the day sheet. - Birthdays are the one tinted row — the only all-day item nobody attends. **Phone** is the only genuinely new visual language in this bundle. At 390px a week column is 47px, so the grid stops pretending to hold content: a date and up to three dots. - **A dot is a person with something on, not an item.** A family generates a dozen items on a Saturday and there is no honest way to draw twelve dots in 47px. "Who has something on" is bounded by the household and answers what a parent actually asks. - Past three, the third slot becomes a split-colour lozenge meaning "and others" — a dot-shaped object, never a numeral at 8px. - Order is fixed: you first, then household order, so your own colour is never merged away. - Filtered to one person the dots count items instead, because colour is then carrying nothing. - Dots stay round. A squircle and a circle are the same object at 5px, so type reappears at the first size that can draw a mark. - Day content lives in a sheet below the grid, full width, 48px rows. --- ## Two requirements added after #213 shipped The job sheet went out to the family's cluster three times before it was right. Seven visual defects, none caught by a suite: pickers that unfolded forms instead of opening, three Save buttons on a commit-on-blur screen, `(optional)` labels, a reward's name used as a field label, an unstyled add row, checkboxes with a ghosted tick, and a create form with a browser spinner. Every one had to be found by a person looking at a screen. ### 1. Screenshot goldens are part of this ticket Record gallery (Playwright) and Roborazzi cases for every surface this ticket builds or visibly changes, and treat them as a deliverable rather than a follow-up. Three of #213's defects — the unstyled add row, the ghosted checkboxes, the spinner in the create form — were pixel faults that a golden would have caught before a deploy did. `#172` deferred its goldens on the reasoning that later tickets would re-record them. That reasoning was sound then and is not now: the row grammar and the pickers are settled, so an image recorded here stays valid. Mechanics, from AGENTS.md: a **new** case rides in the same commit as the code that adds it — a commit that adds a gallery or Roborazzi case without its image is red on its own, because `check / web` runs `npm run test:screens` and `android / build` runs `verifyRoborazziDebug`. A **re-recorded existing** case goes in its own commit, so the reviewable diff stays code. ### 2. Check for leaked form styling before you finish Every visual defect on #213 came from one place: the shipped app's form fragments reused inside the new row grammar. They pass every test, because the tests assert the pieces exist rather than that the screen reads right. Before you call this done, grep the surfaces you touched and report what you found and what you did about each: - a raw `<input>` / `OutlinedTextField` / `BasicTextField` outside the row and picker components — a form field dropped into a list of rows - `type="number"`, which renders browser spinner arrows - `btn`, `link-btn`, `btn-quiet` or `TextButton` where a row or a quiet row verb belongs — underlined links reading as broken text - `(optional)` in any label — §8 names that pattern as the form admitting it should not have asked - **any Save button on a surface that commits on blur**, including `Save changes` and `Save the points` - a disabled-and-grey control where law 5 wants it absent - a record's title used as a field row's `label` — that column is for a field's name (`Who`, `When`, `Worth`), and a long title wraps in it If your ticket is the first to land after this was written, add the check to AGENTS.md beside the goldens rule, so it stops being a thing I remember to say. --- ## Update — the locked demo supersedes the per-row heights (2026-08-25) `calendar-demo.dc.html` is now the design to build from, and it changes one rule above: **every week row in the month is the same height, sized to the busiest day in the month** (the demo tiers it — 96px when the month is empty, 112px light, 132px busy), and the date sits in the same top-left spot in every cell. Today's date is a filled accent pill in that spot with the word *Today* beside it, not an extra line above the content. The "empty weeks collapse to 74px" sentence above is stale; the handoff's acceptance checklist and the demo agree on uniform rows. Phone month, from the demo: a birthday takes a dot slot with the cake (the cap beside it drops to two); unowned jobs draw the hollow dot; soloed to one person the dots count that person's items with fading opacity; past the cap the last slot is the split-colour lozenge. Day content below the grid, full-width rows, unchanged.
Author
Owner

Delivered in PR #260: the desktop hairline month (uniform week-row heights by the busiest day) and the phone dot month, with the dot rule pure and pinned cross-surface by conformance/calendar-dots.json (web/src/calmonth.ts, CalMonth.kt).

Delivered in PR #260: the desktop hairline month (uniform week-row heights by the busiest day) and the phone dot month, with the dot rule pure and pinned cross-surface by conformance/calendar-dots.json (web/src/calmonth.ts, CalMonth.kt).
Author
Owner

Delivered by PR #260 (hairline month grid + phone dots, calendar-dots.json), merged to main 2026-08-26.

Delivered by PR #260 (hairline month grid + phone dots, calendar-dots.json), merged to main 2026-08-26.
nalum closed this issue 2026-08-26 18:47:58 +00:00
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
eagraiclainne/app#190
No description provided.