mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
Reach the track colour from the mobile sheet
MPlaceSheet had no relation to route_geometry at all, so the section is new. It saves through the single-field patch the sheet already uses for the image, which keeps it clear of the edit form and its prefill. The browse list gets the same colour stroke as the desktop sidebar. It matters more here: the mobile map is full-bleed with no sidebar next to it, so without the stroke a coloured line has nothing to tie it to.
This commit is contained in:
@@ -8,6 +8,7 @@ import { useTripStore } from '../../../../store/tripStore'
|
||||
import { useAddonStore } from '../../../../store/addonStore'
|
||||
import PlaceAvatar from '../../../../components/shared/PlaceAvatar'
|
||||
import { getCategoryIcon } from '../../../../components/shared/categoryIcons'
|
||||
import { resolveTrackColor } from '../../../../components/Map/trackColors'
|
||||
import MConfirmSheet from '../../settings/MConfirmSheet'
|
||||
import type { MPlacesBrowserProps } from '../MTripShell'
|
||||
import type { Place } from '../../../../types'
|
||||
@@ -290,6 +291,15 @@ export default function MPlacesBrowser({ planner, shell }: MPlacesBrowserProps)
|
||||
<PlaceAvatar place={place} category={cat} size={40} />
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="flex items-center gap-[6px]">
|
||||
{/* Stroke in the track's colour — the mobile map is full-bleed
|
||||
with no sidebar, so this is the only thing tying a line to
|
||||
a row (#776). */}
|
||||
{place.route_geometry && (
|
||||
<span
|
||||
className="h-[3px] w-[14px] flex-none rounded-full"
|
||||
style={{ background: resolveTrackColor(place) }}
|
||||
/>
|
||||
)}
|
||||
<CatIcon size={12} strokeWidth={2.2} className="flex-none" style={{ color: cat?.color || 'var(--m-muted)' }} />
|
||||
<span className="truncate text-[0.8125rem] font-semibold text-m-ink">{place.name}</span>
|
||||
</span>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMemo, useRef, useState } from 'react'
|
||||
import {
|
||||
Bookmark, Camera, ExternalLink, Loader2, Map as MapIcon, Navigation, Paperclip,
|
||||
Pencil, Phone, Plus, Trash2, Upload, X,
|
||||
Pencil, Phone, Plus, Route, Trash2, Upload, X,
|
||||
} from 'lucide-react'
|
||||
import MSheet from '../../../components/MSheet'
|
||||
import type { MTripSheetsProps } from '../MTripShell'
|
||||
@@ -14,6 +14,8 @@ import { useSaveToCollectionStore } from '../../../../store/saveToCollectionStor
|
||||
import { collectionTargetFromPlace } from '../lib/collectionTarget'
|
||||
import { getCategoryIcon } from '../../../../components/shared/categoryIcons'
|
||||
import PlaceRating from '../../../../components/shared/StarRating'
|
||||
import TrackColorPicker from '../../../../components/shared/TrackColorPicker'
|
||||
import { resolveTrackColor, inheritedTrackColor } from '../../../../components/Map/trackColors'
|
||||
import { avatarSrc } from '../../../../utils/avatarSrc'
|
||||
import { openFile } from '../../../../utils/fileDownload'
|
||||
import { getGoogleMapsUrlForPlace } from '../../../../components/Planner/placeGoogleMaps'
|
||||
@@ -42,6 +44,7 @@ export default function MPlaceSheet({ planner, shell }: MTripSheetsProps) {
|
||||
const [participantPickerOpen, setParticipantPickerOpen] = useState(false)
|
||||
const [uploading, setUploading] = useState(false)
|
||||
const [imgBusy, setImgBusy] = useState(false)
|
||||
const [colorPickerOpen, setColorPickerOpen] = useState(false)
|
||||
const fileInputRef = useRef<HTMLInputElement | null>(null)
|
||||
const imageInputRef = useRef<HTMLInputElement | null>(null)
|
||||
|
||||
@@ -132,6 +135,15 @@ export default function MPlaceSheet({ planner, shell }: MTripSheetsProps) {
|
||||
}
|
||||
}
|
||||
|
||||
const handleTrackColor = async (color: string | null) => {
|
||||
if (!place) return
|
||||
try {
|
||||
await planner.tripActions.updatePlace(planner.tripId, place.id, { route_color: color })
|
||||
} catch (err: unknown) {
|
||||
planner.toast.error(translateApiError(t, err, 'common.unknownError'))
|
||||
}
|
||||
}
|
||||
|
||||
const handleImageRemove = async () => {
|
||||
if (!place) return
|
||||
setImgBusy(true)
|
||||
@@ -290,6 +302,43 @@ export default function MPlaceSheet({ planner, shell }: MTripSheetsProps) {
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* ── Track colour (#776) ── */}
|
||||
{place.route_geometry && (
|
||||
<>
|
||||
<Eyebrow className="mb-[6px] mt-3">{t('inspector.trackColor')}</Eyebrow>
|
||||
<div className={`rounded-[14px] px-3 py-[10px] ${INNER_CLS}`}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setColorPickerOpen(v => !v)}
|
||||
aria-expanded={colorPickerOpen}
|
||||
className="flex w-full items-center justify-between gap-3"
|
||||
>
|
||||
{/* The eyebrow above already names the section — this row says
|
||||
which colour is in effect, not the same word again. */}
|
||||
<span className="flex min-w-0 items-center gap-2">
|
||||
<Route size={14} className="shrink-0 text-m-muted" />
|
||||
<span className="truncate font-geist text-[0.75rem] font-medium">
|
||||
{place.route_color ?? t('inspector.trackColorAuto')}
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="h-6 w-6 shrink-0 rounded-full ring-1 ring-inset ring-black/10 dark:ring-white/15"
|
||||
style={{ background: resolveTrackColor(place) }}
|
||||
/>
|
||||
</button>
|
||||
{colorPickerOpen && (
|
||||
<div className="mt-[10px] border-t border-[color:var(--m-faint)] pt-[10px]">
|
||||
<TrackColorPicker
|
||||
value={place.route_color ?? null}
|
||||
inheritedColor={inheritedTrackColor(place)}
|
||||
onChange={handleTrackColor}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* ── Day assignments ── */}
|
||||
<Eyebrow className="mb-[6px] mt-3">{t('mobileTrip.assignedDays')}</Eyebrow>
|
||||
<div className="flex flex-wrap items-center gap-[6px]">
|
||||
|
||||
Reference in New Issue
Block a user