@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.
Files changed (124) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/docutils.js +21 -6
  3. package/global.d.ts +1 -0
  4. package/iframe.html +15 -0
  5. package/index.html +2 -1
  6. package/index.js +295 -335
  7. package/package.json +16 -17
  8. package/src/{RvfExportMenu/RvfExportMenu.tsx → ExportMenu/ExportMenu.tsx} +12 -12
  9. package/src/ExportMenu/index.tsx +1 -0
  10. package/src/{RvfExportMenuButton/RvfExportMenuButton.tsx → ExportMenuButton/ExportMenuButton.tsx} +5 -5
  11. package/src/ExportMenuButton/index.tsx +1 -0
  12. package/src/FeatureDetails/FeatureDetails.tsx +57 -0
  13. package/src/FeatureDetails/index.ts +1 -0
  14. package/src/FeaturesInfosListener/FeaturesInfosListener.tsx +73 -0
  15. package/src/FeaturesInfosListener/index.tsx +1 -0
  16. package/src/GeolocationButton/GeolocationButton.tsx +0 -1
  17. package/src/LayerTree/LayerTree.tsx +58 -0
  18. package/src/LayerTree/TreeItem/TreeItem.tsx +151 -0
  19. package/src/LayerTree/TreeItem/index.tsx +1 -0
  20. package/src/LayerTree/index.tsx +1 -0
  21. package/src/LayerTree/layersTreeContext.ts +4 -0
  22. package/src/LayerTree/layersTreeReducer.ts +158 -0
  23. package/src/{RvfLayerTreeButton/RvfLayerTreeButton.tsx → LayerTreeButton/LayerTreeButton.tsx} +5 -5
  24. package/src/LayerTreeButton/index.tsx +1 -0
  25. package/src/{RvfTopics/RvfTopics.tsx → LayerTreeMenu/LayerTreeMenu.tsx} +17 -13
  26. package/src/LayerTreeMenu/index.tsx +1 -0
  27. package/src/LayoutState/LayoutState.tsx +277 -0
  28. package/src/LayoutState/index.tsx +1 -0
  29. package/src/LinesNetworkPlanDetails/LinesNetworkPlanDetails.tsx +292 -0
  30. package/src/LinesNetworkPlanDetails/index.tsx +1 -0
  31. package/src/{RvfLineNetworkPlanLayer/RvfLineNetworkPlanLayer.tsx → LinesNetworkPlanLayer/LinesNetworkPlanLayer.tsx} +7 -9
  32. package/src/LinesNetworkPlanLayer/index.tsx +1 -0
  33. package/src/MobilityMap/MobilityMap.tsx +274 -60
  34. package/src/MobilityMap/MobilityMapAttributes.ts +46 -50
  35. package/src/NotificationDetails/NotificationDetails.tsx +468 -0
  36. package/src/NotificationDetails/index.ts +1 -0
  37. package/src/{NotificationLayer/NotificationLayer.tsx → NotificationsLayer/NotificationsLayer.tsx} +9 -4
  38. package/src/NotificationsLayer/index.tsx +1 -0
  39. package/src/Overlay/Overlay.tsx +1 -6
  40. package/src/OverlayContent/OverlayContent.tsx +87 -0
  41. package/src/OverlayContent/index.ts +1 -0
  42. package/src/OverlayDetails/OverlayDetails.tsx +47 -0
  43. package/src/OverlayDetails/index.ts +1 -0
  44. package/src/OverlayDetailsFooter/OverlayDetailsFooter.tsx +51 -0
  45. package/src/OverlayDetailsFooter/index.tsx +1 -0
  46. package/src/OverlayDetailsHeader/OverlayDetailsHeader.tsx +35 -0
  47. package/src/OverlayDetailsHeader/index.ts +1 -0
  48. package/src/OverlayFooter/OverlayFooter.tsx +41 -0
  49. package/src/OverlayFooter/index.tsx +1 -0
  50. package/src/OverlayHeader/OverlayHeader.tsx +44 -0
  51. package/src/OverlayHeader/index.tsx +1 -0
  52. package/src/PermalinkInput/PermalinkInput.tsx +28 -0
  53. package/src/PermalinkInput/index.tsx +1 -0
  54. package/src/RouteSchedule/RouteSchedule.tsx +22 -18
  55. package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +22 -50
  56. package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +108 -104
  57. package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +189 -154
  58. package/src/RvfFeatureDetails/RvfSharedMobilityDetail/RvfSharedMobilityDetails.tsx +12 -14
  59. package/src/RvfFeatureDetailsTitle/RvfFeatureDetailsTitle.tsx +5 -5
  60. package/src/RvfMainLinkButton/RvfMainLinkButton.tsx +65 -0
  61. package/src/RvfMainLinkButton/index.tsx +1 -0
  62. package/src/RvfMobilityMap/RvfMobilityMap.tsx +183 -395
  63. package/src/RvfOverlayContent/RvfOverlayContent.tsx +2 -2
  64. package/src/RvfPoisLayer/RvfPoisLayer.tsx +2 -2
  65. package/src/RvfSearch/RvfSearch.tsx +1 -1
  66. package/src/RvfSellingPointsLayer/RvfSellingPointsLayer.tsx +2 -2
  67. package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +23 -23
  68. package/src/RvfTarifZonenLayer/RvfTarifZonenLayer.tsx +2 -2
  69. package/src/Search/Search.tsx +11 -2
  70. package/src/{RvfSearchButton/RvfSearchButton.tsx → SearchButton/SearchButton.tsx} +5 -5
  71. package/src/SearchButton/index.tsx +1 -0
  72. package/src/ShadowOverflow/ShadowOverflow.tsx +20 -0
  73. package/src/ShadowOverflow/index.tsx +1 -0
  74. package/src/{RvfShare/RvfPermalinkButton/RvfPermalinkButton.tsx → ShareMenu/PermalinkButton/PermalinkButton.tsx} +4 -4
  75. package/src/ShareMenu/PermalinkButton/index.tsx +1 -0
  76. package/src/{RvfShare/RvfShare.tsx → ShareMenu/ShareMenu.tsx} +9 -11
  77. package/src/ShareMenu/index.tsx +1 -0
  78. package/src/{RvfShareMenuButton/RvfShareMenuButton.tsx → ShareMenuButton/ShareMenuButton.tsx} +6 -6
  79. package/src/ShareMenuButton/index.tsx +1 -0
  80. package/src/SingleClickListener/SingleClickListener.tsx +55 -113
  81. package/src/SingleClickListener/index.tsx +1 -1
  82. package/src/Station/Station.tsx +10 -3
  83. package/src/StationsLayer/StationsLayer.tsx +0 -1
  84. package/src/StopsSearch/StopsSearch.tsx +3 -4
  85. package/src/StopsSearch/index.tsx +2 -1
  86. package/src/WindowMessageListener/WindowMessageListener.tsx +7 -1
  87. package/src/{RvfZoomButtons/RvfZoomButtons.tsx → ZoomButtons/ZoomButtons.tsx} +9 -12
  88. package/src/ZoomButtons/index.tsx +1 -0
  89. package/src/icons/Geolocation/airport-14-svgrepo-com.svg +41 -0
  90. package/src/ui/Button/Button.tsx +9 -2
  91. package/src/ui/Checkbox/Checkbox.tsx +32 -0
  92. package/src/ui/Checkbox/index.tsx +1 -0
  93. package/src/ui/IconButton/IconButton.tsx +24 -4
  94. package/src/ui/Input/Input.tsx +17 -0
  95. package/src/ui/Input/index.tsx +1 -0
  96. package/src/ui/InputCopy/InputCopy.tsx +86 -0
  97. package/src/ui/InputCopy/index.tsx +1 -0
  98. package/src/ui/Select/Select.tsx +24 -0
  99. package/src/ui/Select/index.tsx +1 -0
  100. package/src/utils/constants.ts +43 -42
  101. package/src/utils/exportPdf.ts +3 -5
  102. package/src/utils/hooks/useInitialLayersVisiblity.tsx +1 -1
  103. package/src/utils/hooks/useLayerConfig.tsx +2 -2
  104. package/src/utils/hooks/useLayersConfig.tsx +3 -3
  105. package/src/utils/hooks/useMapContext.tsx +67 -8
  106. package/src/utils/hooks/useRvfContext.tsx +0 -44
  107. package/src/NotificationLayer/index.tsx +0 -1
  108. package/src/RvfEmbedNavigation/DragPanWarning.ts +0 -124
  109. package/src/RvfEmbedNavigation/RvfEmbedNavigation.tsx +0 -51
  110. package/src/RvfEmbedNavigation/index.js +0 -1
  111. package/src/RvfExportMenu/index.tsx +0 -1
  112. package/src/RvfExportMenuButton/index.tsx +0 -1
  113. package/src/RvfFloatingMenu/RvfFloatingMenu.tsx +0 -44
  114. package/src/RvfFloatingMenu/index.tsx +0 -1
  115. package/src/RvfLayerTreeButton/index.tsx +0 -1
  116. package/src/RvfLineNetworkPlanLayer/index.tsx +0 -1
  117. package/src/RvfPermalink/RvfPermalink.tsx +0 -18
  118. package/src/RvfPermalink/index.tsx +0 -1
  119. package/src/RvfSearchButton/index.tsx +0 -1
  120. package/src/RvfShare/RvfPermalinkButton/index.tsx +0 -1
  121. package/src/RvfShare/index.tsx +0 -1
  122. package/src/RvfShareMenuButton/index.tsx +0 -1
  123. package/src/RvfTopics/index.tsx +0 -1
  124. package/src/RvfZoomButtons/index.tsx +0 -1
