@geops/rvf-mobility-web-component 0.1.74 → 0.1.76

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 (29) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +17 -55
  3. package/docutils.js +1 -1
  4. package/index.html +9 -1
  5. package/index.js +114 -110
  6. package/package.json +2 -2
  7. package/src/FeatureDetails/FeatureDetails.tsx +9 -18
  8. package/src/LayerTreeMenu/LayerTreeMenu.tsx +1 -1
  9. package/src/LayoutState/LayoutState.tsx +14 -1
  10. package/src/LinesNetworkPlanDetails/LinesNetworkPlanDetails.tsx +37 -68
  11. package/src/LinesNetworkPlanLayerHighlight/LinesNetworkPlanLayerHighlight.tsx +11 -3
  12. package/src/MobilityMap/MobilityMap.tsx +1 -5
  13. package/src/MobilityMap/MobilityMapAttributes.ts +9 -5
  14. package/src/MobilityNotifications/MobilityNotifications.tsx +1 -6
  15. package/src/NotificationsLayer/NotificationsLayer.tsx +1 -1
  16. package/src/OverlayContent/OverlayContent.tsx +1 -2
  17. package/src/OverlayDetails/OverlayDetails.tsx +23 -2
  18. package/src/OverlayDetailsHeader/OverlayDetailsHeader.tsx +3 -0
  19. package/src/OverlayHeader/OverlayHeader.tsx +1 -1
  20. package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +5 -4
  21. package/src/RvfFeatureDetails/RvfSellingPointDetails/RvfSellingPointDetails.tsx +1 -1
  22. package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +95 -84
  23. package/src/SingleClickListener/SingleClickListener.tsx +1 -1
  24. package/src/utils/constants.ts +2 -1
  25. package/src/utils/hooks/useLayersConfig.tsx +3 -0
  26. package/src/utils/hooks/{useLnpLineInfo.tsx → useLnp.tsx} +24 -9
  27. package/src/utils/hooks/useMapContext.tsx +4 -0
  28. package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +0 -238
  29. package/src/RvfSingleClickListener/index.tsx +0 -1
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@geops/rvf-mobility-web-component",
3
3
  "license": "UNLICENSED",
4
4
  "description": "Web components for rvf in the domains of mobility and logistics.",
5
- "version": "0.1.74",
5
+ "version": "0.1.76",
6
6
  "homepage": "https://rvf-mobility-web-component-geops.vercel.app/",
7
7
  "type": "module",
8
8
  "main": "index.js",
@@ -12,7 +12,7 @@
12
12
  "jspdf": "^3.0.3",
13
13
  "lodash.debounce": "^4.0.8",
14
14
  "maplibre-gl": "^5.9.0",
15
- "mobility-toolbox-js": "3.4.5",
15
+ "mobility-toolbox-js": "3.4.6-beta.1",
16
16
  "ol": "^10.6.1",
17
17
  "preact": "^10.27.2",
18
18
  "preact-custom-element": "^4.5.1",
