penpot design work summaries

This commit is contained in:
2026-08-10 23:26:10 -06:00
parent 7932e5d90c
commit 465fb107b2
3 changed files with 74 additions and 0 deletions
@@ -0,0 +1,34 @@
# Work Summary — 2026-08-10 15:43
## Task
"Play around in Penpot and see if you can generalize any of the common elements." Not a git-tracked code change — this is design-system work in the connected Penpot file. Recorded here for continuity since it's real project work.
## Context
The connected Penpot file turned out to be the *unmodified* default Tailwind CSS starter template (raw, unrenamed color swatches, a breakpoint reference, a shadow reference) - no existing mockups of this app's actual UI. Clarified with the user that "generalize the common elements" meant reverse-engineering the app's *real*, already-implemented UI (`templates/components/*.html.tmpl`, `styles/typography.css`) into actual Penpot library assets, not curating the generic starter kit.
`styles/typography.css` turned out to hold a full custom shadcn/ui-style design system already: three OKLCH color scales (`base`, `primary`, `secondary`, 50-1000 each), ~38 semantic tokens (`background`, `card`, `accent`, `border`, `chart-1..5`, `sidebar-*`, `table-*`, etc.) with distinct light/dark values via `@media (prefers-color-scheme: dark)`, and two custom fonts (Geist 600 for headings, Alexandria 300 for body).
No browser extension was available to read live computed styles, so exact OKLCH→hex conversion had to be done by hand-implementing the standard algorithm (Björn Ottosson's OKLab, CSS Color 4 matrices) inside Penpot's JS sandbox, rather than relying on assumption or memory.
## What was built in Penpot
- **OKLCH→hex conversion**: implemented and validated against known-correct reference points (pure black/white exactly, and `oklch(0.577 0.245 27.325)``#E7000B`, which independently matches shadcn/ui's well-known default destructive red) before trusting it for the full palette.
- **Design Tokens** (Penpot's native token system, chosen over flat colors specifically so light/dark could be modeled properly):
- `Primitives` set (40 tokens, always active): `base.50`-`base.1000`, `primary.50`-`primary.1000`, `secondary.50`-`secondary.1000`, `destructive.light`/`.dark`, `white`, `black`.
- `Semantic/Light` and `Semantic/Dark` sets (38 tokens each): every semantic token name the app's CSS defines, referencing the right primitive per theme.
- A `Mode` theme group (Light/Dark), Light active by default - mirrors the app's `:root` vs. `@media (prefers-color-scheme: dark)` structure. Verified references resolve correctly end-to-end.
- **Typography**: `Display/H1`-`H4`,`H6` (Geist 600, sized from Tailwind's `text-6xl`/`3xl`/`xl`/`lg`/`sm`) and `Text/Body` (Alexandria 300, 16px). `H5` deliberately skipped - the source CSS references `--text-md`, which isn't defined anywhere (a real gap in the app's CSS, not something to guess a value for).
- **Button component** (from `templates/components/button.html.tmpl`): a proper Penpot Variant group (`State` property: `Default`/`Hover`/`Active-Disabled`) built entirely from the token system rather than hardcoded colors - background/border/text colors all come from `color.card`/`color.border`/`color.foreground`/`color.accent`/`color.accent-secondary` tokens. Visually verified via export at each stage.
## A real Penpot platform quirk hit and worked around
`penpot.createVariantFromComponents` (and the `penpotUtils.createVariantContainer` wrapper built on it) failed with a server-side validation error (`Value not valid: [object ShapeProxy]... Code: :shapes`) when passed boards where two of the three had been created via `.clone()` of a board that was *already* a component's main instance. Isolated the cause with targeted diagnostics (confirmed flex layout alone was fine; confirmed applied color tokens alone were fine; the only remaining variable - clone-of-an-existing-main-instance - was the actual cause). Fix: rebuild each variant state as an independent board from scratch rather than cloning an already-componentized one, then create each as its own component before combining. Worth remembering if building more variant groups in this file.
## Verification
- OKLCH conversion validated against known reference values before trusting it for ~40 colors.
- Token resolution spot-checked (`color.background``#FAFAFE`, `color.primary``#B8E954`, `color.destructive``#E7000B`), all correct.
- Button auto-sizing confirmed (73×36, correctly hugging text + 8px padding on `p-[0.5em]` at 16px base).
- All three button states exported and visually inspected individually and as a working variant group; no `variantError` on any of the three.
- A Penpot plugin disconnect happened mid-session (browser-side, not caused by this work) - the already-computed, validated hex map was saved to the scratchpad before it could be lost, and reloaded directly (no recomputation needed) once reconnected.
## Follow-ups / not done here
- `Accordion` (`templates/components/accordion.html.tmpl`) and `TutorialTooltip` (`templates/components/tutorial-tooltip.html.tmpl`) components not yet built - user chose to first wire the Button into a proper Variant group (done above) rather than continue to these; picking this back up is the natural next step.
- `H5` typography intentionally left unresolved (`--text-md` undefined in source CSS) - worth a decision on the actual code side (define `--text-md`, or change `h5` to reference an existing size) independent of the Penpot work.
@@ -0,0 +1,20 @@
# Work Summary — 2026-08-10 20:22
## Task
Continue the Penpot design-system work: build the `Accordion` component from `templates/components/accordion.html.tmpl`, following the Button's pattern from the previous session.
## A false alarm, resolved
Mid-build, token resolution appeared to produce scrambled/wrong values - including for the *already-verified-correct* Button component, which seemed to indicate live corruption. Paused and reported rather than continuing to build on top of it. Turned out to be a non-issue: the user had switched Penpot's active theme from Light to Dark while reviewing in the UI. Verified by checking the "wrong" values against the actual Dark-theme semantic mapping - every one matched exactly (`color.accent``base.800``#242237`, `color.foreground``base.200``#E6E7F3`, etc.). The token system was working correctly the whole time; the check was just comparing Dark output against Light expectations. Switched back to Light (`lightTheme.toggleActive()`) and confirmed the Button's Default fill was `#ffffff` again before continuing. No actual reversal was needed - nothing was broken.
## What was built
`Accordion` component (from `accordion.html.tmpl`), as a Penpot Variant group (`State`: `Closed`/`Open`), built fresh per-state (not cloned, per the lesson from the Button session) and entirely from the existing token system:
- **Closed**: just the summary bar - `color.accent` background, `rounded-lg`, header text left / `+` indicator right (Alexandria 700, 2em). No outer background, matching the template (`bg-card` only applies when open).
- **Open**: the same summary bar (indicator now ``) plus an expanded body area below, both wrapped in an outer container using `color.card` background and `rounded-lg` - matching `open:bg-card` applying to the outer `<details>`, with the body's `p-[1em]` padding around placeholder body text.
## Verification
- Both states exported and visually inspected individually before combining - correct token-driven colors, correct layout (row-fill summary bar, centered/padded body).
- Variant group verified: `isVariantContainer()` true, `State` property with `Closed`/`Open` values, no `variantError` on either.
- Final combined export confirms both states render correctly together.
## Follow-ups / not done here
- `TutorialTooltip` (`templates/components/tutorial-tooltip.html.tmpl`) is the last of the three components surveyed at the start of this work - not yet built.
@@ -0,0 +1,20 @@
# Work Summary — 2026-08-10 20:40
## Task
Final piece of the Penpot design-system work: build `TutorialTooltip` from `templates/components/tutorial-tooltip.html.tmpl`, completing the three components surveyed at the start of this thread.
## What was built
`TutorialTooltip` - the popover panel itself (not the invisible anchor wrapper `<div>`, which only carries positioning/click-handler behavior, no visual style of its own). Unlike Button and Accordion, this component has no meaningful *visual* state variants - its only dynamic behavior is show/hide (CSS `popover`/`open`) and a multi-step content walkthrough (swapping which `<span>` is visible on click), neither of which changes its appearance. Built as a single library component rather than a Variant group, which is the correct fit here, not a shortcut.
Structure: `color.card` background, 1px border using `color.sidebar-border` (a token not used by Button or Accordion, since this is the only component that references `--sidebar-border` in its source CSS), `rounded-lg`, a literal drop shadow (`2px 2px 2px 1px rgb(0 0 0 / 20%)` - not backed by any token in the source CSS, so applied as a direct shape shadow rather than invented as one), flex row with content text (fills available space) and a `×` close glyph (fixed, right-aligned) - mirroring the template's `grid-template-columns: 1fr max-content`.
## Verification
- Colors confirmed correct before exporting (`fill: #ffffff`, `stroke: #e6e7f3` - card/sidebar-border in Light theme).
- Visual export matches the template's intent: card panel, subtle border, drop shadow, content + close button.
- Final full-library sweep: 3 components (`Button` and `Accordion` as Variant groups, `TutorialTooltip` as a single component, confirmed via `isVariant()`), token sets in expected state (`Primitives` + `Semantic/Light` active, `Semantic/Dark` inactive), all 6 typographies present. No leftover test/diagnostic artifacts anywhere in the file (swept with a name-based search across all pages).
## Outcome
This closes out the original "generalize the common elements" request. All three reusable UI components implemented in `templates/components/` now exist as real, token-driven Penpot library components, built from the app's actual CSS values (not guessed), with the color/typography foundation they're built on independently reusable for any future component work in this file.
## Follow-ups / not done here
- Two things flagged during this whole thread that are worth a decision on the *code* side, independent of Penpot: `h5 { font-size: var(--text-md) }` in `styles/typography.css` references an undefined variable (no typography asset was created for H5 as a result); and the `TutorialTooltip`'s box-shadow and `animate-pulse` (a pulsing opacity animation on the popover, not represented in the static Penpot export) aren't tied to any reusable token, unlike everything else in the file.