feat(ui): scaffold vite + react 19 frontend

Replaces the CRA + React 16 + class-component frontend with the
shape from architecture/generic.md §4: vite + react + swc + ts,
served as static from nginx in prod, vite dev server in dev with
/api proxied to localhost:8080.

Layout:
  ui/
    package.json, vite.config.ts, tsconfig.{json,app,node}.json
    index.html
    src/
      main.tsx           — react root + react-query provider
      App.tsx            — header, filters, vertical timeline
      App.css            — dark backdrop, hot-pink links
      api/client.ts      — TS types mirroring moments-entities;
                            fetchEvents, fetchSources via /api/v1
      components/
        Filters.tsx      — source toggles, count slider, date range
        TimelineEntry.tsx — renders one TimelineItem with body
                             support for markdown, commits, links
      lib/icon.tsx       — TimelineIcon → react-bootstrap-icons map
                            + colour per icon

Stack: react 19, @tanstack/react-query 5, react-bootstrap 2 (on
bootstrap 5), react-vertical-timeline-component 3, rc-slider 11
(<Slider range /> replaces the removed v8 Range), react-markdown 9.

Dev proxy: /api/* → http://localhost:8080/* (rewrite strips /api).
Backend stays location-agnostic at /v1; ingress prefix is added
by nginx (and the dev proxy) so the same fetch shape works in
both environments.

Verified: tsc -b clean, vite build clean (417 KB js / 245 KB css
gzip 128 / 33), vite dev server serves the index. NOT verified
visually in a browser — that's a `pnpm run dev` away on roosta
once the api is up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-03 19:18:32 +03:00
parent 7772393598
commit b04afd83f9
15 changed files with 2656 additions and 0 deletions

31
ui/package.json Normal file
View File

@@ -0,0 +1,31 @@
{
"name": "moments-ui",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview",
"lint": "tsc --noEmit"
},
"dependencies": {
"@tanstack/react-query": "^5.62.0",
"bootstrap": "^5.3.3",
"rc-slider": "^11.1.7",
"react": "^19.0.0",
"react-bootstrap": "^2.10.6",
"react-bootstrap-icons": "^1.11.4",
"react-dom": "^19.0.0",
"react-markdown": "^9.0.1",
"react-vertical-timeline-component": "^3.6.0"
},
"devDependencies": {
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@types/react-vertical-timeline-component": "^3.3.6",
"@vitejs/plugin-react-swc": "^3.7.2",
"typescript": "~5.7.0",
"vite": "^6.0.0"
}
}