Commit Graph

169 Commits

Author SHA1 Message Date
Davide Scaini 8804bdec37 Add Nerd Corner tab with year-over-year cumulative progress chart 2026-05-14 16:37:01 +02:00
Davide Scaini 487ce42361 Explore: type pill dark/light theme split; freeze active pill on hover in dark theme 2026-05-14 16:24:00 +02:00
Davide Scaini ab112788b4 Explore: grey pill background dark-theme only; transparent in light mode 2026-05-14 16:18:10 +02:00
Davide Scaini 8d799e8e64 Explore: active type pill solid color bg with auto black/white text contrast 2026-05-14 16:17:16 +02:00
Davide Scaini cfb7198d64 Explore: raise inactive type-pill background opacity to 70% for dark theme visibility 2026-05-14 16:11:48 +02:00
Davide Scaini 2b9e080b4c Explore: opacity slider heatmap-only; lines mode width-only at 100% opacity 2026-05-14 16:07:57 +02:00
Davide Scaini 20bb5bfb60 explore: grey background on inactive type pills for readability 2026-05-14 15:59:00 +02:00
Davide Scaini dc719a55d5 explore: show width/opacity sliders in lines mode too 2026-05-14 15:57:20 +02:00
Davide Scaini 5593764fdb explore: skip legacy bare-timestamp geojsons; type pill colors visible when inactive 2026-05-14 15:55:10 +02:00
Davide Scaini e7228c2be8 explore: plasma palette; width + opacity sliders for heatmap 2026-05-14 15:48:30 +02:00
Davide Scaini 298fe3ea39 explore: fix by-type layer visibility — only show selected types 2026-05-14 15:43:12 +02:00
Davide Scaini 4e32cf4f21 explore: grey map default; zoom-scaled heatmap lines; fix all/none type buttons 2026-05-14 15:35:40 +02:00
Davide Scaini a75fabecb9 explore: thicker heatmap lines (4px + blur) 2026-05-14 14:57:39 +02:00
Davide Scaini b3c41967f6 explore: replace gaussian heatmap with line-accumulation (strava-style) 2026-05-14 14:54:47 +02:00
Davide Scaini 6d13993f98 explore: default heatmap/by-type; month All button; bbox filtering on map move 2026-05-14 14:45:54 +02:00
Davide Scaini 5307ae287c Explore: personal GPS heatmap tab under Athlete page
- bincio/explore.py: bake_tracks() simplifies GPS coords (RDP ε=0.0001),
  strips to [lng,lat], groups by sport type, writes per-handle tracks.json
- bake-tracks CLI command; render CLI calls _bake_tracks() after each build;
  strava_zip runs it once at end of batch
- /api/me/tracks endpoint serves the baked file; wipe_user cleans it up
- Explore.svelte: MapLibre full-screen map with sidebar — type pills,
  year/month date filter, Lines / Heatmap (global or by-type) view modes
- AthleteView: Explore tab visible only to profile owner (checks __bincioMe)
- Base.astro: fullscreen prop + Planner nav link
2026-05-14 14:31:21 +02:00
Davide Scaini fb033e3da2 Search: auto-load all year shards when a query is entered so full history is searched 2026-05-13 21:17:55 +02:00
Davide Scaini b9a21e8bcc ideas: add inline edit for own ideas (author + admin) 2026-05-13 19:52:25 +02:00
Davide Scaini aa1c0b38c0 ideas: add Feedback button to header 2026-05-13 19:48:34 +02:00
Davide Scaini c2c4cb9f3a segments: fit initial map view to all existing segments 2026-05-13 19:41:59 +02:00
Davide Scaini d82033fd84 ideas: update bug report link text 2026-05-13 19:34:02 +02:00
Davide Scaini c30a15d295 ideas: add done/reopen status toggle for admins
Admin-only POST /api/ideas/{id}/status toggles status between open and
done. Done ideas are greyed out (opacity 0.55), show a green checkmark,
and sink to the bottom of the list. Admins see done/reopen buttons on
each card.
2026-05-13 19:32:30 +02:00
Davide Scaini 38f2e51788 ideas: add Ideas page, nav link; remove feedback button from About
New /ideas/ page with Svelte component: card list sorted by votes,
inline submit form, optimistic vote toggling, delete for own/admin.
Bug report link moved to bottom of Ideas page. Feedback button removed
from About page.
2026-05-13 19:29:39 +02:00
Davide Scaini cb3c9b6e41 Move search bar above sport/date filters, below page title 2026-05-13 11:54:37 +02:00
Davide Scaini 861748a059 ActivityFeed: add title search bar with URL sync 2026-05-13 11:51:14 +02:00
Davide Scaini f00e5e47b2 SegmentDetail: sort efforts by time by default, sortable column headers 2026-05-13 11:17:22 +02:00
Davide Scaini 0ff5473dfd Athlete segments tab: link best time to activity; expandable effort list
- best_activity_id now included in segment_summary API response
- Best time is a direct link to the activity that produced it
- Clicking a row expands an inline effort list (lazy-loaded from
  /api/segments/{id}/efforts): date linked to activity, time, Δ vs PR
