Commit Graph

270 Commits

Author SHA1 Message Date
Davide Scaini 29eb1dfcdc feat: show percentage next to progress bar in month header 2026-06-03 23:55:52 +02:00
Davide Scaini e967ef5322 feat: show goal progress bar inline in month header row 2026-06-03 23:51:43 +02:00
Davide Scaini 7a20af72fa feat: collapsible month rows in running costs, most recent auto-expanded 2026-06-03 23:47:09 +02:00
Davide Scaini da351cc53b feat: add weight fields to athlete profile and gear items 2026-06-03 23:39:03 +02:00
Davide Scaini 3624fd051f fix: TS syntax in define:vars IIFEs causes SyntaxError — use plain JS for authUrl 2026-06-03 22:03:21 +02:00
Davide Scaini ac18b73c07 feat: email field in settings — lets users set address for self-service password reset 2026-06-03 21:56:35 +02:00
Davide Scaini 5f916461ac fix: logout loop — authUrl was empty in user-widget script due to Astro 5 define:vars behaviour; read from window.__bincioAuthUrl instead
CI / Python tests (push) Waiting to run
CI / Frontend build (push) Waiting to run
2026-06-03 21:23:49 +02:00
Davide Scaini e24d290127 fix: show reset URL inline in admin table (was hidden in tooltip)
CI / Python tests (push) Waiting to run
CI / Frontend build (push) Waiting to run
2026-06-03 12:05:10 +02:00
Davide Scaini 7e8545f8db fix: redirect back to activity.bincio.org after login via bincio.org
Pass ?next=<current URL> when bouncing to bincio.org/login/ so the user
lands back on the activity page they came from instead of bincio.org/.
2026-06-03 11:33:37 +02:00
Davide Scaini ae2737fed1 fix: admin page script crashes — define:vars bypasses TypeScript compilation; use data attribute instead 2026-06-03 11:28:38 +02:00
Davide Scaini 4641ca9b72 fix: show Select button only on own profile feed, not community feed 2026-06-03 11:11:47 +02:00
Davide Scaini 7cec9541e2 fix: restore broken <a> tag in nav after Ideas removal 2026-06-03 11:09:26 +02:00
Davide Scaini 37e91af5bd feat: move Ideas into Support page tab; remove Ideas from nav 2026-06-03 11:07:35 +02:00
Davide Scaini 08f451ec71 feat: recurring budget entries (lazy materialise) + preferred Satispay badge 2026-06-03 10:47:58 +02:00
Davide Scaini cf7ce027b1 fix: support page — donate default tab, split community tab, require login 2026-06-03 10:41:59 +02:00
Davide Scaini fa14d91359 feat: Support page with budget transparency (replaces About) 2026-06-03 10:34:18 +02:00
Davide Scaini b781193d44 feat: bulk delete + merge activities in feed
- Select mode in ActivityFeed: toggle with Select button (logged-in only),
  cards become clickable with checkmark indicator, action bar fixed at bottom
- Bulk delete: calls existing DELETE /api/activity/{id} for each selected,
  removes from local feed state immediately
- Bulk merge: POST /api/merge sorts by started_at (earliest = primary),
  sums distance/duration/elevation, weighted-averages HR/power, concatenates
  geojson and timeseries; backs up originals to _merge_backup/ for recovery
- GET /api/merges returns per-user hidden list; feed filters secondaries
  client-side on load so static shards don't need a rebuild to hide them
- POST /api/unmerge/{id} restores primary from backup, unhides secondaries
- ActivityDetail: shows "Merged (N)" badge + Unmerge button for owners
- Fix: edit button now works from personal profile feed (handle was missing
  from year-shard activities; injected from filterHandle on sessionStorage write)
