
Assembling Components
- 50 installs
- 426 repo stars
- Updated December 11, 2025
- ancoleman/ai-design-components
Assembling Components is a Claude Code skill that assembles AI Design Components outputs into production-ready component systems with validated tokens and framework scaffolding.
About
Assembling Components is a Claude Code skill that turns the outputs of the AI Design Components skill chain (theming, layouts, dashboards, data-viz, feedback) into production-ready applications. It validates that generated CSS uses design tokens, generates framework-specific scaffolding for React/Vite, Next.js, FastAPI, Flask, or Rust/Axum, and wires barrel exports and import chains. A developer uses it as the capstone step after running the other component skills to assemble everything into a working project.
- Capstone skill that assembles AI Design Components outputs into production-ready systems
- Validates that generated CSS uses design tokens instead of hardcoded values
- Generates scaffolding for React/Vite, Next.js, FastAPI, Flask, or Rust/Axum and wires barrel exports
Assembling Components by the numbers
- 50 all-time installs (skills.sh)
- Ranked #1,306 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
assembling-components capabilities & compatibility
- Capabilities
- architecting data · ai data engineering · administering linux
- Use cases
- frontend · ui design · refactoring
- IDEs
- vscode
What assembling-components says it does
Assembles component outputs from AI Design Components skills into unified, production-ready component systems with validated token integration, proper import chains, and framework-specific scaffolding
Use as the capstone skill after running theming, layout, dashboard, data-viz, or feedback skills to wire components into working React/Next.js, Python, or Rust projects.
npx skills add https://github.com/ancoleman/ai-design-components --skill assembling-componentsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 50 |
|---|---|
| repo stars | ★ 426 |
| Last updated | December 11, 2025 |
| Repository | ancoleman/ai-design-components ↗ |
What it does
Wire generated design components into a working React/Next.js, Python, or Rust project with validated design tokens.
Who is it for?
Developers finishing an AI Design Components skill chain who need components wired into a real project.
Skip if: Projects not using the AI Design Components token system or component outputs.
When should I use this skill?
You have run theming, layout, dashboard, data-viz, or feedback skills and need to assemble the outputs.
What you get
A working component system with validated tokens, barrel exports, and framework scaffolding.
- project scaffolding
- barrel exports
- token validation report
By the numbers
- validates tokens across 7 component-skill output types
- scaffolds 5 framework targets (React/Vite, Next.js, FastAPI, Flask, Rust/Axum)
Files
Assembling Components
Purpose
This skill transforms the outputs of AI Design Components skills into production-ready applications. It provides library-specific context for our token system, component patterns, and skill chain workflow - knowledge that generic assembly patterns cannot provide. The skill validates token integration, generates proper scaffolding, and wires components together correctly.
When to Use
Activate this skill when:
- Completing a skill chain workflow (theming → layout → dashboards → data-viz → feedback)
- Generating new project scaffolding for React/Vite, Next.js, FastAPI, Flask, or Rust/Axum
- Validating that all generated CSS uses design tokens (not hardcoded values)
- Creating barrel exports and wiring component imports correctly
- Assembling components from multiple skills into a unified application
- Debugging integration issues (missing entry points, broken imports, theme not switching)
- Preparing generated code for production deployment
Skill Chain Context
This skill understands the output of every AI Design Components skill:
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ theming- │────▶│ designing- │────▶│ creating- │
│ components │ │ layouts │ │ dashboards │
└──────────────────┘ └──────────────────┘ └──────────────────┘
│ │ │
▼ ▼ ▼
tokens.css Layout.tsx Dashboard.tsx
theme-provider.tsx Header.tsx KPICard.tsx
│ │ │
└────────────────────────┴────────────────────────┘
│
▼
┌──────────────────────┐
│ visualizing-data │
│ providing-feedback │
└──────────────────────┘
│
▼
DonutChart.tsx
Toast.tsx, Spinner.tsx
│
▼
┌──────────────────────┐
│ ASSEMBLING- │
│ COMPONENTS │
│ (THIS SKILL) │
└──────────────────────┘
│
▼
WORKING COMPONENT SYSTEMExpected Outputs by Skill
| Skill | Primary Outputs | Token Dependencies |
|---|---|---|
theming-components | tokens.css, theme-provider.tsx | Foundation |
designing-layouts | Layout.tsx, Header.tsx, Sidebar.tsx | --spacing-, --color-border- |
creating-dashboards | Dashboard.tsx, KPICard.tsx | All layout + chart tokens |
visualizing-data | Chart components, legends | --chart-color-, --font-size- |
building-forms | Form inputs, validation | --spacing-, --radius-, --color-error |
building-tables | Table, pagination | --color-, --spacing- |
providing-feedback | Toast, Spinner, EmptyState | --color-success/error/warning |
Token Validation
Run Validation Script (Token-Free Execution)
# Basic validation
python scripts/validate_tokens.py src/styles
# Strict mode with fix suggestions
python scripts/validate_tokens.py src --strict --fix-suggestions
# JSON output for CI/CD
python scripts/validate_tokens.py src --jsonOur Token Naming Conventions
/* Colors - semantic naming */
--color-primary: #FA582D; /* Brand primary */
--color-success: #00CC66; /* Positive states */
--color-warning: #FFCB06; /* Caution states */
--color-error: #C84727; /* Error states */
--color-info: #00C0E8; /* Informational */
--color-bg-primary: #FFFFFF; /* Main background */
--color-bg-secondary: #F8FAFC; /* Elevated surfaces */
--color-text-primary: #1E293B; /* Body text */
--color-text-secondary: #64748B; /* Muted text */
/* Spacing - 4px base unit */
--spacing-xs: 0.25rem; /* 4px */
--spacing-sm: 0.5rem; /* 8px */
--spacing-md: 1rem; /* 16px */
--spacing-lg: 1.5rem; /* 24px */
--spacing-xl: 2rem; /* 32px */
/* Typography */
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */
--font-size-base: 1rem; /* 16px */
--font-size-lg: 1.125rem; /* 18px */
/* Component sizes */
--icon-size-sm: 1rem; /* 16px */
--icon-size-md: 1.5rem; /* 24px */
--radius-sm: 4px;
--radius-md: 8px;
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);Validation Rules
| Must Use Tokens (Errors) | Example Fix |
|---|---|
| Colors | #FA582D → var(--color-primary) |
| Spacing (≥4px) | 16px → var(--spacing-md) |
| Font sizes | 14px → var(--font-size-sm) |
| Should Use Tokens (Warnings) | Example Fix |
|---|---|
| Border radius | 8px → var(--radius-md) |
| Shadows | 0 4px... → var(--shadow-md) |
| Z-index (≥100) | 1000 → var(--z-dropdown) |
Framework Selection
React/TypeScript
Choose Vite + React when:
- Building single-page applications
- Lightweight, fast development builds
- Maximum control over configuration
- No server-side rendering needed
Choose Next.js 14/15 when:
- Need server-side rendering or static generation
- Building full-stack with API routes
- SEO is important
- Using React Server Components
Python
Choose FastAPI when:
- Building modern async APIs
- Need automatic OpenAPI documentation
- High performance is required
- Using Pydantic for validation
Choose Flask when:
- Simpler, more flexible setup
- Familiar with Flask ecosystem
- Template rendering (Jinja2)
- Smaller applications
Rust
Choose Axum when:
- Modern tower-based architecture
- Type-safe extractors
- Async-first design
- Growing ecosystem
Choose Actix Web when:
- Maximum performance required
- Actor model benefits your use case
- More mature ecosystem
Implementation Approach
1. Validate Token Integration
Before assembly, check all CSS uses tokens:
python scripts/validate_tokens.py <component-directory>Fix any violations before proceeding.
2. Generate Project Scaffolding
React/Vite:
// src/main.tsx - Entry point
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { ThemeProvider } from '@/context/theme-provider'
import App from './App'
import './styles/tokens.css' // FIRST - token definitions
import './styles/globals.css' // SECOND - global resets
createRoot(document.getElementById('root')!).render(
<StrictMode>
<ThemeProvider>
<App />
</ThemeProvider>
</StrictMode>,
)index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{PROJECT_TITLE}}</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>3. Wire Components Together
Theme Provider:
// src/context/theme-provider.tsx
import { createContext, useContext, useEffect, useState } from 'react'
type Theme = 'light' | 'dark' | 'system'
const ThemeContext = createContext<{
theme: Theme
setTheme: (theme: Theme) => void
} | undefined>(undefined)
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>('system')
useEffect(() => {
const root = document.documentElement
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark' : 'light'
root.setAttribute('data-theme', theme === 'system' ? systemTheme : theme)
localStorage.setItem('theme', theme)
}, [theme])
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}
export const useTheme = () => {
const context = useContext(ThemeContext)
if (!context) throw new Error('useTheme must be used within ThemeProvider')
return context
}Barrel Exports:
// src/components/ui/index.ts
export { Button } from './button'
export { Card } from './card'
// src/components/features/dashboard/index.ts
export { KPICard } from './kpi-card'
export { DonutChart } from './donut-chart'
export { Dashboard } from './dashboard'4. Configure Build System
vite.config.ts:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
})tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"baseUrl": ".",
"paths": { "@/*": ["./src/*"] }
},
"include": ["src"]
}Cross-Skill Integration
Using Theming Components
// Import tokens first, components inherit token values
import './styles/tokens.css'
// Use ThemeProvider at root
<ThemeProvider>
<App />
</ThemeProvider>Using Dashboard Components
// Components from creating-dashboards skill
import { Dashboard, KPICard } from '@/components/features/dashboard'
// Wire with data
<Dashboard>
<KPICard
label="Total Threats"
value={1234}
severity="critical"
trend={{ value: 15.3, direction: 'up' }}
/>
</Dashboard>Using Data Visualization
// Charts from visualizing-data skill
import { DonutChart } from '@/components/charts'
// Charts use --chart-color-* tokens automatically
<DonutChart
data={threatData}
title="Threats by Severity"
/>Using Feedback Components
// From providing-feedback skill
import { Toast, Spinner, EmptyState } from '@/components/feedback'
// Wire toast notifications
<ToastProvider>
<App />
</ToastProvider>
// Use spinner for loading states
{isLoading ? <Spinner /> : <Dashboard />}Integration Checklist
Before delivery, verify:
- [ ] Token file exists (
tokens.css) with all 7 categories - [ ] Token import order correct (tokens.css → globals.css → components)
- [ ] No hardcoded values (run
validate_tokens.py) - [ ] Theme toggle works (
data-themeattribute switches) - [ ] Reduced motion supported (
@media (prefers-reduced-motion)) - [ ] Build completes without errors
- [ ] Types pass (TypeScript compiles)
- [ ] Imports resolve (no missing modules)
- [ ] Barrel exports exist for each component directory
Bundled Resources
Scripts (Token-Free Execution)
scripts/validate_tokens.py- Validate CSS uses design tokensscripts/generate_scaffold.py- Generate project boilerplatescripts/check_imports.py- Validate import chainsscripts/generate_exports.py- Create barrel export files
Run scripts directly without loading into context:
python scripts/validate_tokens.py demo/examples --fix-suggestionsReferences (Detailed Patterns)
references/library-context.md- AI Design Components library awarenessreferences/react-vite-template.md- Full Vite + React setupreferences/nextjs-template.md- Next.js 14/15 patternsreferences/python-fastapi-template.md- FastAPI project structurereferences/rust-axum-template.md- Rust/Axum project structurereferences/token-validation-rules.md- Complete validation rules
Examples (Complete Implementations)
examples/react-dashboard/- Full Vite + React dashboardexamples/nextjs-dashboard/- Next.js App Router dashboardexamples/fastapi-dashboard/- Python FastAPI dashboardexamples/rust-axum-dashboard/- Rust Axum dashboard
Assets (Templates)
assets/templates/react/- React project templatesassets/templates/python/- Python project templatesassets/templates/rust/- Rust project templates
Application Assembly Workflow
1. Validate Components: Run validate_tokens.py on all generated CSS 2. Choose Framework: React/Vite, Next.js, FastAPI, or Rust based on requirements 3. Generate Scaffolding: Create project structure and configuration 4. Wire Imports: Set up entry point, import chain, barrel exports 5. Add Providers: ThemeProvider, ToastProvider at root 6. Connect Components: Import and compose feature components 7. Configure Build: vite.config, tsconfig, package.json 8. Final Validation: Build, type-check, lint 9. Document: README with setup and usage instructions
For library-specific patterns and complete context, see references/library-context.md.
Python FastAPI Template
Starter template for Python backend applications using FastAPI.
Stack
- FastAPI (async web framework)
- SQLAlchemy 2.0 (ORM)
- Pydantic 2.0 (validation)
- PostgreSQL (database)
- Alembic (migrations)
Project Structure
my-fastapi-app/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI app instance
│ ├── config.py # Settings and environment
│ ├── database.py # Database connection
│ ├── dependencies.py # Shared dependencies
│ ├── models/ # SQLAlchemy models
│ │ ├── __init__.py
│ │ └── user.py
│ ├── schemas/ # Pydantic schemas
│ │ ├── __init__.py
│ │ └── user.py
│ ├── routers/ # API routes
│ │ ├── __init__.py
│ │ ├── auth.py
│ │ └── users.py
│ └── services/ # Business logic
│ ├── __init__.py
│ └── user_service.py
├── alembic/ # Database migrations
├── tests/
├── requirements.txt
├── .env.example
└── README.mdQuick Start
# 1. Create virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 2. Install dependencies
pip install -r requirements.txt
# 3. Configure environment
cp .env.example .env
# Edit .env with your database URL
# 4. Run migrations
alembic upgrade head
# 5. Start server
uvicorn app.main:app --reloadAccess API docs: http://localhost:8000/docs
Use with Skill
This template is referenced by the assembling-components skill for rapidly scaffolding Python backend applications.
React + Vite Template
Modern React template with TypeScript, Vite, TanStack Query, and Tailwind CSS.
Stack
- React 18
- TypeScript
- Vite (build tool)
- TanStack Query (data fetching)
- React Router (routing)
- Tailwind CSS (styling)
- Shadcn/ui (components)
Project Structure
my-react-app/
├── src/
│ ├── main.tsx # Entry point
│ ├── App.tsx # Root component
│ ├── components/ # Reusable components
│ │ ├── ui/ # Shadcn/ui components
│ │ ├── layout/
│ │ │ ├── Header.tsx
│ │ │ ├── Sidebar.tsx
│ │ │ └── Layout.tsx
│ │ └── common/
│ ├── pages/ # Page components
│ │ ├── Home.tsx
│ │ ├── Dashboard.tsx
│ │ └── NotFound.tsx
│ ├── hooks/ # Custom hooks
│ │ ├── useAuth.ts
│ │ └── useApi.ts
│ ├── services/ # API clients
│ │ └── api.ts
│ ├── lib/ # Utilities
│ │ └── utils.ts
│ ├── types/ # TypeScript types
│ │ └── index.ts
│ └── styles/
│ └── index.css
├── public/
├── index.html
├── vite.config.ts
├── tailwind.config.js
├── tsconfig.json
└── package.jsonQuick Start
# 1. Install dependencies
npm install
# 2. Configure environment
cp .env.example .env
# Edit .env with API URL
# 3. Start development server
npm run devAccess app: http://localhost:5173
Features
- Hot Module Replacement (HMR)
- TypeScript strict mode
- ESLint + Prettier configured
- Path aliases (@/components)
- TanStack Query for server state
- React Router for navigation
Use with Skill
This template is referenced by the assembling-components skill for rapidly scaffolding React frontend applications.
Rust Axum Template
High-performance Rust backend template using Axum, SQLx, and PostgreSQL.
Stack
- Axum (web framework)
- SQLx (compile-time checked queries)
- PostgreSQL (database)
- Tower (middleware)
- Tokio (async runtime)
- Serde (serialization)
Project Structure
my-axum-app/
├── src/
│ ├── main.rs # Entry point
│ ├── config.rs # Configuration
│ ├── db.rs # Database connection pool
│ ├── error.rs # Error types
│ ├── models/ # Data models
│ │ ├── mod.rs
│ │ └── user.rs
│ ├── routes/ # API routes
│ │ ├── mod.rs
│ │ ├── auth.rs
│ │ └── users.rs
│ ├── handlers/ # Route handlers
│ │ ├── mod.rs
│ │ └── user_handlers.rs
│ ├── services/ # Business logic
│ │ ├── mod.rs
│ │ └── user_service.rs
│ └── middleware/ # Custom middleware
│ ├── mod.rs
│ └── auth.rs
├── migrations/ # SQLx migrations
├── tests/
├── Cargo.toml
├── .env.example
└── README.mdQuick Start
# 1. Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 2. Install sqlx-cli
cargo install sqlx-cli --no-default-features --features postgres
# 3. Configure environment
cp .env.example .env
# Edit .env with DATABASE_URL
# 4. Run migrations
sqlx database create
sqlx migrate run
# 5. Build and run
cargo run --releaseAccess API: http://localhost:3000
Features
- Compile-time SQL query validation
- Automatic JSON serialization
- Tower middleware (CORS, logging, compression)
- Graceful shutdown
- Connection pooling
- Zero-cost abstractions
Performance
- ~140,000 requests/second (hello world)
- <1ms p99 latency
- ~5MB memory footprint
- Compiles to native binary
Use with Skill
This template is referenced by the assembling-components skill for rapidly scaffolding Rust backend applications.
FastAPI Dashboard Backend Example
Complete FastAPI backend for dashboard applications with PostgreSQL, authentication, and real-time metrics.
Features
- User authentication (JWT)
- Dashboard metrics endpoints
- Real-time data streaming (SSE)
- PostgreSQL with SQLAlchemy 2.0
- CORS configuration
- Rate limiting
- OpenAPI documentation
Project Structure
fastapi-dashboard/
├── app/
│ ├── main.py # FastAPI app
│ ├── auth.py # JWT authentication
│ ├── database.py # SQLAlchemy setup
│ ├── models.py # Database models
│ ├── schemas.py # Pydantic schemas
│ └── routers/
│ ├── dashboard.py # Dashboard endpoints
│ ├── metrics.py # Metrics streaming
│ └── users.py # User management
├── requirements.txt
├── .env.example
└── README.mdEndpoints
POST /auth/login - User login
POST /auth/refresh - Refresh token
GET /dashboard/metrics - Get dashboard KPIs
GET /dashboard/charts - Get chart data
GET /metrics/stream - SSE real-time metrics
GET /users/me - Get current userQuick Start
# Install
pip install -r requirements.txt
# Configure
cp .env.example .env
# Run migrations
alembic upgrade head
# Start server
uvicorn app.main:app --reloadIntegration
This backend pairs with:
- Frontend: React dashboard (see examples/react-dashboard/)
- Database skill: databases-relational
- Auth skill: auth-security
- Real-time skill: realtime-sync (SSE)
API Documentation
Access auto-generated docs at http://localhost:8000/docs
Next.js Dashboard Example
Full-stack Next.js 14 dashboard with App Router, Server Components, and real-time updates.
Features
- Next.js 14 App Router
- Server Components + Client Components
- Authentication (NextAuth.js)
- PostgreSQL with Prisma
- Real-time metrics (SSE)
- TanStack Table
- Recharts visualization
- Tailwind CSS + Shadcn/ui
- TypeScript strict mode
Project Structure
nextjs-dashboard/
├── app/
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page
│ ├── dashboard/
│ │ ├── layout.tsx # Dashboard layout
│ │ ├── page.tsx # Dashboard home
│ │ ├── metrics/
│ │ └── analytics/
│ ├── api/
│ │ ├── auth/[...nextauth]/route.ts
│ │ ├── dashboard/
│ │ │ └── metrics/route.ts
│ │ └── stream/
│ │ └── route.ts # SSE endpoint
│ └── (auth)/
│ ├── login/page.tsx
│ └── register/page.tsx
├── components/
│ ├── ui/ # Shadcn/ui components
│ ├── dashboard/
│ │ ├── KPICard.tsx
│ │ ├── MetricsChart.tsx
│ │ └── DataTable.tsx
│ └── layout/
│ ├── Header.tsx
│ └── Sidebar.tsx
├── lib/
│ ├── db.ts # Prisma client
│ ├── auth.ts # NextAuth config
│ └── utils.ts
├── prisma/
│ └── schema.prisma
├── next.config.js
└── package.jsonQuick Start
# Install
npm install
# Setup database
cp .env.example .env
npx prisma migrate dev
# Start dev server
npm run devAccess: http://localhost:3000
Key Features
Server Components (Default)
// app/dashboard/page.tsx (Server Component)
import { getMetrics } from '@/lib/api';
export default async function DashboardPage() {
const metrics = await getMetrics(); // Fetched on server
return <MetricsDisplay metrics={metrics} />;
}Client Components (Interactive)
'use client';
import { useEffect, useState } from 'react';
export function RealtimeMetrics() {
const [metrics, setMetrics] = useState(null);
useEffect(() => {
const es = new EventSource('/api/stream');
es.onmessage = (e) => setMetrics(JSON.parse(e.data));
return () => es.close();
}, []);
return <MetricsChart data={metrics} />;
}Integration
Combines skills:
- creating-dashboards (KPIs, charts)
- building-tables (data grids)
- visualizing-data (charts)
- auth-security (NextAuth)
- databases-relational (Prisma)
- realtime-sync (SSE streaming)
React SPA Dashboard Example
Single Page Application dashboard using React, Vite, and TanStack ecosystem.
Stack
- React 18
- TypeScript
- Vite
- TanStack Query (data fetching)
- TanStack Table (data grid)
- React Router (routing)
- Recharts (visualization)
- Tailwind CSS + Shadcn/ui
- Zustand (state management)
Project Structure
react-dashboard/
├── src/
│ ├── main.tsx
│ ├── App.tsx
│ ├── pages/
│ │ ├── Dashboard.tsx
│ │ ├── Analytics.tsx
│ │ ├── Reports.tsx
│ │ └── Settings.tsx
│ ├── components/
│ │ ├── ui/ # Shadcn/ui
│ │ ├── dashboard/
│ │ │ ├── KPICard.tsx
│ │ │ ├── MetricsChart.tsx
│ │ │ └── DataTable.tsx
│ │ └── layout/
│ │ ├── Header.tsx
│ │ ├── Sidebar.tsx
│ │ └── Layout.tsx
│ ├── hooks/
│ │ ├── useMetrics.ts
│ │ ├── useAuth.ts
│ │ └── useSSE.ts
│ ├── services/
│ │ └── api.ts # API client
│ ├── stores/
│ │ └── authStore.ts # Zustand store
│ └── lib/
│ └── utils.ts
├── vite.config.ts
└── package.jsonQuick Start
# Install
npm install
# Configure
cp .env.example .env
# Set VITE_API_URL
# Start dev server
npm run devData Fetching Pattern
import { useQuery } from '@tanstack/react-query';
function DashboardMetrics() {
const { data, isLoading } = useQuery({
queryKey: ['metrics'],
queryFn: () => fetch('/api/metrics').then(r => r.json()),
refetchInterval: 30000, // Refresh every 30s
});
if (isLoading) return <Skeleton />;
return <MetricsDisplay data={data} />;
}Real-Time Updates
import { useSSE } from '@/hooks/useSSE';
function RealtimeChart() {
const { data } = useSSE('/api/metrics/stream');
return <LineChart data={data} />;
}Integration
Backend options:
- FastAPI (see examples/fastapi-dashboard/)
- Rust Axum (see examples/rust-axum-dashboard/)
- Node.js Hono/Express
Assembly Examples
This directory contains example implementations demonstrating the assembling-components skill.
Available Examples
Existing Dashboard Example
The Palo Alto Security Dashboard in demo/examples/palo-alto-security-dashboard/ serves as a reference implementation showing:
- Complete token system integration
- Theme toggle with dark mode support
- Component composition (KPICard, DonutChart, Toast, Spinner)
- Proper CSS token usage
Generating New Examples
Use the scaffolding script to create new project examples:
# React + Vite
python scripts/generate_scaffold.py react-dashboard react-vite ./examples
# Next.js
python scripts/generate_scaffold.py nextjs-dashboard nextjs ./examples
# Python FastAPI
python scripts/generate_scaffold.py fastapi-dashboard python-fastapi ./examples
# Rust Axum
python scripts/generate_scaffold.py rust-dashboard rust-axum ./examplesValidation
After creating or modifying examples, validate them:
# Validate CSS tokens
python scripts/validate_tokens.py examples/react-dashboard/src
# Check import chains
python scripts/check_imports.py examples/react-dashboard/src
# Generate barrel exports
python scripts/generate_exports.py examples/react-dashboard/src/componentsExample Structure
Each example should follow this structure:
example-name/
├── src/
│ ├── main.tsx # Entry point
│ ├── App.tsx # Root component
│ ├── styles/
│ │ ├── tokens.css # Design tokens (imported FIRST)
│ │ └── globals.css # Global styles
│ ├── context/
│ │ └── theme-provider.tsx
│ ├── components/
│ │ ├── ui/ # Shared UI components
│ │ │ └── index.ts # Barrel export
│ │ ├── layout/ # Layout components
│ │ │ └── index.ts
│ │ └── features/ # Feature components
│ │ └── dashboard/
│ │ └── index.ts
│ └── lib/
│ └── utils.ts
├── package.json
├── vite.config.ts
└── tsconfig.jsonIntegration Checklist
Before considering an example complete:
- [ ]
tokens.cssexists and is imported first - [ ] All CSS uses token variables (no hardcoded values)
- [ ] ThemeProvider wraps the app
- [ ] Theme toggle works (light/dark)
- [ ] Barrel exports exist for component directories
- [ ] Build completes without errors
- [ ]
npm run validate:tokenspasses
Rust Axum Dashboard Backend
High-performance Rust backend for dashboard applications using Axum and PostgreSQL.
Stack
- Axum (web framework)
- SQLx (compile-time checked SQL)
- PostgreSQL
- Tower (middleware)
- Tokio (async runtime)
- JWT authentication
- SSE streaming
Project Structure
rust-axum-dashboard/
├── src/
│ ├── main.rs
│ ├── config.rs
│ ├── db.rs # Database pool
│ ├── error.rs # Error handling
│ ├── models/
│ │ ├── mod.rs
│ │ └── user.rs
│ ├── routes/
│ │ ├── mod.rs
│ │ ├── auth.rs
│ │ ├── dashboard.rs
│ │ └── metrics.rs
│ ├── handlers/
│ │ └── dashboard_handlers.rs
│ ├── middleware/
│ │ └── auth.rs
│ └── services/
│ └── metrics_service.rs
├── migrations/
├── Cargo.toml
└── .env.exampleQuick Start
# Install SQLx CLI
cargo install sqlx-cli
# Configure
cp .env.example .env
# Setup database
sqlx database create
sqlx migrate run
# Run (development)
cargo run
# Run (production)
cargo build --release
./target/release/axum-dashboardPerformance
- 140,000+ requests/second
- <1ms p99 latency
- 5-10MB memory usage
- Sub-second startup time
API Endpoints
POST /auth/login
GET /dashboard/metrics
GET /dashboard/kpis
GET /stream/metrics (SSE)Integration
Frontend options:
- React (see examples/react-dashboard/)
- Next.js (see examples/nextjs-dashboard/)
Skills used:
- databases-relational (SQLx)
- auth-security (JWT)
- realtime-sync (SSE)
skill: "assembling-components"
version: "1.0"
domain: "frontend"
base_outputs:
- path: "src/main.tsx"
must_contain: ["ThemeProvider", "import './styles/tokens.css'", "createRoot"]
description: "React application entry point with theme provider and token imports"
- path: "src/App.tsx"
must_contain: ["export default", "function App"]
description: "Main application component orchestrating page routing and layout"
- path: "src/styles/tokens.css"
must_contain: ["--color-primary", "--spacing-", "--font-size-"]
description: "Design token definitions (colors, spacing, typography, shadows, borders, motion, z-index)"
- path: "src/styles/globals.css"
must_contain: ["*, *::before, *::after", "box-sizing: border-box"]
description: "Global CSS resets and base styles"
- path: "src/context/theme-provider.tsx"
must_contain: ["createContext", "data-theme", "localStorage"]
description: "Theme context provider for light/dark/system mode switching"
- path: "package.json"
must_contain: ["react", "typescript", "vite"]
description: "Project dependencies and build scripts"
- path: "vite.config.ts"
must_contain: ["@vitejs/plugin-react", "resolve", "alias"]
description: "Vite build configuration with path aliases"
- path: "tsconfig.json"
must_contain: ["@/*", "baseUrl", "paths"]
description: "TypeScript configuration with path mapping"
- path: "index.html"
must_contain: ["<div id=\"root\">", "<script type=\"module\" src=\"/src/main.tsx\">"]
description: "HTML entry point for Vite application"
conditional_outputs:
maturity:
starter:
- path: "src/components/ui/button.tsx"
must_contain: ["export", "React.ComponentPropsWithoutRef"]
description: "Basic button component with design tokens"
- path: "src/components/ui/card.tsx"
must_contain: ["export", "var(--"]
description: "Card component using design tokens"
- path: "README.md"
must_contain: ["npm install", "npm run dev", "Quick Start"]
description: "Project setup and usage documentation"
intermediate:
- path: "src/components/ui/index.ts"
must_contain: ["export {", "} from"]
description: "Barrel exports for UI components"
- path: "src/components/features/dashboard/index.ts"
must_contain: ["export"]
description: "Barrel exports for dashboard feature components"
- path: "src/lib/utils.ts"
must_contain: ["export", "function"]
description: "Utility functions (cn helper, formatters)"
- path: ".env.example"
must_contain: ["VITE_"]
description: "Environment variable template"
advanced:
- path: "src/hooks/useTheme.ts"
must_contain: ["useContext", "ThemeContext"]
description: "Custom hook for theme access"
- path: "src/services/api.ts"
must_contain: ["fetch", "async"]
description: "API client with error handling and interceptors"
- path: ".github/workflows/validate.yml"
must_contain: ["validate_tokens.py", "python"]
description: "CI/CD workflow for token validation"
- path: "vitest.config.ts"
must_contain: ["vitest", "test"]
description: "Vitest configuration for component testing"
frontend_framework:
react:
- path: "src/main.tsx"
must_contain: ["react-dom/client", "createRoot"]
description: "React 18 entry point with concurrent features"
- path: "vite.config.ts"
must_contain: ["@vitejs/plugin-react"]
description: "Vite + React plugin configuration"
- path: "src/components/layout/Layout.tsx"
must_contain: ["children: React.ReactNode"]
description: "Layout component wrapper"
nextjs:
- path: "app/layout.tsx"
must_contain: ["export default function RootLayout", "children"]
description: "Next.js App Router root layout"
- path: "app/page.tsx"
must_contain: ["export default"]
description: "Next.js home page"
- path: "next.config.js"
must_contain: ["module.exports"]
description: "Next.js configuration"
- path: "app/api/stream/route.ts"
must_contain: ["NextResponse", "ReadableStream"]
description: "Server-Sent Events endpoint for real-time updates"
vue:
- path: "src/main.ts"
must_contain: ["createApp", "mount"]
description: "Vue 3 application entry point"
- path: "vite.config.ts"
must_contain: ["@vitejs/plugin-vue"]
description: "Vite + Vue plugin configuration"
styling:
tailwind:
- path: "tailwind.config.js"
must_contain: ["content:", "./src/**/*.{ts,tsx}"]
description: "Tailwind CSS configuration with content paths"
- path: "postcss.config.js"
must_contain: ["tailwindcss", "autoprefixer"]
description: "PostCSS configuration for Tailwind"
css-modules:
- path: "src/components/ui/button.module.css"
must_contain: [".button", "var(--"]
description: "CSS Module with design token usage"
styled-components:
- path: "src/styles/theme.ts"
must_contain: ["export", "const theme"]
description: "Styled-components theme configuration"
state_management:
zustand:
- path: "src/stores/authStore.ts"
must_contain: ["create", "zustand"]
description: "Zustand store for authentication state"
tanstack-query:
- path: "src/hooks/useMetrics.ts"
must_contain: ["useQuery", "@tanstack/react-query"]
description: "TanStack Query hook for data fetching"
- path: "src/lib/queryClient.ts"
must_contain: ["QueryClient", "new QueryClient"]
description: "TanStack Query client configuration"
redux:
- path: "src/store/index.ts"
must_contain: ["configureStore", "@reduxjs/toolkit"]
description: "Redux Toolkit store configuration"
scaffolding:
- path: "src/components/ui/"
reason: "Base component library directory (buttons, cards, inputs from theming-components skill)"
- path: "src/components/features/"
reason: "Feature-specific components directory (dashboard, charts, tables from domain skills)"
- path: "src/components/layout/"
reason: "Layout components directory (Header, Sidebar, Layout from designing-layouts skill)"
- path: "src/pages/"
reason: "Page components directory for routing (React Router or Next.js pages)"
- path: "src/hooks/"
reason: "Custom React hooks directory (useTheme, useMetrics, useAuth)"
- path: "src/lib/"
reason: "Utility functions and shared libraries (utils.ts, cn helper)"
- path: "src/services/"
reason: "API clients and external service integrations"
- path: "src/styles/"
reason: "Global styles, tokens, and CSS files (tokens.css, globals.css)"
- path: "src/stores/"
reason: "State management stores (Zustand/Redux if applicable)"
- path: "src/context/"
reason: "React context providers (ThemeProvider, ToastProvider)"
- path: "src/types/"
reason: "TypeScript type definitions and interfaces"
- path: "public/"
reason: "Static assets (images, fonts, icons)"
metadata:
primary_blueprints: ["dashboard", "frontend", "crud-api"]
contributes_to:
- "Component composition and integration"
- "Design token validation and enforcement"
- "Project scaffolding and build configuration"
- "Theme provider setup and light/dark mode"
- "Import chain wiring and barrel exports"
- "Cross-skill component assembly"
- "Production-ready application structure"
- "Framework-specific entry points"
- "Type-safe component integration"
integrates_with:
- skill: "theming-components"
outputs: ["tokens.css", "theme-provider.tsx"]
relationship: "Consumes design tokens as foundation"
- skill: "designing-layouts"
outputs: ["Layout.tsx", "Header.tsx", "Sidebar.tsx"]
relationship: "Imports and wires layout components"
- skill: "creating-dashboards"
outputs: ["Dashboard.tsx", "KPICard.tsx"]
relationship: "Composes dashboard features"
- skill: "visualizing-data"
outputs: ["Chart components", "legends"]
relationship: "Integrates data visualization"
- skill: "building-forms"
outputs: ["Form inputs", "validation"]
relationship: "Includes form components"
- skill: "building-tables"
outputs: ["Table", "pagination"]
relationship: "Includes data grid components"
- skill: "providing-feedback"
outputs: ["Toast", "Spinner", "EmptyState"]
relationship: "Wires feedback components"
validation:
scripts:
- "scripts/validate_tokens.py"
- "scripts/check_imports.py"
- "scripts/generate_exports.py"
checks:
- "All CSS uses design tokens (no hardcoded values)"
- "Token import order correct (tokens.css → globals.css → components)"
- "Theme toggle functionality works"
- "All imports resolve without errors"
- "TypeScript compiles successfully"
- "Build completes without errors"
- "Barrel exports exist for component directories"
examples:
- name: "react-dashboard"
path: "examples/react-dashboard/"
description: "Complete React SPA with Vite, TanStack Query/Table, Recharts"
- name: "nextjs-dashboard"
path: "examples/nextjs-dashboard/"
description: "Next.js 14 App Router with Server Components, SSE, Prisma"
- name: "fastapi-dashboard"
path: "examples/fastapi-dashboard/"
description: "FastAPI backend with JWT auth, PostgreSQL, SSE streaming"
- name: "rust-axum-dashboard"
path: "examples/rust-axum-dashboard/"
description: "Rust Axum backend with PostgreSQL, authentication"
references:
- "references/library-context.md - AI Design Components library awareness"
- "references/react-vite-template.md - Complete Vite + React setup patterns"
- "references/nextjs-template.md - Next.js 14/15 App Router patterns"
- "references/python-fastapi-template.md - FastAPI project structure"
- "references/rust-axum-template.md - Rust/Axum project structure"
- "references/token-validation-rules.md - Complete validation rules and CI/CD integration"
AI Design Components Library Context
Critical Reference: This document provides the assembling-components skill with deep awareness of the AI Design Components library structure, enabling intelligent assembly that generic LLM knowledge cannot provide.
Table of Contents
- Why This Context Matters
- Skill Chain Architecture
- Standard Skill Chain Flow
- Skill Outputs Reference
- Token System Reference
- Token Naming Conventions
- Component Integration Patterns
- Import Chain (Critical Order)
- Component Directory Structure
- State Integration Patterns
- Skill-Specific Assembly Rules
- After theming-components Skill
- After designing-layouts Skill
- After creating-dashboards Skill
- After visualizing-data Skill
- After providing-feedback Skill
- Validation Checklist (Library-Specific)
- Token Compliance
- Theme System
- Component Integration
- Accessibility
- Common Integration Patterns
- Theme Toggle Button
- KPI Card with Severity
- Toast Notifications
- Version Compatibility
- Summary
Why This Context Matters
LLMs are already proficient at general application assembly. This skill's unique value comes from:
1. Library-Specific Knowledge - Understanding our exact component outputs 2. Token System Mastery - Knowing our precise naming conventions 3. Skill Chain Awareness - Understanding what each skill produces 4. Integration Intelligence - Knowing how our components connect
---
Skill Chain Architecture
Standard Skill Chain Flow
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ theming- │────▶│ designing- │────▶│ creating- │
│ components │ │ layouts │ │ dashboards │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
tokens.css Layout.tsx Dashboard.tsx
globals.css Header.tsx KPICard.tsx
Sidebar.tsx
│ │ │
└───────────────────┴───────────────────┘
│
▼
┌───────────────────────┐
│ visualizing-data │
│ (data-viz skill) │
└───────────────────────┘
│
▼
DonutChart.tsx
BarChart.tsx
LineChart.tsx
│
▼
┌───────────────────────┐
│ providing-feedback │
└───────────────────────┘
│
▼
Toast.tsx
Spinner.tsx
EmptyState.tsx
│
▼
┌───────────────────────┐
│ ASSEMBLING-COMPONENTS │
│ (THIS SKILL) │
└───────────────────────┘
│
▼
WORKING COMPONENT SYSTEMSkill Outputs Reference
| Skill | Primary Outputs | Token Dependencies |
|---|---|---|
theming-components | tokens.css, theme-provider.tsx | Foundation - no deps |
designing-layouts | Layout.tsx, Header.tsx, grid CSS | Spacing, borders |
creating-dashboards | Dashboard.tsx, grid structures | All layout tokens |
visualizing-data | Chart components, legends | Colors, typography |
building-forms | Form inputs, validation | Spacing, borders |
building-tables | Table components, pagination | Colors, spacing |
providing-feedback | Toast, Spinner, EmptyState | Colors, shadows |
---
Token System Reference
Token Naming Conventions
Our library uses a semantic token architecture with these categories:
Color Tokens
/* Brand colors (source of truth) */
--color-cyber-orange: #FA582D;
--color-prisma-blue: #00C0E8;
--color-cortex-green: #00CC66;
--color-strata-yellow: #FFCB06;
--color-unit42-red: #C84727;
/* Semantic mappings */
--color-primary: var(--color-cyber-orange);
--color-success: var(--color-cortex-green);
--color-warning: var(--color-strata-yellow);
--color-error: var(--color-unit42-red);
--color-info: var(--color-prisma-blue);
/* Surface colors */
--color-bg-primary: #FFFFFF; /* Main background */
--color-bg-secondary: #F8FAFC; /* Elevated surfaces */
--color-bg-tertiary: #F1F5F9; /* Subtle backgrounds */
--color-bg-elevated: #FFFFFF; /* Cards, modals */
/* Text colors */
--color-text-primary: #1E293B; /* Headings, body */
--color-text-secondary: #64748B; /* Descriptions */
--color-text-tertiary: #94A3B8; /* Muted text */
--color-text-inverse: #FFFFFF; /* On dark backgrounds */Spacing Tokens
/* Base scale (4px unit) */
--space-1: 0.25rem; /* 4px - xs */
--space-2: 0.5rem; /* 8px - sm */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px - md */
--space-6: 1.5rem; /* 24px - lg */
--space-8: 2rem; /* 32px - xl */
--space-12: 3rem; /* 48px - 2xl */
/* Semantic aliases */
--spacing-xs: var(--space-1);
--spacing-sm: var(--space-2);
--spacing-md: var(--space-4);
--spacing-lg: var(--space-6);
--spacing-xl: var(--space-8);
--spacing-2xl: var(--space-12);Component Size Tokens
/* Icons */
--icon-size-sm: 1rem; /* 16px */
--icon-size-md: 1.5rem; /* 24px */
--icon-size-lg: 2rem; /* 32px */
--icon-size-xl: 3rem; /* 48px */
/* Buttons */
--button-height-sm: 2rem;
--button-height-md: 2.5rem;
--button-height-lg: 3rem;
/* Cards/Charts */
--min-height-card: 140px;
--min-height-chart: 200px;---
Component Integration Patterns
Import Chain (Critical Order)
// src/main.tsx - CORRECT ORDER
import './styles/tokens.css' // 1. Tokens first!
import './styles/globals.css' // 2. Global resets
import './styles/components.css' // 3. Component styles
import { ThemeProvider } from '@/context/theme-provider'
import App from './App'Component Directory Structure
src/components/
├── ui/ # From theming-components, forms skills
│ ├── button.tsx
│ ├── input.tsx
│ ├── card.tsx
│ └── index.ts # Barrel export
├── layout/ # From designing-layouts skill
│ ├── header.tsx
│ ├── sidebar.tsx
│ ├── footer.tsx
│ └── index.ts
├── charts/ # From visualizing-data skill
│ ├── donut-chart.tsx
│ ├── bar-chart.tsx
│ ├── line-chart.tsx
│ └── index.ts
├── feedback/ # From providing-feedback skill
│ ├── toast.tsx
│ ├── spinner.tsx
│ ├── empty-state.tsx
│ └── index.ts
└── features/ # Domain-specific compositions
└── dashboard/
├── kpi-card.tsx
├── dashboard.tsx
└── index.tsState Integration Patterns
// Theme context - always at root
<ThemeProvider>
<App />
</ThemeProvider>
// Toast context - for notifications
<ToastProvider>
<ThemeProvider>
<App />
</ThemeProvider>
</ToastProvider>---
Skill-Specific Assembly Rules
After theming-components Skill
Expected outputs:
tokens.csswith complete token definitions- Dark theme via
[data-theme="dark"]selector - Reduced motion support via
@media (prefers-reduced-motion)
Assembly actions: 1. Verify tokens.css has all 7 categories (colors, spacing, typography, borders, shadows, motion, z-index) 2. Create theme-provider.tsx if not present 3. Ensure index.html has no data-theme attribute (let JS handle it)
After designing-layouts Skill
Expected outputs:
- Layout components (Header, Sidebar, Footer)
- CSS Grid/Flexbox patterns
- Responsive breakpoints
Assembly actions: 1. Wire layout components into App.tsx 2. Verify layout CSS uses spacing tokens (not px values) 3. Check responsive classes use correct breakpoints
After creating-dashboards Skill
Expected outputs:
- Dashboard.tsx with grid layout
- KPI cards with trend indicators
- Section organization
Assembly actions: 1. Import chart components from visualizing-data 2. Wire data fetching/state management 3. Ensure loading states use Spinner from feedback
After visualizing-data Skill
Expected outputs:
- Chart components (Donut, Bar, Line, etc.)
- Legend components
- Accessible chart markup
Assembly actions: 1. Verify chart colors use --chart-color-* tokens 2. Check legends use correct typography tokens 3. Ensure empty states are handled
After providing-feedback Skill
Expected outputs:
- Toast/notification system
- Loading spinners
- Empty states
- Error boundaries
Assembly actions: 1. Create ToastProvider context 2. Wire toast system to API error handlers 3. Add loading spinners to async operations
---
Validation Checklist (Library-Specific)
Token Compliance
- [ ] All colors use
--color-*tokens (not hex/rgb) - [ ] All spacing uses
--spacing-*or--space-*tokens - [ ] All typography uses
--font-size-*,--font-weight-*tokens - [ ] All radii use
--radius-*tokens - [ ] All shadows use
--shadow-*tokens - [ ] All transitions use
--transition-*or--duration-*tokens - [ ] All z-indices use
--z-*tokens
Theme System
- [ ] Theme toggle updates
data-themeattribute on<html> - [ ] Dark theme has all required color overrides
- [ ] System preference detection works
- [ ] Theme persists in localStorage
Component Integration
- [ ] All component CSS imports tokens.css (or inherits)
- [ ] Barrel exports exist for each component directory
- [ ] No circular imports
- [ ] TypeScript types are exported
Accessibility
- [ ]
prefers-reduced-motiondisables animations - [ ] Focus states use
--color-border-focusor--shadow-focus - [ ] Color contrast meets WCAG 2.1 AA
- [ ] Interactive elements have focus-visible styles
---
Common Integration Patterns
Theme Toggle Button
// Uses our token system
function ThemeToggle() {
const { theme, setTheme } = useTheme()
return (
<button
className="theme-toggle"
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
aria-label={`Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`}
>
{theme === 'dark' ? '☀️' : '🌙'}
</button>
)
}.theme-toggle {
width: var(--button-height-md);
height: var(--button-height-md);
background: var(--color-bg-tertiary);
border: var(--border-width-thin) solid var(--color-border-primary);
border-radius: var(--radius-md);
cursor: pointer;
transition: var(--transition-fast);
}
.theme-toggle:hover {
background: var(--color-bg-secondary);
}KPI Card with Severity
interface KPICardProps {
severity: 'critical' | 'high' | 'medium' | 'low' | 'info'
// ...
}
function KPICard({ severity, ...props }: KPICardProps) {
return (
<div className={`kpi-card kpi-card--${severity}`}>
{/* Uses severity-specific tokens */}
</div>
)
}Toast Notifications
// Toast types map to our semantic colors
type ToastType = 'success' | 'error' | 'warning' | 'info'
function Toast({ type, message }: { type: ToastType; message: string }) {
return (
<div className={`toast toast--${type}`}>
<div className="toast__icon">{icons[type]}</div>
<div className="toast__content">{message}</div>
</div>
)
}---
Version Compatibility
| AI Design Components | React | Next.js | Python | Rust |
|---|---|---|---|---|
| v0.2.x | 18.x | 14.x, 15.x | 3.11+ | 1.75+ |
---
Summary
This skill is not about generic app assembly - it's about understanding our specific design library's:
1. 14 component skills and what each produces 2. Token system with precise naming conventions 3. Skill chain workflow and expected outputs at each step 4. Integration patterns unique to our library
The validation scripts and assembly rules encode this library-specific knowledge, ensuring consistent, token-compliant applications regardless of the target ecosystem.
Next.js 14/15 Template
Complete scaffolding template for full-stack applications using Next.js App Router with TypeScript.
Table of Contents
- Project Structure
- Core Files
- package.json
- next.config.mjs
- tsconfig.json
- src/app/layout.tsx
- src/app/globals.css
- src/app/page.tsx
- src/context/theme-provider.tsx
- src/app/api/health/route.ts
- Server Components vs Client Components
- When to use Server Components (default)
- When to use Client Components
- Commands
- Integration Checklist
Project Structure
project-name/
├── package.json
├── next.config.mjs
├── tsconfig.json
├── tailwind.config.ts # Optional: if using Tailwind
├── postcss.config.mjs
├── .env.local
├── public/
│ ├── favicon.ico
│ └── images/
└── src/
├── app/
│ ├── layout.tsx # Root layout with providers
│ ├── page.tsx # Home page
│ ├── globals.css # Global styles + token imports
│ ├── dashboard/
│ │ └── page.tsx
│ └── api/
│ └── health/
│ └── route.ts
├── components/
│ ├── ui/
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ └── index.ts
│ ├── layout/
│ │ ├── header.tsx
│ │ ├── sidebar.tsx
│ │ └── index.ts
│ ├── charts/
│ │ ├── donut-chart.tsx
│ │ └── index.ts
│ ├── feedback/
│ │ ├── toast.tsx
│ │ ├── spinner.tsx
│ │ └── index.ts
│ └── features/
│ └── dashboard/
│ ├── kpi-card.tsx
│ ├── dashboard.tsx
│ └── index.ts
├── lib/
│ └── utils.ts
├── hooks/
│ └── use-theme.ts
├── context/
│ └── theme-provider.tsx
├── styles/
│ └── tokens.css # Design tokens
└── types/
└── index.tsCore Files
package.json
{
"name": "{{PROJECT_NAME}}",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"validate:tokens": "python scripts/validate_tokens.py src"
},
"dependencies": {
"next": "^14.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"typescript": "^5.4.0"
}
}next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
// Enable experimental features if needed
// experimental: {
// serverActions: true,
// },
}
export default nextConfigtsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}src/app/layout.tsx
import type { Metadata } from 'next'
import { ThemeProvider } from '@/context/theme-provider'
// CRITICAL: Import tokens first
import '@/styles/tokens.css'
import './globals.css'
export const metadata: Metadata = {
title: '{{PROJECT_TITLE}}',
description: '{{PROJECT_DESCRIPTION}}',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider
attribute="data-theme"
defaultTheme="system"
enableSystem
>
{children}
</ThemeProvider>
</body>
</html>
)
}src/app/globals.css
/*
* Global styles - tokens.css is imported in layout.tsx before this
* All styles here should use CSS variables from tokens.css
*/
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-family: var(--font-sans);
font-size: var(--font-size-base);
line-height: var(--line-height-normal);
color: var(--color-text-primary);
background: var(--color-bg-primary);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
min-height: 100vh;
}
/* Focus states for accessibility */
:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
/* Reduced motion support */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}src/app/page.tsx
import { Header, Sidebar } from '@/components/layout'
import { Dashboard } from '@/components/features/dashboard'
export default function Home() {
return (
<div className="app">
<Header />
<div className="app__body">
<Sidebar />
<main className="app__main">
<Dashboard />
</main>
</div>
</div>
)
}src/context/theme-provider.tsx
'use client'
import { createContext, useContext, useEffect, useState, ReactNode } from 'react'
type Theme = 'light' | 'dark' | 'system'
interface ThemeContextType {
theme: Theme
setTheme: (theme: Theme) => void
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined)
interface ThemeProviderProps {
children: ReactNode
attribute?: string
defaultTheme?: Theme
enableSystem?: boolean
}
export function ThemeProvider({
children,
attribute = 'data-theme',
defaultTheme = 'system',
enableSystem = true,
}: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(defaultTheme)
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
const stored = localStorage.getItem('theme') as Theme | null
if (stored) {
setTheme(stored)
}
}, [])
useEffect(() => {
if (!mounted) return
const root = window.document.documentElement
if (theme === 'system' && enableSystem) {
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light'
root.setAttribute(attribute, systemTheme)
} else {
root.setAttribute(attribute, theme)
}
localStorage.setItem('theme', theme)
}, [theme, mounted, attribute, enableSystem])
// Prevent flash of incorrect theme
if (!mounted) {
return null
}
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}
export function useTheme() {
const context = useContext(ThemeContext)
if (!context) {
throw new Error('useTheme must be used within ThemeProvider')
}
return context
}src/app/api/health/route.ts
import { NextResponse } from 'next/server'
export async function GET() {
return NextResponse.json({
status: 'ok',
timestamp: new Date().toISOString(),
})
}Server Components vs Client Components
When to use Server Components (default)
- Fetching data from APIs
- Accessing backend resources directly
- Keeping sensitive information on server
- Large dependencies that should stay on server
// app/dashboard/page.tsx (Server Component)
async function getData() {
const res = await fetch('https://api.example.com/data')
return res.json()
}
export default async function DashboardPage() {
const data = await getData()
return <Dashboard data={data} />
}When to use Client Components
- Interactivity (onClick, onChange, etc.)
- Browser APIs (localStorage, window, etc.)
- React hooks (useState, useEffect, useContext)
- Custom hooks that use state
'use client'
// components/ui/button.tsx
import { useState } from 'react'
export function Button({ children, onClick }) {
const [isLoading, setIsLoading] = useState(false)
// ...
}Commands
# Install dependencies
npm install
# Start development server
npm run dev
# Validate CSS tokens
npm run validate:tokens
# Production build
npm run build
# Start production server
npm run startIntegration Checklist
- [ ]
tokens.cssimported in layout.tsx before globals.css - [ ] ThemeProvider wraps entire app with
'use client' - [ ]
suppressHydrationWarningon html tag - [ ] All CSS uses token variables
- [ ] Barrel exports exist for component directories
- [ ] Path aliases configured (@/)
- [ ] Server vs Client components properly separated
- [ ] Build completes without errors
Python FastAPI Template
Complete scaffolding template for modern async APIs using FastAPI with Pydantic validation.
Table of Contents
- Project Structure
- Core Files
- pyproject.toml
- requirements.txt
- src/project_name/main.py
- src/project_name/config.py
- src/project_name/api/routes/health.py
- src/project_name/api/routes/dashboard.py
- src/project_name/templates/base.html
- src/project_name/templates/dashboard.html
- Dockerfile
- docker-compose.yml
- Commands
- Integration Checklist
Project Structure
project-name/
├── pyproject.toml # Modern Python packaging
├── requirements.txt # Production dependencies
├── requirements-dev.txt # Development dependencies
├── .env # Environment variables
├── .env.example # Example environment file
├── Dockerfile
├── docker-compose.yml
├── src/
│ └── project_name/ # Main package
│ ├── __init__.py
│ ├── main.py # Application entry point
│ ├── config.py # Configuration management
│ ├── api/ # API routes
│ │ ├── __init__.py
│ │ ├── dependencies.py
│ │ └── routes/
│ │ ├── __init__.py
│ │ ├── dashboard.py
│ │ └── health.py
│ ├── core/ # Core business logic
│ │ ├── __init__.py
│ │ └── security.py
│ ├── models/ # Data models
│ │ ├── __init__.py
│ │ ├── schemas.py # Pydantic schemas
│ │ └── database.py # SQLAlchemy models
│ ├── services/ # Business logic services
│ │ ├── __init__.py
│ │ └── dashboard_service.py
│ ├── static/ # Static files (CSS, JS)
│ │ ├── css/
│ │ │ └── tokens.css
│ │ └── js/
│ └── templates/ # Jinja2 templates
│ ├── base.html
│ └── dashboard.html
├── tests/
│ ├── __init__.py
│ ├── conftest.py
│ └── test_dashboard.py
└── scripts/
└── validate_tokens.pyCore Files
pyproject.toml
[project]
name = "{{PROJECT_NAME}}"
version = "1.0.0"
description = "{{PROJECT_DESCRIPTION}}"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"fastapi>=0.109.0",
"uvicorn[standard]>=0.27.0",
"pydantic>=2.5.0",
"pydantic-settings>=2.1.0",
"python-dotenv>=1.0.0",
"jinja2>=3.1.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.4.0",
"pytest-asyncio>=0.23.0",
"httpx>=0.26.0",
"ruff>=0.1.0",
"mypy>=1.8.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/project_name"]
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.mypy]
python_version = "3.11"
strict = truerequirements.txt
fastapi>=0.109.0
uvicorn[standard]>=0.27.0
pydantic>=2.5.0
pydantic-settings>=2.1.0
python-dotenv>=1.0.0
jinja2>=3.1.0src/project_name/main.py
"""FastAPI application entry point."""
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from .api.routes import dashboard, health
from .config import settings
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan events."""
# Startup
print(f"Starting {settings.app_name}...")
yield
# Shutdown
print("Shutting down...")
def create_app() -> FastAPI:
"""Create and configure the FastAPI application."""
app = FastAPI(
title=settings.app_name,
version=settings.version,
lifespan=lifespan,
)
# Mount static files
app.mount("/static", StaticFiles(directory="src/project_name/static"), name="static")
# Include routers
app.include_router(health.router, prefix="/api", tags=["health"])
app.include_router(dashboard.router, prefix="/api", tags=["dashboard"])
return app
app = create_app()
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)src/project_name/config.py
"""Application configuration using Pydantic Settings."""
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""Application settings."""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
)
# Application
app_name: str = "{{PROJECT_NAME}}"
version: str = "1.0.0"
debug: bool = False
# Server
host: str = "0.0.0.0"
port: int = 8000
# Database (if needed)
# database_url: str = "sqlite:///./app.db"
settings = Settings()src/project_name/api/routes/health.py
"""Health check routes."""
from datetime import datetime
from fastapi import APIRouter
from pydantic import BaseModel
router = APIRouter()
class HealthResponse(BaseModel):
"""Health check response model."""
status: str
timestamp: datetime
version: str
@router.get("/health", response_model=HealthResponse)
async def health_check() -> HealthResponse:
"""Check API health status."""
from ...config import settings
return HealthResponse(
status="ok",
timestamp=datetime.now(),
version=settings.version,
)src/project_name/api/routes/dashboard.py
"""Dashboard routes."""
from fastapi import APIRouter, Request
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel
router = APIRouter()
templates = Jinja2Templates(directory="src/project_name/templates")
class KPIData(BaseModel):
"""KPI data model."""
label: str
value: int
trend: float
trend_direction: str
class DashboardData(BaseModel):
"""Dashboard data model."""
kpis: list[KPIData]
@router.get("/dashboard")
async def get_dashboard(request: Request):
"""Render dashboard page."""
return templates.TemplateResponse(
"dashboard.html",
{
"request": request,
"theme": "light",
"title": "Dashboard",
}
)
@router.get("/dashboard/data", response_model=DashboardData)
async def get_dashboard_data() -> DashboardData:
"""Get dashboard data as JSON."""
return DashboardData(
kpis=[
KPIData(label="Total Threats", value=1234, trend=15.3, trend_direction="up"),
KPIData(label="Blocked Attacks", value=892, trend=8.2, trend_direction="up"),
KPIData(label="Active Alerts", value=23, trend=-5.1, trend_direction="down"),
]
)src/project_name/templates/base.html
<!DOCTYPE html>
<html lang="en" data-theme="{{ theme | default('light') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }} - {{PROJECT_NAME}}</title>
<!-- Design tokens FIRST -->
<link rel="stylesheet" href="{{ url_for('static', path='css/tokens.css') }}">
<!-- Component styles -->
<link rel="stylesheet" href="{{ url_for('static', path='css/dashboard.css') }}">
<script>
// Theme toggle
(function() {
const theme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', theme);
})();
</script>
</head>
<body>
{% block content %}{% endblock %}
<script>
// Theme toggle button
function toggleTheme() {
const html = document.documentElement;
const current = html.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
html.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
}
</script>
</body>
</html>src/project_name/templates/dashboard.html
{% extends "base.html" %}
{% block content %}
<div class="dashboard">
<header class="dashboard__header">
<h1>Dashboard</h1>
<button onclick="toggleTheme()" class="theme-toggle">
Toggle Theme
</button>
</header>
<main class="dashboard__content">
<section class="kpi-grid" id="kpi-container">
<!-- KPI cards loaded via JavaScript -->
</section>
</main>
</div>
<script>
// Fetch and render KPI data
async function loadDashboard() {
const response = await fetch('/api/dashboard/data');
const data = await response.json();
const container = document.getElementById('kpi-container');
container.innerHTML = data.kpis.map(kpi => `
<div class="kpi-card">
<h3 class="kpi-card__label">${kpi.label}</h3>
<div class="kpi-card__value">${kpi.value.toLocaleString()}</div>
<div class="kpi-card__trend trend--${kpi.trend_direction === 'up' ? 'positive' : 'negative'}">
${kpi.trend_direction === 'up' ? '↑' : '↓'} ${Math.abs(kpi.trend)}%
</div>
</div>
`).join('');
}
loadDashboard();
</script>
{% endblock %}Dockerfile
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY src/ ./src/
# Run application
CMD ["uvicorn", "src.project_name.main:app", "--host", "0.0.0.0", "--port", "8000"]docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
volumes:
- ./src:/app/src
environment:
- DEBUG=true
command: uvicorn src.project_name.main:app --host 0.0.0.0 --port 8000 --reloadCommands
# Create virtual environment
python -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windows
# Install dependencies
pip install -e ".[dev]"
# Start development server
uvicorn src.project_name.main:app --reload
# Validate CSS tokens
python scripts/validate_tokens.py src/project_name/static
# Run tests
pytest
# Type checking
mypy src/
# Linting
ruff check src/Integration Checklist
- [ ]
tokens.cssexists in static/css/ - [ ] Templates load tokens.css before other styles
- [ ] Theme toggle updates
data-themeattribute - [ ] Pydantic models validate all API data
- [ ] Configuration uses pydantic-settings
- [ ] Tests cover critical endpoints
- [ ] Dockerfile builds successfully
React + Vite Template
Complete scaffolding template for single-page applications using Vite and React with TypeScript.
Table of Contents
- Project Structure
- Core Files
- index.html
- package.json
- vite.config.ts
- tsconfig.json
- tsconfig.node.json
- src/main.tsx
- src/App.tsx
- src/context/theme-provider.tsx
- src/lib/utils.ts
- Barrel Export Pattern
- Commands
- Integration Checklist
Project Structure
project-name/
├── index.html # Entry point
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── tsconfig.node.json # Node-specific TypeScript config
├── vite.config.ts # Vite configuration
├── public/
│ └── favicon.svg
└── src/
├── main.tsx # React bootstrap
├── App.tsx # Root component
├── styles/
│ ├── tokens.css # Design tokens (FIRST import)
│ └── globals.css # Global resets
├── context/
│ └── theme-provider.tsx # Theme context
├── components/
│ ├── ui/ # Shared UI components
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ └── index.ts # Barrel export
│ ├── layout/ # Layout components
│ │ ├── header.tsx
│ │ ├── sidebar.tsx
│ │ └── index.ts
│ ├── charts/ # Data visualization
│ │ ├── donut-chart.tsx
│ │ └── index.ts
│ ├── feedback/ # Feedback components
│ │ ├── toast.tsx
│ │ ├── spinner.tsx
│ │ └── index.ts
│ └── features/ # Feature components
│ └── dashboard/
│ ├── kpi-card.tsx
│ ├── dashboard.tsx
│ └── index.ts
├── hooks/
│ └── use-theme.ts
├── lib/
│ └── utils.ts
└── types/
└── index.tsCore Files
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="{{PROJECT_DESCRIPTION}}" />
<title>{{PROJECT_TITLE}}</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>package.json
{
"name": "{{PROJECT_NAME}}",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"validate:tokens": "python scripts/validate_tokens.py src"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
"typescript": "^5.4.0",
"vite": "^5.4.0"
}
}vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
css: {
devSourcemap: true,
},
build: {
sourcemap: true,
},
})tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
},
"include": ["vite.config.ts"]
}src/main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { ThemeProvider } from '@/context/theme-provider'
import App from './App'
// CRITICAL: Import order matters!
import './styles/tokens.css' // 1. Design tokens FIRST
import './styles/globals.css' // 2. Global resets
createRoot(document.getElementById('root')!).render(
<StrictMode>
<ThemeProvider>
<App />
</ThemeProvider>
</StrictMode>,
)src/App.tsx
import { Header, Sidebar } from '@/components/layout'
import { Dashboard } from '@/components/features/dashboard'
import './App.css'
function App() {
return (
<div className="app">
<Header />
<div className="app__body">
<Sidebar />
<main className="app__main">
<Dashboard />
</main>
</div>
</div>
)
}
export default Appsrc/context/theme-provider.tsx
import { createContext, useContext, useEffect, useState, ReactNode } from 'react'
type Theme = 'light' | 'dark' | 'system'
interface ThemeContextType {
theme: Theme
setTheme: (theme: Theme) => void
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined)
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<Theme>(() => {
if (typeof window !== 'undefined') {
return (localStorage.getItem('theme') as Theme) || 'system'
}
return 'system'
})
useEffect(() => {
const root = window.document.documentElement
root.removeAttribute('data-theme')
if (theme === 'system') {
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light'
root.setAttribute('data-theme', systemTheme)
} else {
root.setAttribute('data-theme', theme)
}
localStorage.setItem('theme', theme)
}, [theme])
// Listen for system theme changes
useEffect(() => {
if (theme !== 'system') return
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
const handleChange = () => {
const root = window.document.documentElement
root.setAttribute('data-theme', mediaQuery.matches ? 'dark' : 'light')
}
mediaQuery.addEventListener('change', handleChange)
return () => mediaQuery.removeEventListener('change', handleChange)
}, [theme])
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}
export function useTheme() {
const context = useContext(ThemeContext)
if (!context) {
throw new Error('useTheme must be used within ThemeProvider')
}
return context
}src/lib/utils.ts
import { type ClassValue, clsx } from 'clsx'
/**
* Utility for conditionally joining classNames together
*/
export function cn(...inputs: ClassValue[]) {
return clsx(inputs)
}Barrel Export Pattern
Each component directory should have an index.ts file:
// src/components/ui/index.ts
export { Button } from './button'
export { Card } from './card'
export { Input } from './input'
// src/components/layout/index.ts
export { Header } from './header'
export { Sidebar } from './sidebar'
export { Footer } from './footer'
// src/components/features/dashboard/index.ts
export { Dashboard } from './dashboard'
export { KPICard } from './kpi-card'
export { DonutChart } from './donut-chart'Commands
# Install dependencies
npm install
# Start development server
npm run dev
# Validate CSS tokens
npm run validate:tokens
# Production build
npm run build
# Preview production build
npm run previewIntegration Checklist
- [ ]
tokens.cssimported before all other styles - [ ] ThemeProvider wraps entire app
- [ ] All CSS uses token variables (no hardcoded values)
- [ ] Barrel exports exist for each component directory
- [ ] Path aliases configured (@/)
- [ ] TypeScript strict mode enabled
- [ ] Build completes without errors
Rust Axum Template
Complete scaffolding template for high-performance web applications using Axum with tower middleware.
Table of Contents
- Project Structure
- Core Files
- Cargo.toml
- src/main.rs
- src/config.rs
- src/error.rs
- src/routes/mod.rs
- src/routes/health.rs
- src/routes/dashboard.rs
- src/models/mod.rs
- src/models/dashboard.rs
- templates/base.html (Tera)
- Dockerfile
- docker-compose.yml
- Commands
- Integration Checklist
Project Structure
project-name/
├── Cargo.toml # Dependencies and metadata
├── Cargo.lock
├── .env # Environment variables
├── Dockerfile
├── docker-compose.yml
├── src/
│ ├── main.rs # Application entry point
│ ├── lib.rs # Library crate (optional)
│ ├── config.rs # Configuration
│ ├── error.rs # Error handling
│ ├── routes/ # HTTP routes
│ │ ├── mod.rs
│ │ ├── dashboard.rs
│ │ └── health.rs
│ ├── handlers/ # Request handlers
│ │ ├── mod.rs
│ │ └── dashboard_handler.rs
│ ├── models/ # Data structures
│ │ ├── mod.rs
│ │ └── dashboard.rs
│ ├── services/ # Business logic
│ │ ├── mod.rs
│ │ └── dashboard_service.rs
│ └── middleware/ # Custom middleware
│ └── mod.rs
├── static/ # Static assets
│ ├── css/
│ │ └── tokens.css
│ └── js/
├── templates/ # Tera templates
│ ├── base.html
│ └── dashboard.html
└── tests/
└── integration_tests.rsCore Files
Cargo.toml
[package]
name = "{{PROJECT_NAME}}"
version = "1.0.0"
edition = "2021"
authors = ["{{AUTHOR}}"]
description = "{{PROJECT_DESCRIPTION}}"
[dependencies]
# Web framework
axum = "0.7"
tokio = { version = "1.35", features = ["full"] }
tower = "0.4"
tower-http = { version = "0.5", features = ["fs", "trace", "cors"] }
# Serialization
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
# Configuration
dotenvy = "0.15"
config = "0.14"
# Templating
tera = "1.19"
# Tracing
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
# Error handling
thiserror = "1.0"
anyhow = "1.0"
[dev-dependencies]
axum-test = "14.0"src/main.rs
//! Application entry point.
mod config;
mod error;
mod handlers;
mod models;
mod routes;
mod services;
use axum::Router;
use std::net::SocketAddr;
use tower_http::services::ServeDir;
use tower_http::trace::TraceLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use crate::config::Config;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Initialize tracing
tracing_subscriber::registry()
.with(tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "info".into()))
.with(tracing_subscriber::fmt::layer())
.init();
// Load configuration
let config = Config::from_env()?;
tracing::info!("Starting {} v{}", config.app_name, config.version);
// Build application
let app = Router::new()
.merge(routes::create_router())
.nest_service("/static", ServeDir::new("static"))
.layer(TraceLayer::new_for_http());
// Run server
let addr = SocketAddr::from(([0, 0, 0, 0], config.port));
tracing::info!("Listening on {}", addr);
let listener = tokio::net::TcpListener::bind(addr).await?;
axum::serve(listener, app).await?;
Ok(())
}src/config.rs
//! Application configuration.
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct Config {
#[serde(default = "default_app_name")]
pub app_name: String,
#[serde(default = "default_version")]
pub version: String,
#[serde(default = "default_port")]
pub port: u16,
#[serde(default)]
pub debug: bool,
}
fn default_app_name() -> String {
"{{PROJECT_NAME}}".into()
}
fn default_version() -> String {
"1.0.0".into()
}
fn default_port() -> u16 {
3000
}
impl Config {
pub fn from_env() -> anyhow::Result<Self> {
dotenvy::dotenv().ok();
let config = config::Config::builder()
.add_source(config::Environment::default())
.build()?;
Ok(config.try_deserialize()?)
}
}src/error.rs
//! Application error types.
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use serde_json::json;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum AppError {
#[error("Not found: {0}")]
NotFound(String),
#[error("Bad request: {0}")]
BadRequest(String),
#[error("Internal server error")]
InternalError(#[from] anyhow::Error),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match &self {
AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
AppError::InternalError(_) => {
tracing::error!("Internal error: {:?}", self);
(StatusCode::INTERNAL_SERVER_ERROR, "Internal server error".into())
}
};
let body = Json(json!({
"error": message,
"status": status.as_u16(),
}));
(status, body).into_response()
}
}src/routes/mod.rs
//! Route definitions.
pub mod dashboard;
pub mod health;
use axum::{routing::get, Router};
pub fn create_router() -> Router {
Router::new()
.route("/api/health", get(health::health_check))
.route("/api/dashboard", get(dashboard::get_dashboard))
.route("/api/dashboard/data", get(dashboard::get_dashboard_data))
}src/routes/health.rs
//! Health check routes.
use axum::Json;
use serde::Serialize;
#[derive(Serialize)]
pub struct HealthResponse {
status: String,
version: String,
}
pub async fn health_check() -> Json<HealthResponse> {
Json(HealthResponse {
status: "ok".into(),
version: env!("CARGO_PKG_VERSION").into(),
})
}src/routes/dashboard.rs
//! Dashboard routes.
use axum::Json;
use crate::models::dashboard::{DashboardData, KpiData};
pub async fn get_dashboard() -> &'static str {
// In production, render a template here
"Dashboard"
}
pub async fn get_dashboard_data() -> Json<DashboardData> {
Json(DashboardData {
kpis: vec![
KpiData {
label: "Total Threats".into(),
value: 1234,
trend: 15.3,
trend_direction: "up".into(),
},
KpiData {
label: "Blocked Attacks".into(),
value: 892,
trend: 8.2,
trend_direction: "up".into(),
},
KpiData {
label: "Active Alerts".into(),
value: 23,
trend: -5.1,
trend_direction: "down".into(),
},
],
})
}src/models/mod.rs
//! Data models.
pub mod dashboard;src/models/dashboard.rs
//! Dashboard data models.
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KpiData {
pub label: String,
pub value: i64,
pub trend: f64,
pub trend_direction: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DashboardData {
pub kpis: Vec<KpiData>,
}templates/base.html (Tera)
<!DOCTYPE html>
<html lang="en" data-theme="{{ theme | default(value='light') }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }} - {{PROJECT_NAME}}</title>
<!-- Design tokens FIRST -->
<link rel="stylesheet" href="/static/css/tokens.css">
<link rel="stylesheet" href="/static/css/dashboard.css">
<script>
(function() {
const theme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', theme);
})();
</script>
</head>
<body>
{% block content %}{% endblock %}
<script>
function toggleTheme() {
const html = document.documentElement;
const current = html.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
html.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
}
</script>
</body>
</html>Dockerfile
# Build stage
FROM rust:1.75-slim as builder
WORKDIR /app
COPY . .
RUN cargo build --release
# Runtime stage
FROM debian:bookworm-slim
WORKDIR /app
# Copy binary
COPY --from=builder /app/target/release/{{PROJECT_NAME}} .
# Copy static files and templates
COPY static/ ./static/
COPY templates/ ./templates/
# Run
EXPOSE 3000
CMD ["./{{PROJECT_NAME}}"]docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
volumes:
- ./static:/app/static
- ./templates:/app/templates
environment:
- RUST_LOG=info
- PORT=3000Commands
# Build
cargo build
# Run development server (with auto-reload using cargo-watch)
cargo watch -x run
# Validate CSS tokens
python scripts/validate_tokens.py static
# Run tests
cargo test
# Production build
cargo build --release
# Format code
cargo fmt
# Lint
cargo clippyIntegration Checklist
- [ ]
tokens.cssexists in static/css/ - [ ] Templates load tokens.css before other styles
- [ ] Tower-http serves static files correctly
- [ ] Error types implement IntoResponse
- [ ] Tracing configured for observability
- [ ] Configuration loads from environment
- [ ] Dockerfile builds successfully
- [ ] Tests cover critical routes
Token Validation Rules
Complete reference for CSS design token validation rules used by validate_tokens.py.Table of Contents
- Overview
- Severity Levels
- Validation Rules
- 1. Colors (Error)
- 2. Spacing (Error)
- 3. Font Sizes (Error)
- 4. Border Radius (Warning)
- 5. Box Shadows (Warning)
- 6. Transitions (Info - Strict Mode Only)
- 7. Z-Index (Warning)
- Exceptions (Always Allowed)
- CSS Keywords
- Small Values
- Layout Values
- Context-Specific
- Exception Properties
- Script Usage
- CI/CD Integration
- GitHub Actions
- Pre-commit Hook
- Output Example
Overview
The token validation script scans CSS files for hardcoded values that should use design tokens. This ensures consistent theming and makes dark mode, brand customization, and accessibility features work correctly.
Severity Levels
| Level | Meaning | CI/CD Impact |
|---|---|---|
| Error | Must fix before deployment | Build fails |
| Warning | Should fix but not blocking | Build succeeds |
| Info | Nice to have (strict mode only) | No impact |
Validation Rules
1. Colors (Error)
Pattern: Hardcoded hex, rgb, rgba, hsl values
Bad:
.button {
background: #FA582D;
color: rgb(30, 41, 59);
border-color: rgba(0, 0, 0, 0.1);
}Good:
.button {
background: var(--color-primary);
color: var(--color-text-primary);
border-color: var(--color-border-primary);
}Common Token Mappings:
| Hardcoded | Token |
|---|---|
#FA582D | --color-cyber-orange / --color-primary |
#00C0E8 | --color-prisma-blue / --color-info |
#00CC66 | --color-cortex-green / --color-success |
#FFCB06 | --color-strata-yellow / --color-warning |
#C84727 | --color-unit42-red / --color-error |
#FFFFFF | --color-bg-primary |
#F8FAFC | --color-bg-secondary |
#1E293B | --color-text-primary |
#64748B | --color-text-secondary |
Exceptions:
currentColor- CSS keywordtransparent- CSS keywordinherit- CSS keyword
2. Spacing (Error)
Pattern: Hardcoded pixel values ≥ 4px on spacing properties
Properties: padding, margin, gap, top, right, bottom, left
Bad:
.card {
padding: 16px;
margin-bottom: 24px;
gap: 8px;
}Good:
.card {
padding: var(--spacing-md);
margin-bottom: var(--spacing-lg);
gap: var(--spacing-sm);
}Token Scale:
| Hardcoded | Token | Base Unit |
|---|---|---|
4px | --spacing-xs / --space-1 | 1× |
8px | --spacing-sm / --space-2 | 2× |
12px | --space-3 | 3× |
16px | --spacing-md / --space-4 | 4× |
20px | --space-5 | 5× |
24px | --spacing-lg / --space-6 | 6× |
32px | --spacing-xl / --space-8 | 8× |
40px | --space-10 | 10× |
48px | --spacing-2xl / --space-12 | 12× |
Exceptions:
0,0px- Zero values1px- Hairline borders2px- Focus outlines
3. Font Sizes (Error)
Pattern: Hardcoded font-size values
Bad:
.title {
font-size: 24px;
}
.body {
font-size: 14px;
}Good:
.title {
font-size: var(--font-size-2xl);
}
.body {
font-size: var(--font-size-sm);
}Token Scale:
| Hardcoded | Token | rem |
|---|---|---|
12px | --font-size-xs | 0.75rem |
14px | --font-size-sm | 0.875rem |
16px | --font-size-base | 1rem |
18px | --font-size-lg | 1.125rem |
20px | --font-size-xl | 1.25rem |
24px | --font-size-2xl | 1.5rem |
30px | --font-size-3xl | 1.875rem |
36px | --font-size-4xl | 2.25rem |
4. Border Radius (Warning)
Pattern: Hardcoded border-radius values
Bad:
.button {
border-radius: 8px;
}
.avatar {
border-radius: 9999px;
}Good:
.button {
border-radius: var(--radius-md);
}
.avatar {
border-radius: var(--radius-full);
}Token Scale:
| Hardcoded | Token |
|---|---|
4px | --radius-sm |
8px | --radius-md |
12px | --radius-lg |
16px | --radius-xl |
9999px | --radius-full |
5. Box Shadows (Warning)
Pattern: Hardcoded box-shadow values
Bad:
.card {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.modal {
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}Good:
.card {
box-shadow: var(--shadow-sm);
}
.modal {
box-shadow: var(--shadow-2xl);
}Token Scale:
| Token | Description |
|---|---|
--shadow-sm | Subtle elevation |
--shadow-md | Cards, dropdowns |
--shadow-lg | Popovers |
--shadow-xl | Modals, dialogs |
--shadow-2xl | Overlays |
6. Transitions (Info - Strict Mode Only)
Pattern: Hardcoded transition timing
Bad:
.button {
transition: all 150ms ease;
}Good:
.button {
transition: var(--transition-fast);
}Token Scale:
| Token | Duration |
|---|---|
--duration-fast | 150ms |
--duration-normal | 200ms |
--duration-slow | 300ms |
--transition-fast | all 150ms ease-out |
--transition-normal | all 200ms ease-out |
7. Z-Index (Warning)
Pattern: Hardcoded z-index values ≥ 100
Bad:
.dropdown {
z-index: 1000;
}
.modal {
z-index: 1050;
}Good:
.dropdown {
z-index: var(--z-dropdown);
}
.modal {
z-index: var(--z-modal);
}Token Scale:
| Token | Value |
|---|---|
--z-dropdown | 1000 |
--z-sticky | 1020 |
--z-fixed | 1030 |
--z-modal-backdrop | 1040 |
--z-modal | 1050 |
--z-popover | 1060 |
--z-tooltip | 1070 |
--z-toast | 1080 |
Exceptions (Always Allowed)
CSS Keywords
currentColortransparentinheritinitialunsetnoneauto
Small Values
0,0px- Zero1px- Hairline borders2px- Focus outlines100%,50%- Percentages
Layout Values
These are skipped because they're structural, not themeable:
- Container max-widths (
1400px,1200px,1024px) - Media query breakpoints (
768px,640px,480px) - Grid functions (
minmax(),repeat()) - Grid templates
Context-Specific
- Lines starting with
--(token definitions) - Comments (
/*,*,*/) @mediaquery lines@keyframesdefinitions- Animation percentages (
0%,100%)
Exception Properties
Some properties accept hardcoded values:
outline- Accessibility focus indicatorsoutline-offset- Accessibilitytransform- Animation transformsanimation- Animation definitionscontent- Pseudo-element contentclip-path- Complex clippingmask- Complex masking
Script Usage
# Basic validation
python scripts/validate_tokens.py src/styles
# Strict mode (includes info-level)
python scripts/validate_tokens.py src --strict
# JSON output for CI/CD
python scripts/validate_tokens.py src --json
# Show fix suggestions
python scripts/validate_tokens.py src --fix-suggestionsCI/CD Integration
GitHub Actions
- name: Validate CSS Tokens
run: python scripts/validate_tokens.py src --json > token-report.json
- name: Check for Errors
run: |
errors=$(jq '.errors' token-report.json)
if [ "$errors" -gt 0 ]; then
echo "Found $errors token violations"
exit 1
fiPre-commit Hook
#!/bin/bash
# .git/hooks/pre-commit
python scripts/validate_tokens.py src --strict
if [ $? -ne 0 ]; then
echo "CSS token validation failed. Fix violations before committing."
exit 1
fiOutput Example
======================================================================
CSS DESIGN TOKEN VALIDATION REPORT
======================================================================
src/components/Card.css
------------------------------------------------------------
❌ Line 5:12 [ERROR]
Found: #FA582D
Rule: colors
Fix: Use semantic color token (e.g., --color-primary)
Suggested: var(--color-cyber-orange)
⚠️ Line 12:3 [WARNING]
Found: border-radius: 8px
Rule: radii
Fix: Use radius token (e.g., --radius-md)
Suggested: var(--radius-md)
----------------------------------------------------------------------
SUMMARY
----------------------------------------------------------------------
Files scanned: 15
Files with issues: 3
Total violations: 7
- Errors: 4
- Warnings: 3
- Info: 0
By Category:
- colors: 4
- radii: 2
- shadows: 1#!/usr/bin/env python3
"""
check_imports.py - Import Chain Validator
Validates that import chains are correct in React/TypeScript projects:
- tokens.css is imported before other styles
- ThemeProvider wraps the app
- Barrel exports exist for component directories
- No circular imports
ZERO CONTEXT TOKEN COST - Executed without loading into Claude's context.
Usage:
python check_imports.py <directory>
Examples:
python check_imports.py src
python check_imports.py demo/examples/my-project/src
"""
import sys
import re
import argparse
from pathlib import Path
from dataclasses import dataclass, field
from typing import List, Dict, Set, Optional
from collections import defaultdict
@dataclass
class ImportInfo:
"""Information about an import statement."""
source: str
specifiers: List[str]
is_css: bool
is_relative: bool
line_number: int
@dataclass
class ValidationResult:
"""Result of validation checks."""
file: str
issues: List[str] = field(default_factory=list)
warnings: List[str] = field(default_factory=list)
@dataclass
class ProjectValidation:
"""Overall project validation results."""
total_files: int = 0
files_with_issues: int = 0
total_issues: int = 0
total_warnings: int = 0
results: List[ValidationResult] = field(default_factory=list)
missing_barrel_exports: List[str] = field(default_factory=list)
token_import_issues: List[str] = field(default_factory=list)
def parse_imports(file_path: Path) -> List[ImportInfo]:
"""Parse all import statements from a file."""
imports = []
content = file_path.read_text(encoding='utf-8')
lines = content.split('\n')
# Match various import patterns
patterns = [
# import X from 'path'
r"import\s+(\w+)\s+from\s+['\"]([^'\"]+)['\"]",
# import { X, Y } from 'path'
r"import\s+\{([^}]+)\}\s+from\s+['\"]([^'\"]+)['\"]",
# import 'path' (side-effect import, like CSS)
r"import\s+['\"]([^'\"]+)['\"]",
# import * as X from 'path'
r"import\s+\*\s+as\s+(\w+)\s+from\s+['\"]([^'\"]+)['\"]",
]
for line_num, line in enumerate(lines, 1):
line = line.strip()
if not line.startswith('import'):
continue
# Side-effect import (CSS, etc.)
side_effect_match = re.match(r"import\s+['\"]([^'\"]+)['\"]", line)
if side_effect_match:
source = side_effect_match.group(1)
imports.append(ImportInfo(
source=source,
specifiers=[],
is_css=source.endswith('.css'),
is_relative=source.startswith('.') or source.startswith('@/'),
line_number=line_num
))
continue
# Named or default import
for pattern in patterns[:-1]: # Exclude side-effect pattern
match = re.match(pattern, line)
if match:
if len(match.groups()) == 2:
specifiers_str, source = match.groups()
specifiers = [s.strip() for s in specifiers_str.split(',')]
else:
source = match.group(1)
specifiers = []
imports.append(ImportInfo(
source=source,
specifiers=specifiers,
is_css=source.endswith('.css'),
is_relative=source.startswith('.') or source.startswith('@/'),
line_number=line_num
))
break
return imports
def check_token_import_order(file_path: Path, imports: List[ImportInfo]) -> List[str]:
"""Check that tokens.css is imported before other CSS files."""
issues = []
css_imports = [i for i in imports if i.is_css]
if not css_imports:
return issues
token_import_idx = None
for idx, imp in enumerate(css_imports):
if 'tokens' in imp.source.lower():
token_import_idx = idx
break
if token_import_idx is None:
# No token import found - might be okay if it's not an entry file
if file_path.name in ('main.tsx', 'index.tsx', 'App.tsx', 'layout.tsx'):
issues.append(f"Entry file should import tokens.css")
elif token_import_idx > 0:
issues.append(f"tokens.css should be imported BEFORE other CSS files (line {css_imports[token_import_idx].line_number})")
return issues
def check_theme_provider(file_path: Path) -> List[str]:
"""Check that entry files use ThemeProvider."""
issues = []
if file_path.name not in ('main.tsx', 'index.tsx', 'App.tsx', 'layout.tsx', '_app.tsx'):
return issues
content = file_path.read_text(encoding='utf-8')
# Check for ThemeProvider import
has_theme_import = re.search(r"import.*ThemeProvider", content) is not None
# Check for ThemeProvider usage
has_theme_usage = re.search(r"<ThemeProvider", content) is not None
if file_path.name in ('main.tsx', 'layout.tsx', '_app.tsx'):
if not has_theme_import:
issues.append("Entry file should import ThemeProvider")
if not has_theme_usage:
issues.append("Entry file should wrap app with ThemeProvider")
return issues
def check_barrel_exports(directory: Path) -> List[str]:
"""Check that component directories have barrel exports."""
missing = []
# Find directories with .tsx files but no index.ts
for dir_path in directory.rglob('*'):
if not dir_path.is_dir():
continue
# Skip certain directories
if any(skip in dir_path.parts for skip in ('node_modules', '.next', 'dist', 'build')):
continue
tsx_files = list(dir_path.glob('*.tsx'))
has_index = (dir_path / 'index.ts').exists() or (dir_path / 'index.tsx').exists()
# If there are multiple .tsx files, there should be a barrel export
if len(tsx_files) > 1 and not has_index:
relative = dir_path.relative_to(directory)
missing.append(str(relative))
return missing
def find_circular_imports(directory: Path) -> List[str]:
"""Detect circular imports in the project."""
# Build import graph
import_graph: Dict[str, Set[str]] = defaultdict(set)
for ts_file in directory.rglob('*.ts'):
if 'node_modules' in str(ts_file):
continue
imports = parse_imports(ts_file)
file_key = str(ts_file.relative_to(directory))
for imp in imports:
if imp.is_relative:
# Resolve relative import
if imp.source.startswith('./'):
resolved = ts_file.parent / imp.source[2:]
elif imp.source.startswith('../'):
resolved = (ts_file.parent / imp.source).resolve()
elif imp.source.startswith('@/'):
resolved = directory / imp.source[2:]
else:
continue
# Add .ts or .tsx extension if needed
if not resolved.suffix:
for ext in ['.ts', '.tsx', '/index.ts', '/index.tsx']:
if (resolved.parent / (resolved.name + ext)).exists():
resolved = resolved.parent / (resolved.name + ext)
break
if resolved.exists():
target_key = str(resolved.relative_to(directory))
import_graph[file_key].add(target_key)
# Same for .tsx files
for tsx_file in directory.rglob('*.tsx'):
if 'node_modules' in str(tsx_file):
continue
imports = parse_imports(tsx_file)
file_key = str(tsx_file.relative_to(directory))
for imp in imports:
if imp.is_relative:
if imp.source.startswith('./'):
resolved = tsx_file.parent / imp.source[2:]
elif imp.source.startswith('../'):
resolved = (tsx_file.parent / imp.source).resolve()
elif imp.source.startswith('@/'):
resolved = directory / imp.source[2:]
else:
continue
if not resolved.suffix:
for ext in ['.ts', '.tsx', '/index.ts', '/index.tsx']:
test_path = resolved.parent / (resolved.name + ext)
if test_path.exists():
resolved = test_path
break
if resolved.exists():
target_key = str(resolved.relative_to(directory))
import_graph[file_key].add(target_key)
# Detect cycles using DFS
cycles = []
visited = set()
rec_stack = set()
path = []
def dfs(node: str) -> bool:
visited.add(node)
rec_stack.add(node)
path.append(node)
for neighbor in import_graph.get(node, []):
if neighbor not in visited:
if dfs(neighbor):
return True
elif neighbor in rec_stack:
cycle_start = path.index(neighbor)
cycle = path[cycle_start:] + [neighbor]
cycles.append(' -> '.join(cycle))
return True
path.pop()
rec_stack.remove(node)
return False
for node in import_graph:
if node not in visited:
dfs(node)
return cycles
def validate_file(file_path: Path) -> ValidationResult:
"""Validate a single file."""
result = ValidationResult(file=str(file_path))
try:
imports = parse_imports(file_path)
# Check token import order
result.issues.extend(check_token_import_order(file_path, imports))
# Check ThemeProvider usage
result.issues.extend(check_theme_provider(file_path))
except Exception as e:
result.warnings.append(f"Could not parse file: {e}")
return result
def validate_project(directory: Path) -> ProjectValidation:
"""Validate the entire project."""
validation = ProjectValidation()
# Find all TypeScript/TSX files
ts_files = list(directory.rglob('*.ts')) + list(directory.rglob('*.tsx'))
ts_files = [f for f in ts_files if 'node_modules' not in str(f)]
validation.total_files = len(ts_files)
# Validate each file
for ts_file in ts_files:
result = validate_file(ts_file)
if result.issues or result.warnings:
validation.results.append(result)
validation.files_with_issues += 1
validation.total_issues += len(result.issues)
validation.total_warnings += len(result.warnings)
# Check barrel exports
validation.missing_barrel_exports = check_barrel_exports(directory)
# Check for circular imports
# (Disabled by default as it can be slow on large projects)
# validation.circular_imports = find_circular_imports(directory)
return validation
def format_report(validation: ProjectValidation) -> str:
"""Format the validation report."""
lines = []
lines.append("")
lines.append("=" * 60)
lines.append(" IMPORT CHAIN VALIDATION REPORT")
lines.append("=" * 60)
lines.append("")
if not validation.results and not validation.missing_barrel_exports:
lines.append(" All import chains are valid!")
lines.append("")
lines.append(f" Scanned: {validation.total_files} files")
lines.append("")
return '\n'.join(lines)
# File-specific issues
for result in validation.results:
lines.append(f" {result.file}")
lines.append(" " + "-" * 50)
for issue in result.issues:
lines.append(f" Issue: {issue}")
for warning in result.warnings:
lines.append(f" Warning: {warning}")
lines.append("")
# Missing barrel exports
if validation.missing_barrel_exports:
lines.append(" Missing Barrel Exports (index.ts)")
lines.append(" " + "-" * 50)
for dir_path in validation.missing_barrel_exports:
lines.append(f" - {dir_path}/")
lines.append("")
lines.append(" Run: python scripts/generate_exports.py src/components")
lines.append("")
# Summary
lines.append("-" * 60)
lines.append(" SUMMARY")
lines.append("-" * 60)
lines.append(f" Files scanned: {validation.total_files}")
lines.append(f" Files with issues: {validation.files_with_issues}")
lines.append(f" Total issues: {validation.total_issues}")
lines.append(f" Total warnings: {validation.total_warnings}")
lines.append(f" Missing exports: {len(validation.missing_barrel_exports)}")
lines.append("")
return '\n'.join(lines)
def main():
parser = argparse.ArgumentParser(
description='Validate import chains in React/TypeScript projects',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Checks performed:
- tokens.css imported before other CSS files
- ThemeProvider wraps the app in entry files
- Barrel exports exist for component directories
- No circular imports (optional)
Examples:
%(prog)s src
%(prog)s demo/examples/my-project/src
"""
)
parser.add_argument('directory', type=Path, help='Directory to validate')
parser.add_argument('--json', action='store_true', help='Output as JSON')
parser.add_argument('--check-circular', action='store_true', help='Check for circular imports (slow)')
args = parser.parse_args()
if not args.directory.exists():
print(f"Error: Directory not found: {args.directory}", file=sys.stderr)
sys.exit(1)
validation = validate_project(args.directory)
if args.json:
import json
print(json.dumps({
'total_files': validation.total_files,
'files_with_issues': validation.files_with_issues,
'total_issues': validation.total_issues,
'total_warnings': validation.total_warnings,
'missing_barrel_exports': validation.missing_barrel_exports,
'results': [
{
'file': r.file,
'issues': r.issues,
'warnings': r.warnings
}
for r in validation.results
]
}, indent=2))
else:
print(format_report(validation))
# Exit with error if issues found
if validation.total_issues > 0:
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
generate_exports.py - Barrel Export Generator
Generates index.ts barrel export files for React/TypeScript component directories.
Scans for .tsx files and creates proper exports.
ZERO CONTEXT TOKEN COST - Executed without loading into Claude's context.
Usage:
python generate_exports.py <directory>
Examples:
python generate_exports.py src/components
python generate_exports.py src/components/ui
"""
import sys
import re
import argparse
from pathlib import Path
from dataclasses import dataclass
from typing import List, Optional, Set
@dataclass
class ExportInfo:
"""Information about an export."""
name: str
file_path: str
is_default: bool
def find_exports(file_path: Path) -> List[ExportInfo]:
"""Find all exports in a TypeScript/TSX file."""
exports = []
content = file_path.read_text(encoding='utf-8')
file_stem = file_path.stem
# Check for default export
# Patterns: export default function X, export default X, export default class X
default_patterns = [
r'export\s+default\s+function\s+(\w+)',
r'export\s+default\s+class\s+(\w+)',
r'export\s+default\s+(\w+)',
]
for pattern in default_patterns:
match = re.search(pattern, content)
if match:
name = match.group(1)
# Use PascalCase version of filename if export name is generic
if name in ('default', 'component', 'Component'):
name = to_pascal_case(file_stem)
exports.append(ExportInfo(
name=name,
file_path=f'./{file_stem}',
is_default=True
))
break
# Check for named exports
# Patterns: export function X, export const X, export class X, export type X, export interface X
named_patterns = [
r'export\s+(?:async\s+)?function\s+(\w+)',
r'export\s+const\s+(\w+)',
r'export\s+let\s+(\w+)',
r'export\s+class\s+(\w+)',
r'export\s+type\s+(\w+)',
r'export\s+interface\s+(\w+)',
r'export\s+enum\s+(\w+)',
]
for pattern in named_patterns:
for match in re.finditer(pattern, content):
name = match.group(1)
# Skip if it's a default export we already captured
if any(e.name == name and e.is_default for e in exports):
continue
exports.append(ExportInfo(
name=name,
file_path=f'./{file_stem}',
is_default=False
))
return exports
def to_pascal_case(name: str) -> str:
"""Convert kebab-case or snake_case to PascalCase."""
parts = re.split(r'[-_]', name)
return ''.join(part.capitalize() for part in parts)
def generate_index_content(exports: List[ExportInfo]) -> str:
"""Generate the content for an index.ts barrel export file."""
lines = []
# Group exports by file
files: dict[str, List[ExportInfo]] = {}
for export in exports:
if export.file_path not in files:
files[export.file_path] = []
files[export.file_path].append(export)
# Generate export statements
for file_path, file_exports in sorted(files.items()):
default_exports = [e for e in file_exports if e.is_default]
named_exports = [e for e in file_exports if not e.is_default]
if default_exports and named_exports:
# Both default and named exports
names = ', '.join(e.name for e in named_exports)
lines.append(f"export {{ default as {default_exports[0].name}, {names} }} from '{file_path}'")
elif default_exports:
# Only default export - re-export as named
lines.append(f"export {{ {default_exports[0].name} }} from '{file_path}'")
elif named_exports:
# Only named exports
names = ', '.join(e.name for e in named_exports)
lines.append(f"export {{ {names} }} from '{file_path}'")
return '\n'.join(sorted(lines)) + '\n'
def process_directory(directory: Path, recursive: bool = True) -> dict[Path, str]:
"""Process a directory and generate barrel exports."""
results = {}
# Find all directories with .tsx files
if recursive:
dirs_to_process = set()
for tsx_file in directory.rglob('*.tsx'):
if tsx_file.name != 'index.tsx':
dirs_to_process.add(tsx_file.parent)
else:
dirs_to_process = {directory}
for dir_path in dirs_to_process:
exports = []
# Find all .tsx files (excluding index.tsx)
tsx_files = [f for f in dir_path.glob('*.tsx') if f.name != 'index.tsx']
if not tsx_files:
continue
for tsx_file in tsx_files:
file_exports = find_exports(tsx_file)
if not file_exports:
# If no exports found, assume default export with PascalCase name
exports.append(ExportInfo(
name=to_pascal_case(tsx_file.stem),
file_path=f'./{tsx_file.stem}',
is_default=True
))
else:
exports.extend(file_exports)
if exports:
content = generate_index_content(exports)
results[dir_path / 'index.ts'] = content
return results
def main():
parser = argparse.ArgumentParser(
description='Generate barrel export files for React/TypeScript components',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s src/components
%(prog)s src/components/ui --no-recursive
%(prog)s src/components --dry-run
"""
)
parser.add_argument('directory', type=Path, help='Directory to process')
parser.add_argument('--no-recursive', action='store_true', help='Only process the specified directory')
parser.add_argument('--dry-run', action='store_true', help='Show what would be generated without writing')
parser.add_argument('--overwrite', action='store_true', help='Overwrite existing index.ts files')
args = parser.parse_args()
if not args.directory.exists():
print(f"Error: Directory not found: {args.directory}", file=sys.stderr)
sys.exit(1)
results = process_directory(args.directory, recursive=not args.no_recursive)
if not results:
print("No components found to generate exports for.")
sys.exit(0)
print(f"\n{'=' * 60}")
print(f" BARREL EXPORT GENERATOR")
print(f"{'=' * 60}\n")
created = 0
skipped = 0
for index_path, content in sorted(results.items()):
relative_path = index_path.relative_to(args.directory.parent) if args.directory.parent != index_path.parent else index_path.name
if args.dry_run:
print(f" Would create: {relative_path}")
print(f" {'-' * 40}")
for line in content.split('\n'):
if line:
print(f" {line}")
print()
else:
if index_path.exists() and not args.overwrite:
print(f" Skipped (exists): {relative_path}")
skipped += 1
else:
index_path.write_text(content, encoding='utf-8')
print(f" Created: {relative_path}")
created += 1
print(f"\n{'-' * 60}")
if args.dry_run:
print(f" Dry run: {len(results)} files would be created")
else:
print(f" Created: {created} files")
if skipped:
print(f" Skipped: {skipped} files (use --overwrite to replace)")
print()
if __name__ == "__main__":
main()
Related skills
FAQ
When do I run this skill?
As the capstone after running theming, layout, dashboard, data-viz, or feedback skills to wire their outputs together.
What frameworks can it scaffold?
React/Vite, Next.js, FastAPI, Flask, and Rust/Axum projects.