diff --git a/frontend/src/lib/components/ActivityCard.svelte b/frontend/src/lib/components/ActivityCard.svelte index 7b36c3c..08b8600 100644 --- a/frontend/src/lib/components/ActivityCard.svelte +++ b/frontend/src/lib/components/ActivityCard.svelte @@ -6,11 +6,14 @@ import FileIcon from '~icons/mdi/file'; import TrashIcon from '~icons/mdi/trash-can'; import { formatDateInTimezone } from '$lib/dateUtils'; + import { getDistance, getElevation } from '$lib'; export let activity: Activity; export let trails: Trail[]; export let visit: Visit | TransportationVisit; + export let measurementSystem: 'metric' | 'imperial' = 'metric'; + export let readOnly: boolean = false; $: trail = activity.trail ? trails.find((t) => t.id === activity.trail) : null; @@ -35,7 +38,10 @@
{#if activity.distance}
- Distance: {activity.distance} km + Distance: {getDistance(measurementSystem, activity.distance)} + {measurementSystem === 'imperial' ? 'miles' : 'km'} {#if activity.moving_time} Time: {activity.moving_time} {/if} @@ -45,10 +51,16 @@ {#if activity.elevation_gain || activity.elevation_loss}
{#if activity.elevation_gain} - ↗ {activity.elevation_gain}m + ↗ {getElevation(measurementSystem, activity.elevation_gain)} + {measurementSystem === 'imperial' ? 'feet' : 'm'} {/if} {#if activity.elevation_loss} - ↘ {activity.elevation_loss}m + ↘ {getElevation(measurementSystem, activity.elevation_loss)} + {measurementSystem === 'imperial' ? 'feet' : 'm'} {/if}
{/if} diff --git a/frontend/src/lib/components/NewLocationModal.svelte b/frontend/src/lib/components/NewLocationModal.svelte index 1576923..91ba2d0 100644 --- a/frontend/src/lib/components/NewLocationModal.svelte +++ b/frontend/src/lib/components/NewLocationModal.svelte @@ -294,6 +294,7 @@ steps[2].selected = true; }} on:close={() => close()} + measurementSystem={user?.measurement_system || 'metric'} /> {/if}
diff --git a/frontend/src/lib/components/StravaActivityCard.svelte b/frontend/src/lib/components/StravaActivityCard.svelte index 11a70ee..12c67b3 100644 --- a/frontend/src/lib/components/StravaActivityCard.svelte +++ b/frontend/src/lib/components/StravaActivityCard.svelte @@ -6,6 +6,7 @@ const dispatch = createEventDispatcher(); export let activity: StravaActivity; + export let measurementSystem: 'metric' | 'imperial' = 'metric'; interface SportConfig { color: string; @@ -48,10 +49,21 @@ }); } - function formatPace(seconds: number): string { + function formatPace(seconds: number, system: 'metric' | 'imperial'): string { const minutes = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); - return `${minutes}:${secs.toString().padStart(2, '0')}`; + const unit = system === 'metric' ? 'km' : 'mi'; + return `${minutes}:${secs.toString().padStart(2, '0')}/${unit}`; + } + + function convertElevation( + meters: number, + system: 'metric' | 'imperial' + ): { value: number; unit: string } { + if (system === 'imperial') { + return { value: meters * 3.28084, unit: 'ft' }; + } + return { value: meters, unit: 'm' }; } function handleImportActivity() { @@ -59,6 +71,21 @@ } $: typeConfig = getTypeConfig(activity.sport_type); + $: distance = + measurementSystem === 'metric' + ? { value: activity.distance_km, unit: 'km' } + : { value: activity.distance_miles, unit: 'mi' }; + $: speed = + measurementSystem === 'metric' + ? { value: activity.average_speed_kmh, unit: 'km/h' } + : { value: activity.average_speed_mph, unit: 'mph' }; + $: maxSpeed = + measurementSystem === 'metric' + ? { value: activity.max_speed_kmh, unit: 'km/h' } + : { value: activity.max_speed_mph, unit: 'mph' }; + $: elevation = convertElevation(activity.total_elevation_gain, measurementSystem); + $: paceSeconds = + measurementSystem === 'metric' ? activity.pace_per_km_seconds : activity.pace_per_mile_seconds;
@@ -147,8 +174,8 @@
Distance
-
{activity.distance_km.toFixed(2)}
-
km ({activity.distance_miles.toFixed(2)} mi)
+
{distance.value.toFixed(2)}
+
{distance.unit}
Time
@@ -157,13 +184,13 @@
Avg Speed
-
{activity.average_speed_kmh.toFixed(1)}
-
km/h ({activity.average_speed_mph.toFixed(1)} mph)
+
{speed.value.toFixed(1)}
+
{speed.unit}
Elevation
-
{activity.total_elevation_gain.toFixed(0)}
-
m gain
+
{elevation.value.toFixed(0)}
+
{elevation.unit} gain
@@ -197,15 +224,16 @@
- {#if activity.pace_per_km_seconds} + {#if paceSeconds}
Pace: - {formatPace(activity.pace_per_km_seconds)}/km + {formatPace(paceSeconds, measurementSystem)}
Max Speed: - {activity.max_speed_kmh.toFixed(1)} km/h + {maxSpeed.value.toFixed(1)} + {maxSpeed.unit}
{/if} diff --git a/frontend/src/lib/components/locations/LocationVisits.svelte b/frontend/src/lib/components/locations/LocationVisits.svelte index 69eb83a..f7e9711 100644 --- a/frontend/src/lib/components/locations/LocationVisits.svelte +++ b/frontend/src/lib/components/locations/LocationVisits.svelte @@ -45,6 +45,7 @@ export let visits: (Visit | TransportationVisit)[] | null = null; export let objectId: string; export let trails: Trail[] = []; + export let measurementSystem: 'metric' | 'imperial' = 'metric'; const dispatch = createEventDispatcher(); @@ -627,7 +628,7 @@ name: stravaActivity.name, type: stravaActivity.type, sport_type: stravaActivity.sport_type || stravaActivity.type, - distance: stravaActivity.distance ? stravaActivity.distance / 1000 : null, // Convert to km + distance: stravaActivity.distance || null, // Keep in meters moving_time: stravaActivity.moving_time ? formatDuration(stravaActivity.moving_time) : '', elapsed_time: stravaActivity.elapsed_time ? formatDuration(stravaActivity.elapsed_time) @@ -1175,7 +1176,6 @@ class="input input-bordered input-sm w-full mt-1" placeholder="Morning Run" bind:value={activityForm.name} - readonly={!!pendingStravaImport[visit.id]} />
@@ -1588,6 +1588,7 @@ {activity} {trails} {visit} + {measurementSystem} on:delete={(event) => deleteActivity(event.detail.visitId, event.detail.activityId)} /> @@ -1619,6 +1620,7 @@ handleStravaActivityImport(event, visit.id)} + {measurementSystem} /> {/each} diff --git a/frontend/src/lib/index.ts b/frontend/src/lib/index.ts index 19eb3c8..ce4ca26 100644 --- a/frontend/src/lib/index.ts +++ b/frontend/src/lib/index.ts @@ -623,3 +623,22 @@ export function getBasemapUrl() { } return 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json'; } + +export function getDistance(measurementSystem: 'metric' | 'imperial', meters: number): string { + if (measurementSystem === 'imperial') { + const miles = meters / 1609.34; + return miles.toFixed(2); + } else { + const km = meters / 1000; + return km.toFixed(2); + } +} + +export function getElevation(measurementSystem: 'metric' | 'imperial', elevation: number): string { + if (measurementSystem === 'imperial') { + const feet = elevation * 3.28084; + return Math.round(feet).toString(); + } else { + return Math.round(elevation).toString(); + } +} diff --git a/frontend/src/routes/locations/[id]/+page.svelte b/frontend/src/routes/locations/[id]/+page.svelte index ccbf96b..8e343e0 100644 --- a/frontend/src/routes/locations/[id]/+page.svelte +++ b/frontend/src/routes/locations/[id]/+page.svelte @@ -613,6 +613,7 @@ readOnly={true} trails={adventure.trails} {visit} + measurementSystem={data.user?.measurement_system || 'metric'} /> {/each}