@@ -23,37 +23,28 @@ export interface FeatureDetailsProps {
23
23
  */
24
24
  function FeatureDetails({ feature, featuresInfo, layer }: FeatureDetailsProps) {
25
25
  const {
26
+ linesIds,
26
27
  linesNetworkPlanLayer,
27
28
  notificationsLayer,
28
29
  realtimeLayer,
29
30
  stationId,
30
31
  stationsLayer,
31
- tenant,
32
32
  trainId,
33
33
  } = useMapContext();
34
34
 
35
- if (!feature) {
35
+ if (!layer) {
36
36
  return null;
37
37
  }
38
38
 
39
39
  return (
40
40
  <>
41
- {feature &&
42
- !!realtimeLayer &&
43
- !!layer &&
44
- layer.get("name") === realtimeLayer.get("name") &&
45
- trainId && <RouteSchedule />}
46
- {feature &&
47
- !!stationsLayer &&
48
- !!layer &&
49
- layer.get("name") === stationsLayer.get("name") &&
50
- tenant &&
51
- stationId && <Station />}
52
- {feature &&
53
- !!linesNetworkPlanLayer &&
54
- !!layer &&
55
- layer.get("name") === linesNetworkPlanLayer.get("name") &&
56
- featuresInfo?.features?.length && (
41
+ {!!realtimeLayer && layer === realtimeLayer && trainId && (
42
+ <RouteSchedule />
43
+ )}
44
+ {!!stationsLayer && layer === stationsLayer && stationId && <Station />}
45
+ {!!linesNetworkPlanLayer &&
46
+ layer === linesNetworkPlanLayer &&
47
+ linesIds && (
57
48
  <LinesNetworkPlanDetails
58
49
  className={contentClassName}
59
50
  features={featuresInfo?.features || []}
@@ -28,7 +28,7 @@ export interface LayerTreeConfig {
28
28
 
29
29
  export type LayerTreeMenuProps = {
30
30
  filter?: (layer: BaseLayer) => boolean;
31
- order: string[];
31
+ order?: string[];
32
32
  } & HTMLAttributes<HTMLDivElement> &
33
33
  Partial<LayerTreeProps> &
34
34
  PreactDOMAttributes;
@@ -1,5 +1,6 @@
1
1
  import { useEffect } from "preact/hooks";
2
2
 
3
+ import useLnpLineInfo from "../utils/hooks/useLnp";
3
4
  import useMapContext from "../utils/hooks/useMapContext";
4
5
 
5
6
  /**
@@ -12,6 +13,7 @@ function LayoutState() {
12
13
  geolocation,
13
14
  hasDetails,
14
15
  hasLayerTree,
16
+ hasLnp,
15
17
  hasPrint,
16
18
  hasRealtime,
17
19
  hasShare,
@@ -20,7 +22,9 @@ function LayoutState() {
20
22
  isSearchOpen,
21
23
  isShareMenuOpen,
22
24
  layertree,
25
+ linesIds,
23
26
  lnp,
27
+ lnpid,
24
28
  mapset,
25
29
  notification,
26
30
  permalink,
@@ -59,6 +63,8 @@ function LayoutState() {
59
63
  trainId,
60
64
  } = useMapContext();
61
65
 
66
+ const lineInfo = useLnpLineInfo(lnpid);
67
+
62
68
  useEffect(() => {
63
69
  setHasStations(!!tenant);
64
70
  }, [setHasStations, tenant]);
@@ -115,6 +121,10 @@ function LayoutState() {
115
121
  setHasLayerTree(layertree === "true");
116
122
  }, [layertree, setHasLayerTree]);
117
123
 
124
+ useEffect(() => {
125
+ setLinesIds(lineInfo ? [lineInfo.external_id] : null);
126
+ }, [lineInfo, setLinesIds]);
127
+
118
128
  useEffect(() => {
119
129
  if (isSearchOpen) {
120
130
  setIsLayerTreeOpen(false);
@@ -270,7 +280,8 @@ function LayoutState() {
270
280
  (hasLayerTree && isLayerTreeOpen) ||
271
281
  (hasShare && isShareMenuOpen) ||
272
282
  (hasRealtime && !!trainId) ||
273
- (tenant && !!stationId),
283
+ (tenant && !!stationId) ||
284
+ (hasLnp && !!linesIds),
274
285
  );
275
286
  }, [
276
287
  hasDetails,
@@ -286,6 +297,8 @@ function LayoutState() {
286
297
  tenant,
287
298
  stationId,
288
299
  setIsOverlayOpen,
300
+ hasLnp,
301
+ linesIds,
289
302
  ]);
290
303
 
291
304
  return null;
@@ -1,43 +1,18 @@
1
- import { useEffect, useMemo, useState } from "preact/hooks";
1
+ import { useCallback, useMemo, useState } from "preact/hooks";
2
2
  import { twMerge } from "tailwind-merge";
3
3
 
4
4
  import RouteIcon from "../RouteIcon";
5
5
  import ShadowOverflow from "../ShadowOverflow";
6
- import {
7
- LNP_LINE_ID_PROP,
8
- LNP_MD_LINES,
9
- LNP_MD_STOPS,
10
- LNP_SOURCE_ID,
11
- } from "../utils/constants";
6
+ import { LAYERS_NAMES, LNP_LINE_ID_PROP } from "../utils/constants";
7
+ import useLayerConfig from "../utils/hooks/useLayerConfig";
8
+ import { useLnpLinesInfos, useLnpStopsInfos } from "../utils/hooks/useLnp";
12
9
  import useMapContext from "../utils/hooks/useMapContext";
13
10
 
14
- import type { VectorTileSource } from "maplibre-gl";
15
11
  import type { RealtimeLine } from "mobility-toolbox-js/types";
16
12
  import type { Feature } from "ol";
17
13
  import type { PreactDOMAttributes } from "preact";
18
14
 
19
- let cacheLineInfosById = null;
20
- let cacheStopInfosById = null;
21
-
22
- interface LineInfo {
23
- color: string;
24
- external_id: string;
25
- id: string;
26
- long_name: string;
27
- mot: string;
28
- operator_name: string;
29
- runs: number;
30
- short_name: string;
31
- text_color: string;
32
- }
33
-
34
- interface StopInfo {
35
- external_id: string;
36
- importance: number;
37
- long_name: string;
38
- short_name: string;
39
- visibility_level: number;
40
- }
15
+ import type { LineInfo } from "../utils/hooks/useLnp";
41
16
 
42
17
  const RUNS_PROP = "runs";
43
18
 
@@ -46,9 +21,11 @@ function LinesNetworkPlanDetails({
46
21
  features,
47
22
  ...props
48
23
  }: { className?: string; features: Feature[] } & PreactDOMAttributes) {
49
- const { baseLayer } = useMapContext();
50
- const [lineInfos, setLineInfos] = useState<LineInfo[]>(null);
51
- const [stopInfos, setStopInfos] = useState<StopInfo[]>(null);
24
+ const { linesIds } = useMapContext();
25
+ const lineInfos = useLnpLinesInfos();
26
+ const stopInfos = useLnpStopsInfos();
27
+ const layerConfig = useLayerConfig(LAYERS_NAMES.linesnetworkplan);
28
+
52
29
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
53
30
  const [stopInfosOpenId, setStopInfosOpenId] = useState<string>(null);
54
31
 
@@ -58,45 +35,27 @@ function LinesNetworkPlanDetails({
58
35
  );
59
36
  }, []);
60
37
 
61
- useEffect(() => {
62
- const source = baseLayer?.mapLibreMap?.getSource(LNP_SOURCE_ID);
63
- const abortController = new AbortController();
64
- const fetchInfos = async (url) => {
65
- if (!cacheLineInfosById) {
66
- const response = await fetch(url, { signal: abortController.signal });
67
- const data = await response.json();
68
- cacheLineInfosById = data[LNP_MD_LINES];
69
- cacheStopInfosById = data[LNP_MD_STOPS];
70
- if (!cacheLineInfosById) {
71
- // eslint-disable-next-line no-console
72
- console.warn("No lines informations found from ", url);
73
- }
74
- if (!cacheStopInfosById) {
75
- // eslint-disable-next-line no-console
76
- console.warn("No stops informations found from ", url);
77
- }
38
+ const getLink = useCallback(
39
+ (id: string) => {
40
+ const href = layerConfig?.link?.href;
41
+ if (href) {
42
+ return href.replace(`{{id}}`, id);
78
43
  }
79
- setLineInfos(cacheLineInfosById);
80
- setStopInfos(cacheStopInfosById);
81
- };
82
- const url = (source as VectorTileSource)?.url;
83
- if (url) {
84
- void fetchInfos(url);
85
- }
86
- return () => {
87
- abortController?.abort();
88
- };
89
- }, [baseLayer?.mapLibreMap]);
44
+ return null;
45
+ },
46
+ [layerConfig],
47
+ );
90
48
 
91
49
  const lineInfosByOperator: Record<string, LineInfo[]> = useMemo(() => {
92
50
  const byOperators = {};
93
51
 
94
52
  [
95
- ...new Set(
96
- features.map((f) => {
53
+ ...new Set([
54
+ ...(linesIds || []),
55
+ ...features.map((f) => {
97
56
  return f.get(LNP_LINE_ID_PROP);
98
57
  }),
99
- ),
58
+ ]),
100
59
  ]
101
60
  .filter((id) => {
102
61
  return !!id && !!lineInfos?.[id];
@@ -110,7 +69,7 @@ function LinesNetworkPlanDetails({
110
69
  lineInfos[id].id = id;
111
70
 
112
71
  const runs = features
113
- .filter((f) => {
72
+ ?.filter((f) => {
114
73
  return f.get(LNP_LINE_ID_PROP) === id;
115
74
  })
116
75
  .reduce((acc, featuree) => {
@@ -123,7 +82,7 @@ function LinesNetworkPlanDetails({
123
82
  });
124
83
 
125
84
  return byOperators;
126
- }, [features, lineInfos]);
85
+ }, [features, lineInfos, linesIds]);
127
86
 
128
87
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
129
88
  const stopInfoIdsByLineId: Record<string, string[]> = useMemo(() => {
@@ -143,7 +102,7 @@ function LinesNetworkPlanDetails({
143
102
  return byLineId;
144
103
  }, [features]);
145
104
 
146
- if (!features?.length) {
105
+ if (!features?.length && !linesIds?.length) {
147
106
  return null;
148
107
  }
149
108
 
@@ -231,7 +190,17 @@ function LinesNetworkPlanDetails({
231
190
  // }}
232
191
  >
233
192
  <div>
234
- <RouteIcon line={line}></RouteIcon>
193
+ {getLink(lineInfo.id) ? (
194
+ <a
195
+ href={getLink(lineInfo.id)}
196
+ rel="noreferrer"
197
+ target="_blank"
198
+ >
199
+ <RouteIcon line={line}></RouteIcon>
200
+ </a>
201
+ ) : (
202
+ <RouteIcon line={line}></RouteIcon>
203
+ )}
235
204
  </div>
236
205
  {!!longName && (
237
206
  <div className={"flex-1 text-left"}>
@@ -15,7 +15,6 @@ function LinesNetworkPlanLayerHighlight(props: MaplibreStyleLayerOptions) {
15
15
  const {
16
16
  baseLayer,
17
17
  featuresInfos,
18
- lines,
19
18
  linesIds,
20
19
  linesNetworkPlanLayer,
21
20
  map,
@@ -58,6 +57,11 @@ function LinesNetworkPlanLayerHighlight(props: MaplibreStyleLayerOptions) {
58
57
  return featuresInfo.layer === linesNetworkPlanLayer;
59
58
  })?.features || [];
60
59
 
60
+ if (!features.length) {
61
+ setLinesIds(null);
62
+ return;
63
+ }
64
+
61
65
  const ids = [
62
66
  ...new Set(
63
67
  (features || []).map((f) => {
@@ -65,7 +69,11 @@ function LinesNetworkPlanLayerHighlight(props: MaplibreStyleLayerOptions) {
65
69
  }),
66
70
  ),
67
71
  ];
68
- setLinesIds(ids);
72
+ if (!ids.length) {
73
+ setLinesIds(null);
74
+ return;
75
+ }
76
+ setLinesIds(ids?.length ? ids : null);
69
77
  }, [featuresInfos, layer, linesNetworkPlanLayer, setLinesIds]);
70
78
 
71
79
  useEffect(() => {
@@ -81,7 +89,7 @@ function LinesNetworkPlanLayerHighlight(props: MaplibreStyleLayerOptions) {
81
89
  // Reset the filter
82
90
  highlightLinesNetworkPlan(undefined, baseLayer);
83
91
  };
84
- }, [baseLayer, baseLayer?.loaded, layer, lines, linesIds]);
92
+ }, [baseLayer, baseLayer?.loaded, layer, linesIds]);
85
93
 
86
94
  return null;
87
95
  }
@@ -102,7 +102,7 @@ function MobilityMap(props: MobilityMapProps) {
102
102
  const [previewNotifications, setPreviewNotifications] =
103
103
  useState<SituationType[]>();
104
104
 
105
- const { lang, layers, lines, permalinktemplate } = props;
105
+ const { lang, layers, permalinktemplate } = props;
106
106
 
107
107
  // Apply initial visibility of layers
108
108
  useInitialLayersVisiblity(map, layers, permalinktemplate);
@@ -239,10 +239,6 @@ function MobilityMap(props: MobilityMapProps) {
239
239
  i18n.locale(lang);
240
240
  }, [lang]);
241
241
 
242
- useEffect(() => {
243
- setLinesIds(lines?.split(","));
244
- }, [lines]);
245
-
246
242
  return (
247
243
  <I18nContext.Provider value={i18n}>
248
244
  {/* There is a bug in tailwindcss@4 , variables are not imported in the shadow dom
@@ -35,8 +35,8 @@ export type MobilityMapAttributeName =
35
35
  | "layers"
36
36
  | "layersconfig"
37
37
  | "layertree"
38
- | "lines"
39
38
  | "lnp"
39
+ | "lnpid"
40
40
  | "mainlink"
41
41
  | "mainlinktitle"
42
42
  | "mapset"
@@ -152,6 +152,10 @@ where:
152
152
  <li><i>text</i> is the text display as a link</li>
153
153
  <li><i>show</i> show/hide the link in the details view</li>
154
154
  </ul>
155
+ <li><i>featurelink</i> defined a external link used when you click on single feature in detail view</li>
156
+ <ul style="list-style-type: disc; padding-left: 40px;">
157
+ <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>
158
+ </ul>
155
159
  <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>
156
160
  </ul>`,
157
161
  public: true,
@@ -162,16 +166,16 @@ where:
162
166
  public: true,
163
167
  type: "boolean",
164
168
  },
165
- lines: {
166
- description: `A comma separated list of line ids to highlight on the linesnetworkplan layer. The line ids are the original_line_id property of the lines in the network plan.<br/>Ex: S1,RE10,RE1.`,
167
- public: false,
168
- },
169
169
  lnp: {
170
170
  defaultValue: "true",
171
171
  description: `Add the linesnetworkplans layer to the map. This layer will display lines network plans on the map.`,
172
172
  public: false,
173
173
  type: "boolean",
174
174
  },
175
+ lnpid: {
176
+ description: `An id or a short/long name of a line to highlight. <br/>Ex: S1`,
177
+ public: false,
178
+ },
175
179
  mainlink: {
176
180
  description:
177
181
  "A link displayed on bottom left of the map. The link can be a 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#map/{{x}}/{{y}}/{{z}}.",
@@ -28,11 +28,6 @@ function MobilityNotifications({
28
28
  const [situations, setSituations] = useState<SituationType[]>([]);
29
29
 
30
30
  useEffect(() => {
31
- // Rounded to minutes for caching purposes
32
- const now = new Date();
33
- now.setMilliseconds(0);
34
- now.setSeconds(0);
35
-
36
31
  new MocoAPI({
37
32
  apiKey: apikey || undefined,
38
33
  tenant: notificationtenant,
@@ -43,7 +38,7 @@ function MobilityNotifications({
43
38
  includeGeoms: false,
44
39
  includeLines: true,
45
40
  includeStops: true,
46
- publicAt: now.toISOString(),
41
+ publicNow: true, // improve caching efficiency compare to use of publicAt
47
42
  })
48
43
  .then((data) => {
49
44
  if (data?.paginatedSituations?.results) {
@@ -28,9 +28,9 @@ function NotificationsLayer(props?: Partial<MocoLayerOptions>) {
28
28
  apiParameters: {
29
29
  contentMedium: true,
30
30
  },
31
- date: notificationat ? new Date(notificationat) : undefined,
32
31
  maplibreLayer: baseLayer,
33
32
  name: LAYER_NAME_NOTIFICATIONS,
33
+ publicAt: notificationat ? new Date(notificationat) : undefined,
34
34
  situations: previewNotifications,
35
35
  tenant: notificationtenant,
36
36
  url: notificationurl,
@@ -30,7 +30,6 @@ function OverlayContent({
30
30
  isLayerTreeOpen,
31
31
  isSearchOpen,
32
32
  isShareMenuOpen,
33
- selectedFeature,
34
33
  setIsExportMenuOpen,
35
34
  setIsLayerTreeOpen,
36
35
  setIsShareMenuOpen,
@@ -39,7 +38,7 @@ function OverlayContent({
39
38
 
40
39
  return (
41
40
  <>
42
- {hasDetails && selectedFeature && <OverlayDetails />}
41
+ {hasDetails && <OverlayDetails />}
43
42
  {hasPrint && isExportMenuOpen && (
44
43
  <>
45
44
  <OverlayHeader
@@ -13,10 +13,15 @@ import useMapContext from "../utils/hooks/useMapContext";
13
13
  function OverlayDetails() {
14
14
  const {
15
15
  featuresInfos,
16
+ linesIds,
17
+ linesNetworkPlanLayer,
18
+ notificationId,
19
+ notificationsLayer,
16
20
  realtimeLayer,
17
21
  selectedFeature,
18
22
  setFeaturesInfos,
19
23
  setLinesIds,
24
+ setNotificationId,
20
25
  setStationId,
21
26
  setTrainId,
22
27
  stationId,
@@ -40,9 +45,24 @@ function OverlayDetails() {
40
45
  if (stationId) {
41
46
  return stationsLayer;
42
47
  }
48
+ if (linesIds) {
49
+ return linesNetworkPlanLayer;
50
+ }
51
+ if (notificationId) {
52
+ return notificationsLayer;
53
+ }
43
54
  return undefined;
44
- }, [featuresInfo?.layer, realtimeLayer, stationId, stationsLayer, trainId]);
45
-
55
+ }, [
56
+ featuresInfo?.layer,
57
+ trainId,
58
+ stationId,
59
+ linesIds,
60
+ notificationId,
61
+ realtimeLayer,
62
+ stationsLayer,
63
+ linesNetworkPlanLayer,
64
+ notificationsLayer,
65
+ ]);
46
66
  return (
47
67
  <>
48
68
  <OverlayDetailsHeader
@@ -53,6 +73,7 @@ function OverlayDetails() {
53
73
  setTrainId(null);
54
74
  setStationId(null);
55
75
  setLinesIds(null);
76
+ setNotificationId(null);
56
77
  }}
57
78
  />
58
79
  <FeatureDetails
@@ -22,6 +22,9 @@ function OverlayDetailsHeader({
22
22
  }: OverlayDetailsHeaderProps) {
23
23
  const { t } = useI18n();
24
24
  const layerConfig = useLayerConfig(layer?.get("name"));
25
+ if (!layer) {
26
+ return null;
27
+ }
25
28
  return (
26
29
  <OverlayHeader
27
30
  title={t(layerConfig?.title || "") || (layerConfig?.title ?? "")}
@@ -24,7 +24,7 @@ function OverlayHeader({
24
24
  {...props}
25
25
  className={twMerge(
26
26
  `flex flex-row items-center justify-between gap-2 border-b p-2 pl-4`,
27
- className,
27
+ className as string,
28
28
  )}
29
29
  >
30
30
  {/* We set text-base so the clamp works on overlay container, not main */}
@@ -9,9 +9,10 @@ import type { FeatureDetailsProps } from "../FeatureDetails/FeatureDetails";
9
9
 
10
10
  const getIsSharedMobility = (selectedFeature): boolean => {
11
11
  if (
12
- selectedFeature.get("station_id") ||
13
- selectedFeature.get("vehicle_id") ||
14
- selectedFeature.get("cluster_id")
12
+ !!selectedFeature &&
13
+ (selectedFeature.get("station_id") ||
14
+ selectedFeature.get("vehicle_id") ||
15
+ selectedFeature.get("cluster_id"))
15
16
  ) {
16
17
  return true;
17
18
  }
@@ -23,7 +24,7 @@ function RvfFeatureDetails({
23
24
  layer,
24
25
  }: FeatureDetailsProps) {
25
26
  const isSharedMobility = getIsSharedMobility(feature);
26
- const isSellingPoint = !!feature.get("tickets");
27
+ const isSellingPoint = !!feature?.get("tickets");
27
28
 
28
29
  return (
29
30
  <>
@@ -24,7 +24,7 @@ function RvfSellingPointDetails({ feature }: { feature: Feature }) {
24
24
  zip_code: zip,
25
25
  } = feature.getProperties();
26
26
  return (
27
- <ShadowOverflow className="p-4 text-base">
27
+ <ShadowOverflow className="px-4 text-base">
28
28
  <div className="flex flex-col gap-4">
29
29
  <div className="flex gap-2">
30
30
  <span className={"min-w-[26px]"}>