Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,16 @@ Defined in `config/wrangler.json`:
2. Use `createFileRoute` from TanStack Router
3. Access auth via `useAuth()` hook

### Frontend UI — Design System (Seven)

Every UI element comes from **Seven** (`@etus/seven-react`, which re-exports `@etus/ui` + `@etus/tokens`). Do not build controls with raw HTML or local UI components.

- **Components:** `import { Button, TextInput, Card, Dialog, Switch, Checkbox, Divider, SkeletonLoader, Toaster, Sidebar } from '@etus/seven-react'`. Names are not shadcn's (e.g. `TextInput` not `Input`; `Divider` not `Separator`) — verify exports at **runtime** (`Object.keys(await import('@etus/ui'))`), not from the `.d.ts`.
- **Tokens:** `@etus/tokens` is the source for color/radius/spacing/typography (via `@import "@etus/seven-react/styles.css"` in `src/client/index.css`). The local `@theme` only keeps what Seven does not provide.
- **Brand (`DESIGN.md` in the Seven repo):** Inter + JetBrains Mono; only `mint`/`lime` are brand (fuchsia is charts-only); no decoration; sentence-case pt-BR; Tailwind v4 type hints (`bg-[color:var(--token)]`).
- **Guard-rail:** ESLint bans raw `<button>/<input>/<select>/<textarea>` in routes (`config/eslint.config.js`). Icons via `lucide-react`.
- **Validation:** compare each screen against the published showcase at `seven.etus.io` (not only the code). Reference source: `~/Dropbox/aa-projects/Github/seven` (`apps/showcase`, `DESIGN.md`).

### Database Changes

1. Update `schema.sql`
Expand Down
35 changes: 35 additions & 0 deletions config/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default tseslint.config(
"**/.claude/**",
"**/.agents/**",
"**/.codex/**",
"**/.remember/**",
"**/e2e/**",
"**/packages/**",
"**/.pnpm*",
Expand Down Expand Up @@ -311,6 +312,40 @@ export default tseslint.config(
},
},

// ==============================================
// DS GUARD-RAIL: app screens use Seven controls, not raw HTML
// (every interactive control must come from @etus/seven-react)
// ==============================================
{
files: ["src/client/routes/**/*.{ts,tsx}", "src/client/components/**/*.{ts,tsx}"],
ignores: ["src/client/components/icons.tsx"],
rules: {
"no-restricted-syntax": [
"error",
{
selector: "JSXOpeningElement[name.name='button']",
message:
"Use Button from '@etus/seven-react' instead of a raw <button>.",
},
{
selector: "JSXOpeningElement[name.name='input']",
message:
"Use TextInput/Checkbox/Switch from '@etus/seven-react' instead of a raw <input>.",
},
{
selector: "JSXOpeningElement[name.name='select']",
message:
"Use Select/NativeSelect from '@etus/seven-react' instead of a raw <select>.",
},
{
selector: "JSXOpeningElement[name.name='textarea']",
message:
"Use Textarea from '@etus/seven-react' instead of a raw <textarea>.",
},
],
},
},

// === TEST FILES - DISABLE TYPE-CHECKED RULES ===
{
files: [
Expand Down
319 changes: 319 additions & 0 deletions docs/plans/2026-06-16-001-migrate-frontend-seven-ds-plan.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<title>Hono Boilerplate</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
Expand Down
10 changes: 10 additions & 0 deletions packages/bhono-app/templates/base/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,16 @@ Defined in `config/wrangler.json`:
2. Use `createFileRoute` from TanStack Router
3. Access auth via `useAuth()` hook

### Frontend UI — Design System (Seven)

Every UI element comes from **Seven** (`@etus/seven-react`, which re-exports `@etus/ui` + `@etus/tokens`). Do not build controls with raw HTML or local UI components.

- **Components:** `import { Button, TextInput, Card, Dialog, Switch, Checkbox, Divider, SkeletonLoader, Toaster, Sidebar } from '@etus/seven-react'`. Names are not shadcn's (e.g. `TextInput` not `Input`; `Divider` not `Separator`) — verify exports at **runtime** (`Object.keys(await import('@etus/ui'))`), not from the `.d.ts`.
- **Tokens:** `@etus/tokens` is the source for color/radius/spacing/typography (via `@import "@etus/seven-react/styles.css"` in `src/client/index.css`). The local `@theme` only keeps what Seven does not provide.
- **Brand (`DESIGN.md` in the Seven repo):** Inter + JetBrains Mono; only `mint`/`lime` are brand (fuchsia is charts-only); no decoration; sentence-case pt-BR; Tailwind v4 type hints (`bg-[color:var(--token)]`).
- **Guard-rail:** ESLint bans raw `<button>/<input>/<select>/<textarea>` in routes (`config/eslint.config.js`). Icons via `lucide-react`.
- **Validation:** compare each screen against the published showcase at `seven.etus.io` (not only the code). Reference source: `~/Dropbox/aa-projects/Github/seven` (`apps/showcase`, `DESIGN.md`).

### Database Changes

1. Update `schema.sql`
Expand Down
35 changes: 35 additions & 0 deletions packages/bhono-app/templates/base/config/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default tseslint.config(
"**/.claude/**",
"**/.agents/**",
"**/.codex/**",
"**/.remember/**",
"**/e2e/**",
"**/packages/**",
"**/.pnpm*",
Expand Down Expand Up @@ -311,6 +312,40 @@ export default tseslint.config(
},
},

// ==============================================
// DS GUARD-RAIL: app screens use Seven controls, not raw HTML
// (every interactive control must come from @etus/seven-react)
// ==============================================
{
files: ["src/client/routes/**/*.{ts,tsx}", "src/client/components/**/*.{ts,tsx}"],
ignores: ["src/client/components/icons.tsx"],
rules: {
"no-restricted-syntax": [
"error",
{
selector: "JSXOpeningElement[name.name='button']",
message:
"Use Button from '@etus/seven-react' instead of a raw <button>.",
},
{
selector: "JSXOpeningElement[name.name='input']",
message:
"Use TextInput/Checkbox/Switch from '@etus/seven-react' instead of a raw <input>.",
},
{
selector: "JSXOpeningElement[name.name='select']",
message:
"Use Select/NativeSelect from '@etus/seven-react' instead of a raw <select>.",
},
{
selector: "JSXOpeningElement[name.name='textarea']",
message:
"Use Textarea from '@etus/seven-react' instead of a raw <textarea>.",
},
],
},
},

// === TEST FILES - DISABLE TYPE-CHECKED RULES ===
{
files: [
Expand Down
2 changes: 1 addition & 1 deletion packages/bhono-app/templates/base/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<title>Hono Boilerplate</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Toaster } from '@etus/seven-react'
import { useTheme } from '@/hooks/use-theme'

/** Seven's Toaster wired to the app theme (needs the ThemeProvider context). */
export function AppToaster() {
const { resolvedTheme } = useTheme()
return <Toaster theme={resolvedTheme} />
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// src/client/components/error-boundary.tsx
import { Component, type ReactNode } from 'react'
import { Button } from '@etus/seven-react'

interface ErrorBoundaryProps {
children: ReactNode
Expand Down Expand Up @@ -52,12 +53,12 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
<p className="mt-2 text-sm text-muted-foreground">
{this.state.error?.message ?? 'An unexpected error occurred'}
</p>
<button
<Button
className="mt-4"
onClick={() => { this.setState({ hasError: false, error: null }) }}
className="mt-4 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90"
>
Try again
</button>
</Button>
</div>
</div>
)
Expand Down
Loading
Loading