@@ -1,26 +1,34 @@
1
1
  import { memo } from "preact/compat";
2
2
  import { useMemo, useRef, useState } from "preact/hooks";
3
+ import { twMerge } from "tailwind-merge";
3
4
 
4
5
  import BaseLayer from "../BaseLayer";
5
6
  import Copyright from "../Copyright";
6
7
  import EmbedNavigation from "../EmbedNavigation";
8
+ import ExportMenuButton from "../ExportMenuButton";
9
+ import FeaturesInfosListener from "../FeaturesInfosListener";
7
10
  import GeolocationButton from "../GeolocationButton";
11
+ import LayerTreeButton from "../LayerTreeButton";
12
+ import LayoutState from "../LayoutState";
13
+ import LinesNetworkPlanLayer from "../LinesNetworkPlanLayer";
8
14
  import Map from "../Map";
9
15
  import MapDispatchEvents from "../MapDispatchEvents";
10
- import NotificationLayer from "../NotificationLayer";
16
+ import NotificationsLayer from "../NotificationsLayer";
11
17
  import Overlay from "../Overlay";
18
+ import OverlayContent from "../OverlayContent";
12
19
  import Permalink from "../Permalink";
13
20
  import RealtimeLayer from "../RealtimeLayer";
14
- import RouteSchedule from "../RouteSchedule";
15
21
  import ScaleLine from "../ScaleLine";
