Files
jules 286e2daf95 feat: initial commit — crema-app-aifirst-template
Hybrid traditional + AI-first webapp scaffold. Sibling to crema-app-template,
adds the AI assistant surface, command bus, scripts dialog, and virtual
cursor.

What's pre-wired:
- 6 routes: Overview, Resources, Activity, Assistant, Library, Settings
- Collapsible rail + appbar + avatar dropdown shell (template code, not a lib)
- Mobile sheet at <md
- /assistant: streaming chat via @crema/llm-ui, mock fallback, model selector,
  token meter, retry probe, stop-while-streaming, persistent UI Control toggle
- /settings: editable LM Studio endpoint + context window + response cap, with
  test-connection button
- Markdown rendering for assistant replies; ```action``` blocks rendered as a
  small "Ran N actions" pill
- ⌘⇧P script runner dialog + Play icon in the appbar
- Two demo scripts in public/scripts/
- mightypix theme as default, scoped via <AppShell theme="mightypix">

Libs wired in tsconfig + app.css:
- @crema/action-bus (the bus, parser, runner, cursor, provider, ws, llm-bridge)
- @crema/llm-ui, @crema/chat-ui, @crema/aifirst-ui, @crema/notification-ui
- lib-theme-mightypix

Docs:
- README.md — pitch + quick start + structure
- docs/AI_FIRST.md — full system tour (data-action contract, bus, DSL, scripts,
  cursor, LLM integration)
- app/components/layout/THEME_CONTRACT.md — every CSS variable a theme must declare
- CLAUDE.md — orientation for an LLM working in the repo

Genericized from comfy-cloud (the original prototype):
- Brand defaults to "App" / Sparkles icon (override via app/lib/identity.ts)
- User defaults to a stub (swap useUser() for real auth)
- localStorage namespace is "crema.*" (was "comfy.*")

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 18:31:46 +10:00

133 lines
4.9 KiB
Markdown

# Theme contract
Every Crema theme (`lib-theme-*`) must declare these CSS variables so the
shell, AI surfaces, and shadcn primitives render correctly. Missing a variable
won't crash anything — it'll just look wrong (transparent backgrounds, missing
borders, broken focus rings, etc.).
A theme is a single CSS file that declares variables under `:root` for light
mode and under `.dark` for dark mode. Themes may also `@import url(...)` font
packages at the top of the file — they ship self-contained.
The shell expects the theme to be the **first** import in the consuming app's
entry CSS, so any embedded font URLs land at the top of the resolved output
(CSS spec requires `@import` before any other rules).
## Required tokens
### Surfaces
| Token | Used for |
|---|---|
| `--background` | Page background |
| `--foreground` | Default text color |
| `--card` | Card surfaces, inputs, dropdowns |
| `--card-foreground` | Text on cards |
| `--popover` | Popover/menu surfaces |
| `--popover-foreground` | Text on popovers |
| `--muted` | Subtle backgrounds (hover states, toolbars, code blocks) |
| `--muted-foreground` | Subtle text (timestamps, hints, labels) |
| `--accent` | Hover/focus highlight on items |
| `--accent-foreground` | Text on accent backgrounds |
### Brand & status
| Token | Used for |
|---|---|
| `--primary` | Brand color, primary buttons, active nav, ripple |
| `--primary-foreground` | Text on primary surfaces |
| `--secondary` | Secondary buttons |
| `--secondary-foreground` | Text on secondary |
| `--destructive` | Errors, sign-out, destructive menu items |
| `--success` | Confirmations |
| `--success-foreground` | Text on success surfaces |
### Borders, inputs, focus
| Token | Used for |
|---|---|
| `--border` | Dividers, default borders |
| `--input` | Input field borders |
| `--ring` | Focus rings |
### Sidebar (rail)
| Token | Used for |
|---|---|
| `--sidebar` | Rail background |
| `--sidebar-foreground` | Rail text |
| `--sidebar-primary` | Active nav background |
| `--sidebar-primary-foreground` | Active nav text |
| `--sidebar-accent` | Rail hover |
| `--sidebar-accent-foreground` | Text on rail hover |
| `--sidebar-border` | Rail borders |
| `--sidebar-ring` | Rail focus ring |
### Charts & syntax (optional but recommended)
| Token | Used for |
|---|---|
| `--chart-1``--chart-5` | Chart series colors; `--chart-3` doubles as warning amber |
| `--syntax-keyword`, `--syntax-string`, `--syntax-number`, `--syntax-comment`, `--syntax-function`, `--syntax-type` | Code-block highlighting |
### Typography
| Token | Used for |
|---|---|
| `--font-heading` | Heading font stack |
| `--font-sans` | Default UI font stack |
| `--font-ai-prose` | Assistant prose (the AI surface uses this for replies) |
| `--font-mono` | Code, tabular numbers |
### Type scale
Each pair declares a size and matching line height:
- `--text-display-size` / `--text-display-lh`
- `--text-headline-size` / `--text-headline-lh`
- `--text-title-size` / `--text-title-lh`
- `--text-body-size` / `--text-body-lh`
- `--text-label-size` / `--text-label-lh`
- `--text-caption-size` / `--text-caption-lh`
### Motion
| Token | Used for |
|---|---|
| `--duration-fast`, `--duration-base`, `--duration-slow`, `--duration-slower`, `--duration-spring` | Animation lengths |
| `--ease-standard`, `--ease-emphasized`, `--ease-decelerate`, `--ease-accelerate` | Standard easing curves |
| `--ease-spring-gentle`, `--ease-spring-snappy`, `--ease-spring-bouncy` | Spring curves |
### Radii & elevation
| Token | Used for |
|---|---|
| `--radius` | Base radius (sm/md/lg/xl/2xl computed from this in `app.css`) |
| `--elevation-0``--elevation-5` | Shadow scale |
| `--border-width-thin`, `--border-width-base`, `--border-width-thick`, `--border-width-heavy` | Stroke widths |
## Scoping conventions
- `:root { … }` — theme defaults (light mode).
- `.dark { … }` — dark-mode overrides.
- `[data-theme="<name>"] { … }` — alternate-scoped theme. Only needed if a
theme should coexist with another on the same page (e.g. an AI surface uses
a different theme than the rest of the app). Single-theme apps don't need
this scope.
## Adding a new theme
1. Clone any existing theme as a starting point — `lib-theme-mightypix` is a
good reference because it's complete.
2. Edit tokens (and font `@import url` if changing fonts).
3. Update the consuming app's `app.css`:
```css
@import "../../lib-theme-<your-name>/theme.css"; /* CREMA:THEME */
@import "tailwindcss";
...
```
4. Done. Components automatically pick up the new look — no changes needed in
any TSX file.
## Multi-theme apps (e.g. mightypix on AI surfaces only)
If a theme defines `[data-theme="<name>"]` instead of (or in addition to)
`:root`, you can switch surfaces per route via the shell's `theme` prop:
```tsx
<AppShell title="Assistant" theme="mightypix">…</AppShell>
```
The shell wraps itself in `data-theme={theme}` so the alt theme's tokens
cascade through that subtree only.