- Clicking again collapses; ▲/▼ chevron shows state
2026-05-13 08:40:39 +02:00
Davide Scaini 59cf99f0af Fix stuck segments tab; add /segments/ dev fallback
AthleteView: use segmentsFetched flag to prevent infinite fetch loop when
there are no efforts (segmentSummary.length === 0 was re-triggering the
reactive statement after every empty response). Also improve empty state
message and reset flag after rescan so the table reloads.

astro.config.mjs: extend shell fallback plugin to cover /segments/{id}/
the same way /activity/{id}/ is handled, so segment detail pages work in
the dev server without nginx.
2026-05-13 08:35:00 +02:00
Davide Scaini b8fd4e4ded Move segment rescan button from segments list to athlete/segments tab 2026-05-13 08:20:05 +02:00
Davide Scaini d7fd585e77 Add global segment rescan: POST /api/me/segment-rescan + Rescan all button 2026-05-13 08:17:18 +02:00
Davide Scaini f2075e29d2 Segments Phase 4: detail page, activity efforts, athlete tab, new APIs
New API endpoints:
- GET /api/segments/{id} — single segment metadata
- GET /api/activities/{id}/segment_efforts — efforts for an activity (auth)
- GET /api/users/{handle}/segment_summary — public best time + count per segment

New components:
- SegmentDetail.svelte — map + metadata + effort table (with PR/Δ) + rescan button
- SegmentsPage.svelte — URL router: shows detail when /segments/{id}/, list otherwise

Updated:
- segments/index.astro — now uses SegmentsPage router
- nginx-activity.conf — add /segments/ try_files rule for client-side routing
- ActivityDetail.svelte — segment efforts block below laps
- AthleteView.svelte — Segments tab with best time + effort count per segment
- format.ts — add formatElapsed() for compact m:ss display
2026-05-13 08:09:24 +02:00
Davide Scaini c7f0013e57 SegmentCreate: prompt after save instead of immediate redirect; update plan
After saving, show "Saved! Add another from this activity?" with two
buttons: "Add another" (resets name/handles, keeps map loaded) and
"Done" (navigates to /segments/).
2026-05-13 01:03:34 +02:00
Davide Scaini 6c9de35426 Enforce 500 m minimum segment length in UI and API 2026-05-13 00:56:04 +02:00
Davide Scaini e9e7b5d0e7 SegmentCreate: add elevation profile that zooms to selected portion
Shows a dim area for the visible range around the selection (4% padding)
and a blue overlay for the selected segment, with a light stroke on the
top edge. Both the x-domain and y-domain track the selection, so the
chart zooms in as the handles narrow. Elevation min/max labels overlaid
at top-left and bottom-left.
2026-05-13 00:54:39 +02:00
Davide Scaini 61db0734d2 Move segment shortcut next to Edit button, shorten to '+ segment' 2026-05-13 00:39:51 +02:00
Davide Scaini dd9f7a82dc Segments phase 2: /segments/ browse page, /segments/new/ creation flow, activity detail shortcut 2026-05-13 00:36:44 +02:00
Davide Scaini 6b2698c0c5 Mark fallback NP computation for future removal 2026-05-12 23:52:19 +02:00
Davide Scaini c46e91d0f5 Compute NP from timeseries in frontend for activities missing np_power_w in JSON 2026-05-12 23:51:22 +02:00
Davide Scaini bd0595ee79 Add avg power and NP to activity summary; NP uses Coggan 30s rolling-average method 2026-05-12 23:47:06 +02:00
Davide Scaini f1fec6d825 ActivityCharts: smoothing toggle (Raw/10s/20s) for all line chart metrics 2026-05-12 23:37:41 +02:00
Davide Scaini a5db6142b3 ActivityCharts: 10s rolling mean on cadence and power line charts (display only) 2026-05-12 23:32:33 +02:00
Davide Scaini 1298586a74 ActivityCharts: extend reference lines to HR; use high-contrast label styling 2026-05-12 23:29:09 +02:00
Davide Scaini 3231fdb4b7 ActivityCharts: add avg/P20/P80 reference lines to speed, cadence, and power line charts 2026-05-12 23:24:33 +02:00
Davide Scaini 867da767eb Add sub_sport editing to activity edit drawer 2026-05-12 23:01:12 +02:00
Davide Scaini 680ef9d440 Hide edit controls on activities the logged-in user does not own 2026-05-03 18:51:52 +02:00
Davide Scaini f6e9fe8198 feat(serve): debounced site rebuild — burst uploads trigger one build, not N
Replace per-upload Astro build threads with a single background worker
(_site_rebuild_worker) that waits on an event, sleeps 60 s to let upload
bursts settle, then runs one full build + rsync. 271 concurrent uploads now
produce one build instead of 271 serialised builds, eliminating the OOM kill.
--webroot is re-enabled; merge-only path still runs immediately per upload.

