Synchronous path + rendering for the surface/waytype breakdown: - map-core `computeSurfaceBreakdown(coords, surfaces, highways)` → distance- weighted metres per surface + waytype category (unit-tested); - `SurfaceBreakdownSchema` in @trails-cool/api; - nullable `surfaceBreakdown` jsonb on routes + activities; - Planner `SaveToJournalButton` computes it from the BRouter waytags already in routeData and sends it; `api.save-to-journal` forwards it; the journal route callback validates + persists (journal is the authoritative validator); - `SurfaceBreakdown` component (stacked bars per dimension, map-core palettes, legend category · % · km largest-first, unknown → "other", hidden when empty) on route + activity detail; journal gains a @trails-cool/map-core dep; - i18n journal.surface.* (en + de). Phase 2 (async Overpass backfill + SSE for imports/uploads, and the e2e that seeds a breakdown) follows in a separate PR. Tests: computeSurfaceBreakdown unit (map-core 36); SurfaceBreakdown component (jsdom, journal 326). typecheck + lint green; verified in the browser. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
57 lines
1.7 KiB
JSON
57 lines
1.7 KiB
JSON
{
|
|
"name": "@trails-cool/journal",
|
|
"private": true,
|
|
"version": "0.0.1",
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "react-router dev",
|
|
"build": "react-router build",
|
|
"start": "node --experimental-strip-types server.ts",
|
|
"typecheck": "react-router typegen && tsc",
|
|
"lint": "eslint .",
|
|
"test": "vitest run"
|
|
},
|
|
"dependencies": {
|
|
"@fedify/fedify": "2.2.5",
|
|
"@js-temporal/polyfill": "^0.5.1",
|
|
"@logtape/logtape": "^2.1.4",
|
|
"@react-router/node": "catalog:",
|
|
"@react-router/serve": "catalog:",
|
|
"@sentry/node": "catalog:",
|
|
"@sentry/react": "catalog:",
|
|
"@simplewebauthn/browser": "^13.3.0",
|
|
"@simplewebauthn/server": "^13.3.0",
|
|
"@trails-cool/api": "workspace:*",
|
|
"@trails-cool/db": "workspace:*",
|
|
"@trails-cool/fit": "workspace:*",
|
|
"@trails-cool/gpx": "workspace:*",
|
|
"@trails-cool/i18n": "workspace:*",
|
|
"@trails-cool/jobs": "workspace:*",
|
|
"@trails-cool/map-core": "workspace:*",
|
|
"@trails-cool/sentry-config": "workspace:*",
|
|
"@trails-cool/types": "workspace:*",
|
|
"drizzle-orm": "catalog:",
|
|
"isbot": "^5.1.42",
|
|
"jose": "^6.2.3",
|
|
"nodemailer": "^8.0.11",
|
|
"pino": "^10.3.1",
|
|
"prom-client": "^15.1.3",
|
|
"react": "catalog:",
|
|
"react-dom": "catalog:",
|
|
"react-router": "catalog:",
|
|
"zod": "^4.4.3"
|
|
},
|
|
"devDependencies": {
|
|
"@react-router/dev": "catalog:",
|
|
"@simplewebauthn/types": "^12.0.0",
|
|
"@tailwindcss/vite": "catalog:",
|
|
"@types/nodemailer": "^8.0.1",
|
|
"@types/react": "catalog:",
|
|
"@types/react-dom": "catalog:",
|
|
"@vitejs/plugin-basic-ssl": "^2.3.0",
|
|
"pino-pretty": "^13.1.3",
|
|
"tailwindcss": "catalog:",
|
|
"typescript": "catalog:",
|
|
"vite": "catalog:"
|
|
}
|
|
}
|