2026-06-03 10:32:02 +02:00
Davide Scaini 5287b98bc1 fix: admin reset-pwd button copies full bincio.org link instead of bare code 2026-06-03 09:42:24 +02:00
Davide Scaini 0e5044eb06 fix: close all bincio-auth migration holes
Pages (register, reset-password, invites) now redirect to bincio.org
like login already did. Admin user-state ops (reset-password-code,
suspend, unsuspend, delete account) are proxied to bincio-auth via
httpx so they write to the correct DB. Adds BINCIO_AUTH_API env var.
2026-06-03 09:36:20 +02:00
Davide Scaini 5255e24184 feat: default chart x-axis to distance 2026-06-02 16:49:21 +02:00
Davide Scaini c59fc0073f feat: pace chart and spm cadence for running/hiking/walking/other
Speed tab becomes Pace tab (min/km, y-axis inverted so faster = top).
Cadence label switches to spm. Tooltip and reference lines use m:ss format.
2026-06-02 16:46:16 +02:00
Davide Scaini a142e8732f fix: redirect login to bincio.org (bincio-auth) when PUBLIC_AUTH_URL is set
activity.bincio.org/login/ was issuing plain session tokens; bincio-activity
now validates JWTs, so that path silently broke. Auth wall and logout now
point to the central bincio-auth service instead.
2026-06-02 16:31:46 +02:00
Davide Scaini 13859a34d3 feat: show pace (min/km) for running, hiking, walking, other activities
Cycling keeps km/h; pace sports show e.g. "5:30 /km" in the feed card,
activity stat panel (avg/max), and laps table.
2026-06-02 16:23:03 +02:00
Davide Scaini b827792d16 feat: export gear maintenance log as CSV 2026-05-24 14:07:37 +02:00
Davide Scaini 94cd3f7eb4 fix: show replacement dates as dd/mm/yyyy 2026-05-24 14:01:53 +02:00
Davide Scaini bdee036204 feat: part lifespan tracking in gear tab
API (gear.py):
- POST   /api/gear/{id}/parts
- PATCH  /api/gear/{id}/parts/{pid}
- DELETE /api/gear/{id}/parts/{pid}
- POST   /api/gear/{id}/parts/{pid}/replacements
- DELETE /api/gear/{id}/parts/{pid}/replacements/{rid}

UI (AthleteView.svelte):
- Gear rows are now accordion-expandable
- Collapsed row shows colored status dots (green/yellow/red) per part
- Expanded section: parts list with km-since-replacement colored by threshold,
  Replaced button with date+note form, recent log entries, add-part form
- Contextual suggestion for first part (chain for bikes, shoes for running)
- Edit/delete gear moved into expanded section
2026-05-24 13:40:27 +02:00
Davide Scaini 801140ac51 feat: show accumulated distance per gear item in gear tab
Compute total distance from allActivities where gear name matches and
display it inline next to each gear item. Also add gear field to
ActivitySummary type so index shard gear data is accessible in the UI.
2026-05-24 13:06:37 +02:00
Davide Scaini e553e08663 feat: gear registry — manage bikes/shoes per athlete, set per activity
- New /api/gear CRUD endpoints (gear.json per user)
- Gear tab in AthleteView (owner-only): add, edit, retire items
- EditDrawer gear field becomes a dropdown when registry has items
- Strava API sync now resolves gear_id → name, adds to registry automatically
- Strava ZIP import reads Gear column from activities.csv
- POST /api/strava/import-gear for one-time backfill from stored originals
2026-05-24 12:33:41 +02:00
Davide Scaini aca9f79b46 fix: slope tooltip clipping — use clip:false + marginTop instead of dy function 2026-05-23 22:24:55 +02:00
Davide Scaini 40aa51be4d fix: flip slope tooltip below dot when near chart top edge 2026-05-23 22:06:02 +02:00
Davide Scaini df025873c6 Add map view toggle to activity feed
Adds a List/Map toggle to the feed and @user profile pages. The map view
plots all filtered activities as sport-coloured tracks on a MapLibre map
with no extra requests (uses preview_coords already in memory). Clicking
a track or list row selects it: pans the map to fit, expands the list
item with key stats, and scrolls it into view.
2026-05-22 11:47:47 +02:00
Davide Scaini 7f2a751065 feat: power curve chart on activity page (single-activity MMP) 2026-05-21 21:29:29 +02:00
Davide Scaini 793b719983 fix: stable power curve colors — buttons and chart lines always match 2026-05-21 21:15:44 +02:00
Davide Scaini d4e5b11f71 admin: add Total imported and Last sync columns to Garmin sync table
Matches the Strava sync table layout. Accumulates total_imported in
garmin_sync.json state on each sync run; admin API exposes last_sync_at
and total_imported from that file.
2026-05-21 20:34:25 +02:00
Davide Scaini 29c6e399c0 perf: skip feed index fetch when navigating from activity feed
Write the activity summary to sessionStorage on click in ActivityFeed,
then read it synchronously at module init in ActivityDetailLoader so the
page renders immediately without the "Loading activity…" blank screen
or the 2 round-trip index fetch.

Direct URL / bookmark / shared link falls through to the existing slow
path unchanged.
2026-05-19 19:44:20 +02:00
Davide Scaini bbfab72138 ActivityCharts: switch slope tab to distance-weighted smoothing
Replace time-based rolling mean with a 400 m distance-weighted sliding-
window average (O(n), two advancing pointers) matching the spec in
SLOPE_COLORING.md. Slope values are now spatially consistent regardless
of riding speed. Smoothing buttons are hidden when the slope tab is
active.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 19:03:56 +02:00
Davide Scaini 6faf63c2cd ActivityCharts: add slope coloring tab to elevation profile
New "Slope" tab colours the filled area and stroke line with an SVG
linearGradient driven by per-point slope data (green→yellow→orange→red→
purple scale). Slope is computed from smoothed elevation + cumulative
distance, reusing the existing raw/10s/20s smoothing controls. The
hover tooltip shows slope % (in slope colour) and elevation. Tab is
enabled only when both elevation and distance data are present; the
X-mode and histogram toggles are hidden for this tab.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:57:55 +02:00
Davide Scaini 766da0320b NerdCorner VAM: filter short climbs, opacity-encode confidence, add climbing time to tooltip
- Exclude per-activity VAM contributions where climbing_time_s < 10 min; short
  punchy efforts don't represent aerobic fitness and were skewing monthly averages
