Add Phase 1 Pocket Pascal UI: home, pantry, week plan, and plate.
Replace the hello-world shell with the elevated design system, bilingual screens, recipe/extras data, and the interactive Mein Teller view. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
58
handover/component-library/README.md
Normal file
58
handover/component-library/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Pocket Pascal — Elevated Surface Component Library
|
||||
|
||||
Drop this folder's contents into your Cursor React + TypeScript + Tailwind project. It's framework-agnostic (no Next.js-specific imports), works in Vite or Next.
|
||||
|
||||
> **Pivoted from glassmorphism to elevation (2026-08-03).** The first pass used real see-through glass (12% white fill, 16px blur) — over a plain white/dark background it barely reads as anything, which is exactly the feedback that came back: "I don't see the glass effect." Rather than fight a page background that has nothing distinct behind it to refract, the system now uses **low-transparency solid surfaces (~90% opaque) with visible elevation shadows**, and buttons that visibly **press inward** on tap (inset shadow + 1px downward shift + slight darkening) instead of just scaling down. The `--glass-*` variable names in `theme.css` were kept to minimize the diff across components, but they now mean "surface fill / surface blur," not transparent glass — see the comment block at the top of `theme.css`.
|
||||
|
||||
## Setup
|
||||
|
||||
1. **Copy files**
|
||||
- `styles/theme.css` → your global stylesheet, imported once in your app root (e.g. `main.tsx` or `app/layout.tsx`), **after** `@tailwind base/components/utilities`.
|
||||
- `lib/cx.ts`, `components/*.tsx` → into your `src/` at matching paths, or adjust the relative imports.
|
||||
- `public/fonts/*.woff2` → your project's `public/fonts/` (already the correct static latin-subset files, no need to re-fetch from Google).
|
||||
- `ComponentShowcase.tsx` → mount on a scratch route to sanity-check everything renders before wiring into real screens.
|
||||
|
||||
2. **Tailwind config** — enable class-based dark mode so the `.dark` class in `theme.css` works:
|
||||
|
||||
```ts
|
||||
// tailwind.config.ts
|
||||
export default {
|
||||
darkMode: "class",
|
||||
content: ["./src/**/*.{ts,tsx}"],
|
||||
theme: { extend: {} },
|
||||
};
|
||||
```
|
||||
|
||||
No plugin needed — `backdrop-filter`, `active:`, and arbitrary values (`bg-[image:var(--x)]`) are all core Tailwind v3+. This library leans on CSS variables + inline `style` for the gradient/blur values rather than baking them into the Tailwind theme, so it works the same whether or not you extend the config further.
|
||||
|
||||
3. **Toggle dark mode** by adding/removing the `dark` class on `<html>` (or any ancestor — see `ComponentShowcase.tsx` for a self-contained example that wraps in a `div` instead, for demo purposes only; in a real app put it on `<html>`).
|
||||
|
||||
## What's in here
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `styles/theme.css` | All design tokens: surface fill/blur/bevel-border, three-state shadows (resting/elevated/pressed), brand colors, surface + action gradients, `@font-face`, the `.glass-border` masked-bevel utility, PWA polish resets. |
|
||||
| `components/GlassCard.tsx` | Primary container. `variant="default" \| "interactive"`. Real elevation shadow, settles down 1px on tap. |
|
||||
| `components/BottomNav.tsx` | Floating pill nav, safe-area aware, gradient-on-active-icon, items press inward on tap. |
|
||||
| `components/Button.tsx` | `variant="primary" \| "secondary" \| "fab"`, plus `loading`/`disabled` states. Press state = inset shadow + 1px shift + darken, not just scale. |
|
||||
| `components/PlateChart.tsx` | SVG donut styled as a ceramic plate (rim + recessed well + gapped gradient slices + center label). |
|
||||
| `ComponentShowcase.tsx` | Demo page rendering all of the above over the ambient page gradient, with a light/dark toggle. |
|
||||
|
||||
## Deliberate deviations from the original brief — and why
|
||||
|
||||
**Text color on gradient buttons/badges is `--ink` (near-black), not white.**
|
||||
The brand's action gradients (lime → teal, coral → amber) are light/high-luminance by design — they're the same tokens already WCAG-audited for the rest of the Pocket Pascal system (see `/docs/CONCEPT.html`, decision log). White text on them fails AA contrast outright; a text-shadow doesn't fix a 2:1 ratio. Dark `--ink` text on these gradients measures 5.6–10.6:1 in both themes. If you introduce a new, genuinely dark gradient (e.g. for a destructive/caution CTA), white text + `text-shadow: 0 1px 2px rgba(0,0,0,0.25)` is fine there — just check the ratio first.
|
||||
|
||||
**`--gradient-caution` was added** (coral → deep red) for destructive actions, since the brief's two named gradients (`primary`, `accent`) didn't cover that case and the brand already has a `--color-caution` token.
|
||||
|
||||
**Fonts are loaded via local `@font-face` + static `.woff2` files, not `next/font` or a Google Fonts `<link>`.** Keeps `theme.css` portable across Vite/Next, and avoids a runtime dependency on Google's CDN. The five files in `public/fonts/` are the exact latin-subset statics used everywhere else in this project.
|
||||
|
||||
**`.glass-border` uses a masked pseudo-gradient, not `border-image`.** `border-image` ignores `border-radius` — it would square off every rounded corner. The mask-composite technique in `theme.css` respects `border-radius: inherit`, so it works on the 3xl card, the pill nav, and the 2xl buttons without extra per-component CSS.
|
||||
|
||||
**Pressed state is inset-shadow + 1px shift + darken, applied via `active:` Tailwind classes referencing CSS vars (`active:shadow-[var(--shadow-pressed)]`), not JS state or `active:scale`.** Scale alone reads as "shrinking," not "pushed in" — the eye needs the shadow to flip from outside (elevated) to inside (pressed) to sell the depth illusion. `Button` and the `BottomNav` items use this; `GlassCard`'s interactive variant deliberately uses a milder version (settle 1px + soften shadow, no inset) since a card is a container you tap *into*, not a switch you press.
|
||||
|
||||
## Known follow-ups (not done here)
|
||||
|
||||
- `PlateChart` gap is computed from a **physical pixel gap → angular gap** at a fixed average radius; if you resize the chart a lot at runtime, re-check that 2px still reads as a visible gap at very small sizes (below ~120px it may visually disappear).
|
||||
- No unit/visual regression tests included — this is a first-pass scaffold for Cursor, not a hardened library.
|
||||
- `BottomNav` active-icon gradient uses `background-clip: text`, which needs `-webkit-background-clip: text` too in some older WebKit builds; not added here since Tailwind's `bg-clip-text` utility already handles the prefix.
|
||||
Reference in New Issue
Block a user