16
22
  import Search from "../Search";
17
- import SingleClickListener from "../SingleClickListener/SingleClickListener";
18
- import Station from "../Station";
23
+ import SearchButton from "../SearchButton";
24
+ import ShareMenuButton from "../ShareMenuButton";
25
+ import SingleClickListener from "../SingleClickListener";
19
26
  import StationsLayer from "../StationsLayer";
20
27
  import { I18nContext } from "../utils/hooks/useI18n";
21
28
  import { MapContext } from "../utils/hooks/useMapContext";
22
29
  import i18n from "../utils/i18n";
23
30
  import WindowMessageListener from "../WindowMessageListener";
31
+ import ZoomButtons from "../ZoomButtons";
24
32
 
25
33
  import MobilityMapAttributes from "./MobilityMapAttributes";
26
34
 
@@ -33,8 +41,10 @@ import type {
33
41
  MaplibreLayer,
34
42
  MaplibreStyleLayer,
35
43
  RealtimeLayer as MbtRealtimeLayer,
44
+ MocoLayer,
36
45
  } from "mobility-toolbox-js/ol";
37
46
  import type {
47
+ LayerGetFeatureInfoResponse,
38
48
  RealtimeStation,
39
49
  RealtimeStationId,
40
50
  RealtimeStopSequence,
@@ -50,18 +60,49 @@ export type MobilityMapProps = Record<
50
60
  null | string | undefined
51
61
  >;
52
62
 
63
+ const scrollableHandlerProps = {
64
+ style: { width: "calc(100% - 60px)" },
65
+ };
66
+
53
67
  function MobilityMap(props: MobilityMapProps) {
54
68
  const eventNodeRef = useRef<HTMLDivElement>();
55
69
  const [baseLayer, setBaseLayer] = useState<MaplibreLayer>();
56
- const [isFollowing, setIsFollowing] = useState(false);
57
- const [isTracking, setIsTracking] = useState(false);
70
+ const [isFollowing, setIsFollowing] = useState<boolean>(false);
71
+ const [isTracking, setIsTracking] = useState<boolean>(false);
72
+ const [isEmbed, setIsEmbed] = useState<boolean>(false);
73
+ const [hasGeolocation, setHasGeolocation] = useState<boolean>(false);
74
+ const [hasLnp, setHasLnp] = useState<boolean>(false);
75
+ const [hasDetails, setHasDetails] = useState<boolean>(false);
76
+ const [hasNotification, setHasNotification] = useState<boolean>(false);
77
+ const [hasPermalink, setHasPermalink] = useState<boolean>(false);
78
+ const [hasPrint, setHasPrint] = useState<boolean>(false);
79
+ const [hasRealtime, setHasRealtime] = useState<boolean>(false);
80
+ const [hasSearch, setHasSearch] = useState<boolean>(false);
81
+ const [hasStations, setHasStations] = useState<boolean>(false);
82
+ const [hasToolbar, setHasToolbar] = useState<boolean>(false);
83
+ const [hasShare, setHasShare] = useState<boolean>(false);
84
+ const [hasLayerTree, setHasLayerTree] = useState<boolean>(false);
85
+ const [isOverlayOpen, setIsOverlayOpen] = useState<boolean>(false);
86
+ const [isExportMenuOpen, setIsExportMenuOpen] = useState<boolean>(false);
87
+ const [isShareMenuOpen, setIsShareMenuOpen] = useState<boolean>(false);
88
+ const [isLayerTreeOpen, setIsLayerTreeOpen] = useState<boolean>(false);
89
+ const [isSearchOpen, setIsSearchOpen] = useState<boolean>(false);
58
90
  const [stopSequence, setStopSequence] = useState<RealtimeStopSequence>();
59
91
  const [stationsLayer, setStationsLayer] = useState<MaplibreStyleLayer>();
60
92
  const [station, setStation] = useState<RealtimeStation>();
61
93
  const [realtimeLayer, setRealtimeLayer] = useState<MbtRealtimeLayer>();
94
+ const [notificationsLayer, setNotificationsLayer] = useState<MocoLayer>();
95
+ const [linesNetworkPlanLayer, setLinesNetworkPlanLayer] =
96
+ useState<MaplibreStyleLayer>();
62
97
  const [map, setMap] = useState<OlMap>();
63
98
  const [stationId, setStationId] = useState<RealtimeStationId>();
64
99
  const [trainId, setTrainId] = useState<RealtimeTrainId>();
100
+ const [featuresInfos, setFeaturesInfos] = useState<
101
+ LayerGetFeatureInfoResponse[]
102
+ >([]);
103
+ const [featuresInfosHovered, setFeaturesInfosHovered] = useState<
104
+ LayerGetFeatureInfoResponse[]
105
+ >([]);
65
106
  const [selectedFeature, setSelectedFeature] = useState<Feature>(null);
66
107
  const [selectedFeatures, setSelectedFeatures] = useState<Feature[]>([]);
67
108
  const [permalinkUrlSearchParams, setPermalinkUrlSearchParams] =
@@ -70,40 +111,6 @@ function MobilityMap(props: MobilityMapProps) {
70
111
  const [previewNotifications, setPreviewNotifications] =
71
112
  useState<SituationType[]>();
72
113
 
73
- const {
74
- embed,
75
- geolocation,
76
- notification,
77
- permalink,
78
- realtime,
79
- search,
80
- tenant,
81
- } = props;
82
-
83
- const hasRealtime = useMemo(() => {
84
- return realtime === "true";
85
- }, [realtime]);
86
-
87
- const hasNotification = useMemo(() => {
88
- return notification === "true" || !!previewNotifications;
89
- }, [notification, previewNotifications]);
90
-
91
- const hasGeolocation = useMemo(() => {
92
- return geolocation === "true";
93
- }, [geolocation]);
94
-
95
- const hasPermalink = useMemo(() => {
96
- return permalink === "true";
97
- }, [permalink]);
98
-
99
- const hasSearch = useMemo(() => {
100
- return search === "true";
101
- }, [search]);
102
-
103
- const isEmbed = useMemo(() => {
104
- return embed === "true";
105
- }, [embed]);
106
-
107
114
  // Object representing all the web-component attributes and the map context values.
108
115
  const mapContextValue = useMemo(() => {
109
116
  return {
@@ -111,19 +118,61 @@ function MobilityMap(props: MobilityMapProps) {
111
118
  ...props,
112
119
  // MapContextProps
113
120
  baseLayer,
121
+ featuresInfos,
122
+ featuresInfosHovered,
123
+ hasDetails,
124
+ hasGeolocation,
125
+ hasLayerTree,
126
+ hasLnp,
127
+ hasNotification,
128
+ hasPermalink,
129
+ hasPrint,
130
+ hasRealtime,
131
+ hasSearch,
132
+ hasShare,
133
+ hasToolbar,
114
134
  isEmbed,
135
+ isExportMenuOpen,
115
136
  isFollowing,
137
+ isLayerTreeOpen,
138
+ isOverlayOpen,
139
+ isSearchOpen,
140
+ isShareMenuOpen,
116
141
  isTracking,
142
+ linesNetworkPlanLayer,
117
143
  map,
144
+ notificationsLayer,
118
145
  permalinkUrlSearchParams,
119
146
  previewNotifications,
120
147
  realtimeLayer,
121
148
  selectedFeature,
122
149
  selectedFeatures,
123
150
  setBaseLayer,
151
+ setFeaturesInfos,
152
+ setFeaturesInfosHovered,
153
+ setHasDetails,
154
+ setHasGeolocation,
155
+ setHasLayerTree,
156
+ setHasLnp,
157
+ setHasNotification,
158
+ setHasPermalink,
159
+ setHasPrint,
160
+ setHasRealtime,
161
+ setHasSearch,
162
+ setHasShare,
163
+ setHasStations,
164
+ setHasToolbar,
165
+ setIsEmbed,
166
+ setIsExportMenuOpen,
124
167
  setIsFollowing,
168
+ setIsLayerTreeOpen,
169
+ setIsOverlayOpen,
170
+ setIsSearchOpen,
171
+ setIsShareMenuOpen,
125
172
  setIsTracking,
173
+ setLinesNetworkPlanLayer,
126
174
  setMap,
175
+ setNotificationsLayer,
127
176
  setPermalinkUrlSearchParams,
128
177
  setPreviewNotifications,
129
178
  setRealtimeLayer,
@@ -143,10 +192,30 @@ function MobilityMap(props: MobilityMapProps) {
143
192
  }, [
144
193
  props,
145
194
  baseLayer,
195
+ featuresInfos,
196
+ featuresInfosHovered,
197
+ hasDetails,
198
+ hasGeolocation,
199
+ hasLayerTree,
200
+ hasLnp,
201
+ hasNotification,
202
+ hasPermalink,
203
+ hasPrint,
204
+ hasRealtime,
205
+ hasSearch,
206
+ hasShare,
207
+ hasToolbar,
146
208
  isEmbed,
209
+ isExportMenuOpen,
147
210
  isFollowing,
211
+ isLayerTreeOpen,
212
+ isOverlayOpen,
213
+ isSearchOpen,
214
+ isShareMenuOpen,
148
215
  isTracking,
216
+ linesNetworkPlanLayer,
149
217
  map,
218
+ notificationsLayer,
150
219
  permalinkUrlSearchParams,
151
220
  previewNotifications,
152
221
  realtimeLayer,
@@ -161,52 +230,197 @@ function MobilityMap(props: MobilityMapProps) {
161
230
 
162
231
  return (
163
232
  <I18nContext.Provider value={i18n}>
233
+ {/* There is a bug in tailwindcss@4 , variables are not imported in the shadow dom
234
+ see https://github.com/tailwindlabs/tailwindcss/issues/15005*/}
235
+ <style>
236
+ {`:host {
237
+ --tw-divide-y-reverse: 0;
238
+ --tw-border-style: solid;
239
+ --tw-font-weight: initial;
240
+ --tw-tracking: initial;
241
+ --tw-translate-x: 0;
242
+ --tw-translate-y: 0;
243
+ --tw-translate-z: 0;
244
+ --tw-rotate-x: rotateX(0);
245
+ --tw-rotate-y: rotateY(0);
246
+ --tw-rotate-z: rotateZ(0);
247
+ --tw-skew-x: skewX(0);
248
+ --tw-skew-y: skewY(0);
249
+ --tw-space-x-reverse: 0;
250
+ --tw-gradient-position: initial;
251
+ --tw-gradient-from: #0000;
252
+ --tw-gradient-via: #0000;
253
+ --tw-gradient-to: #0000;
254
+ --tw-gradient-stops: initial;
255
+ --tw-gradient-via-stops: initial;
256
+ --tw-gradient-from-position: 0%;
257
+ --tw-gradient-via-position: 50%;
258
+ --tw-gradient-to-position: 100%;
259
+ --tw-shadow: 0 0 #0000;
260
+ --tw-shadow-color: initial;
261
+ --tw-inset-shadow: 0 0 #0000;
262
+ --tw-inset-shadow-color: initial;
263
+ --tw-ring-color: initial;
264
+ --tw-ring-shadow: 0 0 #0000;
265
+ --tw-inset-ring-color: initial;
266
+ --tw-inset-ring-shadow: 0 0 #0000;
267
+ --tw-ring-inset: initial;
268
+ --tw-ring-offset-width: 0px;
269
+ --tw-ring-offset-color: #fff;
270
+ --tw-ring-offset-shadow: 0 0 #0000;
271
+ --tw-blur: initial;
272
+ --tw-brightness: initial;
273
+ --tw-contrast: initial;
274
+ --tw-grayscale: initial;
275
+ --tw-hue-rotate: initial;
276
+ --tw-invert: initial;
277
+ --tw-opacity: initial;
278
+ --tw-saturate: initial;
279
+ --tw-sepia: initial;
280
+ --tw-drop-shadow: initial;
281
+ --tw-duration: initial;
282
+ --tw-ease: initial;
283
+ }`}
284
+ </style>
164
285
  <style>{tailwind}</style>
165
286
  <style>{style}</style>
166
287
  <MapContext.Provider value={mapContextValue}>
288
+ <LayoutState />
167
289
  <Permalink replaceState={hasPermalink} />
168
290
  <MapDispatchEvents node={eventNodeRef.current} wcAttributes={props} />
169
291
  <WindowMessageListener eventNode={eventNodeRef.current} />
292
+ <SingleClickListener />
293
+ <FeaturesInfosListener />
294
+
295
+ {/* Layers */}
296
+ <BaseLayer />
297
+ {hasNotification && <NotificationsLayer />}
298
+ {hasRealtime && <RealtimeLayer />}
299
+ {hasStations && <StationsLayer />}
300
+ {hasLnp && <LinesNetworkPlanLayer />}
301
+
302
+ {/* Layout */}
170
303
  <div
171
304
  className="@container/main relative size-full border font-sans"
172
305
  ref={eventNodeRef}
173
306
  >
174
307
  <div className="relative flex size-full flex-col @lg/main:flex-row-reverse">
175
308
  <Map className="relative flex-1 overflow-visible">
176
- <BaseLayer />
177
- <SingleClickListener />
178
309
  <EmbedNavigation />
179
310
 
180
- {hasNotification && <NotificationLayer />}
181
- {hasRealtime && <RealtimeLayer />}
182
- {tenant && <StationsLayer />}
183
311
  <div className="absolute inset-x-2 bottom-2 z-10 flex items-end justify-between gap-2 text-[10px]">
184
312
  <ScaleLine className="bg-slate-50/70" />
185
313
  <Copyright className="bg-slate-50/70" />
186
314
  </div>
187
- <div className="absolute top-2 right-2 z-10 flex">
188
- {hasGeolocation && <GeolocationButton />}
315
+
316
+ <div className="absolute right-2 bottom-10 z-10 flex flex-col justify-between gap-2">
317
+ <ZoomButtons />
189
318
  </div>
190
- {hasSearch && (
319
+
320
+ {hasGeolocation && (
321
+ <div className="absolute top-2 right-2 z-10 flex flex-col gap-2">
322
+ <GeolocationButton />
323
+ </div>
324
+ )}
325
+
326
+ {!hasToolbar && hasSearch && (
191
327
  <div className="absolute top-2 right-12 left-2 z-10 flex max-h-[90%] max-w-96 min-w-64 flex-col">
192
328
  <Search />
193
329
  </div>
194
330
  )}
195
331
  </Map>
196
332
 
197
- <Overlay
198
- className={"z-50"}
199
- ScrollableHandlerProps={{
200
- style: { width: "calc(100% - 60px)" },
201
- }}
202
- >
203
- {hasRealtime && trainId && (
204
- <RouteSchedule className="relative overflow-x-hidden overflow-y-auto" />
205
- )}
206
- {tenant && stationId && (
207
- <Station className="relative overflow-x-hidden overflow-y-auto" />
333
+ <div className="pointer-events-none absolute top-2 bottom-2 left-2 z-10 flex flex-col gap-2 *:pointer-events-auto">
334
+ <div
335
+ className={
336
+ "relative z-10 w-fit rounded-2xl bg-black/10 p-0 backdrop-blur-sm"
337
+ }
338
+ >
339
+ {hasToolbar && (
340
+ <div
341
+ className={twMerge(
342
+ "border-grey relative z-10 flex gap-[1px] overflow-hidden rounded-2xl border",
343
+ "*:size-[46px] *:rounded-none *:border-none",
344
+ "*:first:!rounded-l-2xl",
345
+ "*:last:!rounded-r-2xl",
346
+ isSearchOpen
347
+ ? "@sm:rounded-r-none @sm:border-r-0 @sm:*:last:!rounded-r-none @sm:*:last:border-r-0"
348
+ : "",
349
+ )}
350
+ >
351
+ {hasPrint && <ExportMenuButton title={"Drucken"} />}
352
+ {hasShare && <ShareMenuButton title={"Share"} />}
353
+ {hasLayerTree && <LayerTreeButton title={"Layers"} />}
354
+ {hasSearch && <SearchButton title={"Suche"} />}
355
+ </div>
356
+ )}
357
+
358
+ {hasToolbar && hasSearch && (
359
+ <div
360
+ className={twMerge(
361
+ "absolute top-14 left-0 z-5 h-[48px] w-0 p-0 opacity-0 transition-all @sm:top-0 @sm:left-[calc(100%-47px)]",
362
+ isSearchOpen ? "w-64 opacity-100" : "",
363
+ )}
364
+ >
365
+ <Search
366
+ className={
367
+ "border-grey @container m-0 h-[40px] gap-4 rounded-2xl border p-2 px-4 text-base @sm/main:h-[48px] @sm/main:rounded-l-none @sm/main:rounded-r-2xl"
368
+ }
369
+ // inputClassName="h-6 text-base"
370
+ inputContainerClassName="border-none"
371
+ resultClassName="text-base **:hover:cursor-pointer p-2"
372
+ resultsContainerClassName="@container rounded-b-2xl max-h-[200px] overflow-y-auto border border-t-0 "
373
+ withResultsClassName="text-base !rounded-b-none"
374
+ />
375
+ </div>
376
+ )}
377
+ </div>
378
+
379
+ {/* Desktop (>= lg) */}
380
+ {isOverlayOpen && (
381
+ <div
382
+ className={twMerge(
383
+ "flex w-0 flex-1 flex-col overflow-hidden rounded-2xl @lg:min-w-64",
384
+ )}
385
+ style={{ containerType: "normal" }}
386
+ >
387
+ <Overlay
388
+ className={
389
+ "border-grey @container/overlay pointer-events-auto relative hidden flex-col overflow-hidden rounded-2xl border bg-white text-base shadow-lg @lg:flex"
390
+ }
391
+ ScrollableHandlerProps={scrollableHandlerProps}
392
+ >
393
+ <OverlayContent
394
+ hasDetails={hasDetails}
395
+ hasLayerTree={hasLayerTree}
396
+ hasPrint={hasPrint}
397
+ hasRealtime={hasRealtime}
398
+ hasSearch={false}
399
+ hasShare={hasShare}
400
+ />
401
+ </Overlay>
402
+ </div>
208
403
  )}
209
- </Overlay>
404
+ </div>
405
+
406
+ {/* Mobile (< lg) */}
407
+ {isOverlayOpen && (
408
+ <Overlay
409
+ className={
410
+ "absolute bottom-0 z-20 flex max-h-[70%] min-h-[75px] w-full flex-col border-t bg-white @lg:hidden"
411
+ }
412
+ ScrollableHandlerProps={scrollableHandlerProps}
413
+ >
414
+ <OverlayContent
415
+ hasDetails={hasDetails}
416
+ hasLayerTree={hasLayerTree}
417
+ hasPrint={hasPrint}
418
+ hasRealtime={hasRealtime}
419
+ hasSearch={false}
420
+ hasShare={hasShare}
421
+ />
422
+ </Overlay>
423
+ )}
210
424
  </div>
211
425
  </div>
212
426
  </MapContext.Provider>
@@ -2,9 +2,9 @@
2
2
 
3
3
  import {
4
4
  DEFAULT_QUERYABLE_LAYERS,
5
+ LAYERS_NAMES,
5
6
  LAYERS_WITH_LINK,
6
- RVF_EXTENT_3857,
7
- RVF_LAYERS_NAMES,
7
+ MAX_EXTENT,
8
8
  } from "../utils/constants";
9
9
 
10
10
  // import type { LayersConfig } from "../utils/hooks/useLayerConfig";
@@ -13,7 +13,7 @@ import {
13
13
  // const geopsMapsApiLink = `<a href="https://developer.geops.io/apis/maps">geOps Maps API</a>`;
14
14
  // const geopsStopsApiLink = `<a href="https://developer.geops.io/apis/stops">geOps Stops API</a>`;
15
15
  const geopsMocoApiLink = `<a href="https://geops.com/en/solution/disruption-information">geOps MOCO API</a>`;
16
- const geopsRealtimeApiLink = `<a href="https://developer.geops.io/apis/realtime">geOps Realtime API</a>`;
16
+ // const geopsRealtimeApiLink = `<a href="https://developer.geops.io/apis/realtime">geOps Realtime API</a>`;
17
17
 
18
18
  export interface WebComponentAttributeDoc {
19
19
  defaultValue?: string;
@@ -32,6 +32,7 @@ export type MobilityMapAttributeName =
32
32
  | "layers"
33
33
  | "layersconfig"
34
34
  | "layertree"
35
+ | "lnp"
35
36
  | "mainlink"
36
37
  | "mainlinktitle"
37
38
  | "mapsurl"
@@ -79,7 +80,7 @@ const attrs: MobilityMapAttributes = {
79
80
  details: {
80
81
  defaultValue: "true",
81
82
  description:
82
- "Show shared mobility details in the sidebar when we click on an shared mobility feature.",
83
+ "When a feature of a queryable layer is clicked, it displays informations about it.",
83
84
  type: "boolean",
84
85
  },
85
86
  embed: {
@@ -89,7 +90,7 @@ const attrs: MobilityMapAttributes = {
89
90
  type: "boolean",
90
91
  },
91
92
  extent: {
92
- defaultValue: RVF_EXTENT_3857.join(","),
93
+ defaultValue: MAX_EXTENT.join(","),
93
94
  description:
94
95
  "The map's extent in EPSG:3857 coordinates.<br/>Ex: 831634,5933959,940649,6173660 .<br/>Parameter required if center and zoom are not set.",
95
96
  },
@@ -100,59 +101,57 @@ const attrs: MobilityMapAttributes = {
100
101
  },
101
102
  layers: {
102
103
  defaultValue: null,
103
- description: `A comma separated list of layers's name to make visible on load, others are hidden. If empty, all layers will be hidden except the baselayer.<br/>Layers available are ${Object.values(RVF_LAYERS_NAMES).join(", ")}.`,
104
+ description: `A comma separated list of layers's name to make visible on load, others are hidden. If empty, all layers will be hidden except the baselayer.<br/>Layers available are ${Object.values(LAYERS_NAMES).join(", ")}.`,
104
105
  },
105
106
  layersconfig: {
106
- // defaultValue:
107
- // JSON.stringify({
108
- // [RVF_LAYERS_NAMES.liniennetz]: {
109
- // link: {
110
- // href: "https://www.rvf.de/fahrtinfo/netzplan",
111
- // show: true,
112
- // text: "Zu den Liniennetzplänen",
113
- // },
114
- // title: "Liniennetzpläne",
115
- // },
116
- // [RVF_LAYERS_NAMES.meldungen]: {
117
- // link: {
118
- // href: "https://moco.geops.io/situation/{{id}}",
119
- // show: true,
120
- // text: "Zum Moco",
121
- // },
122
- // },
123
- // } as LayersConfig),
124
107
  description: `A JSON string to configure the layers and other components associated to it.<br/>
125
- The layers available are : ${LAYERS_WITH_LINK}.<br/>
108
+ The layers available are : ${LAYERS_WITH_LINK.toString()}.<br/>
126
109
  Definition for a layer :
127
110
  <pre style="font-size: 12px; overflow: auto;">{
128
- liniennetz: { // The layer name, here the liniennetz layer.
129
- link: { // Define the link to display int footer of the details view, if not defined no link is displayed.
130
- text: "Zu den Liniennetzplänen", // The text of the link, if not defined the title is used.
131
- href: "https://www.rvf.de/fahrtinfo/netzplan", // The url of the link, if not defined no link is displayed.
111
+ "liniennetz": {
112
+ "link": {
113
+ "href": "https://www.rvf.de/fahrtinfo/netzplan",
114
+ "show": true,
115
+ "text": "Zu den Liniennetzplänen"
132
116
  },
133
- title: "Liniennetzpläne", // Text displayed on the layer tree and in the header of the details view.
117
+ "title": "Liniennetzpläne"
134
118
  }
135
- </pre>}`,
119
+ </pre>}
120
+ <br/>
121
+ where:
122
+ <ul style="list-style-type: disc; padding-left: 20px;">
123
+ <li><i>link</i> defined a external link displayed at the bottom of the detail view</li>
124
+ <ul style="list-style-type: disc; padding-left: 40px;">
125
+ <li><i>href</i> is the target of the link. The <i>href</i> can be template, for example for the meldungen layer you can use {{id}} to insert the id of the notification in the url.</li>
126
+ <li><i>text</i> is the text display as a link</li>
127
+ <li><i>show</i> show/hide the link in the details view</li>
128
+ </ul>
129
+ <li><i>title</i> is the title of the layer used in the details view header and in the layer tree, if not defined the layer name will be used.</li>
130
+ </ul>`,
136
131
  },
137
132
  layertree: {
138
133
  defaultValue: "true",
139
134
  description: "Show/hide the layers tree button in the toolbar.",
140
135
  type: "boolean",
141
136
  },
137
+ lnp: {
138
+ defaultValue: "true",
139
+ description: null,
140
+ type: "boolean",
141
+ },
142
142
  mainlink: {
143
- // defaultValue: "https://www.rvf.de/",
144
- description: "A link displayed on bottom left of the map.",
143
+ description:
144
+ "A link displayed on bottom left of the map. The link can be template, for example you can use {{x}} {{y}} {{z}} to insert the current position of the map in the url.<br/>Ex: http://mywebsite/mypage#{{x}}/{{y}}/{{z}}.",
145
145
  },
146
146
  mainlinktitle: {
147
- // defaultValue: "Gesamte Karte",
148
147
  description: "A title for the mainlink, used as tooltip.",
149
148
  },
150
149
  mapsurl: {
151
150
  defaultValue: "https://maps.geops.io",
152
- description: null, //`The ${geopsMapsApiLink} url to use.`,
151
+ description: null,
153
152
  },
154
153
  maxextent: {
155
- defaultValue: RVF_EXTENT_3857.join(","),
154
+ defaultValue: MAX_EXTENT.join(","),
156
155
  description:
157
156
  "The maximum extent of the map in EPSG:3857 coordinates.<br/>Ex: 831634,5933959,940649,6173660 .",
158
157
  },
@@ -165,25 +164,23 @@ const attrs: MobilityMapAttributes = {
165
164
  },
166
165
  mots: {
167
166
  description: null,
168
- // "Commas separated list of mots to display on the Realtime layer.<br/>Ex: rail,bus,coach,foot,tram,subway,gondola,funicular,ferry,car .",
169
167
  },
170
168
  notification: {
171
- defaultValue: "false",
169
+ defaultValue: "true",
172
170
  description: `Add the notification layer to the map. This layer will display informations about disruptions on the network. Data comes from
173
171
  our ${geopsMocoApiLink} .`,
174
172
  type: "boolean",
175
173
  },
176
174
  notificationat: {
177
175
  description: null,
178
- // "An ISO date string used to display active notification at this date in the notification layer. If not defined the current date will be used.<br/>Ex: 2025-08-01T00:00:00Z .",
179
176
  },
180
177
  notificationtenant: {
181
178
  defaultValue: "rvf",
182
- description: null, // `The ${geopsMocoApiLink} tenant to get the notification from.`,
179
+ description: null,
183
180
  },
184
181
  notificationurl: {
185
182
  defaultValue: "https://moco.geops.io/api/v2/",
186
- description: `The ${geopsMocoApiLink} url to use.`,
183
+ description: null,
187
184
  },
188
185
  permalink: {
189
186
  defaultValue: "false",
@@ -197,26 +194,25 @@ const attrs: MobilityMapAttributes = {
197
194
  type: "boolean",
198
195
  },
199
196
  queryablelayers: {
200
- defaultValue: DEFAULT_QUERYABLE_LAYERS,
201
- description:
202
- "A comma separated list of layers's name. The data of these layers will be queryable by click on the map (see selectedfeature event). If empty, all layers will not be queryable.",
197
+ defaultValue: DEFAULT_QUERYABLE_LAYERS.toString(),
198
+ description: `A comma separated list of layers's name. The data of these layers will be queryable by click on the map (see selectedfeature event). If empty, all layers will not be queryable.<br/>
199
+ Layers available are ${Object.values(LAYERS_NAMES).join(", ")}`,
203
200
  },
204
201
  realtime: {
205
202
  defaultValue: "true",
206
- description: `Add the realtime layer to the map. Data comes from the ${geopsRealtimeApiLink} .`,
203
+ description: null,
207
204
  type: "boolean",
208
205
  },
209
206
  realtimebboxparameters: {
210
207
  defaultValue: "line_tags=RVF",
211
208
  description: null,
212
- // "A space separated list of parameters to add to the realtime BBOX request to define custom behavior.<br/>Ex: graph=XXX line_tags=XXX.",
213
209
  },
214
210
  realtimetenant: {
215
- description: null, // `The ${geopsRealtimeApiLink} tenant to get the realtime data from.`,
211
+ description: null,
216
212
  },
217
213
  realtimeurl: {
218
214
  defaultValue: "wss://api.geops.io/tracker-ws/v1/ws",
219
- description: null, //`The ${geopsRealtimeApiLink} url to use.`,
215
+ description: null,
220
216
  },
221
217
  runs: {
222
218
  defaultValue: "false",
@@ -236,10 +232,10 @@ const attrs: MobilityMapAttributes = {
236
232
  },
237
233
  stopsurl: {
238
234
  defaultValue: "https://api.geops.io/stops/v1/",
239
- description: null, // `The ${geopsStopsApiLink} to use.`,
235
+ description: null,
240
236
  },
241
237
  tenant: {
242
- description: null, //`The tenant to use by default for all geOps APIs (Stops, Realtime, MOCO ...). Can be override for each API by other XXXXtenant parameters.`,
238
+ description: null,
243
239
  },
244
240
  toolbar: {
245
241
  defaultValue: "true",