My personal website
1# Component Structure
2
3All components follow a consistent 4-file system.
4
5## File Structure
6
7```
8/ComponentName/
9├── ComponentName.tsx # Component implementation
10├── ComponentName.types.ts # TypeScript interfaces
11├── ComponentName.styles.ts # Tailwind class strings
12└── ComponentName.constants.ts # Hardcoded values, configs
13```
14
15**Simple components** may skip `.constants.ts` if they have no hardcoded values.
16
17## Quick Reference
18
19### ComponentName.tsx
20Component logic and JSX. Import from sibling files.
21
22```typescript
23import * as styles from './Button.styles';
24import { DEFAULT_VARIANT } from './Button.constants';
25import { ButtonProps } from './Button.types';
26
27export const Button: React.FC<ButtonProps> = ({
28 variant = DEFAULT_VARIANT,
29 children
30}) => (
31 <button className={styles.getButtonStyles(variant)}>
32 {children}
33 </button>
34);
35```
36
37### ComponentName.types.ts
38All TypeScript interfaces and types.
39
40```typescript
41export interface ButtonProps {
42 variant?: 'primary' | 'secondary';
43 children: React.ReactNode;
44}
45```
46
47### ComponentName.styles.ts
48Tailwind class strings. Use `cn()` for dynamic styles.
49
50```typescript
51import { cn } from '@/lib/utils';
52
53export const button = 'px-4 py-2 rounded font-medium';
54
55export const getButtonStyles = (variant: string) =>
56 cn(button, variant === 'primary' ? 'bg-blue-600' : 'bg-gray-200');
57```
58
59### ComponentName.constants.ts
60Extract hardcoded values here.
61
62```typescript
63export const DEFAULT_VARIANT = 'primary' as const;
64
65export const SOCIAL_LINKS = [
66 { href: 'https://github.com', label: 'GitHub' },
67] as const;
68```
69
70## Styling Rules
71
721. **Use Tailwind utilities only** - No inline styles or CSS modules
732. **Never use margin** - Use `gap` for spacing between children, `padding` for internal spacing
743. **Always include line-height** - Every text element needs leading-*
754. **Scale responsively** - Use breakpoint prefixes: `text-4xl md:text-6xl`
76
77**Good:**
78```typescript
79export const container = 'flex flex-col gap-4 p-6';
80```
81
82**Bad:**
83```typescript
84export const container = 'flex flex-col mt-4 mb-8'; // ❌ No margin!
85```
86
87## Common Patterns
88
89### Base + Variant
90**Card** is the base component. **CardArticle**, **CardRole**, **CardStudy** wrap it with domain-specific logic.
91
92```typescript
93// CardArticle wraps base Card
94import { Card } from '@/components/Card/Card';
95
96export const CardArticle: React.FC<CardArticleProps> = ({ article }) => (
97 <a href={article.url}>
98 <Card title={article.title} description={article.subtitle} />
99 </a>
100);
101```
102
103### Context-Aware
104**Section** provides theme context. **Button**, **Heading**, etc. read from it.
105
106```typescript
107<Section theme="blue">
108 <Button /> {/* Automatically styled for blue theme */}
109</Section>
110```
111
112## Design System
113
114**Colors:** `bones-blue`, `bones-white`, `bones-black`, `bones-yellow`
115**Fonts:** `font-sans` (DM Sans), `font-serif` (DM Serif Display)
116**Themes:** `mono`, `gray`, `yellow`, `blue`, `red`, `purple`
117
118## Quick Start
119
120```bash
121# Create new component
122mkdir src/components/NewComponent
123cd src/components/NewComponent
124
125# Create files
126touch NewComponent.tsx NewComponent.types.ts NewComponent.styles.ts NewComponent.constants.ts
127```
128
129Look at **Button**, **Card**, or **Navigation** for examples.