Highlight waypoint marker on sidebar hover instead of red dot

Replace position-based CircleMarker highlight with index-based marker
highlighting. Hovered waypoint marker grows from 24px to 30px with an
outline ring in its color. Uses CSS transition for smooth animation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-04-11 00:35:42 +02:00
parent 13c2925c18
commit 705252a1c6
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
3 changed files with 17 additions and 11 deletions

View file

@ -14,17 +14,21 @@ import { ColoredRoute, findSegmentForPoint, type ColorMode } from "./ColoredRout
import { RouteInteraction } from "./RouteInteraction";
import "leaflet/dist/leaflet.css";
function waypointIcon(index: number, overnight?: boolean): L.DivIcon {
function waypointIcon(index: number, overnight?: boolean, highlighted?: boolean): L.DivIcon {
const bg = overnight ? "#8B6D3A" : "#2563eb";
const size = highlighted ? 30 : 24;
const offset = size / 2;
const ring = highlighted ? `outline:3px solid ${bg};outline-offset:2px;` : "";
return L.divIcon({
className: "",
html: `<div style="
width:24px;height:24px;border-radius:50%;
width:${size}px;height:${size}px;border-radius:50%;
background:${bg};color:white;
display:flex;align-items:center;justify-content:center;
font-size:12px;font-weight:600;
font-size:${highlighted ? 14 : 12}px;font-weight:600;
border:2px solid white;box-shadow:0 1px 4px rgba(0,0,0,0.3);
transform:translate(-12px,-12px);
transform:translate(-${offset}px,-${offset}px);
${ring}transition:all 0.15s ease;
">${overnight ? "" : index + 1}</div>`,
iconSize: [0, 0],
});
@ -66,6 +70,7 @@ interface PlannerMapProps {
onRouteRequest?: (waypoints: WaypointData[]) => void;
onImportError?: (message: string) => void;
highlightPosition?: [number, number] | null;
highlightedWaypoint?: number | null;
days?: DayStage[];
}
@ -228,7 +233,7 @@ function NoGoAreaButton({ active, onClick }: { active: boolean; onClick: () => v
);
}
export function PlannerMap({ yjs, onRouteRequest, highlightPosition, onImportError, days }: PlannerMapProps) {
export function PlannerMap({ yjs, onRouteRequest, highlightPosition, highlightedWaypoint, onImportError, days }: PlannerMapProps) {
const { t } = useTranslation("planner");
const [waypoints, setWaypoints] = useState<WaypointData[]>([]);
const [draggingOver, setDraggingOver] = useState(false);
@ -466,7 +471,7 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition, onImportErr
key={i}
position={[wp.lat, wp.lon]}
draggable
icon={waypointIcon(i, wp.overnight)}
icon={waypointIcon(i, wp.overnight, highlightedWaypoint === i)}
eventHandlers={{
mouseover: () => {
routeInteractionSuspendedRef.current = true;

View file

@ -142,7 +142,7 @@ function ColorModeToggle({ yjs }: { yjs: YjsState }) {
);
}
function SidebarTabs({ yjs, routeStats, days, onWaypointHover }: { yjs: YjsState; routeStats: ReturnType<typeof useRouting>["routeStats"]; days: ReturnType<typeof useDays>; onWaypointHover: (position: [number, number] | null) => void }) {
function SidebarTabs({ yjs, routeStats, days, onWaypointHover }: { yjs: YjsState; routeStats: ReturnType<typeof useRouting>["routeStats"]; days: ReturnType<typeof useDays>; onWaypointHover: (index: number | null) => void }) {
const { t } = useTranslation("planner");
const [tab, setTab] = useState<"waypoints" | "notes">("waypoints");
@ -193,6 +193,7 @@ export function SessionView({ sessionId, callbackUrl, callbackToken, returnUrl,
useUndoShortcuts(yjs?.undoManager ?? null);
const days = useDays(yjs);
const [highlightPosition, setHighlightPosition] = useState<[number, number] | null>(null);
const [highlightedWaypoint, setHighlightedWaypoint] = useState<number | null>(null);
const { toasts, addToast } = useToasts();
useAwarenessToasts(yjs, t, addToast);
@ -285,14 +286,14 @@ export function SessionView({ sessionId, callbackUrl, callbackToken, returnUrl,
</div>
}
>
<PlannerMap yjs={yjs} onRouteRequest={requestRoute} highlightPosition={highlightPosition} onImportError={(msg) => addToast(msg, "error")} days={days} />
<PlannerMap yjs={yjs} onRouteRequest={requestRoute} highlightPosition={highlightPosition} highlightedWaypoint={highlightedWaypoint} onImportError={(msg) => addToast(msg, "error")} days={days} />
</Suspense>
</div>
<Suspense fallback={null}>
<ElevationChart yjs={yjs} onHover={handleElevationHover} days={days} />
</Suspense>
</main>
<SidebarTabs yjs={yjs} routeStats={routeStats} days={days} onWaypointHover={setHighlightPosition} />
<SidebarTabs yjs={yjs} routeStats={routeStats} days={days} onWaypointHover={setHighlightedWaypoint} />
</div>
<YjsDebugPanel yjs={yjs} />
{toasts.length > 0 && (

View file

@ -30,7 +30,7 @@ interface WaypointSidebarProps {
elevationLoss?: number;
};
days: DayStage[];
onWaypointHover?: (position: [number, number] | null) => void;
onWaypointHover?: (index: number | null) => void;
}
export function WaypointSidebar({ yjs, routeStats, days, onWaypointHover }: WaypointSidebarProps) {
@ -90,7 +90,7 @@ export function WaypointSidebar({ yjs, routeStats, days, onWaypointHover }: Wayp
<li
key={i}
className="group flex items-center gap-2 px-4 py-2 hover:bg-gray-50"
onMouseEnter={() => onWaypointHover?.([wp.lat, wp.lon])}
onMouseEnter={() => onWaypointHover?.(i)}
onMouseLeave={() => onWaypointHover?.(null)}
>
<span className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-blue-100 text-xs font-medium text-blue-700">