Replace the UI with the Organic design handoff (docs/design_handoff_pansy_ui)
Build image / build-and-push (push) Successful in 31s
Gadfly review (reusable) / review (pull_request) Failing after 1s
Adversarial Review (Gadfly) / review (pull_request) Failing after 1s

The frontend is rebuilt screen by screen from the handoff: warm cream ground,
terracotta + sage accents, Caprasimo over Figtree, every control a pill. Same
React/Vite/TanStack stack and the same lib/ data layer; the presentation is new.

- Tokens: web/src/styles/index.css declares the handoff's styles.css variables
  through Tailwind's @theme under the same names; dark mode is those variables
  overridden on <html> by the handoff's pansy-theme.js, inlined in index.html
  so it runs before first paint. Lucide glyphs at stroke 2.75; a small pill kit
  (Button, Dialog, Field, Seg, Toggle, Tag, toast).
- Login / Register: the centered column over soft accent circles; OIDC button
  and signup footer still follow /auth/providers.
- Gardens: cards with a real SVG plot thumbnail (objects + plant-colored dots
  from /full), a `plan` tag for "<name> — <year>" copies, shares line, Open +
  share/copy/edit/delete; New garden / Share / Plan-a-season dialogs.
- Plants: monogram markers derived from the name (collision-resolved across the
  catalog — replaces emoji icons), category chips, expandable lot cards, the
  scan-packet flow as a two-step dialog that never auto-creates.
- Settings: Appearance (theme seg), Who gets in (read-only sign-in config),
  Garden assistant (self-saving toggle + chat/vision model fields), You.
- Editor: a new canvas with the prototype's pointer model (wheel-to-cursor,
  pinch about the centroid, 3″ snap, one PATCH per drop, semantic-zoom
  monograms/labels), plus corner resize handles; desktop three-card workspace
  (toolkit | plan | rail with Plot/Journal/History/Assistant) and, below 760px
  of container width, the phone chrome (header, peek panel, tool strip, mode
  bar). Seasons as a segmented control over the years with data plus plan
  copies; Undo re-reads history before reverting the newest step.
- Public read-only view and the register page restyled to match.
- GET /settings gains a read-only `auth` view (registration mode, local auth,
  OIDC issuer) so the Settings page can show what's in force.
- README / DESIGN.md / CLAUDE.md updated; @use-gesture/react dropped.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
2026-08-22 19:12:29 -04:00
co-authored by Claude Fable 5
parent 18b36870d4
commit 52b2c09a9e
111 changed files with 6621 additions and 7215 deletions
+10
View File
@@ -82,6 +82,16 @@ Local email/password auth is live (`POST /api/v1/auth/register`, `/auth/login`,
OIDC (Authentik-first) is live too: set `PANSY_OIDC_ISSUER`, `PANSY_OIDC_CLIENT_ID`, `PANSY_OIDC_CLIENT_SECRET`, and `PANSY_BASE_URL` (needed for the redirect URI). Register `PANSY_BASE_URL` + `/api/v1/auth/oidc/callback` as the redirect URI in your IdP. `GET /auth/oidc/login` starts an authorization-code + PKCE flow; first login provisions a user just-in-time (a matching *verified* email links to an existing local account instead of duplicating it). Provider discovery is lazy, so a briefly-unreachable IdP never blocks startup or local auth. Set `PANSY_LOCAL_AUTH=false` for pure-Authentik deployments (local register/login are then rejected and hidden from `/auth/providers`).
## The UI
The frontend implements the design handoff in [`docs/design_handoff_pansy_ui/`](docs/design_handoff_pansy_ui/README.md) — read that README before changing how anything looks; the `.dc.html` files there are references, not shipped code.
- **Theme.** Light by default, with a `system | light | dark` preference (the monitor/sun/moon button in every nav, or Settings → Appearance) kept in `localStorage['pansy-theme']`. Dark mode is the same stylesheet with its tokens overridden on `<html>` by a small script in `web/index.html`, which runs before the first paint.
- **Fonts.** Caprasimo and Figtree are loaded from Google Fonts (`fonts.googleapis.com`). That is the app's only request to a third party; offline it falls back to system fonts and everything else works.
- **Phone vs desktop.** The editor picks its chrome by *container* width — below 760px it is the one-column phone layout (mode bar, tool strip, a peek panel that docks between the canvas and the bar); above it, the three-card workspace. Every other page is one responsive layout.
- **Season plans.** "Copy — plan a season from it" duplicates a garden (`POST /gardens/:id/copy`) under the name `<garden> — <year>`; the editor's season control and the `plan` tag on the gardens list read that name back. Rename the copy and it is just a garden again.
- **Settings → Who gets in** is read-only: `PANSY_REGISTRATION`, `PANSY_LOCAL_AUTH` and the OIDC issuer are reported there (the `auth` block of `GET /settings`) so an admin can see what is in force without shell access; they deploy with the environment.
## Docker & deployment
CI (`.gitea/workflows/build-image.yml`) builds the single-binary image and pushes it to the Gitea registry on every branch push: