f3d16d5187
Build pipeline (scripts/build-hikes.ts) parses per-hike GPX, encodes images via sharp, reverse-geocodes the centroid against Swisstopo and emits a typed manifest under src/lib/data/hikes.generated.ts (gitignored). Track JSON + image binaries live outside /static; served in dev by a small hike-images plugin in vite.config.ts, in prod by nginx (private/ images proxied through Node + X-Accel-Redirect for auth-gating). /hikes overview: full-bleed Swisstopo hero map (HikesOverviewMap) sits under the sticky nav, drawing one polyline per route coloured by SAC tier (T1 yellow Wegweiser, T2/T3 white-red-white, T4-T6 white-blue- white). Click navigates, hover thickens + tooltips. Layer toggle, recenter, GPS controls mirror the detail map (minus images toggle). Cards drop the trail SVG, gain a per-route icon + SAC marker pictogram on the cover, altitude range, season label, and "Neu" badge for recently-published hikes. Filter bar + totals strip recompute over the currently-visible set. /hikes/[slug]: hero map with elevation profile, photo strip with map sync, scroll-position pin, GPX download, SAC marker stats + min/max altitude + season. Route-builder (/hikes/route-builder): client-side draft persisted to localStorage, EXIF-driven image placement, snap-to-route via BRouter (OSRM + linear fallback) and Swisstopo profile.json elevation enrichment that handles degenerate same-coord segments via the height endpoint. Filter init switched from a script-time snapshot of data.hikes (which sporadically returned a one-hike subset during dev hydration and locked the page to that single hike) to a post-mount \$effect. Content under src/content/hikes/ intentionally not included (WIP).
47 lines
1.2 KiB
TypeScript
47 lines
1.2 KiB
TypeScript
import type { de } from './de';
|
|
|
|
export const en = {
|
|
// Auth / user header
|
|
login: 'Login',
|
|
|
|
// (main) homepage
|
|
welcome: 'Welcome to bocken.org',
|
|
pages: 'Pages',
|
|
recipes: 'Recipes',
|
|
family_photos: 'Family Photos',
|
|
video_conferences: 'Video Conferences',
|
|
search_engine: 'Search Engine',
|
|
shopping: 'Shopping',
|
|
family_tree: 'Family Tree',
|
|
faith: 'Faith',
|
|
documents: 'Documents',
|
|
audiobooks_podcasts: 'Audiobooks & Podcasts',
|
|
nutrition: 'Nutrition',
|
|
tasks: 'Tasks',
|
|
|
|
// Offline sync button
|
|
sync_for_offline: 'Save for offline',
|
|
syncing: 'Syncing…',
|
|
offline_ready: 'Offline ready',
|
|
last_sync: 'Last sync',
|
|
recipes_word: 'recipes',
|
|
sync_now: 'Sync now',
|
|
clear_offline_data: 'Clear offline data',
|
|
offline_banner_title: 'Save recipes for the kitchen',
|
|
offline_banner_body: 'Download every recipe to your device so they stay available without internet — ideal while cooking.',
|
|
offline_banner_action: 'Download recipes',
|
|
dismiss: 'Dismiss',
|
|
offline_data: 'Offline data',
|
|
|
|
// Date picker
|
|
select_date: 'Select date',
|
|
select_time: 'Select time',
|
|
today: 'Today',
|
|
now: 'Now',
|
|
apply_inherited: 'Apply',
|
|
clear: 'Clear',
|
|
|
|
// Error view
|
|
error_label: 'Error'
|
|
} as const satisfies Record<keyof typeof de, string>;
|