Also: date filter row added to ActivityFeed.svelte (sport + date presets
with dynamic year pills); deploy/vps gitignored for VPS config backups.
2026-04-30 21:23:29 +02:00
Davide Scaini ebac3f50f4 fix: DEM elevation overcounting and add hysteresis-only recalculation button
- dem.py: apply 45s median filter before hysteresis to suppress SRTM
  tile-boundary steps that were accumulating through the 5m threshold;
  raise DEM hysteresis threshold from 5m to 10m
- dem.py: back up elevation_m as elevation_m_original in timeseries
  before the first DEM overwrite, so original sensor data is preserved
- dem.py: add recalculate_elevation_hysteresis() — recomputes gain/loss
  from original recorded elevation (reads elevation_m_original if a DEM
  run already replaced elevation_m) using source-aware thresholds
  (5m barometric, 10m GPS/unknown); does not touch the elevation array
- edit/server.py, serve/server.py: split /recalculate-elevation into
  two endpoints: /recalculate-elevation/dem and
  /recalculate-elevation/hysteresis
- EditDrawer.svelte: replace single DEM button with two side-by-side
  buttons — "Recalculate (hysteresis)" (fast, offline) and
  "Recalculate (DEM)" (SRTM lookup)
2026-04-20 21:41:23 +02:00
Davide Scaini 1940e2409b feat: DEM-based elevation recalculation via edit drawer button
Adds a "Recalculate from terrain map (DEM)" button to the activity edit
drawer. On click it queries an Open-Elevation-compatible API to replace
GPS altitude with SRTM terrain data, applies 5m hysteresis, and updates
the activity's elevation stats and timeseries chart in place.

- bincio/extract/dem.py: lookup_elevations() (batched HTTP POST) +
  recalculate_elevation() (subsample → DEM → interpolate → hysteresis →
  patch activity JSON, timeseries JSON, index.json)
- POST /api/activity/{id}/recalculate-elevation on both serve and edit
  servers; serve endpoint is auth-gated and triggers merge + rebuild
- --dem-url flag (also DEM_URL env var) on bincio serve and bincio edit;
  logged at startup; missing URL returns a clear 503 with setup instructions
- /api/me response gains dem_configured bool
- EditDrawer: button with loading state, shows new ↑/↓ values on success
2026-04-20 20:45:06 +02:00
Davide Scaini 6491e4fd8c fix: show total activity count in global feed counter
The counter now shows "50 of 16398 activities" using the total from
feed.json, matching the previous behaviour where all activities were
loaded upfront.
2026-04-20 17:12:50 +02:00
Davide Scaini 104328bc50 fix: stable y-axis range and sane dist_km in activity charts
Three bugs in the time↔distance x-axis toggle:

1. GPS speed glitches (e.g. a 1-second spike at 222 km/h) were accumulated
   into dist_km, pushing all subsequent points ~60 m too far right on the
   distance axis and compressing the rest of the chart.  Cap speed at 150 km/h
   during dist_km integration; values above that are treated as 0 movement.

2. Observable Plot auto-infers the y domain from plottable points only.
   When x-mode changes, which points are "plottable" changes too, so the
   y axis range silently shifted between time and distance views.  Fix by
   computing lineDomainMin/Max once from the full dataset and passing an
   explicit domain to Plot.

3. monotone-x curve requires strictly increasing x.  In distance mode,
   stopped segments produce consecutive points with identical dist_km,
   causing NaN Bézier control points and visual artifacts.  Use linear
   curve for distance mode (data is dense enough that it looks smooth).
2026-04-20 17:06:56 +02:00