@geops/rvf-mobility-web-component 0.1.55 → 0.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/docutils.js +21 -6
- package/global.d.ts +1 -0
- package/iframe.html +15 -0
- package/index.html +2 -1
- package/index.js +295 -335
- package/package.json +16 -17
- package/src/{RvfExportMenu/RvfExportMenu.tsx → ExportMenu/ExportMenu.tsx} +12 -12
- package/src/ExportMenu/index.tsx +1 -0
- package/src/{RvfExportMenuButton/RvfExportMenuButton.tsx → ExportMenuButton/ExportMenuButton.tsx} +5 -5
- package/src/ExportMenuButton/index.tsx +1 -0
- package/src/FeatureDetails/FeatureDetails.tsx +57 -0
- package/src/FeatureDetails/index.ts +1 -0
- package/src/FeaturesInfosListener/FeaturesInfosListener.tsx +73 -0
- package/src/FeaturesInfosListener/index.tsx +1 -0
- package/src/GeolocationButton/GeolocationButton.tsx +0 -1
- package/src/LayerTree/LayerTree.tsx +58 -0
- package/src/LayerTree/TreeItem/TreeItem.tsx +151 -0
- package/src/LayerTree/TreeItem/index.tsx +1 -0
- package/src/LayerTree/index.tsx +1 -0
- package/src/LayerTree/layersTreeContext.ts +4 -0
- package/src/LayerTree/layersTreeReducer.ts +158 -0
- package/src/{RvfLayerTreeButton/RvfLayerTreeButton.tsx → LayerTreeButton/LayerTreeButton.tsx} +5 -5
- package/src/LayerTreeButton/index.tsx +1 -0
- package/src/{RvfTopics/RvfTopics.tsx → LayerTreeMenu/LayerTreeMenu.tsx} +17 -13
- package/src/LayerTreeMenu/index.tsx +1 -0
- package/src/LayoutState/LayoutState.tsx +277 -0
- package/src/LayoutState/index.tsx +1 -0
- package/src/LinesNetworkPlanDetails/LinesNetworkPlanDetails.tsx +292 -0
- package/src/LinesNetworkPlanDetails/index.tsx +1 -0
- package/src/{RvfLineNetworkPlanLayer/RvfLineNetworkPlanLayer.tsx → LinesNetworkPlanLayer/LinesNetworkPlanLayer.tsx} +7 -9
- package/src/LinesNetworkPlanLayer/index.tsx +1 -0
- package/src/MobilityMap/MobilityMap.tsx +274 -60
- package/src/MobilityMap/MobilityMapAttributes.ts +46 -50
- package/src/NotificationDetails/NotificationDetails.tsx +468 -0
- package/src/NotificationDetails/index.ts +1 -0
- package/src/{NotificationLayer/NotificationLayer.tsx → NotificationsLayer/NotificationsLayer.tsx} +9 -4
- package/src/NotificationsLayer/index.tsx +1 -0
- package/src/Overlay/Overlay.tsx +1 -6
- package/src/OverlayContent/OverlayContent.tsx +87 -0
- package/src/OverlayContent/index.ts +1 -0
- package/src/OverlayDetails/OverlayDetails.tsx +47 -0
- package/src/OverlayDetails/index.ts +1 -0
- package/src/OverlayDetailsFooter/OverlayDetailsFooter.tsx +51 -0
- package/src/OverlayDetailsFooter/index.tsx +1 -0
- package/src/OverlayDetailsHeader/OverlayDetailsHeader.tsx +35 -0
- package/src/OverlayDetailsHeader/index.ts +1 -0
- package/src/OverlayFooter/OverlayFooter.tsx +41 -0
- package/src/OverlayFooter/index.tsx +1 -0
- package/src/OverlayHeader/OverlayHeader.tsx +44 -0
- package/src/OverlayHeader/index.tsx +1 -0
- package/src/PermalinkInput/PermalinkInput.tsx +28 -0
- package/src/PermalinkInput/index.tsx +1 -0
- package/src/RouteSchedule/RouteSchedule.tsx +22 -18
- package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +22 -50
- package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +108 -104
- package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +189 -154
- package/src/RvfFeatureDetails/RvfSharedMobilityDetail/RvfSharedMobilityDetails.tsx +12 -14
- package/src/RvfFeatureDetailsTitle/RvfFeatureDetailsTitle.tsx +5 -5
- package/src/RvfMainLinkButton/RvfMainLinkButton.tsx +65 -0
- package/src/RvfMainLinkButton/index.tsx +1 -0
- package/src/RvfMobilityMap/RvfMobilityMap.tsx +183 -395
- package/src/RvfOverlayContent/RvfOverlayContent.tsx +2 -2
- package/src/RvfPoisLayer/RvfPoisLayer.tsx +2 -2
- package/src/RvfSearch/RvfSearch.tsx +1 -1
- package/src/RvfSellingPointsLayer/RvfSellingPointsLayer.tsx +2 -2
- package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +23 -23
- package/src/RvfTarifZonenLayer/RvfTarifZonenLayer.tsx +2 -2
- package/src/Search/Search.tsx +11 -2
- package/src/{RvfSearchButton/RvfSearchButton.tsx → SearchButton/SearchButton.tsx} +5 -5
- package/src/SearchButton/index.tsx +1 -0
- package/src/ShadowOverflow/ShadowOverflow.tsx +20 -0
- package/src/ShadowOverflow/index.tsx +1 -0
- package/src/{RvfShare/RvfPermalinkButton/RvfPermalinkButton.tsx → ShareMenu/PermalinkButton/PermalinkButton.tsx} +4 -4
- package/src/ShareMenu/PermalinkButton/index.tsx +1 -0
- package/src/{RvfShare/RvfShare.tsx → ShareMenu/ShareMenu.tsx} +9 -11
- package/src/ShareMenu/index.tsx +1 -0
- package/src/{RvfShareMenuButton/RvfShareMenuButton.tsx → ShareMenuButton/ShareMenuButton.tsx} +6 -6
- package/src/ShareMenuButton/index.tsx +1 -0
- package/src/SingleClickListener/SingleClickListener.tsx +55 -113
- package/src/SingleClickListener/index.tsx +1 -1
- package/src/Station/Station.tsx +10 -3
- package/src/StationsLayer/StationsLayer.tsx +0 -1
- package/src/StopsSearch/StopsSearch.tsx +3 -4
- package/src/StopsSearch/index.tsx +2 -1
- package/src/WindowMessageListener/WindowMessageListener.tsx +7 -1
- package/src/{RvfZoomButtons/RvfZoomButtons.tsx → ZoomButtons/ZoomButtons.tsx} +9 -12
- package/src/ZoomButtons/index.tsx +1 -0
- package/src/icons/Geolocation/airport-14-svgrepo-com.svg +41 -0
- package/src/ui/Button/Button.tsx +9 -2
- package/src/ui/Checkbox/Checkbox.tsx +32 -0
- package/src/ui/Checkbox/index.tsx +1 -0
- package/src/ui/IconButton/IconButton.tsx +24 -4
- package/src/ui/Input/Input.tsx +17 -0
- package/src/ui/Input/index.tsx +1 -0
- package/src/ui/InputCopy/InputCopy.tsx +86 -0
- package/src/ui/InputCopy/index.tsx +1 -0
- package/src/ui/Select/Select.tsx +24 -0
- package/src/ui/Select/index.tsx +1 -0
- package/src/utils/constants.ts +43 -42
- package/src/utils/exportPdf.ts +3 -5
- package/src/utils/hooks/useInitialLayersVisiblity.tsx +1 -1
- package/src/utils/hooks/useLayerConfig.tsx +2 -2
- package/src/utils/hooks/useLayersConfig.tsx +3 -3
- package/src/utils/hooks/useMapContext.tsx +67 -8
- package/src/utils/hooks/useRvfContext.tsx +0 -44
- package/src/NotificationLayer/index.tsx +0 -1
- package/src/RvfEmbedNavigation/DragPanWarning.ts +0 -124
- package/src/RvfEmbedNavigation/RvfEmbedNavigation.tsx +0 -51
- package/src/RvfEmbedNavigation/index.js +0 -1
- package/src/RvfExportMenu/index.tsx +0 -1
- package/src/RvfExportMenuButton/index.tsx +0 -1
- package/src/RvfFloatingMenu/RvfFloatingMenu.tsx +0 -44
- package/src/RvfFloatingMenu/index.tsx +0 -1
- package/src/RvfLayerTreeButton/index.tsx +0 -1
- package/src/RvfLineNetworkPlanLayer/index.tsx +0 -1
- package/src/RvfPermalink/RvfPermalink.tsx +0 -18
- package/src/RvfPermalink/index.tsx +0 -1
- package/src/RvfSearchButton/index.tsx +0 -1
- package/src/RvfShare/RvfPermalinkButton/index.tsx +0 -1
- package/src/RvfShare/index.tsx +0 -1
- package/src/RvfShareMenuButton/index.tsx +0 -1
- package/src/RvfTopics/index.tsx +0 -1
- package/src/RvfZoomButtons/index.tsx +0 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { memo } from "preact/compat";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
|
|
4
|
+
import ArrowRight from "../icons/ArrowRight";
|
|
5
|
+
import Button from "../ui/Button";
|
|
6
|
+
import useLayerConfig from "../utils/hooks/useLayerConfig";
|
|
7
|
+
|
|
8
|
+
import type { Feature } from "ol";
|
|
9
|
+
import type BaseLayer from "ol/layer/Base";
|
|
10
|
+
import type { HTMLAttributes, PreactDOMAttributes } from "preact";
|
|
11
|
+
|
|
12
|
+
export type OverlayDetailsFooterProps = {
|
|
13
|
+
className?: string;
|
|
14
|
+
feature?: Feature;
|
|
15
|
+
layer?: BaseLayer;
|
|
16
|
+
} & HTMLAttributes<HTMLDivElement> &
|
|
17
|
+
PreactDOMAttributes;
|
|
18
|
+
|
|
19
|
+
function OverlayDetailsFooter({
|
|
20
|
+
className,
|
|
21
|
+
feature,
|
|
22
|
+
layer,
|
|
23
|
+
...props
|
|
24
|
+
}: OverlayDetailsFooterProps) {
|
|
25
|
+
const layerConfig = useLayerConfig(layer?.get("name"));
|
|
26
|
+
|
|
27
|
+
if (!layerConfig?.link || layerConfig?.link?.show === false) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let id = feature?.get("id");
|
|
32
|
+
const situation = feature?.get("situation");
|
|
33
|
+
if (situation) {
|
|
34
|
+
const situationParsed = JSON.parse(situation);
|
|
35
|
+
id = situationParsed?.id || id;
|
|
36
|
+
}
|
|
37
|
+
return (
|
|
38
|
+
<div {...props} className={twMerge("flex flex-row p-4", className)}>
|
|
39
|
+
<Button
|
|
40
|
+
href={layerConfig.link.href.replace("{{id}}", id)}
|
|
41
|
+
target="_blank"
|
|
42
|
+
theme="primary"
|
|
43
|
+
>
|
|
44
|
+
<span>{layerConfig.link.text || "Mehr erfahren"}</span>
|
|
45
|
+
<ArrowRight />
|
|
46
|
+
</Button>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default memo(OverlayDetailsFooter);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./OverlayDetailsFooter";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { memo, useMemo } from "preact/compat";
|
|
2
|
+
|
|
3
|
+
import OverlayHeader from "../OverlayHeader";
|
|
4
|
+
import { LAYERS_NAMES, LAYERS_TITLES } from "../utils/constants";
|
|
5
|
+
|
|
6
|
+
import type { Feature } from "ol";
|
|
7
|
+
import type BaseLayer from "ol/layer/Base";
|
|
8
|
+
|
|
9
|
+
import type { OverlayHeaderProps } from "../OverlayHeader/OverlayHeader";
|
|
10
|
+
|
|
11
|
+
export type OverlayDetailsHeaderProps = {
|
|
12
|
+
feature?: Feature;
|
|
13
|
+
layer?: BaseLayer;
|
|
14
|
+
} & OverlayHeaderProps;
|
|
15
|
+
|
|
16
|
+
function OverlayDetailsHeader({
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
18
|
+
feature,
|
|
19
|
+
layer,
|
|
20
|
+
...props
|
|
21
|
+
}: OverlayDetailsHeaderProps) {
|
|
22
|
+
const title = useMemo(() => {
|
|
23
|
+
let ttle = layer?.get("title");
|
|
24
|
+
if (!ttle) {
|
|
25
|
+
const key = Object.keys(LAYERS_TITLES).find((titleKey) => {
|
|
26
|
+
return LAYERS_NAMES[titleKey] === layer?.get("name");
|
|
27
|
+
});
|
|
28
|
+
ttle = LAYERS_TITLES[key];
|
|
29
|
+
}
|
|
30
|
+
return ttle || layer?.get("name") || "Details";
|
|
31
|
+
}, [layer]);
|
|
32
|
+
|
|
33
|
+
return <OverlayHeader title={title} {...props}></OverlayHeader>;
|
|
34
|
+
}
|
|
35
|
+
export default memo(OverlayDetailsHeader);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./OverlayDetailsHeader";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { memo } from "preact/compat";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
|
|
4
|
+
import Cancel from "../icons/Cancel";
|
|
5
|
+
import IconButton from "../ui/IconButton";
|
|
6
|
+
|
|
7
|
+
import type { HTMLAttributes, PreactDOMAttributes } from "preact";
|
|
8
|
+
|
|
9
|
+
export type RvfOverlayHeaderProps = {
|
|
10
|
+
onClose?: () => void;
|
|
11
|
+
title?: React.ReactNode;
|
|
12
|
+
} & HTMLAttributes<HTMLDivElement> &
|
|
13
|
+
PreactDOMAttributes;
|
|
14
|
+
|
|
15
|
+
function OverlayFooter({
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
onClose,
|
|
19
|
+
title,
|
|
20
|
+
...props
|
|
21
|
+
}: RvfOverlayHeaderProps) {
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
{...props}
|
|
25
|
+
className={twMerge(
|
|
26
|
+
`flex flex-row items-center justify-between gap-2 border-b p-2 pl-4`,
|
|
27
|
+
className,
|
|
28
|
+
)}
|
|
29
|
+
>
|
|
30
|
+
{/* We set text-base so the clamp works on overlay container, not main */}
|
|
31
|
+
{children || <span className={"text-base font-bold"}>{title}</span>}
|
|
32
|
+
{onClose && (
|
|
33
|
+
<IconButton className={"!size-[32px] border-none"} onClick={onClose}>
|
|
34
|
+
<Cancel />
|
|
35
|
+
</IconButton>
|
|
36
|
+
)}
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default memo(OverlayFooter);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./OverlayFooter";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { memo } from "preact/compat";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
|
|
4
|
+
import Cancel from "../icons/Cancel";
|
|
5
|
+
import IconButton from "../ui/IconButton";
|
|
6
|
+
|
|
7
|
+
import type { HTMLAttributes, PreactDOMAttributes } from "preact";
|
|
8
|
+
|
|
9
|
+
export type OverlayHeaderProps = {
|
|
10
|
+
onClose?: () => void;
|
|
11
|
+
title?: React.ReactNode;
|
|
12
|
+
} & HTMLAttributes<HTMLDivElement> &
|
|
13
|
+
PreactDOMAttributes;
|
|
14
|
+
|
|
15
|
+
function OverlayHeader({
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
onClose,
|
|
19
|
+
title,
|
|
20
|
+
...props
|
|
21
|
+
}: OverlayHeaderProps) {
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
{...props}
|
|
25
|
+
className={twMerge(
|
|
26
|
+
`flex flex-row items-center justify-between gap-2 border-b p-2 pl-4`,
|
|
27
|
+
className,
|
|
28
|
+
)}
|
|
29
|
+
>
|
|
30
|
+
{/* We set text-base so the clamp works on overlay container, not main */}
|
|
31
|
+
{children || <span className={"text-base font-bold"}>{title}</span>}
|
|
32
|
+
{onClose && (
|
|
33
|
+
<IconButton
|
|
34
|
+
className={"!size-[32px] border-none shadow-none"}
|
|
35
|
+
onClick={onClose}
|
|
36
|
+
>
|
|
37
|
+
<Cancel />
|
|
38
|
+
</IconButton>
|
|
39
|
+
)}
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default memo(OverlayHeader);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./OverlayHeader";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import InputCopy from "../ui/InputCopy";
|
|
2
|
+
|
|
3
|
+
import type { HTMLAttributes, PreactDOMAttributes } from "preact";
|
|
4
|
+
|
|
5
|
+
import type { InputCopyProps } from "../ui/InputCopy/InputCopy";
|
|
6
|
+
|
|
7
|
+
export type PermalinkInputProps = {
|
|
8
|
+
inputProps?: InputCopyProps;
|
|
9
|
+
} & HTMLAttributes<HTMLDivElement> &
|
|
10
|
+
PreactDOMAttributes;
|
|
11
|
+
|
|
12
|
+
const emptyProps = {}; // avoid re-rendering
|
|
13
|
+
|
|
14
|
+
function PermalinkInput({
|
|
15
|
+
inputProps = emptyProps,
|
|
16
|
+
...props
|
|
17
|
+
}: PermalinkInputProps) {
|
|
18
|
+
return (
|
|
19
|
+
<div {...props}>
|
|
20
|
+
<InputCopy value={window?.location.href} {...inputProps} />
|
|
21
|
+
<p className="py-2">
|
|
22
|
+
Sie können auch den Link aus der Adresszeile des Browsers kopieren.
|
|
23
|
+
</p>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default PermalinkInput;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./PermalinkInput";
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { memo } from "preact/compat";
|
|
2
2
|
import { useEffect, useRef } from "preact/hooks";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
3
4
|
|
|
4
5
|
import RouteScheduleFooter from "../RouteScheduleFooter";
|
|
5
6
|
import RouteScheduleHeader from "../RouteScheduleHeader";
|
|
6
7
|
import RouteStop from "../RouteStop";
|
|
8
|
+
import ShadowOverflow from "../ShadowOverflow";
|
|
7
9
|
import useMapContext from "../utils/hooks/useMapContext";
|
|
8
10
|
|
|
9
11
|
import type { RealtimeStop } from "mobility-toolbox-js/types";
|
|
@@ -25,7 +27,7 @@ function RouteSchedule(props: RouteScheduleProps) {
|
|
|
25
27
|
const nextStation = elt.querySelector("[data-station-passed=false]");
|
|
26
28
|
if (nextStation) {
|
|
27
29
|
// We use scrollTo avoid scrolling the entire window.
|
|
28
|
-
(nextStation.parentNode as Element).scrollTo({
|
|
30
|
+
(nextStation.parentNode.parentNode as Element).scrollTo({
|
|
29
31
|
behavior: "smooth",
|
|
30
32
|
top: (nextStation as HTMLElement).offsetTop || 0,
|
|
31
33
|
});
|
|
@@ -47,23 +49,25 @@ function RouteSchedule(props: RouteScheduleProps) {
|
|
|
47
49
|
return (
|
|
48
50
|
<>
|
|
49
51
|
<RouteScheduleHeader />
|
|
50
|
-
<
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
<ShadowOverflow>
|
|
53
|
+
<div className={twMerge("text-base", className)} ref={ref}>
|
|
54
|
+
{stopSequence.stations.map((stop: RealtimeStop, index: number) => {
|
|
55
|
+
const { arrivalTime, departureTime, stationId, stationName } = stop;
|
|
56
|
+
return (
|
|
57
|
+
<RouteStop
|
|
58
|
+
// Train line can go in circle so begin and end have the same id,
|
|
59
|
+
index={index}
|
|
60
|
+
// using the time in the key should fix the issue.
|
|
61
|
+
key={
|
|
62
|
+
(`${stationId}` || stationName) + arrivalTime + departureTime
|
|
63
|
+
}
|
|
64
|
+
stop={stop}
|
|
65
|
+
/>
|
|
66
|
+
);
|
|
67
|
+
})}
|
|
68
|
+
<RouteScheduleFooter />
|
|
69
|
+
</div>
|
|
70
|
+
</ShadowOverflow>
|
|
67
71
|
</>
|
|
68
72
|
);
|
|
69
73
|
}
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { memo } from "preact/compat";
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import FeatureDetails from "../FeatureDetails/FeatureDetails";
|
|
4
4
|
|
|
5
|
-
import RvfLineNetworkDetails from "./RvfLineNetworkDetails/RvfLineNetworkDetails";
|
|
6
|
-
import RvfNotificationDetails from "./RvfNotificationDetails";
|
|
7
5
|
import RvfSellingPointDetails from "./RvfSellingPointDetails";
|
|
8
6
|
import RvfSharedMobilityDetails from "./RvfSharedMobilityDetail";
|
|
9
7
|
|
|
10
|
-
import type {
|
|
11
|
-
|
|
12
|
-
export type RvfFeatureDetailsProps = JSX.HTMLAttributes<HTMLDivElement> &
|
|
13
|
-
PreactDOMAttributes;
|
|
8
|
+
import type { FeatureDetailsProps } from "../FeatureDetails/FeatureDetails";
|
|
14
9
|
|
|
15
10
|
const getIsSharedMobility = (selectedFeature): boolean => {
|
|
16
11
|
if (
|
|
@@ -22,51 +17,28 @@ const getIsSharedMobility = (selectedFeature): boolean => {
|
|
|
22
17
|
}
|
|
23
18
|
};
|
|
24
19
|
|
|
25
|
-
function RvfFeatureDetails(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
const showDefaultData = () => {
|
|
33
|
-
return Object.entries(selectedFeature.getProperties()).map(
|
|
34
|
-
([key, value]) => {
|
|
35
|
-
return (
|
|
36
|
-
<div className="flex gap-2" key={key}>
|
|
37
|
-
<span>
|
|
38
|
-
<b>{key}:</b>
|
|
39
|
-
</span>
|
|
40
|
-
<div>{value}</div>
|
|
41
|
-
</div>
|
|
42
|
-
);
|
|
43
|
-
},
|
|
44
|
-
);
|
|
45
|
-
};
|
|
20
|
+
function RvfFeatureDetails({
|
|
21
|
+
feature,
|
|
22
|
+
featuresInfo,
|
|
23
|
+
layer,
|
|
24
|
+
}: FeatureDetailsProps) {
|
|
25
|
+
const isSharedMobility = getIsSharedMobility(feature);
|
|
26
|
+
const isSellingPoint = !!feature.get("tickets");
|
|
46
27
|
|
|
47
28
|
return (
|
|
48
|
-
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{!isLineNetwork &&
|
|
62
|
-
!isNotification &&
|
|
63
|
-
!isSharedMobility &&
|
|
64
|
-
!isSellingPoint &&
|
|
65
|
-
showDefaultData()}
|
|
66
|
-
</div>
|
|
67
|
-
{/* TODO find why -1px is necessary */}
|
|
68
|
-
<div className="pointer-events-none sticky bottom-[-1px] h-6 w-full bg-gradient-to-b from-transparent to-white" />
|
|
69
|
-
</div>
|
|
29
|
+
<>
|
|
30
|
+
<FeatureDetails
|
|
31
|
+
feature={feature}
|
|
32
|
+
featuresInfo={featuresInfo}
|
|
33
|
+
layer={layer}
|
|
34
|
+
/>
|
|
35
|
+
{(isSellingPoint || isSharedMobility) && (
|
|
36
|
+
<div className="p-4 text-base">
|
|
37
|
+
{isSellingPoint && <RvfSellingPointDetails feature={feature} />}
|
|
38
|
+
{isSharedMobility && <RvfSharedMobilityDetails feature={feature} />}
|
|
39
|
+
</div>
|
|
40
|
+
)}
|
|
41
|
+
</>
|
|
70
42
|
);
|
|
71
43
|
}
|
|
72
44
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { useEffect, useMemo, useState } from "preact/hooks";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
2
3
|
|
|
3
4
|
import RouteIcon from "../../RouteIcon";
|
|
5
|
+
import ShadowOverflow from "../../ShadowOverflow";
|
|
4
6
|
import useMapContext from "../../utils/hooks/useMapContext";
|
|
5
7
|
|
|
6
8
|
import type { RealtimeLine } from "mobility-toolbox-js/types";
|
|
7
9
|
import type { Feature } from "ol";
|
|
10
|
+
import type { PreactDOMAttributes } from "preact";
|
|
8
11
|
|
|
9
12
|
let cacheLineInfosById = null;
|
|
10
13
|
let cacheStopInfosById = null;
|
|
@@ -35,13 +38,11 @@ const LNP_MD_STOPS = "geops.lnp.stops";
|
|
|
35
38
|
const RUNS_PROP = "runs";
|
|
36
39
|
const ORIGINAL_LINE_ID_PROP = "original_line_id";
|
|
37
40
|
|
|
38
|
-
function
|
|
39
|
-
|
|
41
|
+
function LinesNetworkPlanDetails({
|
|
42
|
+
className,
|
|
40
43
|
features,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
features: Feature[];
|
|
44
|
-
}) {
|
|
44
|
+
...props
|
|
45
|
+
}: { className?: string; features: Feature[] } & PreactDOMAttributes) {
|
|
45
46
|
const { baseLayer } = useMapContext();
|
|
46
47
|
const [lineInfos, setLineInfos] = useState<LineInfo[]>(null);
|
|
47
48
|
const [stopInfos, setStopInfos] = useState<StopInfo[]>(null);
|
|
@@ -65,9 +66,7 @@ function RvfLineNetworkDetails({
|
|
|
65
66
|
setLineInfos(cacheLineInfosById);
|
|
66
67
|
setStopInfos(cacheStopInfosById);
|
|
67
68
|
};
|
|
68
|
-
// @ts-expect-error --- IGNORE ---
|
|
69
69
|
if (source?.url) {
|
|
70
|
-
// @ts-expect-error --- IGNORE ---git as
|
|
71
70
|
void fetchInfos(source?.url);
|
|
72
71
|
}
|
|
73
72
|
return () => {
|
|
@@ -129,107 +128,111 @@ function RvfLineNetworkDetails({
|
|
|
129
128
|
return byLineId;
|
|
130
129
|
}, [features]);
|
|
131
130
|
|
|
132
|
-
if (!
|
|
131
|
+
if (!features?.length || !lineInfos) {
|
|
133
132
|
return null;
|
|
134
133
|
}
|
|
135
134
|
|
|
136
135
|
return (
|
|
137
|
-
<
|
|
138
|
-
|
|
139
|
-
.
|
|
140
|
-
|
|
141
|
-
lineInfosByOperator[
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
<div
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
136
|
+
<ShadowOverflow {...props} className={twMerge("px-4 text-base", className)}>
|
|
137
|
+
<div className="space-y-4">
|
|
138
|
+
{Object.entries(lineInfosByOperator)
|
|
139
|
+
.sort(([operatorNameA], [operatorNameB]) => {
|
|
140
|
+
return lineInfosByOperator[operatorNameA].runs <
|
|
141
|
+
lineInfosByOperator[operatorNameB].runs
|
|
142
|
+
? 1
|
|
143
|
+
: -1;
|
|
144
|
+
})
|
|
145
|
+
.map(([operatorName, linesInfos]) => {
|
|
146
|
+
return (
|
|
147
|
+
<div className={"flex flex-col gap-2"} key={operatorName}>
|
|
148
|
+
<div>{operatorName}</div>
|
|
149
|
+
<div className="flex flex-wrap gap-2">
|
|
150
|
+
{linesInfos
|
|
151
|
+
.sort((a, b) => {
|
|
152
|
+
return a.runs < b.runs ? 1 : -1;
|
|
153
|
+
})
|
|
154
|
+
.map((lineInfo) => {
|
|
155
|
+
const {
|
|
156
|
+
color: backgroundColor,
|
|
157
|
+
// color,
|
|
158
|
+
// external_id,
|
|
159
|
+
long_name,
|
|
160
|
+
mot,
|
|
161
|
+
runs,
|
|
162
|
+
short_name: shortName,
|
|
163
|
+
text_color: textColor,
|
|
164
|
+
} = lineInfo;
|
|
165
|
+
let longName = long_name;
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
167
|
+
let stops = null;
|
|
168
|
+
//stopInfoIdsByLineId?.[id] || null;
|
|
169
|
+
if (!stops?.length) {
|
|
170
|
+
stops = null;
|
|
171
|
+
}
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
173
|
+
if (!longName && stops) {
|
|
174
|
+
const names = stops.map((stopId) => {
|
|
175
|
+
return stopInfos[stopId].short_name;
|
|
176
|
+
});
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
178
|
+
longName = [
|
|
179
|
+
...new Set([names[0], names[names.length - 1]]),
|
|
180
|
+
].join(" - ");
|
|
181
|
+
}
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
183
|
+
// Build a line object
|
|
184
|
+
const line: { type: string } & RealtimeLine = {
|
|
185
|
+
color: null,
|
|
186
|
+
id: null,
|
|
187
|
+
name: shortName,
|
|
188
|
+
stroke: null,
|
|
189
|
+
text_color: null,
|
|
190
|
+
type: mot,
|
|
191
|
+
};
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
193
|
+
if (textColor) {
|
|
194
|
+
line.text_color = textColor.startsWith("#")
|
|
195
|
+
? textColor
|
|
196
|
+
: `#${textColor}`;
|
|
197
|
+
}
|
|
198
198
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
199
|
+
if (backgroundColor) {
|
|
200
|
+
line.color = backgroundColor.startsWith("#")
|
|
201
|
+
? backgroundColor
|
|
202
|
+
: `#${backgroundColor}`;
|
|
203
|
+
}
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
<div className={longName ? "w-full" : ""} key={shortName}>
|
|
205
|
+
return (
|
|
207
206
|
<div
|
|
208
|
-
className={
|
|
209
|
-
|
|
210
|
-
// setStopInfosOpenId(stopInfosOpenId === id ? null : id);
|
|
211
|
-
// }}
|
|
207
|
+
className={longName ? "w-full" : ""}
|
|
208
|
+
key={shortName}
|
|
212
209
|
>
|
|
213
|
-
<div
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
>
|
|
222
|
-
{longName.split("-").map((name) => {
|
|
223
|
-
return <div key={name}>{name}</div>;
|
|
224
|
-
})}
|
|
210
|
+
<div
|
|
211
|
+
className={"flex justify-between gap-2"}
|
|
212
|
+
// onClick={() => {
|
|
213
|
+
// setStopInfosOpenId(stopInfosOpenId === id ? null : id);
|
|
214
|
+
// }}
|
|
215
|
+
>
|
|
216
|
+
<div>
|
|
217
|
+
<RouteIcon line={line}></RouteIcon>
|
|
225
218
|
</div>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
219
|
+
{!!longName && (
|
|
220
|
+
<div
|
|
221
|
+
className={
|
|
222
|
+
"flex-1 text-left *:before:content-['_–'] *:first:font-semibold *:first:before:!content-[_p] *:last:font-semibold *:last:before:!content-[_p]"
|
|
223
|
+
}
|
|
224
|
+
>
|
|
225
|
+
{longName.split("-").map((name) => {
|
|
226
|
+
return <div key={name}>{name}</div>;
|
|
227
|
+
})}
|
|
228
|
+
</div>
|
|
229
|
+
)}
|
|
230
|
+
{isRunsDisplay && (
|
|
231
|
+
<div className={"text-xs"}>{runs}</div>
|
|
232
|
+
)}
|
|
230
233
|
|
|
231
|
-
|
|
232
|
-
|
|
234
|
+
{/* We deactivate the list of stopsfor now */}
|
|
235
|
+
{/* {!!stops && (
|
|
233
236
|
<button className={"shrink-0"}>
|
|
234
237
|
{stopInfosOpenId === id ? (
|
|
235
238
|
<ArrowUp />
|
|
@@ -238,8 +241,8 @@ function RvfLineNetworkDetails({
|
|
|
238
241
|
)}
|
|
239
242
|
</button>
|
|
240
243
|
)} */}
|
|
241
|
-
|
|
242
|
-
|
|
244
|
+
</div>
|
|
245
|
+
{/* {!!stops && (
|
|
243
246
|
<div
|
|
244
247
|
className={`${stopInfosOpenId === id ? "" : "hidden"}`}
|
|
245
248
|
>
|
|
@@ -274,15 +277,16 @@ function RvfLineNetworkDetails({
|
|
|
274
277
|
})}
|
|
275
278
|
</div>
|
|
276
279
|
)} */}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
+
</div>
|
|
281
|
+
);
|
|
282
|
+
})}
|
|
283
|
+
</div>
|
|
280
284
|
</div>
|
|
281
|
-
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
</
|
|
285
|
+
);
|
|
286
|
+
})}
|
|
287
|
+
</div>
|
|
288
|
+
</ShadowOverflow>
|
|
285
289
|
);
|
|
286
290
|
}
|
|
287
291
|
|
|
288
|
-
export default
|
|
292
|
+
export default LinesNetworkPlanDetails;
|