Inital template

This commit is contained in:
Martin Kivi committed 2026-10-15 14:21:55 +02:00
commit 54faec3540
62 files changed
+6808

No files matched your search

+83
View File
@@ -0,0 +1,83 @@
# Stackship Circuit template
A React 19 + Vite starting point for apps that Circuit builds and Stackship runs. Routing,
light/dark theming, a typed API layer and the Stackship components are already wired, so an
agent (or you) starts with product work instead of plumbing.
It follows the same contract as Circuit's frontend template — dev server on `:5173`, mock API
at `/api`, `.eventsourced/session.yaml` for the live preview — with the Stackship design system
on top.
## Stack
- **React 19** with the React Compiler enabled
- **Vite 8** dev server, with a mock API served at `/api`
- **Tailwind v4** — Stackship tokens defined as CSS variables in `src/index.css`
- **Radix UI** (unified `radix-ui` package) for accessible primitives
- **SWR** for data fetching, **react-router** for routing, **lucide-react** for icons
- **Poppins + JetBrains Mono** bundled through Fontsource — no CDN calls, works air-gapped
## Structure
```
src/
api/ # typed API layer — one SWR hook per endpoint
types.ts # response types
client.ts # fetch wrapper (all network calls go through here)
hooks.ts # useStats(), useResources(), … consumed by pages
components/
ui/ # Stackship primitives: Button, Card, Badge, ServiceIcon, ProgressBar, Skeleton
gallery/ # component-gallery demos, one primitive per file
dashboard/ # dashboard sections (StatGrid, ResourcesTable, SentinelCard…)
home/ # home page sections (Hero, EnvironmentCard, LoopSection, StackGrid)
Layout.tsx # header + footer, wraps every route
Logo.tsx # Stackship wordmark, light/dark aware
ThemeProvider.tsx / ThemeToggle.tsx
pages/ # one file per route, registered in App.tsx
mock/server.mjs # zero-dependency mock API (started by the dev server)
public/ # favicon and Stackship logos
```
## Conventions (follow these when editing — applies to AI agents too)
- **Colours and fonts come from tokens only.** Use Tailwind classes like `bg-card`,
`text-muted-foreground`, `border-border`, `bg-primary`. Never hardcode hex values; both modes
read from the variables at the top of `src/index.css`. The one exception is the always-dark
hero surface, which uses `bg-night` and white text in both themes.
- **Brand utilities:** `text-gradient` (blue→green headline words), `bg-brand` (gradient CTAs
and meters), `glass`, `glow-primary` / `glow-accent` (blurred backdrops on dark sections).
Use the gradient sparingly — one highlight per screen reads as deliberate.
- **Resource types** get their accent from `ServiceIcon` (`app`, `database`, `storage`, …).
Don't invent new hues for them.
- **Sentinel** (the AI/ops assistant) uses the rose `sentinel` colour and nothing else does.
- **New route** = one file in `src/pages/` + one line in `src/App.tsx` (+ nav entry in
`Layout.tsx`).
- **New data** = type in `src/api/types.ts`, route in `mock/server.mjs`, hook in
`src/api/hooks.ts`. Pages never call `fetch` directly.
- **Loading** with `<Skeleton />`, **errors** inline with `<ErrorNote />` and a retry — see
`src/pages/Dashboard.tsx`.
- **Pages are compositions.** A page owns layout and data fetching, then renders sections from
`src/components/<page>/`. If a page file grows past ~100 lines, extract sections.
- **Copy:** sentence case for headings and buttons, no exclamation marks, no emoji. Calm and
declarative — "You control where data lives", not "Unleash your data".
- Radix provides behaviour, Tailwind provides looks. Copy styles from the gallery
(`src/pages/Components.tsx`) rather than inventing new patterns.
## Commands
```bash
npm run dev # app on :5173, mock API proxied at /api
npm run build # type-check + production build
npm run lint # oxlint
```
## Theming
Light and dark are two sets of CSS variables in `src/index.css` (`:root` and `.dark`). The
header toggle offers light, dark and system, and persists to `localStorage`. To retheme, change
the variable values — no component edits needed.
## Swapping in a real API
Point `server.proxy['/api']` in `vite.config.ts` at your backend and remove the `mockApi()`
plugin. Endpoint shapes stay in `src/api/types.ts`.