From a9d805be4b2a57c568cb4c01446863543c651a9d Mon Sep 17 00:00:00 2001 From: Clawy Date: Sat, 7 Mar 2026 01:54:20 +0000 Subject: [PATCH 01/15] chore: remove AUDIT.md, update docs for Storybook as core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove AUDIT.md (served its purpose) - README: add Storybook to stack table, commands, project structure, and a new 'What's Included' section with story example - README: remove stale recipes/storybook/ reference - CLAUDE.md: update recipe list (storybook → storybook-deploy) - recipes/README.md: same - skills/recipe-install: update available recipes table --- AUDIT.md | 174 --------------------------------- CLAUDE.md | 2 +- README.md | 58 +++++++---- recipes/README.md | 2 +- skills/recipe-install/SKILL.md | 6 +- 5 files changed, 45 insertions(+), 197 deletions(-) delete mode 100644 AUDIT.md diff --git a/AUDIT.md b/AUDIT.md deleted file mode 100644 index f2a1c38..0000000 --- a/AUDIT.md +++ /dev/null @@ -1,174 +0,0 @@ -# 🔍 Technical Audit Report — React Starter Kit - -**Auditor:** Skeptical Technical Lead (subagent) -**Date:** 2026-03-06 -**Scope:** Full codebase read-through + dependency verification + claim cross-referencing - ---- - -## 🔴 Verified Issues - -### 1. `@storybook/test` version mismatch with Storybook 10 -**File:** `package.json` -**Details:** All Storybook packages are `^10.1.11` except `@storybook/test` which is `^8.6.15`. As of this audit, `@storybook/test` on npm has a **latest version of 8.6.15** — there is no v10 release of this package. This means either: -- Storybook 10 folded `@storybook/test` into another package and this dep is dead weight -- Or it's genuinely incompatible and will cause version resolution warnings or runtime issues - -**Impact:** Tests in stories may break or silently use the wrong testing utilities. The `@storybook/addon-vitest` (v10) likely supersedes `@storybook/test` (v8) anyway. - -**Recommendation:** Remove `@storybook/test` or verify Storybook 10's migration guide for the replacement. - -### 2. Both `bun.lock` and `package-lock.json` exist -**File:** Project root -**Details:** Two lockfiles coexist. The project claims to use Bun exclusively, but having both lockfiles is a recipe for install confusion. CI uses `bun install --frozen-lockfile` which reads `bun.lock`, so `package-lock.json` is dead weight at best and misleading at worst. - -**Recommendation:** Delete `package-lock.json` and add it to `.gitignore`. - -### 3. `@slideIn` animation used but not declared in Panda CSS config -**File:** `src/components/ui/ToastProvider.tsx` line: `animation: "slideIn 200ms ease-out"` -**Details:** The `slideIn` keyframes are defined in `src/styles/global.css`, not in `panda.config.ts`. This works because the CSS is loaded globally, but it bypasses Panda's animation system. If someone removes or refactors `global.css`, toast animations silently break with no build error. Panda CSS supports `keyframes` in config — this should live there for consistency. - -**Impact:** Low — it works. But it's inconsistent with the "everything through Panda" philosophy. - ---- - -## 🟡 Dubious Claims - -### 1. "13 Core Components" (README) -**Claim:** README says "13 Core Components" but never enumerates all 13. The barrel export would need to be checked to verify the count. The README shows examples of: Button, Input, TextArea, Select, Checkbox, Modal, ConfirmDialog, LoadingSpinner, Skeleton, Badge, EmptyState, ToastProvider/useToast. That's 12 distinct components (counting Toast as one). Could be 13 if you count the hook separately, but that's a stretch. - -**Verdict:** Minor marketing claim, not a real problem. But "13" is likely wrong. - -### 2. "Zero-runtime" claim for Panda CSS -**Claim:** CLAUDE.md and README both claim Panda CSS is "zero-runtime — CSS generated at build time, no JS shipped for styles." -**Reality:** This is *mostly* true but nuanced. The `css()` and `cva()` calls still ship JS — they're function calls that return class name strings at runtime. The *styles* are pre-generated, but the class name resolution logic is in the bundle. This is different from truly zero-runtime solutions like vanilla-extract where even the class names are statically resolved. Panda CSS's own docs call it "zero-runtime" too, so this is industry-standard marketing, but it's technically misleading. - -### 3. varlock integration is placeholder-level -**Claim:** README and CLAUDE.md present varlock as a key part of the stack with `.env.schema` validation. -**Reality:** The `.env.schema` has almost nothing in it — just `APP_ENV`, `VITE_APP_NAME`, and `VITE_APP_URL` with everything else commented out as examples. The `serverEnv.ts` just re-exports `ENV` from `varlock/env`. There's no evidence this has been tested with actual Cloudflare Worker bindings. For a starter kit, this is fine, but the docs oversell it as if it's a battle-tested setup. - -### 4. "forwardRef for broad compatibility" (CLAUDE.md) -**Claim:** "The existing components use `forwardRef` for broad compatibility." -**Reality:** React 19 (which this project uses — `^19.1.0`) supports ref as a regular prop. `forwardRef` still works but is officially legacy. The "broad compatibility" claim implies supporting React 18 consumers, but the `package.json` pins `react: ^19.1.0`, so there's no backward compatibility to preserve. This is cargo cult from the React 18 era. - ---- - -## 🟢 Verified Good - -### 1. All dependency versions are real and resolve correctly -Every pinned version in `package.json` resolves to real, published packages: -- `zod@^4.3.5` → installed `4.3.6` ✅ (Zod 4 is real, released 2025) -- `vite@^7.2.6` → installed `7.3.1` ✅ -- `vitest@^4.0.16` → installed `4.0.18` ✅ -- `typescript@^5.9.3` → installed `5.9.3` ✅ -- `storybook@^10.1.11` → installed `10.2.15` ✅ -- `@base-ui-components/react@^1.0.0-rc.0` → installed `1.0.0-rc.0` ✅ -- `@tanstack/react-start@^1.145.5` → installed `1.166.2` ✅ - -### 2. BaseUI sub-path imports are correct -The imports like `@base-ui-components/react/dialog`, `@base-ui-components/react/button`, `@base-ui-components/react/input` all exist and export the expected components. Verified in node_modules. - -### 3. `typeof className === "string"` guard in Button.tsx is correct -I was initially suspicious of this, but BaseUI's `BaseUIComponentProps` type allows `className` to be `string | ((state: State) => string | undefined)`. The guard correctly prevents passing a function to `cx()`, which expects strings. - -### 4. z-index strategy is consistently applied -Checked `dialogStyles.ts` — both backdrop and popup use `zIndex: 1`, relying on DOM order for stacking. The comment explaining this is accurate. ToastProvider also uses `zIndex: 1`. No arbitrary z-index values found anywhere. - -### 5. `server.handlers` pattern for API routes is real -Verified via Elysia integration docs and the actual TanStack Start codebase — `createFileRoute` with `server: { handlers: { GET, POST } }` is a legitimate pattern for API routes in TanStack Start. - -### 6. `createAPIFileRoute` correctly noted as not-yet-available -The TODO in `health.ts` says to migrate to `createAPIFileRoute` "when available." Grep of entire `node_modules/@tanstack/` confirms this export doesn't exist yet. The TODO is accurate. - -### 7. Theme system dark-mode-flash prevention -The inline script in `__root.tsx` that reads `localStorage` and sets `data-theme` before first paint is a well-known pattern to prevent FOUC (Flash of Unstyled Content) for dark mode. Correctly implemented. - -### 8. Router creates per-request instances for SSR safety -`router.ts` creates a new `QueryClient` and router per call to `createAppRouter()`. This is correct for SSR on Cloudflare Workers where you must not share state across requests. - -### 9. `use-sync-external-store` shim aliases -The vite `resolve.alias` entries redirect the shim packages to the real `use-sync-external-store`. This is a legitimate workaround for libraries that still import the React 18 shim when running on React 19. - ---- - -## 📋 Cargo Cult Watch - -### 1. `forwardRef` everywhere -As noted above, every component uses `forwardRef` despite React 19 supporting ref as a prop. The CLAUDE.md even acknowledges this ("forwardRef is technically legacy in React 19") but keeps it anyway for "broad compatibility" that doesn't exist given the `react: ^19.1.0` pin. New components should just accept `ref` as a prop. - -### 2. `@types/bun` pinned to exact version -**File:** `package.json` — `"@types/bun": "1.3.5"` (no caret) -Every other dependency uses `^` ranges. This one is pinned exactly. There's no comment explaining why. This looks like someone copied a lockfile version into package.json. - -### 3. Both `jsdom` and `happy-dom` as dev dependencies -The project has both `jsdom@^28.1.0` and `happy-dom@^20.0.11`. The CLAUDE.md recommends `happy-dom` for tests. Having both is confusing — pick one. - -### 4. `optimizeDeps.exclude` for TanStack packages -**File:** `vite.config.ts` -```ts -optimizeDeps: { - exclude: ["@tanstack/react-start", "@tanstack/start-server-core"], -} -``` -This is likely copied from a GitHub issue or Discord recommendation. It may have been needed for an earlier version of TanStack Start but could be unnecessary now. No comment explains why it's there or when it can be removed. - -### 5. `exclude` in tsconfig.json excludes test files -**File:** `tsconfig.json` — test files (`**/*.test.ts`, `**/*.test.tsx`) are excluded from type checking. -This means `bun run typecheck` will NOT catch type errors in tests. This is a common pattern to "speed up" type checking, but it means your tests could have type errors that nobody notices until they fail at runtime. Tests should be type-checked. - ---- - -## 💀 Silent Bugs - -### 1. Toast auto-dismiss uses `setTimeout` — not cleared on unmount -**File:** `src/components/ui/ToastProvider.tsx` -```tsx -setTimeout(() => { - setToasts((prev) => prev.filter((t) => t.id !== id)); -}, durationRef.current); -``` -If the `ToastProvider` unmounts before the timeout fires (e.g., route change that unmounts the root), this will call `setToasts` on an unmounted component. In React 18 this would warn; in React 19 it's silently ignored. But more importantly, the timeout is never cleaned up — if you show 100 toasts rapidly, you have 100 pending timeouts. No `clearTimeout` on dismiss either, so dismissing a toast manually still leaves the timeout running (it will try to remove an already-removed toast, which is harmless but wasteful). - -**Fix:** Store timeout IDs and clear them on dismiss and unmount. - -### 2. `env.ts` falls back to empty string in production -**File:** `src/lib/env.ts` -```tsx -VITE_APP_URL: import.meta.env.VITE_APP_URL || (import.meta.env.DEV ? "http://localhost:3000" : ""), -``` -In production, if `VITE_APP_URL` isn't set, this silently falls back to `""`. The `head.ts` helper uses this to build OG image URLs: `${appUrl}${options.image}`. So your OG images would get paths like `/og-image.png` instead of `https://mysite.com/og-image.png`. No error, just broken social previews. - -### 3. `panda.config.ts` excludes `src/lib/**` from style scanning -**File:** `panda.config.ts` — `exclude: ["./src/lib/**"]` -If anyone adds Panda CSS utilities (`css()`, `cva()`) in a file under `src/lib/`, the styles will silently not be generated. There's no warning. This is probably intentional (lib files shouldn't have styles), but it's undocumented and will bite someone who creates a `src/lib/someHelper.ts` that returns class names. - -### 4. Head metadata `{ title }` is not a valid meta tag -**File:** `src/lib/head.ts` -```tsx -const meta = [ - { title }, // ← This is { title: "My Title" } - ... -] -``` -The `meta` array includes `{ title }` as the first entry. This is a TanStack-specific convention where `{ title }` is a special meta entry that sets the `` tag. This works with TanStack's `HeadContent` component, so it's not actually a bug — but it looks wrong if you're used to standard HTML meta tags. Verified it's intentional TanStack Start behavior. - -### 5. CI caches Playwright by `bun.lock` hash, not Playwright version -**File:** `.github/workflows/ci.yml` -```yaml -key: playwright-${{ runner.os }}-${{ hashFiles('bun.lock') }} -``` -If you update Playwright's version in `package.json` but `bun.lock` doesn't change (unlikely but possible with range deps), you'd get stale browser binaries. More practically: if ANY dependency changes in `bun.lock`, the entire Playwright browser cache is invalidated and re-downloaded, even if Playwright itself didn't change. The key should include the Playwright version specifically, e.g., from `node_modules/@playwright/test/package.json`. - ---- - -## Summary - -The starter kit is **well-structured and mostly correct**. The dependency versions are real (not hallucinated), the architecture claims are largely accurate, and the patterns are sound. The main concerns are: - -1. **`@storybook/test` version mismatch** — needs attention -2. **`forwardRef` cargo cult** — unnecessary with React 19 -3. **Toast timer leak** — minor but real -4. **Empty `VITE_APP_URL` in production** — will cause silent OG metadata issues -5. **Test files excluded from type checking** — type errors in tests go unnoticed - -Nothing is catastrophically broken, but items #3, #4, and #5 are the kind of silent bugs that surface months later in production. diff --git a/CLAUDE.md b/CLAUDE.md index 8b2ed41..0a1fec8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -313,7 +313,7 @@ The `recipes/` directory contains drop-in patterns: - **authoring/** — Markdown rendering + TipTap rich text editor - **convex/** — Convex real-time database integration - **analytics/** — PostHog scaffolding -- **storybook/** — Storybook configuration +- **storybook-deploy/** — Storybook deployment to CF Pages Each recipe has its own README with setup instructions and required dependencies. diff --git a/README.md b/README.md index d102b2d..1132ff4 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ bun run dev | **Components** | [BaseUI](https://base-ui.com) | Headless accessible primitives | | **Deployment** | [Cloudflare Workers](https://workers.cloudflare.com) | Edge SSR via `@cloudflare/vite-plugin` | | **Testing** | [Vitest](https://vitest.dev) | Vite-native, fast | +| **Storybook** | [Storybook 10](https://storybook.js.org) | Component explorer with a11y addon | ## What's Included @@ -175,6 +176,36 @@ export const getItems = createServerFn({ method: "GET" }) }); ``` +### Storybook + +Storybook 10 is pre-configured with Panda CSS support and the a11y addon. The config filters out TanStack Start and Cloudflare plugins that don't apply in the Storybook context. + +```bash +bun run storybook # Opens on http://localhost:6006 +``` + +Add stories next to your components: + +```tsx +// src/components/ui/Button.stories.tsx +import type { Meta, StoryObj } from "@storybook/react-vite"; +import { Button } from "./Button"; + +const meta = { + component: Button, + args: { children: "Click me" }, +} satisfies Meta<typeof Button>; + +export default meta; +type Story = StoryObj<typeof meta>; + +export const Primary: Story = { args: { variant: "primary" } }; +export const Ghost: Story = { args: { variant: "ghost" } }; +export const Loading: Story = { args: { loading: true } }; +``` + +For deployment options (CF Pages, subdirectory), see `recipes/storybook-deploy/`. + ### Environment Variables Environment validation is handled by [varlock](https://varlock.dev) via `.env.schema`. The included schema is scaffolded — expand for your project. Add `@required`, `@type`, `@sensitive` decorators to define your schema. Varlock validates on load and fails fast with clear errors. @@ -291,27 +322,17 @@ function CheckoutButton() { **Extra deps:** `posthog-js`, `posthog-node` -### `recipes/storybook/` -- Component Stories - -Storybook config pre-wired for Panda CSS + BaseUI components. Includes a11y addon. - -```bash -# After copying .storybook/ config: -bun run storybook -# Opens on http://localhost:6006 -``` - -**Extra deps:** `storybook`, `@storybook/react-vite`, `@storybook/addon-a11y` - ## Commands ```bash -bun run dev # Start dev server (port 3000) -bun run build # Production build -bun run preview # Preview production build locally -bun run test # Run tests (Vitest) -bun run typecheck # TypeScript check -bun run deploy # Deploy to Cloudflare Workers +bun run dev # Start dev server (port 3000) +bun run build # Production build +bun run preview # Preview production build locally +bun run test # Run tests (Vitest) +bun run typecheck # TypeScript check +bun run storybook # Storybook dev server (port 6006) +bun run build:storybook # Build static Storybook +bun run deploy # Deploy to Cloudflare Workers ``` ## Project Structure @@ -331,6 +352,7 @@ bun run deploy # Deploy to Cloudflare Workers │ ├── router.ts # Router config + context type │ ├── start.ts # SSR entry │ └── client.tsx # Client entry +├── .storybook/ # Storybook config (pre-wired for Panda CSS + BaseUI) ├── recipes/ # Opt-in patterns (auth, markdown, convex, etc.) ├── docs/ # Architecture decisions, component API, deployment ├── styled-system/ # Generated by Panda CSS (gitignored) diff --git a/recipes/README.md b/recipes/README.md index faa6265..94eecd0 100644 --- a/recipes/README.md +++ b/recipes/README.md @@ -10,7 +10,7 @@ Drop-in patterns you can copy into your project. Each recipe is self-contained w | **authoring/** | Markdown rendering + rich text editing | `react-markdown`, `remark-gfm`, TipTap | | **convex/** | Convex real-time database integration | `convex`, `@convex-dev/react-query` | | **analytics/** | PostHog analytics scaffolding | `posthog-js`, `posthog-node` | -| **storybook/** | Storybook configuration for components | `storybook`, `@storybook/react-vite` | +| **storybook-deploy/** | Storybook deployment to CF Pages | None (Storybook is a core dependency) | ## How to Use diff --git a/skills/recipe-install/SKILL.md b/skills/recipe-install/SKILL.md index a6e29c0..0872db3 100644 --- a/skills/recipe-install/SKILL.md +++ b/skills/recipe-install/SKILL.md @@ -4,7 +4,7 @@ Installs a recipe from the `recipes/` directory into the active project. ## When to Use -When asked to add auth, forms, authoring/markdown, Convex, PostHog analytics, or Storybook to the project. +When asked to add auth, forms, authoring/markdown, Convex, or PostHog analytics to the project. ## Available Recipes @@ -15,7 +15,7 @@ When asked to add auth, forms, authoring/markdown, Convex, PostHog analytics, or | Authoring (Markdown + rich text) | `recipes/authoring/` | `react-markdown`, `remark-gfm`, `@tiptap/react`, `@tiptap/starter-kit`, `@tiptap/extension-placeholder` | | Convex | `recipes/convex/` | `convex`, `@convex-dev/react-query` | | Analytics (PostHog) | `recipes/analytics/` | `posthog-js`, `posthog-node` | -| Storybook | `recipes/storybook/` | `storybook`, `@storybook/react-vite`, `@storybook/addon-a11y`, `@storybook/test` | +| Storybook Deploy | `recipes/storybook-deploy/` | None (Storybook is already a core dependency) | ## Process @@ -45,7 +45,7 @@ Copy recipe files into the appropriate location in `src/`. Recommended structure | Authoring | `src/features/authoring/` | | Convex | `convex/` (project root) + `src/lib/convex.ts` | | Analytics | `src/lib/analytics.ts` + provider in `__root.tsx` | -| Storybook | `.storybook/` (project root) | +| Storybook Deploy | CI config (`.github/workflows/`) | ### 4. Wire Up From eb2f4f896d47a941fc427c3376684ab3d70ad75c Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 02:33:12 +0000 Subject: [PATCH 02/15] feat: promote data-display, layout, and forms from recipes to core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Avatar, List, Table, Timestamp → src/components/ui/ (from recipes/data-display) - Card, Header, Main, Section, Sidebar → src/components/ui/ (from recipes/layout) - Forms recipe → docs/forms.md (was just a usage pattern, deps already core) - All new components exported from ui barrel - 23 core components total (was 14) - Updated recipe-install skill --- README.md | 2 +- recipes/forms/README.md => docs/forms.md | 0 skills/recipe-install/SKILL.md | 3 +-- .../components => src/components/ui}/Avatar.stories.tsx | 0 .../components => src/components/ui}/Avatar.tsx | 0 .../components => src/components/ui}/Card.stories.tsx | 0 .../layout/components => src/components/ui}/Card.tsx | 0 .../components => src/components/ui}/Header.stories.tsx | 0 .../layout/components => src/components/ui}/Header.tsx | 0 .../components => src/components/ui}/List.stories.tsx | 0 .../components => src/components/ui}/List.tsx | 0 .../components => src/components/ui}/Main.stories.tsx | 0 .../layout/components => src/components/ui}/Main.tsx | 0 .../components => src/components/ui}/Section.stories.tsx | 0 .../layout/components => src/components/ui}/Section.tsx | 0 .../components => src/components/ui}/Sidebar.stories.tsx | 0 .../layout/components => src/components/ui}/Sidebar.tsx | 0 .../components => src/components/ui}/Table.stories.tsx | 0 .../components => src/components/ui}/Table.tsx | 0 .../components/ui}/Timestamp.stories.tsx | 0 .../components => src/components/ui}/Timestamp.tsx | 0 src/components/ui/index.ts | 9 +++++++++ 22 files changed, 11 insertions(+), 3 deletions(-) rename recipes/forms/README.md => docs/forms.md (100%) rename {recipes/data-display/components => src/components/ui}/Avatar.stories.tsx (100%) rename {recipes/data-display/components => src/components/ui}/Avatar.tsx (100%) rename {recipes/layout/components => src/components/ui}/Card.stories.tsx (100%) rename {recipes/layout/components => src/components/ui}/Card.tsx (100%) rename {recipes/layout/components => src/components/ui}/Header.stories.tsx (100%) rename {recipes/layout/components => src/components/ui}/Header.tsx (100%) rename {recipes/data-display/components => src/components/ui}/List.stories.tsx (100%) rename {recipes/data-display/components => src/components/ui}/List.tsx (100%) rename {recipes/layout/components => src/components/ui}/Main.stories.tsx (100%) rename {recipes/layout/components => src/components/ui}/Main.tsx (100%) rename {recipes/layout/components => src/components/ui}/Section.stories.tsx (100%) rename {recipes/layout/components => src/components/ui}/Section.tsx (100%) rename {recipes/layout/components => src/components/ui}/Sidebar.stories.tsx (100%) rename {recipes/layout/components => src/components/ui}/Sidebar.tsx (100%) rename {recipes/data-display/components => src/components/ui}/Table.stories.tsx (100%) rename {recipes/data-display/components => src/components/ui}/Table.tsx (100%) rename {recipes/data-display/components => src/components/ui}/Timestamp.stories.tsx (100%) rename {recipes/data-display/components => src/components/ui}/Timestamp.tsx (100%) diff --git a/README.md b/README.md index 1132ff4..227e402 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ bun run dev ## What's Included -### 14 Core Components +### 23 Core Components All follow the same pattern: BaseUI primitive → Panda CSS `cva()` recipe → typed props → `ref` as a regular prop (React 19). diff --git a/recipes/forms/README.md b/docs/forms.md similarity index 100% rename from recipes/forms/README.md rename to docs/forms.md diff --git a/skills/recipe-install/SKILL.md b/skills/recipe-install/SKILL.md index 0872db3..90d3232 100644 --- a/skills/recipe-install/SKILL.md +++ b/skills/recipe-install/SKILL.md @@ -11,7 +11,7 @@ When asked to add auth, forms, authoring/markdown, Convex, or PostHog analytics | Recipe | Directory | Extra Dependencies | |--------|-----------|-------------------| | Auth (OTP + sessions) | `recipes/auth/` | `twilio` (or your SMS/email provider) | -| Forms | `recipes/forms/` | None (zod + @tanstack/react-form already included) | + | Authoring (Markdown + rich text) | `recipes/authoring/` | `react-markdown`, `remark-gfm`, `@tiptap/react`, `@tiptap/starter-kit`, `@tiptap/extension-placeholder` | | Convex | `recipes/convex/` | `convex`, `@convex-dev/react-query` | | Analytics (PostHog) | `recipes/analytics/` | `posthog-js`, `posthog-node` | @@ -41,7 +41,6 @@ Copy recipe files into the appropriate location in `src/`. Recommended structure | Recipe | Target Location | |--------|----------------| | Auth | `src/features/auth/` | -| Forms | Follow pattern in README (no files to copy, just a pattern) | | Authoring | `src/features/authoring/` | | Convex | `convex/` (project root) + `src/lib/convex.ts` | | Analytics | `src/lib/analytics.ts` + provider in `__root.tsx` | diff --git a/recipes/data-display/components/Avatar.stories.tsx b/src/components/ui/Avatar.stories.tsx similarity index 100% rename from recipes/data-display/components/Avatar.stories.tsx rename to src/components/ui/Avatar.stories.tsx diff --git a/recipes/data-display/components/Avatar.tsx b/src/components/ui/Avatar.tsx similarity index 100% rename from recipes/data-display/components/Avatar.tsx rename to src/components/ui/Avatar.tsx diff --git a/recipes/layout/components/Card.stories.tsx b/src/components/ui/Card.stories.tsx similarity index 100% rename from recipes/layout/components/Card.stories.tsx rename to src/components/ui/Card.stories.tsx diff --git a/recipes/layout/components/Card.tsx b/src/components/ui/Card.tsx similarity index 100% rename from recipes/layout/components/Card.tsx rename to src/components/ui/Card.tsx diff --git a/recipes/layout/components/Header.stories.tsx b/src/components/ui/Header.stories.tsx similarity index 100% rename from recipes/layout/components/Header.stories.tsx rename to src/components/ui/Header.stories.tsx diff --git a/recipes/layout/components/Header.tsx b/src/components/ui/Header.tsx similarity index 100% rename from recipes/layout/components/Header.tsx rename to src/components/ui/Header.tsx diff --git a/recipes/data-display/components/List.stories.tsx b/src/components/ui/List.stories.tsx similarity index 100% rename from recipes/data-display/components/List.stories.tsx rename to src/components/ui/List.stories.tsx diff --git a/recipes/data-display/components/List.tsx b/src/components/ui/List.tsx similarity index 100% rename from recipes/data-display/components/List.tsx rename to src/components/ui/List.tsx diff --git a/recipes/layout/components/Main.stories.tsx b/src/components/ui/Main.stories.tsx similarity index 100% rename from recipes/layout/components/Main.stories.tsx rename to src/components/ui/Main.stories.tsx diff --git a/recipes/layout/components/Main.tsx b/src/components/ui/Main.tsx similarity index 100% rename from recipes/layout/components/Main.tsx rename to src/components/ui/Main.tsx diff --git a/recipes/layout/components/Section.stories.tsx b/src/components/ui/Section.stories.tsx similarity index 100% rename from recipes/layout/components/Section.stories.tsx rename to src/components/ui/Section.stories.tsx diff --git a/recipes/layout/components/Section.tsx b/src/components/ui/Section.tsx similarity index 100% rename from recipes/layout/components/Section.tsx rename to src/components/ui/Section.tsx diff --git a/recipes/layout/components/Sidebar.stories.tsx b/src/components/ui/Sidebar.stories.tsx similarity index 100% rename from recipes/layout/components/Sidebar.stories.tsx rename to src/components/ui/Sidebar.stories.tsx diff --git a/recipes/layout/components/Sidebar.tsx b/src/components/ui/Sidebar.tsx similarity index 100% rename from recipes/layout/components/Sidebar.tsx rename to src/components/ui/Sidebar.tsx diff --git a/recipes/data-display/components/Table.stories.tsx b/src/components/ui/Table.stories.tsx similarity index 100% rename from recipes/data-display/components/Table.stories.tsx rename to src/components/ui/Table.stories.tsx diff --git a/recipes/data-display/components/Table.tsx b/src/components/ui/Table.tsx similarity index 100% rename from recipes/data-display/components/Table.tsx rename to src/components/ui/Table.tsx diff --git a/recipes/data-display/components/Timestamp.stories.tsx b/src/components/ui/Timestamp.stories.tsx similarity index 100% rename from recipes/data-display/components/Timestamp.stories.tsx rename to src/components/ui/Timestamp.stories.tsx diff --git a/recipes/data-display/components/Timestamp.tsx b/src/components/ui/Timestamp.tsx similarity index 100% rename from recipes/data-display/components/Timestamp.tsx rename to src/components/ui/Timestamp.tsx diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 360172a..72fbc12 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -12,3 +12,12 @@ export { LoadingSpinner, type LoadingSpinnerProps } from "./LoadingSpinner"; export { Skeleton, type SkeletonProps } from "./Skeleton"; export { Badge, type BadgeProps } from "./Badge"; export { EmptyState, type EmptyStateProps } from "./EmptyState"; +export { Avatar, type AvatarProps } from "./Avatar"; +export { Card, type CardProps } from "./Card"; +export { Header, type HeaderProps } from "./Header"; +export { List, type ListProps } from "./List"; +export { Main, type MainProps } from "./Main"; +export { Section, type SectionProps } from "./Section"; +export { Sidebar, type SidebarProps } from "./Sidebar"; +export { Table, type TableProps, type Column } from "./Table"; +export { Timestamp, type TimestampProps } from "./Timestamp"; From 2d707a8c997e7948f52b2752844713a427e15045 Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 02:33:42 +0000 Subject: [PATCH 03/15] chore: remove duplicate recipes/markdown (same as authoring) --- recipes/markdown/README.md | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 recipes/markdown/README.md diff --git a/recipes/markdown/README.md b/recipes/markdown/README.md deleted file mode 100644 index eac2d4a..0000000 --- a/recipes/markdown/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Markdown Recipe - -Rich text editing with TipTap + collaborative sync + Markdown rendering. - -## What's Included - -- `components/MarkdownEditor.tsx` — TipTap-based rich text editor -- `components/Markdown.tsx` — Markdown renderer (react-markdown + remark-gfm) -- Collaborative sync pattern via Convex ProseMirror (optional) - -## Additional Dependencies - -```bash -bun add @tiptap/react @tiptap/starter-kit @tiptap/extension-placeholder react-markdown remark-gfm -# For collaborative sync: -bun add @convex-dev/prosemirror-sync -``` - -## Key Patterns - -- **Client-only rendering**: MarkdownEditor skips SSR (avoids sessionStorage issues) -- **Document ID convention**: `{entity}:{id}:{field}` (e.g., `zone:abc123:description`) -- **Auto-create on first edit**: Documents are lazily created -- **Markdown subset**: Headings, lists, code, links, emphasis - -## Integration - -1. Copy components into your preferred location (e.g., `src/components/markdown/`) -2. Install dependencies -3. Import and use — no provider setup needed for standalone mode -4. For collaborative sync, set up Convex ProseMirror (see your project's Convex sync setup) From 5d99f350c39008b51b88b7c29b9bff056d70aa0e Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 02:36:29 +0000 Subject: [PATCH 04/15] feat: promote DangerZone from pickers recipe to core UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pickers (ColorPicker, IconPicker) stay as a recipe — they pull external deps and are domain-specific. DangerZone is a generic settings pattern. --- README.md | 2 +- .../components => src/components/ui}/DangerZone.stories.tsx | 0 .../pickers/components => src/components/ui}/DangerZone.tsx | 0 src/components/ui/index.ts | 1 + 4 files changed, 2 insertions(+), 1 deletion(-) rename {recipes/pickers/components => src/components/ui}/DangerZone.stories.tsx (100%) rename {recipes/pickers/components => src/components/ui}/DangerZone.tsx (100%) diff --git a/README.md b/README.md index 227e402..cec82c9 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ bun run dev ## What's Included -### 23 Core Components +### 24 Core Components All follow the same pattern: BaseUI primitive → Panda CSS `cva()` recipe → typed props → `ref` as a regular prop (React 19). diff --git a/recipes/pickers/components/DangerZone.stories.tsx b/src/components/ui/DangerZone.stories.tsx similarity index 100% rename from recipes/pickers/components/DangerZone.stories.tsx rename to src/components/ui/DangerZone.stories.tsx diff --git a/recipes/pickers/components/DangerZone.tsx b/src/components/ui/DangerZone.tsx similarity index 100% rename from recipes/pickers/components/DangerZone.tsx rename to src/components/ui/DangerZone.tsx diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 72fbc12..2993a02 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -21,3 +21,4 @@ export { Section, type SectionProps } from "./Section"; export { Sidebar, type SidebarProps } from "./Sidebar"; export { Table, type TableProps, type Column } from "./Table"; export { Timestamp, type TimestampProps } from "./Timestamp"; +export { DangerZone, type DangerZoneProps } from "./DangerZone"; From 5e0fed1c3974342be4e8ae3037bf6005239900ca Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 02:36:49 +0000 Subject: [PATCH 05/15] chore: remove duplicate recipes/posthog (same as analytics) --- recipes/posthog/README.md | 41 --------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 recipes/posthog/README.md diff --git a/recipes/posthog/README.md b/recipes/posthog/README.md deleted file mode 100644 index 94e1bcf..0000000 --- a/recipes/posthog/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# PostHog Recipe - -Product analytics with PostHog (client + server). - -## Additional Dependencies - -```bash -bun add posthog-js posthog-node -``` - -## Setup - -1. Add `VITE_POSTHOG_KEY` to `src/lib/env.ts` -2. Add `POSTHOG_API_KEY` to `src/lib/serverEnv.ts` -3. Initialize client-side in `__root.tsx`: - -```typescript -import posthog from "posthog-js"; - -if (typeof window !== "undefined") { - posthog.init(env.VITE_POSTHOG_KEY, { - api_host: "https://us.i.posthog.com", - }); -} -``` - -4. Server-side (in server functions): - -```typescript -import { PostHog } from "posthog-node"; - -const posthog = new PostHog(serverEnv.POSTHOG_API_KEY); -posthog.capture({ distinctId: userId, event: "action_name" }); -await posthog.shutdown(); -``` - -## Key Patterns - -- Client: auto-capture enabled by default, feature flags via `posthog.isFeatureEnabled()` -- Server: explicit capture only, always `shutdown()` in Workers (flush before response ends) -- Use feature flags for gradual rollouts From 620e6e4a6c7ba03639a5164b8950b9395960618b Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 02:39:45 +0000 Subject: [PATCH 06/15] chore: update component scaffold skill to use React 19 ref-as-prop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove forwardRef from template and rules. React 19 passes ref as a regular prop — forwardRef is legacy and will be removed in a future React version. --- skills/component-scaffold/SKILL.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/skills/component-scaffold/SKILL.md b/skills/component-scaffold/SKILL.md index 6ad9527..e4e40ec 100644 --- a/skills/component-scaffold/SKILL.md +++ b/skills/component-scaffold/SKILL.md @@ -21,7 +21,6 @@ Ask for (if not provided): Create `src/components/ui/{Name}.tsx` following this exact pattern: ```tsx -import { forwardRef, type ComponentPropsWithoutRef } from "react"; // Import BaseUI primitive if wrapping one: // import { SomePrimitive } from "@base-ui-components/react/some-primitive"; import { cva, type RecipeVariantProps } from "styled-system/css"; @@ -47,22 +46,21 @@ const {name}Recipe = cva({ type {Name}Variants = RecipeVariantProps<typeof {name}Recipe>; -export type {Name}Props = ComponentPropsWithoutRef<"div"> & // or BaseUI type +export type {Name}Props = React.ComponentPropsWithoutRef<"div"> & // or BaseUI type {Name}Variants & { + ref?: React.Ref<HTMLDivElement>; // Custom props here }; -export const {Name} = forwardRef<HTMLDivElement, {Name}Props>( - function {Name}({ variant, size, className, ...props }, ref) { - return ( - <div - ref={ref} - className={{name}Recipe({ variant, size }) + (className ? ` ${className}` : "")} - {...props} - /> - ); - } -); +export function {Name}({ variant, size, className, ref, ...props }: {Name}Props) { + return ( + <div + ref={ref} + className={{name}Recipe({ variant, size }) + (className ? ` ${className}` : "")} + {...props} + /> + ); +} ``` ### 3. Update the Barrel Export @@ -79,7 +77,7 @@ Create `src/components/ui/{Name}.stories.tsx` (see storybook-gen skill). ## Rules - **`cva()` only** -- never use `styled()` -- **`forwardRef` with named function** -- `forwardRef(function MyComponent(...))` +- **No `forwardRef`** -- React 19 passes `ref` as a regular prop. Accept `ref?: React.Ref<HTMLElement>` in your props type and pass it through directly. `forwardRef` is legacy and will be removed in a future React version. - **Export both component and Props type** from the barrel - **No `any` types** -- use proper generics or `unknown` - **z-index: only -1, 0, 1** -- if the component needs stacking, justify it From 17bd53c6043586e066f26a83703195c6fc30798e Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 02:41:26 +0000 Subject: [PATCH 07/15] chore: sync docs after recipe promotions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AGENTS.md: forwardRef → ref-as-prop in component checklist - recipe-install skill: remove forms, add pickers, fix blank table row - CLAUDE.md: add pickers to recipe list - recipes/README.md: add pickers - README.md: update project structure recipe list --- AGENTS.md | 2 +- CLAUDE.md | 1 + README.md | 2 +- recipes/README.md | 1 + skills/recipe-install/SKILL.md | 5 +++-- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 0cefddc..ca16dd1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,7 +36,7 @@ chore: update panda css to v1.9 - [ ] Uses `cva()` for variants, `css()` for static styles - [ ] Wraps BaseUI primitive if interactive (Dialog, Select, etc.) - [ ] Accepts `className` prop for composition -- [ ] Uses `forwardRef` for DOM elements +- [ ] Accepts `ref` as a regular prop (React 19 — no `forwardRef`) - [ ] Exported from `src/components/ui/index.ts` - [ ] Types exported (`ComponentNameProps`) - [ ] No `styled()` — only `css()`/`cva()` diff --git a/CLAUDE.md b/CLAUDE.md index 0a1fec8..c306bb2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -313,6 +313,7 @@ The `recipes/` directory contains drop-in patterns: - **authoring/** — Markdown rendering + TipTap rich text editor - **convex/** — Convex real-time database integration - **analytics/** — PostHog scaffolding +- **pickers/** — Color + Icon pickers (react-colorful, lucide-react) - **storybook-deploy/** — Storybook deployment to CF Pages Each recipe has its own README with setup instructions and required dependencies. diff --git a/README.md b/README.md index cec82c9..844137a 100644 --- a/README.md +++ b/README.md @@ -353,7 +353,7 @@ bun run deploy # Deploy to Cloudflare Workers │ ├── start.ts # SSR entry │ └── client.tsx # Client entry ├── .storybook/ # Storybook config (pre-wired for Panda CSS + BaseUI) -├── recipes/ # Opt-in patterns (auth, markdown, convex, etc.) +├── recipes/ # Opt-in patterns (auth, authoring, convex, analytics, pickers, storybook-deploy) ├── docs/ # Architecture decisions, component API, deployment ├── styled-system/ # Generated by Panda CSS (gitignored) ├── panda.config.ts # Design tokens + theme diff --git a/recipes/README.md b/recipes/README.md index 94eecd0..3103f6f 100644 --- a/recipes/README.md +++ b/recipes/README.md @@ -10,6 +10,7 @@ Drop-in patterns you can copy into your project. Each recipe is self-contained w | **authoring/** | Markdown rendering + rich text editing | `react-markdown`, `remark-gfm`, TipTap | | **convex/** | Convex real-time database integration | `convex`, `@convex-dev/react-query` | | **analytics/** | PostHog analytics scaffolding | `posthog-js`, `posthog-node` | +| **pickers/** | Color + Icon pickers | `react-colorful`, `lucide-react` | | **storybook-deploy/** | Storybook deployment to CF Pages | None (Storybook is a core dependency) | ## How to Use diff --git a/skills/recipe-install/SKILL.md b/skills/recipe-install/SKILL.md index 90d3232..dd4504a 100644 --- a/skills/recipe-install/SKILL.md +++ b/skills/recipe-install/SKILL.md @@ -4,15 +4,15 @@ Installs a recipe from the `recipes/` directory into the active project. ## When to Use -When asked to add auth, forms, authoring/markdown, Convex, or PostHog analytics to the project. +When asked to add auth, authoring/markdown, Convex, PostHog analytics, or pickers to the project. ## Available Recipes | Recipe | Directory | Extra Dependencies | |--------|-----------|-------------------| | Auth (OTP + sessions) | `recipes/auth/` | `twilio` (or your SMS/email provider) | - | Authoring (Markdown + rich text) | `recipes/authoring/` | `react-markdown`, `remark-gfm`, `@tiptap/react`, `@tiptap/starter-kit`, `@tiptap/extension-placeholder` | +| Pickers (Color + Icon) | `recipes/pickers/` | `react-colorful`, `lucide-react` | | Convex | `recipes/convex/` | `convex`, `@convex-dev/react-query` | | Analytics (PostHog) | `recipes/analytics/` | `posthog-js`, `posthog-node` | | Storybook Deploy | `recipes/storybook-deploy/` | None (Storybook is already a core dependency) | @@ -44,6 +44,7 @@ Copy recipe files into the appropriate location in `src/`. Recommended structure | Authoring | `src/features/authoring/` | | Convex | `convex/` (project root) + `src/lib/convex.ts` | | Analytics | `src/lib/analytics.ts` + provider in `__root.tsx` | +| Pickers | `src/components/ui/` or `src/features/pickers/` | | Storybook Deploy | CI config (`.github/workflows/`) | ### 4. Wire Up From 5d344db06449e26977070bbe09975797b06c6e62 Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 02:55:22 +0000 Subject: [PATCH 08/15] docs: add post-clone checklist to README --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 844137a..ca7ef6b 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,24 @@ bun install bun run dev ``` +### Post-Clone Checklist + +After cloning, replace these placeholders with your project's details: + +| File | What to change | +|------|---------------| +| `package.json` | `"name"` — your package name | +| `wrangler.jsonc` | `"name"` — your Cloudflare Worker name | +| `.env.schema` | Add `VITE_APP_NAME` with your app name (used in page titles via `makeHead()`) | +| `src/routes/_app/index.tsx` | Replace landing page heading and description | +| `README.md` | Replace this README with your own | +| `CLAUDE.md` | Update project-specific conventions as you go | + +For local dev, create a `.dev.vars` file: +``` +VITE_APP_NAME=My App +``` + ## Stack | Layer | Choice | Why | From 2e5ea599b5c4728e37beabc8391d970f645d3e59 Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 02:57:14 +0000 Subject: [PATCH 09/15] chore: move test/setup.ts out of src/ --- {src/test => test}/setup.ts | 0 vitest.config.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename {src/test => test}/setup.ts (100%) diff --git a/src/test/setup.ts b/test/setup.ts similarity index 100% rename from src/test/setup.ts rename to test/setup.ts diff --git a/vitest.config.ts b/vitest.config.ts index 94907cb..4e84a20 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -8,7 +8,7 @@ export default defineConfig({ test: { globals: true, environment: "happy-dom", - setupFiles: ["./src/test/setup.ts"], + setupFiles: ["./test/setup.ts"], include: ["./src/**/*.test.ts", "./src/**/*.test.tsx"], exclude: ["node_modules", "dist", "**/*.stories.*"], alias: { From 205fe011730eb07834f71319a856381b9f04af1c Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 02:58:30 +0000 Subject: [PATCH 10/15] =?UTF-8?q?chore:=20flatten=20styles/global.css=20?= =?UTF-8?q?=E2=86=92=20src/styles.css?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +-- src/routes/__root.tsx | 2 +- src/{styles/global.css => styles.css} | 0 3 files changed, 2 insertions(+), 3 deletions(-) rename src/{styles/global.css => styles.css} (100%) diff --git a/README.md b/README.md index ca7ef6b..5de3cc6 100644 --- a/README.md +++ b/README.md @@ -365,8 +365,7 @@ bun run deploy # Deploy to Cloudflare Workers │ │ ├── env.ts # Client env flags (isProduction, isDevelopment) │ │ └── serverEnv.ts # Server env (re-exports varlock ENV) │ ├── routes/ # File-based routing (TanStack Start) -│ ├── styles/ -│ │ └── global.css # Global styles + Panda CSS layers +│ ├── styles.css # Global styles + Panda CSS layers │ ├── router.ts # Router config + context type │ ├── start.ts # SSR entry │ └── client.tsx # Client entry diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index e502bc8..44b6193 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -3,7 +3,7 @@ import { type ReactNode, useEffect } from "react"; import * as tsr from "@tanstack/react-router"; import { QueryClientProvider } from "@tanstack/react-query"; import type { RouterContext } from "@/router"; -import globalStyles from "@/styles/global.css?url"; +import globalStyles from "@/styles.css?url"; import { ToastProvider } from "@/components/ui"; import { DefaultErrorComponent, diff --git a/src/styles/global.css b/src/styles.css similarity index 100% rename from src/styles/global.css rename to src/styles.css From e32c9ce9aef29faa26e4aa30e9a24895d2a27847 Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 03:20:05 +0000 Subject: [PATCH 11/15] fix: update storybook preview import after styles.css move --- .storybook/preview.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 94da16b..e202bc0 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,7 +1,7 @@ import type { Preview } from "@storybook/react-vite"; import React from "react"; import { ToastProvider } from "../src/components/ui/ToastProvider"; -import "../src/styles/global.css"; +import "../src/styles.css"; const preview: Preview = { parameters: { From a27999f082a6e2c90f09c57949bf15cf67ad0853 Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 03:57:37 +0000 Subject: [PATCH 12/15] docs: attribute icons to Untitled UI --- README.md | 2 +- src/components/icons/index.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5de3cc6..228955a 100644 --- a/README.md +++ b/README.md @@ -360,7 +360,7 @@ bun run deploy # Deploy to Cloudflare Workers │ ├── components/ │ │ ├── ui/ # Design system (Button, Input, Modal, etc.) │ │ ├── layout/ # Flex, Grid, HStack, VStack, Box, Center -│ │ └── icons/ # Minimal icon set (7 icons) +│ │ └── icons/ # 7 icons from Untitled UI (thin React wrappers) │ ├── lib/ │ │ ├── env.ts # Client env flags (isProduction, isDevelopment) │ │ └── serverEnv.ts # Server env (re-exports varlock ENV) diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts index e8a4d00..7e06d49 100644 --- a/src/components/icons/index.ts +++ b/src/components/icons/index.ts @@ -1,3 +1,7 @@ +/** + * Icons from Untitled UI (https://untitledui.com/icons). + * Thin React components wrapping their SVG paths. + */ export { CheckIcon } from "./CheckIcon"; export { CloseIcon } from "./CloseIcon"; export { ChevronDownIcon } from "./ChevronDownIcon"; From bc28aa9ac95574fd28de863c68faf63a0b4d2d88 Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 04:01:36 +0000 Subject: [PATCH 13/15] chore: remove stale createAPIFileRoute TODOs --- src/routes/api/health.ts | 2 -- src/routes/api/liveness.ts | 1 - 2 files changed, 3 deletions(-) diff --git a/src/routes/api/health.ts b/src/routes/api/health.ts index b8d8fcc..f4bdf24 100644 --- a/src/routes/api/health.ts +++ b/src/routes/api/health.ts @@ -3,8 +3,6 @@ * * Returns 200 with status. Add your own dependency checks here. */ -// TODO: Migrate to createAPIFileRoute from "@tanstack/react-start/api" when available. -// See: https://tanstack.com/router/latest/docs/framework/react/start/api-routes import { createFileRoute } from "@tanstack/react-router"; export const Route = createFileRoute("/api/health")({ diff --git a/src/routes/api/liveness.ts b/src/routes/api/liveness.ts index f31fcf5..d94dd06 100644 --- a/src/routes/api/liveness.ts +++ b/src/routes/api/liveness.ts @@ -1,7 +1,6 @@ /** * Liveness Probe — returns 204 No Content for uptime monitoring. */ -// TODO: Migrate to createAPIFileRoute from "@tanstack/react-start/api" when available. import { createFileRoute } from "@tanstack/react-router"; export const Route = createFileRoute("/api/liveness")({ From 73b5d74f872dfd1dd7f436fbc2b90862a5ff7558 Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 04:10:17 +0000 Subject: [PATCH 14/15] fixup! feat: promote DangerZone from pickers recipe to core UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix DangerZone.stories.tsx import: @storybook/test → storybook/test (Storybook 10 moved test utils to storybook/test subpath export). --- src/components/ui/DangerZone.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ui/DangerZone.stories.tsx b/src/components/ui/DangerZone.stories.tsx index 69c588b..814de1e 100644 --- a/src/components/ui/DangerZone.stories.tsx +++ b/src/components/ui/DangerZone.stories.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import type { Meta, StoryObj } from "@storybook/react-vite"; -import { userEvent, within, expect, waitFor } from "@storybook/test"; -import { fn } from "@storybook/test"; +import { userEvent, within, expect, waitFor } from "storybook/test"; +import { fn } from "storybook/test"; import { DangerZone } from "./DangerZone"; const meta = { From c98d3d4ce232612d8fb52e3e6263a8842f1c2dd4 Mon Sep 17 00:00:00 2001 From: Clawy <clawy@openclaw.ai> Date: Sat, 7 Mar 2026 04:14:58 +0000 Subject: [PATCH 15/15] fixup! chore: move test/setup.ts out of src/ Include test/ in tsconfig.test.json so jest-dom type augmentation is picked up for .toBeInTheDocument() etc. --- tsconfig.test.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.test.json b/tsconfig.test.json index 1d9adac..a205d41 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -1,6 +1,6 @@ { "extends": "./tsconfig.json", - "include": ["src/**/*.ts", "src/**/*.tsx", "e2e/**/*.ts"], + "include": ["src/**/*.ts", "src/**/*.tsx", "e2e/**/*.ts", "test/**/*.ts"], "exclude": [ "node_modules", "dist",