Replace this description with a short summary of what this project does.
| Tool | Role |
|---|---|
| Vite | Dev server & bundler |
| TypeScript | Language |
| React | UI framework |
| Tailwind CSS v4 | Styling |
| shadcn/ui | Component library (radix-nova style, neutral base) |
| Biome | Linter & formatter |
| Vitest | Unit testing (jsdom) |
| Husky + lint-staged | Pre-commit hook |
| commitlint | Commit message linting |
| semantic-release | Automated versioning & changelog |
| GitHub Actions | CI, releases, and deployment |
| Cloudflare Pages | Hosting |
- Node.js ≥ 24 (the exact version is pinned in
.nvmrc— usenvm useif you have nvm) - npm (comes with Node)
npm install| Script | Description |
|---|---|
npm run dev |
Start the Vite dev server at http://localhost:5173 |
npm run build |
Type-check + production build → dist/ |
npm run preview |
Serve the production build locally |
npm run verify |
TypeScript type check only (no output files) |
npm run check |
Biome lint & format check (dry run) |
npm run fix |
Biome lint & format with auto-fix |
npm test |
Run tests in watch mode via Vitest |
npm run coverage |
Single test run with coverage report |
shadcn/ui components are not bundled, they are copied into src/components/ui/ when added:
npx shadcn@latest add <component>The theme uses CSS custom properties defined in src/style.css. Dark mode is applied by toggling the .dark class on any ancestor element (typically <html>).
Biome handles both linting and formatting in one tool. The pre-commit hook runs lint-staged, which automatically runs biome check --write on every staged .js, .jsx, .ts, .tsx, .json, .css, etc. file before a commit goes through.
Tests live in src/tests/. The environment is jsdom, so DOM APIs are available.
@ is aliased to ./src:
import { something } from '@/utils/something'The current package.json version is exposed at runtime as the global __APP_VERSION__ (a string), injected by Vite at build time:
console.log(__APP_VERSION__) // e.g. "1.3.0"This project enforces Conventional Commits via commitlint. The commit-msg Git hook rejects any message that doesn't follow the format:
<type>(<optional scope>): <short description>
Common types: feat, fix, chore, docs, test, refactor, perf, ci.
Why this matters:
semantic-releasereads the commit history to determine the next version number and generate the changelog. Afeattriggers a minor bump, afixtriggers a patch, and aBREAKING CHANGEfooter triggers a major bump.
The GitHub Actions workflow (.github/workflows/ci.yml) has two jobs.
check — runs on every push and pull request to dev, develop, main, or master:
npm run check— Biome lint & format checknpm run verify— TypeScript type checknpm test— Vitest test suitenpm run build— production build
release-deploy — runs on push to main / master only, after check passes:
- Runs
semantic-releaseto bump the version, updateCHANGELOG.md, and create a GitHub Release. - Rebuilds the app so the injected version matches the new release.
- Deploys to Cloudflare Pages.