update site

Changed files
+217 -4
public
src
components
sections
data
styles
+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
··· 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 + did:plc:ttdrpj45ibqunmfhdsb4zdwq
public/nekomata.png

This is a binary file and will not be displayed.

+6
public/netlify.toml
··· 1 + [[headers]] 2 + for = "/*" 3 + [headers.values] 4 + Access-Control-Allow-Origin = "*" 5 + Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, OPTIONS" 6 + Access-Control-Allow-Headers = "Content-Type, Authorization"
+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
··· 61 61 tech: ["React", "TypeScript", "Bun", "ElysiaJS", "Hono", "Docker"], 62 62 links: { 63 63 live: "https://wisp.place", 64 - github: "#", 64 + github: "https://tangled.org/@nekomimi.pet/wisp.place", 65 65 }, 66 66 }, 67 67 {
+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
+1 -1
styles/globals.css
··· 160 160 .glass-hover:hover { 161 161 background: rgba(255, 255, 255, 0.12); 162 162 box-shadow: 163 - 0 0 0 2px rgba(255, 255, 255, 0.7), 163 + /*0 0 0 2px rgba(255, 255, 255, 0.7),*/ 164 164 0 20px 40px rgba(0, 0, 0, 0.16); 165 165 } 166 166 }