+184
CRUSH.md
+184
CRUSH.md
···
1
+
# CRUSH.md
2
+
3
+
## Project Overview
4
+
5
+
This is a personal portfolio website built with Bun, React, TypeScript, and Tailwind CSS. It uses the shadcn/ui component library and serves as both a portfolio and development environment for AT Protocol-related projects. The project demonstrates modern web development practices with a focus on decentralized technologies.
6
+
7
+
## Development Commands
8
+
9
+
### Core Commands
10
+
- `bun install` - Install dependencies
11
+
- `bun dev` - Start development server with hot reload and HMR
12
+
- `bun start` - Run production server
13
+
- `bun run build.ts` - Build for production (outputs to `dist/`)
14
+
- `bun run build.ts --help` - Show all build options
15
+
16
+
### Build System
17
+
The custom build script (`build.ts`) supports various options:
18
+
- `--outdir <path>` - Output directory (default: "dist")
19
+
- `--minify` - Enable minification
20
+
- `--sourcemap <type>` - Sourcemap type (none|linked|inline|external)
21
+
- `--external <list>` - External packages (comma separated)
22
+
23
+
The build automatically:
24
+
- Processes all HTML files in `src/` as entrypoints
25
+
- Copies `public/` folder to dist
26
+
- Uses Tailwind plugin for CSS processing
27
+
- Includes linked sourcemaps by default
28
+
29
+
## Architecture
30
+
31
+
### Project Structure
32
+
```
33
+
src/
34
+
├── components/
35
+
│ ├── ui/ # shadcn/ui components (Button, Card, Input, etc.)
36
+
│ ├── sections/ # Main page sections (Header, Work, Connect)
37
+
│ └── ... # Other React components
38
+
├── data/
39
+
│ └── portfolio.ts # Portfolio content and metadata
40
+
├── hooks/ # Custom React hooks
41
+
├── lib/ # Utility functions
42
+
└── styles/ # Global CSS and Tailwind config
43
+
```
44
+
45
+
### Server Architecture
46
+
- Uses Bun's built-in server (`src/index.ts`)
47
+
- Serves React SPA with API routes
48
+
- API routes use pattern matching (`/api/hello/:name`)
49
+
- CORS headers configured for cross-origin requests
50
+
- Development mode includes HMR and browser console echoing
51
+
52
+
### Key Files
53
+
- `src/index.ts` - Server entry point with API routes
54
+
- `src/App.tsx` - Main React component with intersection observer animations
55
+
- `src/data/portfolio.ts` - All portfolio content (personal info, work experience, skills)
56
+
- `build.ts` - Custom build script with extensive CLI options
57
+
- `styles/globals.css` - Tailwind imports, CSS variables, and custom animations
58
+
59
+
## Code Conventions
60
+
61
+
### TypeScript Configuration
62
+
- Strict mode enabled with `noUncheckedIndexedAccess`
63
+
- Path aliases: `@/*` maps to `./src/*`
64
+
- JSX: `react-jsx` transform
65
+
- Module resolution: `bundler` mode
66
+
- Target: `ESNext` with DOM libraries
67
+
68
+
### Component Patterns
69
+
- Uses shadcn/ui component library with `class-variance-authority`
70
+
- Utility function `cn()` combines `clsx` and `tailwind-merge`
71
+
- Components follow Radix UI patterns for accessibility
72
+
- File exports: Named exports for components, default for main App
73
+
74
+
### Styling
75
+
- Tailwind CSS v4 with custom CSS variables
76
+
- Dark theme by default with light mode support
77
+
- Glassmorphism effects with custom utilities
78
+
- Custom animations: `fade-in-up`, `bounce-slow`
79
+
- Fira Code monospace font throughout
80
+
81
+
### Import Aliases (from components.json)
82
+
```typescript
83
+
"@/components" → "./src/components"
84
+
"@/lib/utils" → "./src/lib/utils"
85
+
"@/components/ui" → "./src/components/ui"
86
+
"@/lib" → "./src/lib"
87
+
"@/hooks" → "./src/hooks"
88
+
```
89
+
90
+
## UI Components
91
+
92
+
### shadcn/ui Integration
93
+
The project uses shadcn/ui with:
94
+
- Style variant: "new-york"
95
+
- Base color: "neutral"
96
+
- Icon library: Lucide React
97
+
- CSS variables enabled
98
+
- Custom CSS location: `styles/globals.css`
99
+
100
+
### Available UI Components
101
+
- Button (multiple variants: default, destructive, outline, secondary, ghost, link)
102
+
- Card
103
+
- Input
104
+
- Label
105
+
- Select
106
+
- Textarea
107
+
108
+
### Custom Components
109
+
- ThemeToggle (dark/light mode switching)
110
+
- SectionNav (navigation between portfolio sections)
111
+
- ProjectCard/WorkExperienceCard (portfolio item displays)
112
+
- SocialLink (social media links with icons)
113
+
114
+
## Content Management
115
+
116
+
Portfolio data is centralized in `src/data/portfolio.ts`:
117
+
- `personalInfo` - Name, title, description, availability, contact
118
+
- `currentRole` - Current employment status
119
+
- `skills` - Array of technical skills
120
+
- `workExperience` - Array of work history with projects
121
+
- `socialLinks` - Social media profiles
122
+
- `sections` - Page section identifiers
123
+
124
+
The description format supports rich text with bold styling and URLs:
125
+
```typescript
126
+
type DescriptionPart = {
127
+
text: string
128
+
bold?: boolean
129
+
url?: string
130
+
}
131
+
```
132
+
133
+
## Deployment
134
+
135
+
### Netlify Configuration
136
+
- Static site hosting
137
+
- CORS headers configured in `public/netlify.toml`
138
+
- AT Protocol DID file at `public/.well-known/atproto-did`
139
+
140
+
### Build Output
141
+
- Production builds output to `dist/`
142
+
- All HTML files in `src/` become entrypoints
143
+
- Public assets copied automatically
144
+
- Source maps linked for debugging
145
+
146
+
## Development Notes
147
+
148
+
### Hot Module Replacement
149
+
- Development server includes HMR
150
+
- Browser console logs echoed to server
151
+
- Automatic reloading on file changes
152
+
153
+
### Performance Features
154
+
- Intersection Observer for scroll-triggered animations
155
+
- Code splitting support in build configuration
156
+
- Minification enabled by default in production
157
+
- Lazy loading with `react` imports
158
+
159
+
### AT Protocol Integration
160
+
- Project showcases AT Protocol-related work
161
+
- Uses `atproto-ui` component library
162
+
- Bluesky and Tangled integration in portfolio
163
+
164
+
## Gotchas
165
+
166
+
### Build System
167
+
- Custom build script requires Bun runtime (not Node.js)
168
+
- HTML files in `src/` automatically become entrypoints
169
+
- Must use `--external` flag for libraries that shouldn't be bundled
170
+
171
+
### Styling
172
+
- Dark mode is default styling approach
173
+
- CSS variables are used extensively for theming
174
+
- Custom glassmorphism effects require SVG filters (defined in CSS)
175
+
176
+
### Server Routes
177
+
- API routes use Bun's pattern matching syntax
178
+
- All unmatched routes serve the main SPA (catch-all route)
179
+
- CORS headers pre-configured for API access
180
+
181
+
### Content Structure
182
+
- Portfolio content is TypeScript data, not markdown
183
+
- Rich text descriptions use specific object structure
184
+
- Projects support multiple links (live demo, GitHub, etc.)
+8
-1
build.ts
+8
-1
build.ts
···
1
1
#!/usr/bin/env bun
2
2
import plugin from "bun-plugin-tailwind";
3
3
import { existsSync } from "fs";
4
-
import { rm } from "fs/promises";
4
+
import { rm, cp } from "fs/promises";
5
5
import path from "path";
6
6
7
7
if (process.argv.includes("--help") || process.argv.includes("-h")) {
···
145
145
146
146
console.table(outputTable);
147
147
const buildTime = (end - start).toFixed(2);
148
+
149
+
// Copy public folder to dist
150
+
const publicDir = path.join(process.cwd(), "public");
151
+
if (existsSync(publicDir)) {
152
+
console.log("📁 Copying public folder to dist...");
153
+
await cp(publicDir, outdir, { recursive: true });
154
+
}
148
155
149
156
console.log(`\n✅ Build completed in ${buildTime}ms\n`);
+1
public/.well-known/atproto-did
+1
public/.well-known/atproto-did
···
1
+
did:plc:ttdrpj45ibqunmfhdsb4zdwq
public/nekomata.png
public/nekomata.png
This is a binary file and will not be displayed.
+6
public/netlify.toml
+6
public/netlify.toml
+6
-1
src/components/sections/Work.tsx
+6
-1
src/components/sections/Work.tsx
···
19
19
color: 'oklch(0.2 0.02 255)'
20
20
} : {}}
21
21
>
22
-
<div className="max-w-4xl mx-auto px-6 sm:px-8 lg:px-16">
22
+
<div className="relative max-w-4xl mx-auto px-6 sm:px-8 lg:px-16">
23
+
<img
24
+
src="/nekomata.png"
25
+
alt=""
26
+
className="absolute left-0 top-1/3 -translate-y-1/2 -translate-x-56 w-96 h-auto opacity-100 hidden lg:block pointer-events-none"
27
+
/>
23
28
<div className="space-y-12 sm:space-y-16">
24
29
<div className="flex flex-col sm:flex-row sm:items-end sm:justify-between gap-4">
25
30
<h2 className="text-3xl sm:text-4xl font-light">Selected Work</h2>
+1
-1
src/data/portfolio.ts
+1
-1
src/data/portfolio.ts
+10
src/index.ts
+10
src/index.ts
···
11
11
});
12
12
},
13
13
14
+
// Serve static files from public directory
15
+
"/nekomata.png": async () => {
16
+
try {
17
+
const file = Bun.file("public/nekomata.png");
18
+
return new Response(file);
19
+
} catch {
20
+
return new Response("File not found", { status: 404 });
21
+
}
22
+
},
23
+
14
24
// Serve index.html for all unmatched routes.
15
25
"/*": index,
16
26