135 lines
4.9 KiB
TypeScript
135 lines
4.9 KiB
TypeScript
import { createResource, For, JSX, ParentComponent, Show, useContext, VoidComponent } from 'solid-js';
|
|
|
|
import { Stop } from '../types';
|
|
import { renderLineTransportMode, renderLinePicto, ScrollingText, TransportModeWeights } from '../utils';
|
|
import { AppContextContext, AppContextStore } from "../appContext";
|
|
import { BusinessDataContext, BusinessDataStore } from "../businessData";
|
|
import { SearchContext, SearchStore } from "./searchStore";
|
|
|
|
|
|
import "./stopPanel.scss";
|
|
|
|
|
|
const StopRepr: VoidComponent<{ stop: Stop }> = (props) => {
|
|
const fontSize: number = 40;
|
|
|
|
const businessDataStore: BusinessDataStore | undefined = useContext(BusinessDataContext);
|
|
if (businessDataStore === undefined)
|
|
return <div />;
|
|
|
|
const { getLine } = businessDataStore;
|
|
|
|
const fetchLinesRepr = async (lineIds: string[]): Promise<JSX.Element[]> => {
|
|
const reprs = [];
|
|
for (const lineId of lineIds) {
|
|
const line = await getLine(lineId);
|
|
if (line !== undefined) {
|
|
reprs.push(<div class="transportMode">{renderLineTransportMode(line)}</div>);
|
|
reprs.push(renderLinePicto(line));
|
|
}
|
|
}
|
|
return reprs;
|
|
}
|
|
|
|
const [lineReprs] = createResource<JSX.Element[], string[]>(props.stop.lines, fetchLinesRepr);
|
|
|
|
return <div class="stop">
|
|
<svg class="name" viewBox={`0 0 215 ${fontSize}`}>
|
|
<text
|
|
x="100%" y="55%"
|
|
dominant-baseline="middle" text-anchor="end"
|
|
font-size={fontSize}>
|
|
{props.stop.name}
|
|
</text>
|
|
</svg>
|
|
<For each={lineReprs()}>{(line: JSX.Element) => line}</For>
|
|
</div>;
|
|
}
|
|
|
|
|
|
type ByTransportModeReprs = {
|
|
mode: JSX.Element | undefined;
|
|
lines: Record<string, JSX.Element | JSX.Element[] | undefined>;
|
|
}
|
|
|
|
|
|
const StopAreaRepr: VoidComponent<{ stop: Stop }> = (props) => {
|
|
const fontSize: number = 10;
|
|
|
|
const businessDataStore: BusinessDataStore | undefined = useContext(BusinessDataContext);
|
|
const appContextStore: AppContextStore | undefined = useContext(AppContextContext);
|
|
const searchStore: SearchStore | undefined = useContext(SearchContext);
|
|
|
|
if (businessDataStore === undefined || appContextStore === undefined || searchStore === undefined)
|
|
return <div />;
|
|
|
|
const { getLine } = businessDataStore;
|
|
const { setDisplayedStops } = appContextStore;
|
|
const { setHighlightedStop, resetHighlightedStop } = searchStore;
|
|
|
|
|
|
const fetchLinesRepr = async (stop: Stop): Promise<JSX.Element> => {
|
|
const lineIds = new Set(stop.lines);
|
|
const stops = stop.stops;
|
|
for (const stop of stops) {
|
|
stop.lines.forEach(lineIds.add, lineIds);
|
|
}
|
|
|
|
const byModeReprs: Record<string, ByTransportModeReprs> = {};
|
|
for (const lineId of lineIds) {
|
|
const line = await getLine(lineId);
|
|
if (line !== undefined) {
|
|
if (!(line.transportMode in byModeReprs)) {
|
|
byModeReprs[line.transportMode] = {
|
|
mode: <div class="transportMode"> {renderLineTransportMode(line)}</div>,
|
|
lines: {}
|
|
};
|
|
}
|
|
byModeReprs[line.transportMode].lines[line.shortName] = renderLinePicto(line);
|
|
}
|
|
}
|
|
|
|
const sortedTransportModes = Object.keys(byModeReprs).sort((x, y) => TransportModeWeights[x] < TransportModeWeights[y] ? 1 : -1);
|
|
|
|
return <div class="lineRepr">
|
|
<For each={sortedTransportModes}>
|
|
{(transportMode) => {
|
|
const reprs = byModeReprs[transportMode];
|
|
const lineNames = Object.keys(reprs.lines).sort((x, y) => x.localeCompare(y));
|
|
return <>
|
|
{reprs.mode}
|
|
<div class="linesRepresentationMatrix">
|
|
<For each={lineNames}>{(lineName) => reprs.lines[lineName]}</For>
|
|
</div>
|
|
</>;
|
|
}}</For>
|
|
</div>;
|
|
}
|
|
|
|
const [lineReprs] = createResource(props.stop, fetchLinesRepr);
|
|
|
|
return <div
|
|
class="stop"
|
|
onClick={() => setDisplayedStops([props.stop])}
|
|
onMouseEnter={() => setHighlightedStop(props.stop)}
|
|
onMouseLeave={resetHighlightedStop}
|
|
>
|
|
<div class="name">
|
|
<ScrollingText height={fontSize} width={100} content={props.stop.name} />
|
|
</div>
|
|
{lineReprs()}
|
|
</div>;
|
|
}
|
|
|
|
export const StopsPanel: ParentComponent<{ stops: Stop[], show: boolean }> = (props) => {
|
|
|
|
return <div classList={{ "stopPanel": true, "displayed": props.show }}>
|
|
<For each={props.stops.sort((x, y) => x.name.localeCompare(y.name))}>
|
|
{(stop) => {
|
|
return <Show when={stop.stops !== undefined} fallback={<StopRepr stop={stop} />}>
|
|
<StopAreaRepr stop={stop} />
|
|
</Show>;
|
|
}}</For>
|
|
</div>;
|
|
}
|