feat(hunt): track walking distance via GPS, show live locations on map
Docker Image CI / test (push) Failing after 41s
Docker Image CI / deploy (push) Skipped
Tests / unit (push) Failing after 36s
Tests / integration (push) Successful in 1m34s

Add foreground-only GPS distance tracking for hunts
This commit is contained in:
2026-09-27 20:55:58 +02:00
parent a0fc836c05
commit 61cc516f47
43 changed files with 2313 additions and 24 deletions
+65
View File
@@ -0,0 +1,65 @@
/**
* Client-only team color assignment for the live map.
*
* A fixed 20-color high-contrast palette is shuffled once per page-load and
* assigned to teams by their stable order (the order returned by the map
* endpoint). Colors are team-shared but NOT persisted, so a refresh may
* reassign them. Every member of a team resolves to the same color.
*/
const PALETTE = [
'#e6194b',
'#3cb44b',
'#4363d8',
'#f58231',
'#911eb4',
'#46f0f0',
'#f032e6',
'#bcf60c',
'#fabebe',
'#008080',
'#e6beff',
'#9a6324',
'#fffac8',
'#800000',
'#aaffc3',
'#808000',
'#ffd8b1',
'#000075',
'#808080',
'#ff4d00'
] as const;
function shuffled<T>(input: readonly T[]): T[] {
const arr = [...input];
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j]!, arr[i]!];
}
return arr;
}
/** Darken a hex color by a factor (0..1) for trail lines. */
export function darken(hex: string, factor = 0.75): string {
const n = parseInt(hex.slice(1), 16);
const r = Math.round(((n >> 16) & 255) * factor);
const g = Math.round(((n >> 8) & 255) * factor);
const b = Math.round((n & 255) * factor);
return `#${((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1)}`;
}
export function useTeamColors() {
// Shuffled once per composable instance (i.e. per page-load).
const colors = shuffled(PALETTE);
/** Build a teamId -> color map from an ordered list of team ids. */
function assign(orderedTeamIds: number[]): Map<number, string> {
const map = new Map<number, string>();
orderedTeamIds.forEach((id, i) => {
map.set(id, colors[i % colors.length]!);
});
return map;
}
return { assign, colors, darken };
}