mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 16:03:02 +00:00
feat(tours): plan ski and winter tours, snowshoeing and winter hiking among them
Ski becomes "Ski & winter", a type the planner plans with six disciplines (alpine, snowboard, cross-country, ski touring, snowshoeing, winter hiking), nothing preselected; saving needs a discipline, and a technique for cross-country. Every leg is drawn straight between the points through planner/skiRouting.ts, the one place the piste router will plug in, with its heights from the elevation source and no ski time worked out. The hike's winter label goes entirely: its migration, column, field, marks, GPX rule, MCP field and strings. A hike is summer only; a ski tour with the snowshoe discipline exports as snowshoeing. The unreleased ski migration takes the six disciplines and the collection migration loses the winter column. The pistes are offered for a ski tour, shown until switched off, and with no tour open, never for a hike. Export, copy, collections, stages (untimed), actual tracks, the atlas, list and day marks (one glyph per discipline), 3D, planning over a ski import and list_tours/get_tour_plan know the planned ski tour.
This commit is contained in:
@@ -57,8 +57,11 @@ export interface SegmentedOption<T extends string> {
|
||||
icon?: ReactNode
|
||||
}
|
||||
|
||||
/** The track laid out as a grid of this many columns, for more choices than one row holds. */
|
||||
const SEGMENTED_COLUMNS = { 2: 'grid w-full grid-cols-2', 3: 'grid w-full grid-cols-3' } as const
|
||||
|
||||
/** A row of choices on a grey track, the chosen one raised like the status filter (or filled like the view switcher). */
|
||||
export function Segmented<T extends string>({ value, options, onChange, label, accent = false, fill = false }: {
|
||||
export function Segmented<T extends string>({ value, options, onChange, label, accent = false, fill = false, columns }: {
|
||||
value: T
|
||||
options: readonly SegmentedOption<T>[]
|
||||
onChange: (value: T) => void
|
||||
@@ -68,15 +71,18 @@ export function Segmented<T extends string>({ value, options, onChange, label, a
|
||||
accent?: boolean
|
||||
/** Stretch across the row, each option taking an equal share. */
|
||||
fill?: boolean
|
||||
/** Wrap the options into a grid of this many equal columns on the same track. */
|
||||
columns?: keyof typeof SEGMENTED_COLUMNS
|
||||
}) {
|
||||
const track = columns ? SEGMENTED_COLUMNS[columns] : fill ? 'flex w-full' : 'inline-flex'
|
||||
return (
|
||||
<div role="group" aria-label={label} className={`${fill ? 'flex w-full' : 'inline-flex'} flex-none gap-0.5 rounded-[10px] bg-surface-tertiary p-[3px]`}>
|
||||
<div role="group" aria-label={label} className={`${track} flex-none gap-0.5 rounded-[10px] bg-surface-tertiary p-[3px]`}>
|
||||
{options.map(o => {
|
||||
const on = o.value === value
|
||||
const look = on ? (accent ? 'bg-accent text-accent-text' : 'bg-surface-card text-content shadow-sm') : 'text-content-muted hover:text-content'
|
||||
return (
|
||||
<button key={o.value} type="button" onClick={() => onChange(o.value)} aria-pressed={on}
|
||||
className={`${fill ? 'flex-1' : ''} inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-[8px] px-3 py-1.5 font-medium ${look}`}
|
||||
className={`${fill ? 'flex-1' : ''} ${columns ? 'min-w-0' : ''} inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-[8px] px-3 py-1.5 font-medium ${look}`}
|
||||
style={fs(12.5, 'body')}>
|
||||
{o.icon}{o.label}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user