150 lines
4.7 KiB
Markdown
150 lines
4.7 KiB
Markdown
# Smash or Pass — Frontend
|
|
|
|
Vue 3 + TypeScript + Vite + Pinia + Tailwind CSS v4. Talks to the [`sop-back`](../sop-back/) FastAPI server.
|
|
|
|
See [`../CLAUDE.md`](../CLAUDE.md) for full architecture notes.
|
|
|
|
---
|
|
|
|
## Stack
|
|
|
|
- Vue 3 with `<script setup lang="ts">` (TypeScript everywhere)
|
|
- Vite 8 (dev server + bundler)
|
|
- Vue Router (SPA: `/`, `/game/:id`, `/summary`)
|
|
- Pinia (game state: queue / smashed / passed)
|
|
- Tailwind CSS v4 via `@tailwindcss/vite`. Custom palette + fonts in [`src/assets/main.css`](src/assets/main.css) inside an `@theme { ... }` block.
|
|
|
|
---
|
|
|
|
## Project layout
|
|
|
|
```
|
|
sop-front/
|
|
├── index.html
|
|
├── vite.config.ts # Tailwind v4 plugin + alias '@'
|
|
├── nginx.conf # SPA fallback for production image
|
|
├── Dockerfile # multi-stage: vite build → nginx
|
|
└── src/
|
|
├── main.ts # imports ./assets/main.css
|
|
├── App.vue # only <RouterView />
|
|
├── router/index.ts
|
|
├── api/client.ts # typed fetch wrapper, reads VITE_API_BASE_URL
|
|
├── stores/game.ts # Pinia store
|
|
├── assets/main.css # Tailwind + @theme tokens (palette, fonts)
|
|
├── components/
|
|
│ ├── SwipeCard.vue # pointer-event drag, exposes triggerSmash/Pass
|
|
│ └── AdminPanel.vue
|
|
└── views/
|
|
├── HomeView.vue
|
|
├── GameView.vue
|
|
└── SummaryView.vue
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
One environment variable, **build-time** (Vite inlines it):
|
|
|
|
| Var | Default | Notes |
|
|
|---|---|---|
|
|
| `VITE_API_BASE_URL` | `http://localhost:8000` | Backend origin |
|
|
|
|
For dev, set in a `.env.local`:
|
|
|
|
```
|
|
VITE_API_BASE_URL=http://localhost:8000
|
|
```
|
|
|
|
For Docker builds, pass it as a build arg (already wired in the repo-root `docker-compose.yml`):
|
|
|
|
```yaml
|
|
frontend:
|
|
build:
|
|
context: ./sop-front
|
|
args:
|
|
VITE_API_BASE_URL: "https://api.example.com"
|
|
```
|
|
|
|
---
|
|
|
|
## Local development
|
|
|
|
```bash
|
|
cd sop-front
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
- App: http://localhost:5173
|
|
- Make sure the backend is running at `VITE_API_BASE_URL` (default `http://localhost:8000`).
|
|
|
|
### Other scripts
|
|
|
|
| Command | What |
|
|
|---|---|
|
|
| `npm run dev` | Vite dev server with HMR |
|
|
| `npm run build` | Type-check + production build into `dist/` |
|
|
| `npm run type-check` | `vue-tsc --build` only |
|
|
| `npm run preview` | Serve the built `dist/` locally |
|
|
| `npm run lint` | oxlint + eslint |
|
|
| `npm run format` | Prettier |
|
|
| `npm run test:unit` | Vitest |
|
|
|
|
---
|
|
|
|
## Customizing colors / fonts
|
|
|
|
**All design tokens live in [`src/assets/main.css`](src/assets/main.css)** under `@theme`. Add new colors there as `--color-<name>: #hex;` and they become available as Tailwind utilities (`bg-<name>`, `text-<name>`) and as `var(--color-<name>)`. Don't hardcode hex values in components.
|
|
|
|
Current palette comes from the user's reference image:
|
|
|
|
| Token | Hex | Role |
|
|
|---|---|---|
|
|
| `--color-clothes` | `#8324DE` | Primary purple (CTAs) |
|
|
| `--color-smash` / `--color-tongue` | `#B9D532` | Smash green |
|
|
| `--color-pass` / `--color-iris` | `#FF453B` | Pass red |
|
|
| `--color-bg` | `#16141A` | Dark grey background |
|
|
| `--color-surface` | `#1F1C24` | Card surface |
|
|
| `--color-fur` | `#FBF9FD` | Off-white text |
|
|
|
|
Fonts: **Bebas Neue** (display) + **Inter** (body), loaded via Google Fonts in `main.css`.
|
|
|
|
---
|
|
|
|
## Production deployment
|
|
|
|
### Docker (recommended)
|
|
|
|
A multi-stage Dockerfile builds the SPA with Vite and serves the static bundle with nginx. From the repo root:
|
|
|
|
```bash
|
|
docker compose up -d --build frontend
|
|
```
|
|
|
|
The image listens on port 80 inside the container; the compose file maps it to host `:8080`.
|
|
|
|
For a real deployment:
|
|
|
|
1. **Set `VITE_API_BASE_URL`** to the public backend URL **at build time** (build arg, not runtime env). Rebuild the image whenever it changes.
|
|
2. **Front it with HTTPS** — Caddy / Traefik / Cloudflare in front of port 80.
|
|
3. The bundled `nginx.conf` already does SPA fallback (`try_files $uri /index.html`).
|
|
4. Make sure the backend CORS `ALLOWED_ORIGINS` includes the frontend's public origin.
|
|
|
|
### Static hosting (no Docker)
|
|
|
|
```bash
|
|
npm install
|
|
VITE_API_BASE_URL=https://api.example.com npm run build
|
|
```
|
|
|
|
Upload the contents of `dist/` to any static host (S3+CloudFront, Netlify, Vercel, GitHub Pages, etc.). Configure SPA fallback so any unknown path serves `index.html`.
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- `VITE_API_BASE_URL` is **baked into the JS bundle** at build time. Changing it requires a rebuild.
|
|
- All API calls go through [`src/api/client.ts`](src/api/client.ts) — extend that wrapper rather than calling `fetch` directly from components.
|
|
- The admin panel renders only when `GET /admin/status` returns `admin_enabled: true`. That flag lives in the **backend's** `.env`.
|