diff --git a/.work/todo.jsonl b/.work/todo.jsonl index 424329d..8479d57 100644 --- a/.work/todo.jsonl +++ b/.work/todo.jsonl @@ -333,3 +333,30 @@ {"actor":"richardhightower","ev":"01M5GRYQY7EZMDFZQ3BKVPJRVQ","git":"a2f4dcd","item":"01M5GRYQY7ZAK975G44M0G6T6N","op":"create","set":{"acceptance_criteria":"bun test src/lib/workspaceSynthesis.test.ts src/lib/ai/run.test.ts src/lib/ReadmeGenerator.test.ts passes, and the CI unit job passes on main.","body":"workspaceSynthesis.test.ts spies on callLLMFromUI in stubLLM() and never restores the spy. Tests in other files then see the old calls and fail. Which test fails depends on the order in which Bun runs the files, so the bug showed up only after PR 63 added test files. It fails CI on PR 63 and PR 64.","discovered_during":"01M5FT7DV6ZMNBXWA883G6CDC8","estimate":"XS","kind":"bug","labels":["tests","ci"],"level":"task","owner":"Rick Hightower","priority":"P1","status":"todo","title":"Restore the LLM spy after each workspace synthesis test","unplanned":true},"ts":"2026-10-22T03:02:28Z"} {"actor":"richardhightower","ev":"01M5GTCRJQ4SQPCBRC58ETWECP","git":"b14bcab","item":"01M5GTCRJQPGX82TS89Y93732Z","op":"create","set":{"acceptance_criteria":"A change to src/**/*.test.ts alone passes the UI Guard. A change to src/App.tsx with no wireframes/ update still fails it.","body":"scripts/check-ui-guard.sh treats every .ts file under src/ as UI source, including unit test files. A test-only fix then fails the UI Guard job and asks for a wireframe that cannot exist. Test files have no UI.","discovered_during":"01M5GRYQY7ZAK975G44M0G6T6N","estimate":"XS","kind":"bug","labels":["ci","ui-guard"],"level":"task","owner":"Rick Hightower","priority":"P2","status":"todo","title":"Stop the UI Guard from treating test files as UI source","unplanned":true},"ts":"2026-10-22T03:27:36Z"} {"actor":"richardhightower","ev":"01M5J4C2147SY139VY006Q6E54","item":"01M5J4C2142M28BJZPBSWJ4Y04","op":"create","set":{"body":"Stamp CHANGELOG 0.6.6 (reload, themed PDF and Word export, themes), lockstep Cargo.toml / Cargo.lock / tauri.conf to 0.6.6, freeze the roadmap snapshot, tag and GitHub release after merge, then install the build locally.","kind":"ops","level":"task","milestone":"v0.6.6","priority":"P2","status":"todo","title":"chore(release): v0.6.6 changelog, version bump, roadmap snapshot"},"ts":"2026-10-22T15:41:13Z"} +{"actor":"richardhightower","ev":"01M5JJZFC18WW6HYA0AVXZSGDN","item":"01M5JJZFC11HAXZHJJ6N10S79G","op":"create","set":{"body":"PDF export prints tables as spaced text. This work draws real tables in the PDF and adds table colors (header, row, alternate row, border) to export themes, so PDF, Word, and the preview all match.","kind":"feature","level":"epic","plan":"docs/plans/2026-10-22-pdf-tables.md","priority":"P1","status":"todo","title":"Themed tables in PDF export"},"ts":"2026-10-22T19:56:29Z"} +{"actor":"richardhightower","ev":"01M5JJZFC1C30T19BW61RM33EH","item":"01M5JJZFC1Y253JZSTV70R3S3P","op":"create","set":{"body":"Legacy custom themes fall back to their own codeBg, heading, page, and muted colors.","kind":"feature","level":"task","parent":"01M5JJZFC11HAXZHJJ6N10S79G","plan":"docs/plans/2026-10-22-pdf-tables.md","priority":"P1","status":"todo","title":"Add the five table color fields to ExportTheme and both builtins"},"ts":"2026-10-22T19:56:29Z"} +{"actor":"richardhightower","ev":"01M5JJZFC1YC4BYFX3AR7BWTF7","item":"01M5JJZFC136XTFWX2GB74JF2W","op":"create","set":{"body":"Hand-written with jsPDF. No new dependency.","kind":"feature","level":"task","parent":"01M5JJZFC11HAXZHJJ6N10S79G","plan":"docs/plans/2026-10-22-pdf-tables.md","priority":"P1","status":"todo","title":"Draw PDF tables with borders, a header row, stripes, wrapping, and a repeated header"},"ts":"2026-10-22T19:56:29Z"} +{"actor":"richardhightower","ev":"01M5JJZFC1H45N2A94ECPMAQAF","item":"01M5JJZFC1GTE6MWBQE89529RQ","op":"create","set":{"kind":"feature","level":"task","parent":"01M5JJZFC11HAXZHJJ6N10S79G","plan":"docs/plans/2026-10-22-pdf-tables.md","priority":"P2","status":"todo","title":"Use the table fields in the Word export and the HTML preview"},"ts":"2026-10-22T19:56:29Z"} +{"actor":"richardhightower","ev":"01M5JJZFC1TKY4T8BVWF8AW9XP","item":"01M5JJZFC14JQC2NNTQKG2B4GV","op":"create","set":{"kind":"feature","level":"task","parent":"01M5JJZFC11HAXZHJJ6N10S79G","plan":"docs/plans/2026-10-22-pdf-tables.md","priority":"P2","status":"todo","title":"Add a Tables group to the Themes dialog with a wireframe"},"ts":"2026-10-22T19:56:29Z"} +{"actor":"richardhightower","ev":"01M5JJZFC1JJJV4XDQFB84VYBD","item":"01M5JJZFC1QWPY3EV9WCNZVC01","op":"create","set":{"kind":"feature","level":"task","parent":"01M5JJZFC11HAXZHJJ6N10S79G","plan":"docs/plans/2026-10-22-pdf-tables.md","priority":"P1","status":"todo","title":"Unit and Playwright tests for themed tables"},"ts":"2026-10-22T19:56:29Z"} +{"actor":"richardhightower","ev":"01M5JJZFC1FQ5FJGAJ8Z0T2HYK","item":"01M5JJZFC1MD61SVP5QBX9Q9JR","op":"create","set":{"kind":"feature","level":"task","parent":"01M5JJZFC11HAXZHJJ6N10S79G","plan":"docs/plans/2026-10-22-pdf-tables.md","priority":"P2","status":"todo","title":"Update the user guide, README, design doc, changelog, and wiki"},"ts":"2026-10-22T19:56:29Z"} +{"actor":"richardhightower","ev":"01M5JJZFC1P1RR4ZH8HYRFC63F","item":"01M5JJZFC1B9P22KTJF6JS378H","op":"create","set":{"kind":"feature","level":"task","parent":"01M5JJZFC11HAXZHJJ6N10S79G","plan":"docs/plans/2026-10-22-pdf-tables.md","priority":"P2","status":"todo","title":"Clean up the v0.6.6 branches and file the DMG build failure"},"ts":"2026-10-22T19:56:29Z"} +{"actor":"richardhightower","ev":"01M5JJZKJCA9TEEQRS3HA62QBY","item":"01M5JJZFC1Y253JZSTV70R3S3P","op":"update","set":{"milestone":"v0.6.7"},"ts":"2026-10-22T19:56:34Z"} +{"actor":"richardhightower","ev":"01M5JJZKM9BBMK8R40NRKMCSMA","item":"01M5JJZFC136XTFWX2GB74JF2W","op":"update","set":{"milestone":"v0.6.7"},"ts":"2026-10-22T19:56:34Z"} +{"actor":"richardhightower","ev":"01M5JJZKP7B97HWN4HVR1PEGFN","item":"01M5JJZFC1GTE6MWBQE89529RQ","op":"update","set":{"milestone":"v0.6.7"},"ts":"2026-10-22T19:56:34Z"} +{"actor":"richardhightower","ev":"01M5JJZKR55PJM3PQ1TMWBNN1X","item":"01M5JJZFC14JQC2NNTQKG2B4GV","op":"update","set":{"milestone":"v0.6.7"},"ts":"2026-10-22T19:56:34Z"} +{"actor":"richardhightower","ev":"01M5JJZKT15114PY8YWPYYYTBA","item":"01M5JJZFC1QWPY3EV9WCNZVC01","op":"update","set":{"milestone":"v0.6.7"},"ts":"2026-10-22T19:56:34Z"} +{"actor":"richardhightower","ev":"01M5JJZKW1QX7M4JAS67XWAK62","item":"01M5JJZFC1MD61SVP5QBX9Q9JR","op":"update","set":{"milestone":"v0.6.7"},"ts":"2026-10-22T19:56:34Z"} +{"actor":"richardhightower","ev":"01M5JJZKY0V4VXYK5H56FKCFND","item":"01M5JJZFC1B9P22KTJF6JS378H","op":"update","set":{"milestone":"v0.6.7"},"ts":"2026-10-22T19:56:34Z"} +{"actor":"richardhightower","ev":"01M5JJZM00XP21G71CGCDJ4HM1","item":"01M5FSD7MA4Z0KY4ZRWRV0XJZ3","op":"update","set":{"milestone":"v0.6.7","status":"in_progress"},"ts":"2026-10-22T19:56:34Z"} +{"actor":"richardhightower","ev":"01M5JJZRM89V5P4FQFJPDNJCMF","item":"01M5JJZRM87A0Y5YFFHE8WF2GR","op":"create","set":{"body":"The v0.6.6 release build made Motion.app, but the DMG step in bundle_dmg.sh failed. The app itself is fine. Releases attach no files, so nothing is missing yet. Find the cause, so a release can attach a DMG.","discovered_during":"01M5J4C2142M28BJZPBSWJ4Y04","kind":"bug","level":"task","priority":"P2","status":"todo","title":"bun tauri build fails at the DMG step (bundle_dmg.sh)","unplanned":true},"ts":"2026-10-22T19:56:39Z"} +{"actor":"richardhightower","ev":"01M5JKR1P3MVZ7FXQ9FB3DDPTT","item":"01M5JKR1P3V9VD5TGSFYFXCV6D","op":"create","set":{"body":"Full Playwright runs fail one to four tests that pass when run again. On main the same day, persistence 'a new note is created, listed, and opens' failed once in a full run. On the PDF table branch, the dataset JOIN, both new-note persistence tests, and the sanitize test failed in one run and passed in the next. The machine load average was about 6. The tests use 5 s waits and retries is 0. Find the race, or give these waits more time.","discovered_during":"01M5JJZFC1QWPY3EV9WCNZVC01","kind":"bug","level":"task","priority":"P2","status":"todo","title":"E2E: new-note and dataset journeys fail at random under load","unplanned":true},"ts":"2026-10-22T20:09:55Z"} +{"actor":"richardhightower","ev":"01M5JKV9HQX2E03XRF92RPCKHD","item":"01M5JKV9HQZ7X83CD6X1SMP6VV","op":"create","set":{"body":"CLAUDE.md says to publish docs to the GitHub wiki. worklog ia-render writes publish-manifest.json (203 pages), but nothing copies the doc pages into .work/wiki-checkout and pushes them. The wiki checkout has 100 pages, and its last publish commit is from 2026-07-29. Add a publish command, or change the Definition of Done to match what really happens.","discovered_during":"01M5JJZFC1MD61SVP5QBX9Q9JR","kind":"ops","level":"task","priority":"P2","status":"todo","title":"Wiki publish: no script applies publish-manifest.json to the wiki","unplanned":true},"ts":"2026-10-22T20:11:41Z"} +{"actor":"richardhightower","ev":"01M5JM6Y8D8B2GNKPYDBYGCRXM","item":"01M5JJZFC1Y253JZSTV70R3S3P","op":"close","set":{"resolution":"Shipped in PR 67.","status":"done"},"ts":"2026-10-22T20:18:03Z"} +{"actor":"richardhightower","ev":"01M5JM6YA7Z4Q1E5MC8AQFPN3W","item":"01M5JJZFC136XTFWX2GB74JF2W","op":"close","set":{"resolution":"Shipped in PR 67.","status":"done"},"ts":"2026-10-22T20:18:03Z"} +{"actor":"richardhightower","ev":"01M5JM6YC1ZX3MRPKQ3J9HCSV1","item":"01M5JJZFC1GTE6MWBQE89529RQ","op":"close","set":{"resolution":"Shipped in PR 67.","status":"done"},"ts":"2026-10-22T20:18:03Z"} +{"actor":"richardhightower","ev":"01M5JM6YDTXJNK5MQZZ0TJ0NFW","item":"01M5JJZFC14JQC2NNTQKG2B4GV","op":"close","set":{"resolution":"Shipped in PR 67.","status":"done"},"ts":"2026-10-22T20:18:03Z"} +{"actor":"richardhightower","ev":"01M5JM6YFNMEE57GTRCYX8Y39A","item":"01M5JJZFC1QWPY3EV9WCNZVC01","op":"close","set":{"resolution":"Shipped in PR 67.","status":"done"},"ts":"2026-10-22T20:18:03Z"} +{"actor":"richardhightower","ev":"01M5JM6YHFF1K6PB3Y7TS9FTVB","item":"01M5JJZFC1MD61SVP5QBX9Q9JR","op":"close","set":{"resolution":"Docs updated in PR 67. The wiki publish has no script; tracked in 01M5JKV9HQZ7X83CD6X1SMP6VV.","status":"done"},"ts":"2026-10-22T20:18:03Z"} +{"actor":"richardhightower","ev":"01M5JM6YK83T9XZG8Y5XJ6MNZ9","item":"01M5FSD7MA4Z0KY4ZRWRV0XJZ3","op":"close","set":{"resolution":"PDF tables now draw borders, a bold filled header row, and stripes. PR 67.","status":"done"},"ts":"2026-10-22T20:18:03Z"} +{"actor":"richardhightower","ev":"01M5JM6YN52NDA42G7VX6P5H25","item":"01M5JJZFC1B9P22KTJF6JS378H","op":"update","set":{"status":"in_progress"},"ts":"2026-10-22T20:18:03Z"} diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ff35ab..7841e59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to Motion are recorded here. Dates are UTC. ## Unreleased +### Added + +- **Themed tables in export.** Each theme now sets five table colors: header, + header text, row, alternate row, and border. **Themes** has a **Tables** + group to edit them. Ice Snowstorm has a navy header and ice stripes. Clay + has a terracotta header and warm stripes. + +### Fixed + +- **PDF tables** were plain spaced text. They are now a grid with borders, a + bold filled header row, striped body rows, and text that wraps in each cell. + The header row repeats on each new page. Word and the preview use the same + theme colors. + ## 0.6.6, 2026-10-22 Reload a note from disk, and export it as a themed PDF or Word file. diff --git a/README.md b/README.md index 673c9e4..42bade7 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,9 @@ natural-language prompts using CLI tools you already have installed. previews the page first. Ice Snowstorm (ice page, black text, navy headings, blue rules) and Clay (Anthropic ivory paper, terracotta accent) are built in. **Themes** adds more and sets the export default. PDF uses standard fonts; - Word uses Calibri or Georgia. + Word uses Calibri or Georgia. Tables export as a bordered grid with a filled + header row and striped body rows in both PDF and Word. Each theme sets the + table header, header text, row, alternate row, and border colors. - **Zoom** — ⌘+ / ⌘- / ⌘0 scale the editor and the file tree, not the header. A brief overlay shows the percentage. Remembered in the settings file. - **Layout** — the editor fills the window. Drag the sidebar edge or the Split @@ -165,6 +167,9 @@ Recorded here rather than discovered later: - **PDF export** uses Helvetica, Times, or Courier. Word uses Calibri, Georgia, or Consolas. The on-screen preview uses system fonts, so it can look slightly closer to the theme than the PDF does. +- **PDF tables** size each column by its longest cell text, counted in + characters, so a column of wide letters can wrap early. A single table row + taller than a page runs off the page. The header row repeats on each page. See [CHANGELOG.md](CHANGELOG.md) for release history and [docs/roadmap.md](docs/roadmap.md) for what is planned. diff --git a/docs/.index/_graph.json b/docs/.index/_graph.json index 4892269..a1e1fb8 100644 --- a/docs/.index/_graph.json +++ b/docs/.index/_graph.json @@ -972,7 +972,12 @@ }, { "from": "item/01M5FSD7MA4Z0KY4ZRWRV0XJZ3", - "to": "release/v0.6.6", + "to": "pr/67", + "type": "lands-in" + }, + { + "from": "item/01M5FSD7MA4Z0KY4ZRWRV0XJZ3", + "to": "release/v0.6.7", "type": "targets" }, { @@ -1010,6 +1015,81 @@ "to": "release/v0.6.6", "type": "targets" }, + { + "from": "item/01M5JJZFC11HAXZHJJ6N10S79G", + "to": "pr/67", + "type": "lands-in" + }, + { + "from": "item/01M5JJZFC136XTFWX2GB74JF2W", + "to": "item/01M5JJZFC11HAXZHJJ6N10S79G", + "type": "belongs-to" + }, + { + "from": "item/01M5JJZFC136XTFWX2GB74JF2W", + "to": "release/v0.6.7", + "type": "targets" + }, + { + "from": "item/01M5JJZFC14JQC2NNTQKG2B4GV", + "to": "item/01M5JJZFC11HAXZHJJ6N10S79G", + "type": "belongs-to" + }, + { + "from": "item/01M5JJZFC14JQC2NNTQKG2B4GV", + "to": "release/v0.6.7", + "type": "targets" + }, + { + "from": "item/01M5JJZFC1B9P22KTJF6JS378H", + "to": "item/01M5JJZFC11HAXZHJJ6N10S79G", + "type": "belongs-to" + }, + { + "from": "item/01M5JJZFC1B9P22KTJF6JS378H", + "to": "release/v0.6.7", + "type": "targets" + }, + { + "from": "item/01M5JJZFC1GTE6MWBQE89529RQ", + "to": "item/01M5JJZFC11HAXZHJJ6N10S79G", + "type": "belongs-to" + }, + { + "from": "item/01M5JJZFC1GTE6MWBQE89529RQ", + "to": "release/v0.6.7", + "type": "targets" + }, + { + "from": "item/01M5JJZFC1MD61SVP5QBX9Q9JR", + "to": "item/01M5JJZFC11HAXZHJJ6N10S79G", + "type": "belongs-to" + }, + { + "from": "item/01M5JJZFC1MD61SVP5QBX9Q9JR", + "to": "release/v0.6.7", + "type": "targets" + }, + { + "from": "item/01M5JJZFC1QWPY3EV9WCNZVC01", + "to": "item/01M5JJZFC11HAXZHJJ6N10S79G", + "type": "belongs-to" + }, + { + "from": "item/01M5JJZFC1QWPY3EV9WCNZVC01", + "to": "release/v0.6.7", + "type": "targets" + }, + { + "from": "item/01M5JJZFC1Y253JZSTV70R3S3P", + "to": "item/01M5JJZFC11HAXZHJJ6N10S79G", + "type": "belongs-to" + }, + { + "from": "item/01M5JJZFC1Y253JZSTV70R3S3P", + "to": "release/v0.6.7", + "type": "targets" + }, { "from": "plan/2026-07-26-motion-next-phase", "to": "item/01KYFZ6RBH4J746JDANTQKYVSN", @@ -1475,6 +1555,46 @@ "to": "item/01M1MVB300WYDPA67T9FNDM51R", "type": "produces" }, + { + "from": "plan/2026-10-22-pdf-tables", + "to": "item/01M5JJZFC11HAXZHJJ6N10S79G", + "type": "produces" + }, + { + "from": "plan/2026-10-22-pdf-tables", + "to": "item/01M5JJZFC136XTFWX2GB74JF2W", + "type": "produces" + }, + { + "from": "plan/2026-10-22-pdf-tables", + "to": "item/01M5JJZFC14JQC2NNTQKG2B4GV", + "type": "produces" + }, + { + "from": "plan/2026-10-22-pdf-tables", + "to": "item/01M5JJZFC1B9P22KTJF6JS378H", + "type": "produces" + }, + { + "from": "plan/2026-10-22-pdf-tables", + "to": "item/01M5JJZFC1GTE6MWBQE89529RQ", + "type": "produces" + }, + { + "from": "plan/2026-10-22-pdf-tables", + "to": "item/01M5JJZFC1MD61SVP5QBX9Q9JR", + "type": "produces" + }, + { + "from": "plan/2026-10-22-pdf-tables", + "to": "item/01M5JJZFC1QWPY3EV9WCNZVC01", + "type": "produces" + }, + { + "from": "plan/2026-10-22-pdf-tables", + "to": "item/01M5JJZFC1Y253JZSTV70R3S3P", + "type": "produces" + }, { "from": "roadmap-snapshot/2026-07-28_v0.1.0-release", "to": "roadmap", @@ -1580,6 +1700,11 @@ "to": "roadmap", "type": "snapshot-of" }, + { + "from": "roadmap-snapshot/2026-10-22_v0.6.6-release", + "to": "roadmap-snapshot/2026-09-10_v0.6.5-release", + "type": "supersedes" + }, { "from": "roadmap-snapshot/2026-10-22_v0.6.6-release", "to": "release/v0.6.6", @@ -2276,7 +2401,7 @@ }, "item/01M5FSD7MA4Z0KY4ZRWRV0XJZ3": { "doc_type": "item", - "status": "todo", + "status": "done", "title": "PDF export: draw table borders and a header row style" }, "item/01M5FSD7PJCJXQ9VE693ACM4B2": { @@ -2349,6 +2474,61 @@ "status": "todo", "title": "chore(release): v0.6.6 changelog, version bump, roadmap snapshot" }, + "item/01M5JJZFC11HAXZHJJ6N10S79G": { + "doc_type": "item", + "status": "todo", + "title": "Themed tables in PDF export" + }, + "item/01M5JJZFC136XTFWX2GB74JF2W": { + "doc_type": "item", + "status": "done", + "title": "Draw PDF tables with borders, a header row, stripes, wrapping, and a repeated header" + }, + "item/01M5JJZFC14JQC2NNTQKG2B4GV": { + "doc_type": "item", + "status": "done", + "title": "Add a Tables group to the Themes dialog with a wireframe" + }, + "item/01M5JJZFC1B9P22KTJF6JS378H": { + "doc_type": "item", + "status": "in_progress", + "title": "Clean up the v0.6.6 branches and file the DMG build failure" + }, + "item/01M5JJZFC1GTE6MWBQE89529RQ": { + "doc_type": "item", + "status": "done", + "title": "Use the table fields in the Word export and the HTML preview" + }, + "item/01M5JJZFC1MD61SVP5QBX9Q9JR": { + "doc_type": "item", + "status": "done", + "title": "Update the user guide, README, design doc, changelog, and wiki" + }, + "item/01M5JJZFC1QWPY3EV9WCNZVC01": { + "doc_type": "item", + "status": "done", + "title": "Unit and Playwright tests for themed tables" + }, + "item/01M5JJZFC1Y253JZSTV70R3S3P": { + "doc_type": "item", + "status": "done", + "title": "Add the five table color fields to ExportTheme and both builtins" + }, + "item/01M5JJZRM87A0Y5YFFHE8WF2GR": { + "doc_type": "item", + "status": "todo", + "title": "bun tauri build fails at the DMG step (bundle_dmg.sh)" + }, + "item/01M5JKR1P3V9VD5TGSFYFXCV6D": { + "doc_type": "item", + "status": "todo", + "title": "E2E: new-note and dataset journeys fail at random under load" + }, + "item/01M5JKV9HQZ7X83CD6X1SMP6VV": { + "doc_type": "item", + "status": "todo", + "title": "Wiki publish: no script applies publish-manifest.json to the wiki" + }, "plan/2026-07-26-motion-next-phase": { "doc_type": "plan", "source": "docs/plans/2026-07-26-motion-next-phase.md", @@ -2385,6 +2565,12 @@ "title": "Editor surface, zoom scope, resizable layout, icon toolbar, and window drag", "truth_state": "current" }, + "plan/2026-10-22-pdf-tables": { + "doc_type": "plan", + "source": "docs/plans/2026-10-22-pdf-tables.md", + "title": "Themed tables in PDF export", + "truth_state": "current" + }, "pr/42": { "doc_type": "pr" }, @@ -2448,6 +2634,9 @@ "pr/66": { "doc_type": "pr" }, + "pr/67": { + "doc_type": "pr" + }, "release/v0.1.0": { "doc_type": "release" }, @@ -2475,6 +2664,9 @@ "release/v0.6.6": { "doc_type": "release" }, + "release/v0.6.7": { + "doc_type": "release" + }, "roadmap": { "doc_type": "roadmap", "source": "docs/roadmap.md", diff --git a/docs/.index/_inventory.json b/docs/.index/_inventory.json index d69e0f3..c4c06a8 100644 --- a/docs/.index/_inventory.json +++ b/docs/.index/_inventory.json @@ -204,13 +204,34 @@ "truth_state": "current", "wiki_key": "plan/2026-09-03-editor-surface-zoom-layout-icons" }, + { + "canonical_key": "plan/2026-10-22-pdf-tables", + "date": "2026-10-22", + "doc_type": "plan", + "epic": "01M5JJZFC11HAXZHJJ6N10S79G", + "items": [ + "01M5JJZFC1Y253JZSTV70R3S3P", + "01M5JJZFC136XTFWX2GB74JF2W", + "01M5JJZFC1GTE6MWBQE89529RQ", + "01M5JJZFC14JQC2NNTQKG2B4GV", + "01M5JJZFC1QWPY3EV9WCNZVC01", + "01M5JJZFC1MD61SVP5QBX9Q9JR", + "01M5JJZFC1B9P22KTJF6JS378H" + ], + "slug": "pdf-tables", + "source": "docs/plans/2026-10-22-pdf-tables.md", + "status": "active", + "title": "Themed tables in PDF export", + "truth_state": "current", + "wiki_key": "plan/2026-10-22-pdf-tables" + }, { "canonical_key": "roadmap", "doc_type": "roadmap", - "generated_at": "2026-10-22T15:41:13Z", + "generated_at": "2026-10-22T20:18:03Z", "slug": "roadmap", "source": "docs/roadmap.md", - "source_hash": "30098f35", + "source_hash": "e439eb28", "title": "Roadmap", "truth_state": "current", "wiki": "https://github.com/SpillwaveSolutions/motion/wiki/Roadmap", @@ -322,6 +343,7 @@ "slug": "2026-09-10_v0.6.5-release", "source": "docs/roadmap/2026-09-10_v0.6.5-release.md", "source_hash": "084d94a8", + "superseded_by": "roadmap-snapshot/2026-10-22_v0.6.6-release", "supersedes": "roadmap-snapshot/2026-09-04_v0.6.4-release", "title": "Roadmap", "truth_state": "snapshot", @@ -337,6 +359,7 @@ "slug": "2026-10-22_v0.6.6-release", "source": "docs/roadmap/2026-10-22_v0.6.6-release.md", "source_hash": "0cea7d08", + "supersedes": "roadmap-snapshot/2026-09-10_v0.6.5-release", "title": "Roadmap", "truth_state": "snapshot", "wiki_key": "roadmap-snapshot/2026-10-22_v0.6.6-release" diff --git a/docs/.index/item/01M5FSD7MA4Z0KY4ZRWRV0XJZ3.yml b/docs/.index/item/01M5FSD7MA4Z0KY4ZRWRV0XJZ3.yml new file mode 100644 index 0000000..a77dfc0 --- /dev/null +++ b/docs/.index/item/01M5FSD7MA4Z0KY4ZRWRV0XJZ3.yml @@ -0,0 +1,2 @@ +code: + - {pr: 67} diff --git a/docs/.index/item/01M5JJZFC11HAXZHJJ6N10S79G.yml b/docs/.index/item/01M5JJZFC11HAXZHJJ6N10S79G.yml new file mode 100644 index 0000000..a77dfc0 --- /dev/null +++ b/docs/.index/item/01M5JJZFC11HAXZHJJ6N10S79G.yml @@ -0,0 +1,2 @@ +code: + - {pr: 67} diff --git a/docs/.index/plan/2026-10-22-pdf-tables.yml b/docs/.index/plan/2026-10-22-pdf-tables.yml new file mode 100644 index 0000000..9a26818 --- /dev/null +++ b/docs/.index/plan/2026-10-22-pdf-tables.yml @@ -0,0 +1,5 @@ +canonical_key: plan/2026-10-22-pdf-tables +doc_type: plan +status: active +truth_state: current +wiki_key: plan/2026-10-22-pdf-tables diff --git a/docs/.index/publish-manifest.json b/docs/.index/publish-manifest.json index 96a5d2b..7579e6b 100644 --- a/docs/.index/publish-manifest.json +++ b/docs/.index/publish-manifest.json @@ -4,7 +4,7 @@ "frozen": false, "page_name": "Home", "render": "as-is", - "render_hash": "d8ef7f9e7ef8", + "render_hash": "b7ef0450f3b7", "source": "docs/.index/rendered/home.md", "title": "Home", "truth_state": "current", @@ -14,7 +14,7 @@ "frozen": false, "page_name": "Index-Decisions", "render": "as-is", - "render_hash": "03d6da4edbba", + "render_hash": "a3f7c62e34aa", "source": "docs/.index/rendered/decisions.md", "title": "Decisions Index", "truth_state": "current", @@ -44,7 +44,7 @@ "frozen": false, "page_name": "Index-Traceability", "render": "as-is", - "render_hash": "b2aa254f5316", + "render_hash": "fbfeec8a22ea", "source": "docs/.index/rendered/traceability.md", "title": "Traceability Index", "truth_state": "current", @@ -260,6 +260,16 @@ "truth_state": "not tracked", "wiki_key": "pr/66" }, + { + "frozen": false, + "page_name": "PR-67", + "render": "as-is", + "render_hash": "11cc69ef6bb7", + "source": "docs/.index/rendered/prs/67.md", + "title": "PR #67", + "truth_state": "not tracked", + "wiki_key": "pr/67" + }, { "frozen": false, "page_name": "Release-v0.1.0+dogfood", @@ -350,6 +360,16 @@ "truth_state": "shipped", "wiki_key": "release/v0.6.6" }, + { + "frozen": false, + "page_name": "Release-v0.6.7", + "render": "as-is", + "render_hash": "9794a21fb5db", + "source": "docs/.index/rendered/releases/v0.6.7.md", + "title": "Release v0.6.7", + "truth_state": "shipped", + "wiki_key": "release/v0.6.7" + }, { "frozen": false, "page_name": "Ticket-01KYDZ4A5HN1AZ7BN8Q2WV3XVN", @@ -1664,7 +1684,7 @@ "frozen": false, "page_name": "Ticket-01M5FP83K2ZA8P1FJ9AF3EK5Y8", "render": "as-is", - "render_hash": "67994ccf2414", + "render_hash": "cf2ee3436737", "source": "docs/.index/rendered/tickets/01M5FP83K2ZA8P1FJ9AF3EK5Y8.md", "title": "Reload a note and export themed PDF and Word", "truth_state": "done", @@ -1704,10 +1724,10 @@ "frozen": false, "page_name": "Ticket-01M5FSD7MA4Z0KY4ZRWRV0XJZ3", "render": "as-is", - "render_hash": "fce1b961f328", + "render_hash": "d39d9025a683", "source": "docs/.index/rendered/tickets/01M5FSD7MA4Z0KY4ZRWRV0XJZ3.md", "title": "PDF export: draw table borders and a header row style", - "truth_state": "open", + "truth_state": "done", "wiki_key": "item/01M5FSD7MA4Z0KY4ZRWRV0XJZ3" }, { @@ -1850,6 +1870,116 @@ "truth_state": "open", "wiki_key": "item/01M5J4C2142M28BJZPBSWJ4Y04" }, + { + "frozen": false, + "page_name": "Ticket-01M5JJZFC11HAXZHJJ6N10S79G", + "render": "as-is", + "render_hash": "39adbfd17b6d", + "source": "docs/.index/rendered/tickets/01M5JJZFC11HAXZHJJ6N10S79G.md", + "title": "Themed tables in PDF export", + "truth_state": "open", + "wiki_key": "item/01M5JJZFC11HAXZHJJ6N10S79G" + }, + { + "frozen": false, + "page_name": "Ticket-01M5JJZFC136XTFWX2GB74JF2W", + "render": "as-is", + "render_hash": "4bfae483b4ff", + "source": "docs/.index/rendered/tickets/01M5JJZFC136XTFWX2GB74JF2W.md", + "title": "Draw PDF tables with borders, a header row, stripes, wrapping, and a repeated header", + "truth_state": "done", + "wiki_key": "item/01M5JJZFC136XTFWX2GB74JF2W" + }, + { + "frozen": false, + "page_name": "Ticket-01M5JJZFC14JQC2NNTQKG2B4GV", + "render": "as-is", + "render_hash": "b9109065edfd", + "source": "docs/.index/rendered/tickets/01M5JJZFC14JQC2NNTQKG2B4GV.md", + "title": "Add a Tables group to the Themes dialog with a wireframe", + "truth_state": "done", + "wiki_key": "item/01M5JJZFC14JQC2NNTQKG2B4GV" + }, + { + "frozen": false, + "page_name": "Ticket-01M5JJZFC1B9P22KTJF6JS378H", + "render": "as-is", + "render_hash": "8c45a903f9c2", + "source": "docs/.index/rendered/tickets/01M5JJZFC1B9P22KTJF6JS378H.md", + "title": "Clean up the v0.6.6 branches and file the DMG build failure", + "truth_state": "in-progress", + "wiki_key": "item/01M5JJZFC1B9P22KTJF6JS378H" + }, + { + "frozen": false, + "page_name": "Ticket-01M5JJZFC1GTE6MWBQE89529RQ", + "render": "as-is", + "render_hash": "dfded56c6651", + "source": "docs/.index/rendered/tickets/01M5JJZFC1GTE6MWBQE89529RQ.md", + "title": "Use the table fields in the Word export and the HTML preview", + "truth_state": "done", + "wiki_key": "item/01M5JJZFC1GTE6MWBQE89529RQ" + }, + { + "frozen": false, + "page_name": "Ticket-01M5JJZFC1MD61SVP5QBX9Q9JR", + "render": "as-is", + "render_hash": "5618bb91e878", + "source": "docs/.index/rendered/tickets/01M5JJZFC1MD61SVP5QBX9Q9JR.md", + "title": "Update the user guide, README, design doc, changelog, and wiki", + "truth_state": "done", + "wiki_key": "item/01M5JJZFC1MD61SVP5QBX9Q9JR" + }, + { + "frozen": false, + "page_name": "Ticket-01M5JJZFC1QWPY3EV9WCNZVC01", + "render": "as-is", + "render_hash": "9f6ac3d55580", + "source": "docs/.index/rendered/tickets/01M5JJZFC1QWPY3EV9WCNZVC01.md", + "title": "Unit and Playwright tests for themed tables", + "truth_state": "done", + "wiki_key": "item/01M5JJZFC1QWPY3EV9WCNZVC01" + }, + { + "frozen": false, + "page_name": "Ticket-01M5JJZFC1Y253JZSTV70R3S3P", + "render": "as-is", + "render_hash": "ee153485cd23", + "source": "docs/.index/rendered/tickets/01M5JJZFC1Y253JZSTV70R3S3P.md", + "title": "Add the five table color fields to ExportTheme and both builtins", + "truth_state": "done", + "wiki_key": "item/01M5JJZFC1Y253JZSTV70R3S3P" + }, + { + "frozen": false, + "page_name": "Ticket-01M5JJZRM87A0Y5YFFHE8WF2GR", + "render": "as-is", + "render_hash": "b63bd965619a", + "source": "docs/.index/rendered/tickets/01M5JJZRM87A0Y5YFFHE8WF2GR.md", + "title": "bun tauri build fails at the DMG step (bundle_dmg.sh)", + "truth_state": "open", + "wiki_key": "item/01M5JJZRM87A0Y5YFFHE8WF2GR" + }, + { + "frozen": false, + "page_name": "Ticket-01M5JKR1P3V9VD5TGSFYFXCV6D", + "render": "as-is", + "render_hash": "2ca91cf5b68b", + "source": "docs/.index/rendered/tickets/01M5JKR1P3V9VD5TGSFYFXCV6D.md", + "title": "E2E: new-note and dataset journeys fail at random under load", + "truth_state": "open", + "wiki_key": "item/01M5JKR1P3V9VD5TGSFYFXCV6D" + }, + { + "frozen": false, + "page_name": "Ticket-01M5JKV9HQZ7X83CD6X1SMP6VV", + "render": "as-is", + "render_hash": "6a12b5047e54", + "source": "docs/.index/rendered/tickets/01M5JKV9HQZ7X83CD6X1SMP6VV.md", + "title": "Wiki publish: no script applies publish-manifest.json to the wiki", + "truth_state": "open", + "wiki_key": "item/01M5JKV9HQZ7X83CD6X1SMP6VV" + }, { "banner": "> **Current** \u2014 this is the living version; regenerated at 2026-07-29T23:00:00Z. Historical snapshots are linked from [[Index-Releases]].", "frozen": false, @@ -1866,7 +1996,7 @@ "frozen": false, "page_name": "Design-Doc", "render": "doc+banner", - "render_hash": "895832776055", + "render_hash": "aa0dc9bbf05f", "source": "docs/designs/current_design_doc.md", "title": "Motion \u2014 Current Design Document", "truth_state": "current", @@ -1939,11 +2069,22 @@ "wiki_key": "plan/2026-09-03-editor-surface-zoom-layout-icons" }, { - "banner": "> **Current** \u2014 this is the living version; regenerated at 2026-10-22T15:41:13Z. Historical snapshots are linked from [[Index-Releases]].", + "banner": "> **Current** \u2014 the latest status report. Reports freeze once published; corrections appear in later reports.", + "frozen": true, + "page_name": "Plan-pdf-tables", + "render": "doc+banner", + "render_hash": "29371571d03b", + "source": "docs/plans/2026-10-22-pdf-tables.md", + "title": "Themed tables in PDF export", + "truth_state": "current", + "wiki_key": "plan/2026-10-22-pdf-tables" + }, + { + "banner": "> **Current** \u2014 this is the living version; regenerated at 2026-10-22T20:18:03Z. Historical snapshots are linked from [[Index-Releases]].", "frozen": false, "page_name": "Roadmap", "render": "doc+banner", - "render_hash": "ca10d728e849", + "render_hash": "2c2533414ba7", "source": "docs/roadmap.md", "title": "Roadmap", "truth_state": "current", @@ -2042,7 +2183,7 @@ "frozen": false, "page_name": "User-Guide", "render": "doc+banner", - "render_hash": "4cb07641a268", + "render_hash": "c5ffca301c20", "source": "docs/user_guide/user-guide.md", "title": "User Guide", "truth_state": "current", @@ -2050,7 +2191,7 @@ } ], "sidebar": { - "render_hash": "4131676f8111", + "render_hash": "904a7d458a91", "source": "docs/.index/rendered/_Sidebar.md" }, "version": 1 diff --git a/docs/.index/rendered/_Sidebar.md b/docs/.index/rendered/_Sidebar.md index ad4bafd..5544219 100644 --- a/docs/.index/rendered/_Sidebar.md +++ b/docs/.index/rendered/_Sidebar.md @@ -2,6 +2,7 @@ - [[Roadmap]] - [[Design-Doc]] · [[Code-Walkthrough]] +- Plan: [[Plan-pdf-tables]] - Plan: [[Plan-editor-surface-zoom-layout-icons]] - Plan: [[Plan-ai-editor]] - Plan: [[Plan-save-ux-and-next]] diff --git a/docs/.index/rendered/decisions.md b/docs/.index/rendered/decisions.md index f4ee16f..2dd8356 100644 --- a/docs/.index/rendered/decisions.md +++ b/docs/.index/rendered/decisions.md @@ -11,6 +11,7 @@ _Why things are the way they are: ADRs (rules adopted) and plans (designs execut | Plan | Lifecycle | Truth | Date | |---|---|---|---| +| [[Plan-pdf-tables]] Themed tables in PDF export | active | current | 2026-10-22 | | [[Plan-editor-surface-zoom-layout-icons]] Editor surface, zoom scope, resizable layout, icon toolbar, and window drag | active | current | 2026-09-03 | | [[Plan-native-mac-app]] Behave like a native Mac app | completed | current | 2026-08-30 | | [[Plan-ai-editor]] AI editor: selection, /ai, preview | active | current | 2026-08-30 | diff --git a/docs/.index/rendered/home.md b/docs/.index/rendered/home.md index 35ac6a4..aaee17b 100644 --- a/docs/.index/rendered/home.md +++ b/docs/.index/rendered/home.md @@ -7,7 +7,7 @@ ## What are we working on now? [[Roadmap]] -Active plans: [[Plan-editor-surface-zoom-layout-icons]], [[Plan-ai-editor]], [[Plan-save-ux-and-next]] +Active plans: [[Plan-pdf-tables]], [[Plan-editor-surface-zoom-layout-icons]], [[Plan-ai-editor]], [[Plan-save-ux-and-next]] ## Why was it built this way? [[Index-Decisions]] — ADRs and plans, with supersede chains diff --git a/docs/.index/rendered/prs/67.md b/docs/.index/rendered/prs/67.md new file mode 100644 index 0000000..aeb4f47 --- /dev/null +++ b/docs/.index/rendered/prs/67.md @@ -0,0 +1,18 @@ +# PR #67 + +`pr/67` · status: **not tracked** + +Changed files: not tracked. Test/Review status: not tracked (see the deferred PR live-metadata sync item). + +## Linked Tickets + +- [[Ticket-01M5FSD7MA4Z0KY4ZRWRV0XJZ3]] PDF export: draw table borders and a header row style — Tables export to PDF as spaced text with no grid and no header style. +- [[Ticket-01M5JJZFC11HAXZHJJ6N10S79G]] Themed tables in PDF export — PDF export prints tables as spaced text. + +## Related Releases + +- [[Release-v0.6.7]] + +## Traceability + +- back to: [[Ticket-01M5FP83K2ZA8P1FJ9AF3EK5Y8]] Reload a note and export themed PDF and Word diff --git a/docs/.index/rendered/releases/v0.6.7.md b/docs/.index/rendered/releases/v0.6.7.md new file mode 100644 index 0000000..981fd60 --- /dev/null +++ b/docs/.index/rendered/releases/v0.6.7.md @@ -0,0 +1,34 @@ +# Release v0.6.7 + +`release/v0.6.7` · **shipped** + +7 item(s) shipped. + +## Change Log + +- [[Ticket-01M5FSD7MA4Z0KY4ZRWRV0XJZ3]] PDF export: draw table borders and a header row style — Tables export to PDF as spaced text with no grid and no header style. +- [[Ticket-01M5JJZFC136XTFWX2GB74JF2W]] Draw PDF tables with borders, a header row, stripes, wrapping, and a repeated header — Hand-written with jsPDF. +- [[Ticket-01M5JJZFC14JQC2NNTQKG2B4GV]] Add a Tables group to the Themes dialog with a wireframe — Add a Tables group to the Themes dialog with a wireframe +- [[Ticket-01M5JJZFC1GTE6MWBQE89529RQ]] Use the table fields in the Word export and the HTML preview — Use the table fields in the Word export and the HTML preview +- [[Ticket-01M5JJZFC1MD61SVP5QBX9Q9JR]] Update the user guide, README, design doc, changelog, and wiki — Update the user guide, README, design doc, changelog, and wiki +- [[Ticket-01M5JJZFC1QWPY3EV9WCNZVC01]] Unit and Playwright tests for themed tables — Unit and Playwright tests for themed tables +- [[Ticket-01M5JJZFC1Y253JZSTV70R3S3P]] Add the five table color fields to ExportTheme and both builtins — Legacy custom themes fall back to their own codeBg, heading, page, and muted colors. + +## Release Tree + +- [[Ticket-01M5FSD7MA4Z0KY4ZRWRV0XJZ3]] PDF export: draw table borders and a header row style (task) +- [[Ticket-01M5JJZFC136XTFWX2GB74JF2W]] Draw PDF tables with borders, a header row, stripes, wrapping, and a repeated header (task) +- [[Ticket-01M5JJZFC14JQC2NNTQKG2B4GV]] Add a Tables group to the Themes dialog with a wireframe (task) +- [[Ticket-01M5JJZFC1GTE6MWBQE89529RQ]] Use the table fields in the Word export and the HTML preview (task) +- [[Ticket-01M5JJZFC1MD61SVP5QBX9Q9JR]] Update the user guide, README, design doc, changelog, and wiki (task) +- [[Ticket-01M5JJZFC1QWPY3EV9WCNZVC01]] Unit and Playwright tests for themed tables (task) +- [[Ticket-01M5JJZFC1Y253JZSTV70R3S3P]] Add the five table color fields to ExportTheme and both builtins (task) + +## Related PRs + +- [[PR-67]] + +## Related Tickets + +- [[Ticket-01M5FP83K2ZA8P1FJ9AF3EK5Y8]] Reload a note and export themed PDF and Word (story) +- [[Ticket-01M5JJZFC11HAXZHJJ6N10S79G]] Themed tables in PDF export (epic) diff --git a/docs/.index/rendered/tickets/01M5FP83K2ZA8P1FJ9AF3EK5Y8.md b/docs/.index/rendered/tickets/01M5FP83K2ZA8P1FJ9AF3EK5Y8.md index 8cbc1d7..46c5562 100644 --- a/docs/.index/rendered/tickets/01M5FP83K2ZA8P1FJ9AF3EK5Y8.md +++ b/docs/.index/rendered/tickets/01M5FP83K2ZA8P1FJ9AF3EK5Y8.md @@ -9,10 +9,10 @@ Reload the open note from disk (confirm when dirty). - [[Ticket-01M5FSD7DGETDXNZ9DBQCSTM0T]] Word export: keep line breaks in code blocks — A fenced code block with more than one line exports to Word as a single line. (open) - [[Ticket-01M5FSD7FX4ZP6BR5YQT8KHDAD]] PDF export: keep bold, italic, and inline code — The PDF export prints bold, italic, and inline code as plain body text. (open) - [[Ticket-01M5FSD7J51R65WWC8VF85M0W2]] PDF export: add space between the title rule and the first paragraph — The accent rule under the h1 touches the top of the first paragraph line in the PDF. (open) -- [[Ticket-01M5FSD7MA4Z0KY4ZRWRV0XJZ3]] PDF export: draw table borders and a header row style — Tables export to PDF as spaced text with no grid and no header style. (open) +- [[Ticket-01M5FSD7MA4Z0KY4ZRWRV0XJZ3]] PDF export: draw table borders and a header row style — Tables export to PDF as spaced text with no grid and no header style. (done) - [[Ticket-01M5FSD7PJCJXQ9VE693ACM4B2]] Rust settings test: themes array round-trips through apply_settings_partial — The desktop app keeps only settings keys that the Rust side copies. (open) -Progress: 0/5 done +Progress: 1/5 done ## Linked PRs diff --git a/docs/.index/rendered/tickets/01M5FSD7MA4Z0KY4ZRWRV0XJZ3.md b/docs/.index/rendered/tickets/01M5FSD7MA4Z0KY4ZRWRV0XJZ3.md index c900423..30ea8b2 100644 --- a/docs/.index/rendered/tickets/01M5FSD7MA4Z0KY4ZRWRV0XJZ3.md +++ b/docs/.index/rendered/tickets/01M5FSD7MA4Z0KY4ZRWRV0XJZ3.md @@ -1,6 +1,6 @@ # PDF export: draw table borders and a header row style -`01M5FSD7MA4Z0KY4ZRWRV0XJZ3` · task/bug · **open** +`01M5FSD7MA4Z0KY4ZRWRV0XJZ3` · task/bug · **done** Tables export to PDF as spaced text with no grid and no header style. @@ -8,6 +8,10 @@ Tables export to PDF as spaced text with no grid and no header style. - story: [[Ticket-01M5FP83K2ZA8P1FJ9AF3EK5Y8]] Reload a note and export themed PDF and Word — Reload the open note from disk (confirm when dirty). +## Linked PRs + +- [[PR-67]] + ## Release -- [[Release-v0.6.6]] +- [[Release-v0.6.7]] diff --git a/docs/.index/rendered/tickets/01M5JJZFC11HAXZHJJ6N10S79G.md b/docs/.index/rendered/tickets/01M5JJZFC11HAXZHJJ6N10S79G.md new file mode 100644 index 0000000..c9aaa23 --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JJZFC11HAXZHJJ6N10S79G.md @@ -0,0 +1,21 @@ +# Themed tables in PDF export + +`01M5JJZFC11HAXZHJJ6N10S79G` · epic/feature · **open** + +PDF export prints tables as spaced text. + +## Children + +- [[Ticket-01M5JJZFC136XTFWX2GB74JF2W]] Draw PDF tables with borders, a header row, stripes, wrapping, and a repeated header — Hand-written with jsPDF. (done) +- [[Ticket-01M5JJZFC14JQC2NNTQKG2B4GV]] Add a Tables group to the Themes dialog with a wireframe — Add a Tables group to the Themes dialog with a wireframe (done) +- [[Ticket-01M5JJZFC1B9P22KTJF6JS378H]] Clean up the v0.6.6 branches and file the DMG build failure — Clean up the v0.6.6 branches and file the DMG build failure (in-progress) +- [[Ticket-01M5JJZFC1GTE6MWBQE89529RQ]] Use the table fields in the Word export and the HTML preview — Use the table fields in the Word export and the HTML preview (done) +- [[Ticket-01M5JJZFC1MD61SVP5QBX9Q9JR]] Update the user guide, README, design doc, changelog, and wiki — Update the user guide, README, design doc, changelog, and wiki (done) +- [[Ticket-01M5JJZFC1QWPY3EV9WCNZVC01]] Unit and Playwright tests for themed tables — Unit and Playwright tests for themed tables (done) +- [[Ticket-01M5JJZFC1Y253JZSTV70R3S3P]] Add the five table color fields to ExportTheme and both builtins — Legacy custom themes fall back to their own codeBg, heading, page, and muted colors. (done) + +Progress: 6/7 done + +## Linked PRs + +- [[PR-67]] diff --git a/docs/.index/rendered/tickets/01M5JJZFC136XTFWX2GB74JF2W.md b/docs/.index/rendered/tickets/01M5JJZFC136XTFWX2GB74JF2W.md new file mode 100644 index 0000000..a9b9f94 --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JJZFC136XTFWX2GB74JF2W.md @@ -0,0 +1,13 @@ +# Draw PDF tables with borders, a header row, stripes, wrapping, and a repeated header + +`01M5JJZFC136XTFWX2GB74JF2W` · task/feature · **done** + +Hand-written with jsPDF. + +## Hierarchy + +- epic: [[Ticket-01M5JJZFC11HAXZHJJ6N10S79G]] Themed tables in PDF export — PDF export prints tables as spaced text. + +## Release + +- [[Release-v0.6.7]] diff --git a/docs/.index/rendered/tickets/01M5JJZFC14JQC2NNTQKG2B4GV.md b/docs/.index/rendered/tickets/01M5JJZFC14JQC2NNTQKG2B4GV.md new file mode 100644 index 0000000..19476b6 --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JJZFC14JQC2NNTQKG2B4GV.md @@ -0,0 +1,13 @@ +# Add a Tables group to the Themes dialog with a wireframe + +`01M5JJZFC14JQC2NNTQKG2B4GV` · task/feature · **done** + +Add a Tables group to the Themes dialog with a wireframe + +## Hierarchy + +- epic: [[Ticket-01M5JJZFC11HAXZHJJ6N10S79G]] Themed tables in PDF export — PDF export prints tables as spaced text. + +## Release + +- [[Release-v0.6.7]] diff --git a/docs/.index/rendered/tickets/01M5JJZFC1B9P22KTJF6JS378H.md b/docs/.index/rendered/tickets/01M5JJZFC1B9P22KTJF6JS378H.md new file mode 100644 index 0000000..d8ddccc --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JJZFC1B9P22KTJF6JS378H.md @@ -0,0 +1,13 @@ +# Clean up the v0.6.6 branches and file the DMG build failure + +`01M5JJZFC1B9P22KTJF6JS378H` · task/feature · **in-progress** + +Clean up the v0.6.6 branches and file the DMG build failure + +## Hierarchy + +- epic: [[Ticket-01M5JJZFC11HAXZHJJ6N10S79G]] Themed tables in PDF export — PDF export prints tables as spaced text. + +## Release + +- [[Release-v0.6.7]] diff --git a/docs/.index/rendered/tickets/01M5JJZFC1GTE6MWBQE89529RQ.md b/docs/.index/rendered/tickets/01M5JJZFC1GTE6MWBQE89529RQ.md new file mode 100644 index 0000000..b256765 --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JJZFC1GTE6MWBQE89529RQ.md @@ -0,0 +1,13 @@ +# Use the table fields in the Word export and the HTML preview + +`01M5JJZFC1GTE6MWBQE89529RQ` · task/feature · **done** + +Use the table fields in the Word export and the HTML preview + +## Hierarchy + +- epic: [[Ticket-01M5JJZFC11HAXZHJJ6N10S79G]] Themed tables in PDF export — PDF export prints tables as spaced text. + +## Release + +- [[Release-v0.6.7]] diff --git a/docs/.index/rendered/tickets/01M5JJZFC1MD61SVP5QBX9Q9JR.md b/docs/.index/rendered/tickets/01M5JJZFC1MD61SVP5QBX9Q9JR.md new file mode 100644 index 0000000..08a6363 --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JJZFC1MD61SVP5QBX9Q9JR.md @@ -0,0 +1,13 @@ +# Update the user guide, README, design doc, changelog, and wiki + +`01M5JJZFC1MD61SVP5QBX9Q9JR` · task/feature · **done** + +Update the user guide, README, design doc, changelog, and wiki + +## Hierarchy + +- epic: [[Ticket-01M5JJZFC11HAXZHJJ6N10S79G]] Themed tables in PDF export — PDF export prints tables as spaced text. + +## Release + +- [[Release-v0.6.7]] diff --git a/docs/.index/rendered/tickets/01M5JJZFC1QWPY3EV9WCNZVC01.md b/docs/.index/rendered/tickets/01M5JJZFC1QWPY3EV9WCNZVC01.md new file mode 100644 index 0000000..923b385 --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JJZFC1QWPY3EV9WCNZVC01.md @@ -0,0 +1,13 @@ +# Unit and Playwright tests for themed tables + +`01M5JJZFC1QWPY3EV9WCNZVC01` · task/feature · **done** + +Unit and Playwright tests for themed tables + +## Hierarchy + +- epic: [[Ticket-01M5JJZFC11HAXZHJJ6N10S79G]] Themed tables in PDF export — PDF export prints tables as spaced text. + +## Release + +- [[Release-v0.6.7]] diff --git a/docs/.index/rendered/tickets/01M5JJZFC1Y253JZSTV70R3S3P.md b/docs/.index/rendered/tickets/01M5JJZFC1Y253JZSTV70R3S3P.md new file mode 100644 index 0000000..7763ea7 --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JJZFC1Y253JZSTV70R3S3P.md @@ -0,0 +1,13 @@ +# Add the five table color fields to ExportTheme and both builtins + +`01M5JJZFC1Y253JZSTV70R3S3P` · task/feature · **done** + +Legacy custom themes fall back to their own codeBg, heading, page, and muted colors. + +## Hierarchy + +- epic: [[Ticket-01M5JJZFC11HAXZHJJ6N10S79G]] Themed tables in PDF export — PDF export prints tables as spaced text. + +## Release + +- [[Release-v0.6.7]] diff --git a/docs/.index/rendered/tickets/01M5JJZRM87A0Y5YFFHE8WF2GR.md b/docs/.index/rendered/tickets/01M5JJZRM87A0Y5YFFHE8WF2GR.md new file mode 100644 index 0000000..3452b3b --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JJZRM87A0Y5YFFHE8WF2GR.md @@ -0,0 +1,5 @@ +# bun tauri build fails at the DMG step (bundle_dmg.sh) + +`01M5JJZRM87A0Y5YFFHE8WF2GR` · task/bug · **open** + +The v0.6.6 release build made Motion.app, but the DMG step in bundle_dmg.sh failed. diff --git a/docs/.index/rendered/tickets/01M5JKR1P3V9VD5TGSFYFXCV6D.md b/docs/.index/rendered/tickets/01M5JKR1P3V9VD5TGSFYFXCV6D.md new file mode 100644 index 0000000..2f05a4a --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JKR1P3V9VD5TGSFYFXCV6D.md @@ -0,0 +1,5 @@ +# E2E: new-note and dataset journeys fail at random under load + +`01M5JKR1P3V9VD5TGSFYFXCV6D` · task/bug · **open** + +Full Playwright runs fail one to four tests that pass when run again. diff --git a/docs/.index/rendered/tickets/01M5JKV9HQZ7X83CD6X1SMP6VV.md b/docs/.index/rendered/tickets/01M5JKV9HQZ7X83CD6X1SMP6VV.md new file mode 100644 index 0000000..7c294e3 --- /dev/null +++ b/docs/.index/rendered/tickets/01M5JKV9HQZ7X83CD6X1SMP6VV.md @@ -0,0 +1,5 @@ +# Wiki publish: no script applies publish-manifest.json to the wiki + +`01M5JKV9HQZ7X83CD6X1SMP6VV` · task/ops · **open** + +CLAUDE.md says to publish docs to the GitHub wiki. diff --git a/docs/.index/rendered/traceability.md b/docs/.index/rendered/traceability.md index 8b8e3a0..73f2f70 100644 --- a/docs/.index/rendered/traceability.md +++ b/docs/.index/rendered/traceability.md @@ -2,6 +2,69 @@ _The evidence chain: plan → item → ticket → code → release, forward and backward. Generated from `docs/.index/_graph.json`; do not edit._ +### Wiki publish: no script applies publish-manifest.json to the wiki +`01M5JKV9HQZ7X83CD6X1SMP6VV` · status: todo + +### E2E: new-note and dataset journeys fail at random under load +`01M5JKR1P3V9VD5TGSFYFXCV6D` · status: todo + +### bun tauri build fails at the DMG step (bundle_dmg.sh) +`01M5JJZRM87A0Y5YFFHE8WF2GR` · status: todo + +### Add the five table color fields to ExportTheme and both builtins +`01M5JJZFC1Y253JZSTV70R3S3P` · status: done +- belongs-to: Themed tables in PDF export +- targets: release/v0.6.7 +- produced-by: [[Plan-pdf-tables]] + +### Unit and Playwright tests for themed tables +`01M5JJZFC1QWPY3EV9WCNZVC01` · status: done +- belongs-to: Themed tables in PDF export +- targets: release/v0.6.7 +- produced-by: [[Plan-pdf-tables]] + +### Update the user guide, README, design doc, changelog, and wiki +`01M5JJZFC1MD61SVP5QBX9Q9JR` · status: done +- belongs-to: Themed tables in PDF export +- targets: release/v0.6.7 +- produced-by: [[Plan-pdf-tables]] + +### Use the table fields in the Word export and the HTML preview +`01M5JJZFC1GTE6MWBQE89529RQ` · status: done +- belongs-to: Themed tables in PDF export +- targets: release/v0.6.7 +- produced-by: [[Plan-pdf-tables]] + +### Clean up the v0.6.6 branches and file the DMG build failure +`01M5JJZFC1B9P22KTJF6JS378H` · status: in_progress +- belongs-to: Themed tables in PDF export +- targets: release/v0.6.7 +- produced-by: [[Plan-pdf-tables]] + +### Add a Tables group to the Themes dialog with a wireframe +`01M5JJZFC14JQC2NNTQKG2B4GV` · status: done +- belongs-to: Themed tables in PDF export +- targets: release/v0.6.7 +- produced-by: [[Plan-pdf-tables]] + +### Draw PDF tables with borders, a header row, stripes, wrapping, and a repeated header +`01M5JJZFC136XTFWX2GB74JF2W` · status: done +- belongs-to: Themed tables in PDF export +- targets: release/v0.6.7 +- produced-by: [[Plan-pdf-tables]] + +### Themed tables in PDF export +`01M5JJZFC11HAXZHJJ6N10S79G` · status: todo +- lands-in: pr/67 +- contains: Draw PDF tables with borders, a header row, stripes, wrapping, and a repeated header +- contains: Add a Tables group to the Themes dialog with a wireframe +- contains: Clean up the v0.6.6 branches and file the DMG build failure +- contains: Use the table fields in the Word export and the HTML preview +- contains: Update the user guide, README, design doc, changelog, and wiki +- contains: Unit and Playwright tests for themed tables +- contains: Add the five table color fields to ExportTheme and both builtins +- produced-by: [[Plan-pdf-tables]] + ### chore(release): v0.6.6 changelog, version bump, roadmap snapshot `01M5J4C2142M28BJZPBSWJ4Y04` · status: todo - lands-in: pr/66 @@ -52,9 +115,10 @@ _The evidence chain: plan → item → ticket → code → release, forward and - targets: release/v0.6.6 ### PDF export: draw table borders and a header row style -`01M5FSD7MA4Z0KY4ZRWRV0XJZ3` · status: todo +`01M5FSD7MA4Z0KY4ZRWRV0XJZ3` · status: done - belongs-to: Reload a note and export themed PDF and Word -- targets: release/v0.6.6 +- lands-in: pr/67 +- targets: release/v0.6.7 ### PDF export: add space between the title rule and the first paragraph `01M5FSD7J51R65WWC8VF85M0W2` · status: todo diff --git a/docs/.index/roadmap-snapshot/2026-09-10_v0.6.5-release.yml b/docs/.index/roadmap-snapshot/2026-09-10_v0.6.5-release.yml index f934ae8..01af6f7 100644 --- a/docs/.index/roadmap-snapshot/2026-09-10_v0.6.5-release.yml +++ b/docs/.index/roadmap-snapshot/2026-09-10_v0.6.5-release.yml @@ -2,6 +2,7 @@ canonical_key: roadmap-snapshot/2026-09-10_v0.6.5-release doc_type: roadmap-snapshot release: v0.6.5 slug: 2026-09-10_v0.6.5-release +superseded_by: roadmap-snapshot/2026-10-22_v0.6.6-release supersedes: roadmap-snapshot/2026-09-04_v0.6.4-release title: Roadmap truth_state: snapshot diff --git a/docs/.index/roadmap-snapshot/2026-10-22_v0.6.6-release.yml b/docs/.index/roadmap-snapshot/2026-10-22_v0.6.6-release.yml new file mode 100644 index 0000000..c1bdff7 --- /dev/null +++ b/docs/.index/roadmap-snapshot/2026-10-22_v0.6.6-release.yml @@ -0,0 +1,8 @@ +canonical_key: roadmap-snapshot/2026-10-22_v0.6.6-release +doc_type: roadmap-snapshot +release: v0.6.6 +slug: 2026-10-22_v0.6.6-release +supersedes: roadmap-snapshot/2026-09-10_v0.6.5-release +title: Roadmap +truth_state: snapshot +wiki_key: roadmap-snapshot/2026-10-22_v0.6.6-release diff --git a/docs/designs/current_design_doc.md b/docs/designs/current_design_doc.md index 070cc69..aa4908a 100644 --- a/docs/designs/current_design_doc.md +++ b/docs/designs/current_design_doc.md @@ -102,7 +102,15 @@ unit → E2E). Snowstorm or Clay, plus custom themes in settings). The dialog iframe is the preview; `exportPdf` / `exportDocx` build the download from the same block list. Desktop settings pass `exportThemeId` and `themes` through - `get_settings` / `set_settings`. + `get_settings` / `set_settings`. Rust stores `themes` as opaque JSON, so + `sanitizeTheme` in `src/lib/themes.ts` is the one schema. Tables use five + theme colors: `tableHeaderBg`, `tableHeaderText`, `tableRowBg`, + `tableRowAltBg`, and `tableBorder`. A theme with no table keys gets its + pre-0.6.7 look (header `codeBg` and `heading`, rows `page`, no stripes, + border `muted`). A bad hex in one table key falls back to the default + table color. The + PDF grid is hand-drawn with jsPDF (`drawTable` in `exportPdf.ts`) and + repeats the header row after a page break. --- diff --git a/docs/plans/2026-10-22-pdf-tables.md b/docs/plans/2026-10-22-pdf-tables.md new file mode 100644 index 0000000..05d8218 --- /dev/null +++ b/docs/plans/2026-10-22-pdf-tables.md @@ -0,0 +1,170 @@ +--- +date: 2026-10-22 +slug: pdf-tables +title: Themed tables in PDF export +epic: 01M5JJZFC11HAXZHJJ6N10S79G +items: [01M5JJZFC1Y253JZSTV70R3S3P, 01M5JJZFC136XTFWX2GB74JF2W, 01M5JJZFC1GTE6MWBQE89529RQ, 01M5JJZFC14JQC2NNTQKG2B4GV, 01M5JJZFC1QWPY3EV9WCNZVC01, 01M5JJZFC1MD61SVP5QBX9Q9JR, 01M5JJZFC1B9P22KTJF6JS378H] +--- + +# Add themed table support to PDF export, clean up v0.6.6, and release v0.6.7 + +## Context + +The PDF export does not draw tables. In `src/lib/exportPdf.ts:125`, the PDF exporter writes each table row as one line of text, with the cells joined by three spaces. Word export (`src/lib/exportDocx.ts:166`) and the HTML preview (`src/lib/exportHtml.ts:38`) draw real tables. Their colors are borrowed from `codeBg`, `heading`, and `muted`. No theme field controls table style. + +The v0.6.6 release notes list this defect as work item `01M5FSD7MA4Z0KY4ZRWRV0XJZ3` ("draws tables with no borders"). This plan closes that item. + +The outcome: + +- PDF export draws real tables with a header row, cell borders, alternating row colors, and text that wraps inside each cell. +- `ExportTheme` gets table fields. You can edit them in the **Themes** dialog. +- Ice Snowstorm and Clay both ship with header and alternating row styles. +- PDF, Word, and the preview all read the same table fields, so the preview still matches the downloaded file. +- The open items from the v0.6.6 release are closed or filed. +- v0.6.7 ships with the release process that v0.6.6 used. + +## Set up the worktree + +v0.6.6 is on `main` at `5358991` and includes all of the theme work. Branch from `origin/main`: + +```bash +git fetch origin +git worktree add ../motion-pdf-tables -b feat/pdf-tables origin/main +cd ../motion-pdf-tables && bun install +``` + +Open the PR against `main`. + +## Add table fields to the theme + +File: `src/lib/themes.ts`. + +1. Add five color fields to `ExportTheme`: + + | Field | Use | + | --- | --- | + | `tableHeaderBg` | Header row fill | + | `tableHeaderText` | Header row text, bold | + | `tableRowBg` | Odd body row fill | + | `tableRowAltBg` | Even body row fill (the alternating stripe) | + | `tableBorder` | Cell border lines | + + Body cell text uses the existing `text` field. + +2. Set the builtin values: + + | Field | Ice Snowstorm | Clay | + | --- | --- | --- | + | `tableHeaderBg` | `#1D4E89` (accent) | `#D97757` (clay) | + | `tableHeaderText` | `#FFFFFF` | `#141413` | + | `tableRowBg` | `#FFFFFF` | `#FAF9F5` | + | `tableRowAltBg` | `#E4EDF7` | `#F0EEE6` | + | `tableBorder` | `#B8C7DB` | `#E8E6DC` | + + The header text contrast is 8.4:1 on Ice and 5.9:1 on Clay. Both pass WCAG AA. + +3. In `sanitizeTheme`, read the new fields with `colorOf`. For a field that is missing, fall back to the theme's own colors, not to `CLAY`: `codeBg`, `heading`, `page`, `codeBg`, and `muted`. A custom theme saved by v0.6.6 then exports exactly as it does today. Keep `colorOf` and `parseHex` as the only validation. + +## Draw tables in the PDF + +File: `src/lib/exportPdf.ts`. Do not add a dependency. `jspdf-autotable` is not installed, and the drawing code is about 60 lines with the existing `jsPDF` calls. + +Replace the fallthrough table branch at line 125 with `drawTable(cursor, block)`: + +1. Find the column count from the widest row. Pad short rows with empty cells. +2. Give each column a width in proportion to its longest cell text, clamped to 4 to 40 characters, across `PAGE_W - 2 * MARGIN`. Mark this with a `ponytail:` comment. The comment names the ceiling (a character count, not a measured width) and the upgrade path (`doc.getTextWidth`). +3. For each row, wrap each cell with `doc.splitTextToSize(text, colWidth - 2 * PAD)`. The row height is the tallest cell plus padding. +4. Call the existing `ensure(cursor, rowHeight)`. If `ensure` adds a page before a body row, draw the header row again at the top of the new page. +5. Fill the row background with `tableHeaderBg`, `tableRowBg`, or `tableRowAltBg`. Draw each cell border with `rect(..., "S")` in `tableBorder` at 0.5 pt. Draw the text with the existing `PDF_FONT` mapping, bold for the header. +6. Use 10 pt text, matching the current table size. Reuse `hexToRgb` for all colors. + +A single cell that is taller than one page overflows the page. Mark it with a `ponytail:` comment. The fix is to split the cell lines across pages, if a real note needs it. + +## Use the fields in Word and the preview + +- `src/lib/exportDocx.ts`, `table()`: header shading `tableHeaderBg` and header text `tableHeaderText`. Even body rows get `tableRowAltBg` shading, and odd body rows get `tableRowBg`. Set the table `borders` (top, bottom, left, right, insideHorizontal, insideVertical) to `tableBorder`. Keep `hexBare`. +- `src/lib/exportHtml.ts`, the ` diff --git a/src/lib/exportPdf.ts b/src/lib/exportPdf.ts index 6956b8c..c913ff5 100644 --- a/src/lib/exportPdf.ts +++ b/src/lib/exportPdf.ts @@ -122,10 +122,81 @@ function drawBlock(cursor: Cursor, block: ExportBlock) { cursor.y += 12; return; } - for (const row of [block.header, ...block.rows]) { - writeLines(cursor, row.join(" "), 10, theme.font, "normal", theme.text, 0); - } - cursor.y += 6; + drawTable(cursor, block); +} + +const TABLE_SIZE = 10; +const TABLE_LINE = 1.3; +const CELL_PAD = 5; + +interface TableRowLayout { + lines: string[][]; + height: number; +} + +/** + * Bordered grid with a filled header row and striped body rows. The header + * repeats at the top of each page the table runs onto. + */ +function drawTable(cursor: Cursor, block: ExportBlock & { type: "table" }) { + const { doc, theme } = cursor; + const cols = Math.max(block.header.length, ...block.rows.map((row) => row.length)); + if (cols === 0) return; + const pad = (row: string[]) => Array.from({ length: cols }, (_, i) => row[i] ?? ""); + const header = pad(block.header); + const rows = block.rows.map(pad); + // ponytail: widths follow character counts, not measured text. Weigh by doc.getTextWidth if columns look off. + const weights = header.map((_, i) => Math.min(40, Math.max(4, ...[header, ...rows].map((row) => row[i]!.length)))); + const total = weights.reduce((sum, weight) => sum + weight, 0); + const widths = weights.map((weight) => (weight / total) * (PAGE_W - MARGIN * 2)); + const lineH = TABLE_SIZE * TABLE_LINE; + // cursor.y is the next text baseline. The grid works from the row top. + let top = cursor.y - TABLE_SIZE; + + const layout = (cells: string[], style: Style): TableRowLayout => { + doc.setFont(PDF_FONT[theme.font], style); + doc.setFontSize(TABLE_SIZE); + const lines = cells.map((cell, i) => doc.splitTextToSize(cell || " ", widths[i]! - CELL_PAD * 2) as string[]); + return { lines, height: Math.max(...lines.map((cell) => cell.length)) * lineH + CELL_PAD * 2 }; + }; + + const paint = (row: TableRowLayout, style: Style, fill: string, color: string) => { + doc.setFont(PDF_FONT[theme.font], style); + doc.setFontSize(TABLE_SIZE); + doc.setDrawColor(...hexToRgb(theme.tableBorder)); + doc.setLineWidth(0.5); + let x = MARGIN; + row.lines.forEach((lines, i) => { + doc.setFillColor(...hexToRgb(fill)); + doc.rect(x, top, widths[i]!, row.height, "FD"); + doc.setTextColor(...hexToRgb(color)); + doc.text(lines, x + CELL_PAD, top + CELL_PAD + TABLE_SIZE * 0.8, { lineHeightFactor: TABLE_LINE }); + x += widths[i]!; + }); + top += row.height; + }; + + // ponytail: a single row taller than a page overflows it. Split the cell lines across pages if a note needs that. + const fits = (height: number) => top + height <= PAGE_H - MARGIN; + const newPage = () => { + doc.addPage(); + paintPage(cursor); + top = MARGIN; + }; + const head = layout(header, "bold"); + const paintHead = () => paint(head, "bold", theme.tableHeaderBg, theme.tableHeaderText); + const first = rows[0] ? layout(rows[0], "normal").height : 0; + if (!fits(head.height + first)) newPage(); + paintHead(); + rows.forEach((cells, i) => { + const row = layout(cells, "normal"); + if (!fits(row.height)) { + newPage(); + paintHead(); + } + paint(row, "normal", i % 2 === 1 ? theme.tableRowAltBg : theme.tableRowBg, theme.text); + }); + cursor.y = top + TABLE_SIZE + 10; } function writeRuns(cursor: Cursor, runs: InlineRun[]) { diff --git a/src/lib/themes.ts b/src/lib/themes.ts index e3ee95e..afc9e42 100644 --- a/src/lib/themes.ts +++ b/src/lib/themes.ts @@ -18,6 +18,12 @@ export interface ExportTheme { muted: string; codeBg: string; codeText: string; + tableHeaderBg: string; + tableHeaderText: string; + tableRowBg: string; + /** Every second body row, for the striped look. */ + tableRowAltBg: string; + tableBorder: string; font: ThemeFont; headingFont: ThemeFont; } @@ -33,6 +39,11 @@ export const ICE_SNOWSTORM: ExportTheme = { muted: "#4A6280", codeBg: "#E4EDF7", codeText: "#0B1F4B", + tableHeaderBg: "#1D4E89", + tableHeaderText: "#FFFFFF", + tableRowBg: "#FFFFFF", + tableRowAltBg: "#E4EDF7", + tableBorder: "#B8C7DB", font: "sans", headingFont: "sans", }; @@ -49,6 +60,11 @@ export const CLAY: ExportTheme = { muted: "#5E5D59", codeBg: "#F0EEE6", codeText: "#141413", + tableHeaderBg: "#D97757", + tableHeaderText: "#141413", + tableRowBg: "#FAF9F5", + tableRowAltBg: "#F0EEE6", + tableBorder: "#E8E6DC", font: "sans", headingFont: "serif", }; @@ -95,6 +111,25 @@ function colorOf(value: unknown, fallback: string): string { return typeof value === "string" ? (parseHex(value) ?? fallback) : fallback; } +const TABLE_KEYS = ["tableHeaderBg", "tableHeaderText", "tableRowBg", "tableRowAltBg", "tableBorder"] as const; + +type TableColors = Pick; + +/** The table look themes had before table colors existed: tinted header, plain rows. */ +function legacyTable(page: string, heading: string, muted: string, codeBg: string): TableColors { + return { tableHeaderBg: codeBg, tableHeaderText: heading, tableRowBg: page, tableRowAltBg: page, tableBorder: muted }; +} + +function tableColors(raw: Record, fallback: TableColors): TableColors { + return { + tableHeaderBg: colorOf(raw.tableHeaderBg, fallback.tableHeaderBg), + tableHeaderText: colorOf(raw.tableHeaderText, fallback.tableHeaderText), + tableRowBg: colorOf(raw.tableRowBg, fallback.tableRowBg), + tableRowAltBg: colorOf(raw.tableRowAltBg, fallback.tableRowAltBg), + tableBorder: colorOf(raw.tableBorder, fallback.tableBorder), + }; +} + export function sanitizeTheme(value: unknown, fallback: ExportTheme): ExportTheme | null { if (!value || typeof value !== "object") return null; const raw = value as Record; @@ -102,17 +137,22 @@ export function sanitizeTheme(value: unknown, fallback: ExportTheme): ExportThem const name = typeof raw.name === "string" ? raw.name.trim() : ""; if (!id || !name || isBuiltinThemeId(id)) return null; if (!/^[a-z0-9][a-z0-9-]{0,40}$/.test(id)) return null; + const page = colorOf(raw.page, fallback.page); + const heading = colorOf(raw.heading, fallback.heading); + const muted = colorOf(raw.muted, fallback.muted); + const codeBg = colorOf(raw.codeBg, fallback.codeBg); return { id, name: name.slice(0, 40), builtin: false, - page: colorOf(raw.page, fallback.page), + page, text: colorOf(raw.text, fallback.text), - heading: colorOf(raw.heading, fallback.heading), + heading, accent: colorOf(raw.accent, fallback.accent), - muted: colorOf(raw.muted, fallback.muted), - codeBg: colorOf(raw.codeBg, fallback.codeBg), + muted, + codeBg, codeText: colorOf(raw.codeText, fallback.codeText), + ...tableColors(raw, TABLE_KEYS.some((key) => key in raw) ? fallback : legacyTable(page, heading, muted, codeBg)), font: fontOf(raw.font, fallback.font), headingFont: fontOf(raw.headingFont, fallback.headingFont), }; diff --git a/wireframes/themes.md b/wireframes/themes.md new file mode 100644 index 0000000..9ac05ce --- /dev/null +++ b/wireframes/themes.md @@ -0,0 +1,67 @@ +# Screen: Theme settings + +## Goal + +You pick an export theme, or make your own, and set the colors that PDF and Word export use. This includes the table colors. + +## Layout + +The **Theme settings** dialog opens from the **Themes** button in the header. + +``` ++------------------------------------------------------------+ +| Themes | +| Ice Snowstorm is navy and ice. Clay is ... | ++------------------+-----------------------------------------+ +| [Ice Snowstorm] | Name [Harbor ] | +| [Clay] | Page [#] [#F3F6FB] | +| [Harbor] | Text [#] [#111111] | +| | Headings [#] [#0B1F4B] | +| | Accent [#] [#1D4E89] | +| | Tables | +| | Table header [#] [#1D4E89] | +| | Table header text [#] [#FFFFFF] | +| | Table row [#] [#FFFFFF] | +| | Table alternate row [#] [#E4EDF7] | +| | Table border [#] [#B8C7DB] | +| | Body font [sans v] | +| | Heading font [sans v] | +| | (o) Use for export | ++------------------+-----------------------------------------+ +| [New theme] [Delete] [Cancel] [Save themes] | ++------------------------------------------------------------+ +``` + +## Key elements + +| Element | Type | Behavior or notes | +| --- | --- | --- | +| Theme list | Toggle buttons | Selects the theme that the form shows. | +| Color fields | Color picker and hex input | One pair per color. Disabled for builtin themes. | +| **Tables** | Group heading | Groups the five table colors. It is a heading, not a control. | +| **Table header** | Color field | Header row fill in the preview, PDF, and Word. | +| **Table header text** | Color field | Header row text. The header text is bold. | +| **Table row** | Color field | Fill for odd body rows. | +| **Table alternate row** | Color field | Fill for even body rows, for the stripes. | +| **Table border** | Color field | Cell border lines. | + +## States + +- **Default**: The form shows the selected theme. Builtin themes show all values, disabled. +- **Empty**: Not applicable. The two builtins always exist. +- **Loading**: Not applicable. The themes come from settings that are already loaded. +- **Error**: A hex value that does not parse falls back to the default color for that field when you save. + +## Acceptance criteria + +- [x] The five table color fields show under a **Tables** heading, after **Accent**. +- [x] Each table field has the accessible names `