Alex, delivered as a service.
A static marketing site promoting the professional services of Alex. Built as a fast, modern SSG site — no backend, just signal.
- Vite — build tool & dev server
- vite-react-ssg — static site generation (pre-renders each route to its own HTML file at build time)
- React — component model
- React Router — client-side routing
- TypeScript — type safety
- Tailwind CSS v4 — utility-first styling with class-based dark mode
- vite-plugin-svgr — SVG files as inline React components
- Vitest — unit testing
- Prettier — code formatting (semicolons on, single quotes)
- ESLint — linting (with
eslint-config-prettierto avoid conflicts)
pnpm install
pnpm dev| Command | Description |
|---|---|
pnpm dev |
Start local dev server at http://localhost:5173 |
pnpm build |
Pre-render all routes to static HTML via vite-react-ssg |
pnpm preview |
Preview the production build locally |
pnpm test |
Run unit tests with Vitest |
pnpm lint |
Lint with ESLint |
pnpm format |
Format all source files with Prettier |
pnpm format:check |
Check formatting without writing (useful in CI) |
src/
├── assets/
│ └── icons/ # SVG icon files (imported as React components via ?react)
├── components/
│ ├── Footer.tsx
│ ├── Header.tsx
│ ├── Layout.tsx # Root shell — composes Header, Outlet, Footer
│ ├── Nav.tsx
│ └── ThemeToggle.tsx
├── hooks/
│ └── useTheme.ts # Dark/light mode toggle, persists to localStorage
├── pages/
│ ├── Home.tsx # Landing page with hero / value proposition
│ ├── About.tsx
│ └── Contact.tsx
├── test/
│ └── setup.ts # Vitest setup (jest-dom matchers)
├── routes.tsx # Route manifest — each entry pre-renders to its own HTML
├── main.tsx # ViteReactSSG entry point
└── index.css # Tailwind import + class-based dark mode variant
Dark mode is on by default. The toggle in the header switches between dark and light, persisting the preference to localStorage. An inline script in index.html applies the correct class before React hydrates to prevent any flash of the wrong theme.