- Store climbing_time_s alongside climbing_vam_mh in metrics, detail JSON, and
  summary JSON so the frontend has the data to reason about confidence
- Accumulate total climbing time per period; opacity scales from 0.25 (10 min,
  minimum threshold) to 1.0 (≥ 1 h) so thin-evidence months read as faint dots
- Render VAM as dots only (no lines) since each period is an independent average,
  not a cumulative — lines implied continuity that isn't there
- Tooltip now shows "1060 m/h · 38 min climbing"
2026-05-17 10:13:39 +02:00
Davide Scaini 7a44cbbef0 change segment width and opacity 2026-05-17 09:51:11 +02:00
Davide Scaini 979a6c527f Segment create: load existing segments in activity bbox as reference layer 2026-05-17 09:40:41 +02:00
Davide Scaini 6bc77486f1 Segments: color track green→red along direction of travel 2026-05-17 09:32:31 +02:00
Davide Scaini 9521a64da4 Activity stats: fixed-position pairs so optional values don't shift layout 2026-05-17 09:15:11 +02:00
Davide Scaini 7953e05241 Fix build: use class ternary instead of class: directive for Tailwind /opacity class 2026-05-17 09:06:04 +02:00
Davide Scaini db9b4ce32c Activity map: click stat to lock track color mode, hover still previews 2026-05-17 09:01:59 +02:00
Davide Scaini 14a4a0b994 Activity detail: layout refactor + GPS-derived speed for map coloring
Layout: map + charts stacked left, stats panel (2-col) on the right.
Cadence moved to last stat. Charts sit directly below the map.

Speed coloring: most FIT files don't record per-second speed, leaving
timeseries speed_kmh all-null and the hover link dead. Fix: derive speed
from consecutive GPS coordinates (haversine + 5-pt moving average) when
the device didn't record it. Add --backfill-speed render flag to retrofit
existing timeseries files.
2026-05-16 23:24:29 +02:00
Davide Scaini 0dc450ba30 Fix track coloring hover: inline reactive vars so Svelte tracks deps
statColorMode() hid hasSpeedTrack etc. from Svelte's compiler so the
{#each} block never re-rendered when timeseries loaded. Inline the
ternary directly so all reactive variables are visible to the tracker.
2026-05-16 22:56:20 +02:00
Davide Scaini 1cca485062 Activity map: extend track coloring to HR, power, elevation, cadence
Refactor the metric gradient code into shared _computeProgress +
_buildGradient helpers. Hovering any of speed/HR/power/elevation/cadence
stats switches the track to a blue→green→yellow→red gradient for that
metric. A small legend (min ·gradient bar· max + label) appears in the
bottom-left corner of the map while active. Absolute elevation used
(not slope), so blue=valleys, red=peaks.
2026-05-16 22:50:24 +02:00
Davide Scaini f71fe2ddf5 Activity map: color track by speed when hovering speed stats
Hovering avg/max speed in the stats panel switches the track from the
default gradient to a blue→green→yellow→red speed gradient. Progress
along the track is computed from cumulative distance (speed × time) so
fast sections appear proportionally long rather than time-weighted.
Reverts to default on mouse-leave. No-op when timeseries has no speed
data or the activity has no GPS track.
2026-05-16 22:43:12 +02:00
Davide Scaini 08e8e54c36 Power curve: show record holder in tooltip and add records table
Find the activity that holds each MMP record by scanning per-activity
mmp arrays. Activity title appears in the chart hover tooltip. A table
below the chart lists every duration with the record watts, activity
title (linked), and date. The table has its own all-time/365d/90d toggle
independent of the chart overlays.
2026-05-16 22:25:30 +02:00
Davide Scaini 003b540481 VAM: drop duration curve, show avg climbing VAM in Nerd Corner
Remove the per-duration VAM curve everywhere (metrics, summaries, detail
JSON, athlete.json, VamChart.svelte, AthleteView VAM tab). Keep only
climbing_vam_mh per activity. Add it to activity summaries so NerdCorner
can plot average climbing VAM per week/month year-over-year alongside
distance/elevation/time. Add --backfill-vam-summary flag to copy the
field from existing detail JSONs into index.json without re-extracting.
2026-05-16 22:03:40 +02:00