| name | ui-component |
| description | Use when creating new UI components under apps/web/src/components/ |
UI Component Creation Skill
Checklist (MUST complete all)
Component Types
1. Pure UI Components (components/charts/ or components/ui/)
Data-agnostic, reusable components. Receive all data via props.
"use client";
interface MyChartProps {
data: Array<{ label: string; value: number }>;
}
export function MyChart({ data }: MyChartProps) {
return ();
}
2. Data-Fetching Components (components/info/)
| File | Purpose |
|---|
foo.tsx | Server Component - fetches data via lib/queries |
foo.client.tsx | Client Component - handles interactivity (ONLY if needed) |
foo.stories.tsx | Storybook - uses mock data |
IMPORTANT: Only create .client.tsx when interactivity is required (useState, useEffect, event handlers, etc.). If the component only displays data, keep it as a Server Component.
Server Component Only (no interactivity)
import { getMyData } from "../../lib/queries";
export function MyInfo() {
const data = getMyData();
return (
<Card>
<CardHeader>
<CardTitle>My Info</CardTitle>
</CardHeader>
<CardContent>{/* render data */}</CardContent>
</Card>
);
}
With Client Component (interactivity required)
import { getMyData } from "../../lib/queries";
import { MyInfoClient } from "./my-info.client";
export function MyInfo() {
const data = getMyData();
return <MyInfoClient data={data} />;
}
"use client";
interface MyInfoClientProps {
data: MyData;
}
export function MyInfoClient({ data }: MyInfoClientProps) {
const [state, setState] = useState();
return ();
}
File Locations
- Pure charts:
apps/web/src/components/charts/
- UI primitives:
apps/web/src/components/ui/
- Data-fetching:
apps/web/src/components/info/
- Queries:
apps/web/src/lib/queries.ts
Storybook Template
import type { Meta, StoryObj } from "@storybook/react";
import { MyInfoClient } from "./my-info.client";
const meta = {
component: MyInfoClient,
} satisfies Meta<typeof MyInfoClient>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
data: {
},
},
};
Semantic Colors (MUST use)
| Purpose | Class |
|---|
| Income amount | text-income |
| Expense amount | text-expense |
| Positive balance | text-balance-positive |
| Negative balance | text-balance-negative |