@geops/rvf-mobility-web-component 0.1.9 → 0.1.11
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/.github/CODEOWNERS +37 -0
- package/.github/workflows/conventional-pr-title.yml +36 -0
- package/CHANGELOG.md +55 -0
- package/README.md +3 -1
- package/doc/package.json +5 -5
- package/doc/src/app/components/GeopsMobilityDoc.tsx +19 -0
- package/docutils.js +198 -0
- package/index.html +48 -217
- package/index.js +683 -91
- package/input.css +15 -1
- package/jest-setup.js +3 -2
- package/package.json +9 -8
- package/scripts/dev.mjs +1 -1
- package/search.html +38 -69
- package/src/GeolocationButton/GeolocationButton.tsx +6 -17
- package/src/LayerTree/LayerTree.tsx +44 -0
- package/src/LayerTree/TreeItem/TreeItem.tsx +145 -0
- package/src/LayerTree/TreeItem/index.tsx +1 -0
- package/src/LayerTree/TreeItemContainer/TreeItemContainer.tsx +16 -0
- package/src/LayerTree/TreeItemContainer/index.tsx +1 -0
- package/src/LayerTree/index.tsx +1 -0
- package/src/LayerTree/layersTreeContext.ts +4 -0
- package/src/LayerTree/layersTreeReducer.ts +156 -0
- package/src/Map/Map.tsx +57 -12
- package/src/MobilityMap/MobilityMap.tsx +22 -9
- package/src/MobilityMap/index.css +0 -13
- package/src/RealtimeLayer/RealtimeLayer.tsx +1 -1
- package/src/RvfButton/RvfButton.tsx +45 -0
- package/src/RvfButton/index.tsx +1 -0
- package/src/RvfExportMenu/RvfExportMenu.tsx +95 -0
- package/src/RvfExportMenu/index.tsx +1 -0
- package/src/RvfExportMenuButton/RvfExportMenuButton.tsx +27 -0
- package/src/RvfExportMenuButton/index.tsx +1 -0
- package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +29 -0
- package/src/RvfFeatureDetails/index.tsx +1 -0
- package/src/RvfIconButton/RvfIconButton.tsx +35 -0
- package/src/RvfIconButton/index.tsx +1 -0
- package/src/RvfMobilityMap/RvfMobilityMap.tsx +132 -52
- package/src/RvfMobilityMap/index.css +0 -13
- package/src/RvfModal/RvfModal.tsx +52 -0
- package/src/RvfModal/index.tsx +1 -0
- package/src/RvfPoisLayer/RvfPoisLayer.tsx +39 -0
- package/src/RvfPoisLayer/index.tsx +1 -0
- package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +88 -0
- package/src/RvfSharedMobilityLayerGroup/index.tsx +1 -0
- package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +137 -0
- package/src/RvfSingleClickListener/index.tsx +1 -0
- package/src/RvfZoomButtons/RvfZoomButtons.tsx +73 -0
- package/src/RvfZoomButtons/index.tsx +1 -0
- package/src/Search/Search.tsx +11 -9
- package/src/SingleClickListener/index.tsx +1 -1
- package/src/StationsLayer/StationsLayer.tsx +0 -1
- package/src/StopsSearch/StopsSearch.tsx +38 -6
- package/src/TopicMenu/TopicMenu.tsx +143 -0
- package/src/TopicMenu/index.tsx +1 -0
- package/src/icons/Cancel/Cancel.tsx +21 -0
- package/src/icons/Cancel/cancel.svg +7 -0
- package/src/icons/Cancel/index.tsx +1 -0
- package/src/icons/Download/Download.tsx +20 -0
- package/src/icons/Download/download.svg +15 -0
- package/src/icons/Download/index.tsx +1 -0
- package/src/icons/Elevator/Elevator.tsx +1 -1
- package/src/icons/Geolocation/Geolocation.tsx +21 -0
- package/src/icons/Geolocation/index.tsx +1 -0
- package/src/icons/Menu/Menu.tsx +32 -0
- package/src/icons/Menu/index.tsx +1 -0
- package/src/icons/Menu/menu.svg +9 -0
- package/src/icons/Minus/Minus.tsx +19 -0
- package/src/icons/Minus/index.tsx +1 -0
- package/src/icons/Minus/minus.svg +7 -0
- package/src/icons/Plus/Plus.tsx +19 -0
- package/src/icons/Plus/index.tsx +1 -0
- package/src/icons/Plus/plus.svg +7 -0
- package/src/index.tsx +2 -0
- package/src/utils/constants.ts +9 -0
- package/src/utils/createMobiDataBwWfsLayer.ts +120 -0
- package/src/utils/exportPdf.ts +677 -0
- package/src/utils/hooks/useRvfContext.tsx +37 -0
- package/src/utils/hooks/useUpdatePermalink.tsx +2 -9
- package/tailwind.config.mjs +60 -8
package/src/Map/Map.tsx
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Map as OlMap } from "ol";
|
|
1
|
+
import { Map as OlMap, View } from "ol";
|
|
2
|
+
import { unByKey } from "ol/Observable";
|
|
2
3
|
// @ts-expect-error bad type definition
|
|
3
4
|
import olStyle from "ol/ol.css";
|
|
4
5
|
import { JSX, PreactDOMAttributes } from "preact";
|
|
5
6
|
import { memo } from "preact/compat";
|
|
6
|
-
import { useEffect, useRef } from "preact/hooks";
|
|
7
|
+
import { useEffect, useMemo, useRef } from "preact/hooks";
|
|
7
8
|
|
|
8
9
|
import useMapContext from "../utils/hooks/useMapContext";
|
|
9
10
|
|
|
@@ -12,19 +13,51 @@ export type RealtimeMapProps = JSX.HTMLAttributes<HTMLDivElement> &
|
|
|
12
13
|
|
|
13
14
|
function Map({ children, ...props }: RealtimeMapProps) {
|
|
14
15
|
const mapRef = useRef();
|
|
15
|
-
const {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
const { center, extent, map, maxextent, maxzoom, minzoom, setMap, zoom } =
|
|
17
|
+
useMapContext();
|
|
18
|
+
|
|
19
|
+
const view = useMemo(() => {
|
|
20
|
+
if (!maxextent) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const bbox = maxextent.split(",").map((c) => {
|
|
24
|
+
return parseFloat(c);
|
|
25
|
+
});
|
|
26
|
+
return new View({
|
|
27
|
+
constrainOnlyCenter: false, // allow to have the same value as extent and max extent
|
|
28
|
+
extent: bbox,
|
|
29
|
+
showFullExtent: true,
|
|
30
|
+
});
|
|
31
|
+
}, [maxextent]);
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (!map || !view) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const key = map.on("change:view", (evt) => {
|
|
38
|
+
const oldView = evt.oldValue;
|
|
39
|
+
if (oldView) {
|
|
40
|
+
view.setMinZoom(oldView.getMinZoom());
|
|
41
|
+
view.setMaxZoom(oldView.getMaxZoom());
|
|
42
|
+
view.setCenter(oldView.getCenter());
|
|
43
|
+
view.setZoom(oldView.getZoom());
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
map.setView(view);
|
|
47
|
+
|
|
48
|
+
return () => {
|
|
49
|
+
unByKey(key);
|
|
50
|
+
};
|
|
51
|
+
}, [map, view]);
|
|
23
52
|
|
|
24
53
|
useEffect(() => {
|
|
25
54
|
let newMap: OlMap;
|
|
26
55
|
if (mapRef.current) {
|
|
27
|
-
newMap = new OlMap({
|
|
56
|
+
newMap = new OlMap({
|
|
57
|
+
controls: [],
|
|
58
|
+
// pixelRatio: 3,
|
|
59
|
+
target: mapRef.current,
|
|
60
|
+
});
|
|
28
61
|
setMap(newMap);
|
|
29
62
|
}
|
|
30
63
|
|
|
@@ -35,7 +68,19 @@ function Map({ children, ...props }: RealtimeMapProps) {
|
|
|
35
68
|
}, [setMap]);
|
|
36
69
|
|
|
37
70
|
useEffect(() => {
|
|
38
|
-
if (!map) {
|
|
71
|
+
if (!map || !extent) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const bbox = extent.split(",").map((c) => {
|
|
75
|
+
return parseFloat(c);
|
|
76
|
+
});
|
|
77
|
+
if (bbox) {
|
|
78
|
+
map.getView().fit(bbox);
|
|
79
|
+
}
|
|
80
|
+
}, [map, extent]);
|
|
81
|
+
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (!map || !center) {
|
|
39
84
|
return;
|
|
40
85
|
}
|
|
41
86
|
const [x, y] = center.split(",").map((c) => {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "mobility-toolbox-js/types";
|
|
12
12
|
import { Map as OlMap } from "ol";
|
|
13
13
|
import { memo } from "preact/compat";
|
|
14
|
-
import { useEffect, useMemo, useState } from "preact/hooks";
|
|
14
|
+
import { useEffect, useMemo, useRef, useState } from "preact/hooks";
|
|
15
15
|
|
|
16
16
|
import BaseLayer from "../BaseLayer";
|
|
17
17
|
import Copyright from "../Copyright";
|
|
@@ -41,8 +41,10 @@ export interface MobilityMapProps {
|
|
|
41
41
|
apikey?: string;
|
|
42
42
|
baselayer?: string;
|
|
43
43
|
center?: string;
|
|
44
|
+
extent?: string;
|
|
44
45
|
geolocation?: string;
|
|
45
46
|
mapsurl?: string;
|
|
47
|
+
maxextent?: string;
|
|
46
48
|
maxzoom?: string;
|
|
47
49
|
minzoom?: string;
|
|
48
50
|
mots?: string;
|
|
@@ -63,8 +65,10 @@ function MobilityMap({
|
|
|
63
65
|
apikey = null,
|
|
64
66
|
baselayer = "travic_v2",
|
|
65
67
|
center = "831634,5933959",
|
|
68
|
+
extent = null,
|
|
66
69
|
geolocation = "true",
|
|
67
70
|
mapsurl = "https://maps.geops.io",
|
|
71
|
+
maxextent = null,
|
|
68
72
|
maxzoom = null,
|
|
69
73
|
minzoom = null,
|
|
70
74
|
mots = null,
|
|
@@ -80,6 +84,7 @@ function MobilityMap({
|
|
|
80
84
|
tenant = null,
|
|
81
85
|
zoom = "13",
|
|
82
86
|
}: MobilityMapProps) {
|
|
87
|
+
const eventNodeRef = useRef<HTMLDivElement>();
|
|
83
88
|
const [baseLayer, setBaseLayer] = useState<MaplibreLayer>();
|
|
84
89
|
const [isFollowing, setIsFollowing] = useState(false);
|
|
85
90
|
const [isTracking, setIsTracking] = useState(false);
|
|
@@ -93,7 +98,7 @@ function MobilityMap({
|
|
|
93
98
|
|
|
94
99
|
// TODO: this should be removed. The parent application should be responsible to do this
|
|
95
100
|
// or we should find something that fit more usecases
|
|
96
|
-
|
|
101
|
+
useUpdatePermalink(map, permalink === "true");
|
|
97
102
|
|
|
98
103
|
const mapContextValue = useMemo(() => {
|
|
99
104
|
return {
|
|
@@ -102,11 +107,13 @@ function MobilityMap({
|
|
|
102
107
|
baselayer,
|
|
103
108
|
baseLayer,
|
|
104
109
|
center,
|
|
110
|
+
extent,
|
|
105
111
|
geolocation,
|
|
106
112
|
isFollowing,
|
|
107
113
|
isTracking,
|
|
108
114
|
map,
|
|
109
115
|
mapsurl,
|
|
116
|
+
maxextent,
|
|
110
117
|
maxzoom,
|
|
111
118
|
minzoom,
|
|
112
119
|
mots,
|
|
@@ -141,11 +148,13 @@ function MobilityMap({
|
|
|
141
148
|
baselayer,
|
|
142
149
|
baseLayer,
|
|
143
150
|
center,
|
|
151
|
+
extent,
|
|
144
152
|
geolocation,
|
|
145
153
|
isFollowing,
|
|
146
154
|
isTracking,
|
|
147
155
|
map,
|
|
148
156
|
mapsurl,
|
|
157
|
+
maxextent,
|
|
149
158
|
maxzoom,
|
|
150
159
|
minzoom,
|
|
151
160
|
mots,
|
|
@@ -167,12 +176,14 @@ function MobilityMap({
|
|
|
167
176
|
]);
|
|
168
177
|
|
|
169
178
|
useEffect(() => {
|
|
170
|
-
dispatchEvent(
|
|
179
|
+
eventNodeRef.current?.dispatchEvent(
|
|
171
180
|
new MobilityEvent<MobilityMapProps>("mwc:attribute", {
|
|
172
181
|
baselayer,
|
|
173
|
-
center
|
|
182
|
+
center,
|
|
183
|
+
extent,
|
|
174
184
|
geolocation,
|
|
175
185
|
mapsurl,
|
|
186
|
+
maxextent,
|
|
176
187
|
maxzoom,
|
|
177
188
|
minzoom,
|
|
178
189
|
mots,
|
|
@@ -184,14 +195,16 @@ function MobilityMap({
|
|
|
184
195
|
realtimeurl,
|
|
185
196
|
search,
|
|
186
197
|
tenant,
|
|
187
|
-
zoom
|
|
198
|
+
zoom,
|
|
188
199
|
}),
|
|
189
200
|
);
|
|
190
201
|
}, [
|
|
191
202
|
baselayer,
|
|
192
203
|
center,
|
|
204
|
+
extent,
|
|
193
205
|
geolocation,
|
|
194
206
|
mapsurl,
|
|
207
|
+
maxextent,
|
|
195
208
|
maxzoom,
|
|
196
209
|
minzoom,
|
|
197
210
|
mots,
|
|
@@ -204,9 +217,6 @@ function MobilityMap({
|
|
|
204
217
|
search,
|
|
205
218
|
tenant,
|
|
206
219
|
zoom,
|
|
207
|
-
x,
|
|
208
|
-
y,
|
|
209
|
-
z,
|
|
210
220
|
]);
|
|
211
221
|
|
|
212
222
|
return (
|
|
@@ -214,7 +224,10 @@ function MobilityMap({
|
|
|
214
224
|
<style>{tailwind}</style>
|
|
215
225
|
<style>{style}</style>
|
|
216
226
|
<MapContext.Provider value={mapContextValue}>
|
|
217
|
-
<div
|
|
227
|
+
<div
|
|
228
|
+
className="relative size-full border font-sans @container/main"
|
|
229
|
+
ref={eventNodeRef}
|
|
230
|
+
>
|
|
218
231
|
<div className="relative flex size-full flex-col @lg/main:flex-row-reverse">
|
|
219
232
|
<Map className="relative flex-1 overflow-visible ">
|
|
220
233
|
<BaseLayer />
|
|
@@ -16,7 +16,7 @@ import useMapContext from "../utils/hooks/useMapContext";
|
|
|
16
16
|
|
|
17
17
|
const TRACKING_ZOOM = 16;
|
|
18
18
|
|
|
19
|
-
export type RealtimeLayerProps = RealtimeLayerOptions
|
|
19
|
+
export type RealtimeLayerProps = RealtimeLayerOptions & Record<string, unknown>;
|
|
20
20
|
|
|
21
21
|
function RealtimeLayer(props: RealtimeLayerProps) {
|
|
22
22
|
const {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { JSX, PreactDOMAttributes } from "preact";
|
|
2
|
+
|
|
3
|
+
import { memo, useMemo } from "preact/compat";
|
|
4
|
+
|
|
5
|
+
export type RvfButtonProps = {
|
|
6
|
+
selected?: boolean;
|
|
7
|
+
theme?: "primary" | "secondary";
|
|
8
|
+
} & JSX.ButtonHTMLAttributes<HTMLButtonElement> &
|
|
9
|
+
PreactDOMAttributes;
|
|
10
|
+
|
|
11
|
+
const baseClasses =
|
|
12
|
+
"flex h-8 md:h-9 lg:h-10 px-5 py-1.75 max-h-button items-center justify-center rounded-full border";
|
|
13
|
+
|
|
14
|
+
export const themes = {
|
|
15
|
+
primary: {
|
|
16
|
+
classes:
|
|
17
|
+
"border-red bg-red text-white disabled:bg-lightgrey disabled:border-lightgrey hover:bg-darkred hover:border-darkred active:bg-lightred active:border-lightred",
|
|
18
|
+
selectedClasses: "bg-darkred border-darkred",
|
|
19
|
+
},
|
|
20
|
+
secondary: {
|
|
21
|
+
classes:
|
|
22
|
+
"border border-current bg-white text-grey hover:text-red disabled:text-lightgrey active:text-lightred",
|
|
23
|
+
selectedClasses: "text-red",
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function RvfButton({
|
|
28
|
+
children,
|
|
29
|
+
className,
|
|
30
|
+
selected = false,
|
|
31
|
+
theme = "secondary",
|
|
32
|
+
...props
|
|
33
|
+
}: RvfButtonProps) {
|
|
34
|
+
const classes = useMemo(() => {
|
|
35
|
+
return `${baseClasses} ${themes[theme].classes} ${selected ? themes[theme].selectedClasses : ""} ${className || ""}`;
|
|
36
|
+
}, [className, selected, theme]);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<button className={classes} {...props}>
|
|
40
|
+
{children}
|
|
41
|
+
</button>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default memo(RvfButton);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./RvfButton";
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { JSX, PreactDOMAttributes } from "preact";
|
|
2
|
+
|
|
3
|
+
import { memo, useId, useState } from "preact/compat";
|
|
4
|
+
|
|
5
|
+
import Cancel from "../icons/Cancel";
|
|
6
|
+
import RvfButton from "../RvfButton";
|
|
7
|
+
import RvfIconButton from "../RvfIconButton";
|
|
8
|
+
import exportPdf from "../utils/exportPdf";
|
|
9
|
+
import useMapContext from "../utils/hooks/useMapContext";
|
|
10
|
+
import useRvfContext from "../utils/hooks/useRvfContext";
|
|
11
|
+
|
|
12
|
+
export type RvfExportMenuButtonProps = JSX.HTMLAttributes<HTMLDivElement> &
|
|
13
|
+
PreactDOMAttributes;
|
|
14
|
+
|
|
15
|
+
const formats = ["A4", "A1", "A3", "A0"];
|
|
16
|
+
|
|
17
|
+
function RvfExportMenu({ ...props }: RvfExportMenuButtonProps) {
|
|
18
|
+
const { setIsExportMenuOpen } = useRvfContext();
|
|
19
|
+
const { map } = useMapContext();
|
|
20
|
+
const [useMaxExtent, setUseMaxExtent] = useState(false);
|
|
21
|
+
const [format, setFormat] = useState<string>(formats[0]);
|
|
22
|
+
const checkboxId = useId();
|
|
23
|
+
const selectId = useId();
|
|
24
|
+
const [isExporting, setIsExporting] = useState(false);
|
|
25
|
+
const [isExportingError, setIsExportingError] = useState(false);
|
|
26
|
+
return (
|
|
27
|
+
<div {...props}>
|
|
28
|
+
<div className={"flex h-full flex-col gap-2 p-2"}>
|
|
29
|
+
{/* <!-- Header --> */}
|
|
30
|
+
<div className={"flex flex-row items-center justify-between gap-2"}>
|
|
31
|
+
<h1>Export </h1>
|
|
32
|
+
<RvfIconButton
|
|
33
|
+
onClick={() => {
|
|
34
|
+
setIsExportMenuOpen(false);
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
<Cancel />
|
|
38
|
+
</RvfIconButton>
|
|
39
|
+
</div>
|
|
40
|
+
{/* <!-- Content --> */}
|
|
41
|
+
<div className="flex flex-1 flex-col gap-2">
|
|
42
|
+
<div className={"flex gap-2"}>
|
|
43
|
+
<input
|
|
44
|
+
checked={useMaxExtent}
|
|
45
|
+
id={checkboxId}
|
|
46
|
+
onChange={() => {
|
|
47
|
+
setUseMaxExtent(!useMaxExtent);
|
|
48
|
+
}}
|
|
49
|
+
type="checkbox"
|
|
50
|
+
/>
|
|
51
|
+
<label htmlFor={checkboxId}>Ganze Region exportieren</label>
|
|
52
|
+
</div>
|
|
53
|
+
<div className={"flex gap-2"}>
|
|
54
|
+
<label htmlFor={selectId}>Format:</label>
|
|
55
|
+
<select
|
|
56
|
+
className={"w-24"}
|
|
57
|
+
id={selectId}
|
|
58
|
+
onChange={(evt) => {
|
|
59
|
+
setFormat((evt.target as HTMLSelectElement).value);
|
|
60
|
+
}}
|
|
61
|
+
value={format}
|
|
62
|
+
>
|
|
63
|
+
{formats.map((format) => {
|
|
64
|
+
return <option key={format}>{format}</option>;
|
|
65
|
+
})}
|
|
66
|
+
</select>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
{/* <!-- Footer --> */}
|
|
70
|
+
<div>
|
|
71
|
+
<RvfButton
|
|
72
|
+
disabled={isExporting}
|
|
73
|
+
onClick={async () => {
|
|
74
|
+
setIsExportingError(false);
|
|
75
|
+
setIsExporting(true);
|
|
76
|
+
const result = await exportPdf(map, { format }, { useMaxExtent });
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
setIsExporting(false);
|
|
79
|
+
setIsExportingError(!result);
|
|
80
|
+
}, 1000);
|
|
81
|
+
}}
|
|
82
|
+
>
|
|
83
|
+
{isExporting
|
|
84
|
+
? "Exporting..."
|
|
85
|
+
: isExportingError
|
|
86
|
+
? "Error"
|
|
87
|
+
: "Download"}
|
|
88
|
+
</RvfButton>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export default memo(RvfExportMenu);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./RvfExportMenu";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { JSX, PreactDOMAttributes } from "preact";
|
|
2
|
+
|
|
3
|
+
import { memo } from "preact/compat";
|
|
4
|
+
import { useCallback } from "preact/hooks";
|
|
5
|
+
|
|
6
|
+
import Download from "../icons/Download";
|
|
7
|
+
import RvfIconButton from "../RvfIconButton";
|
|
8
|
+
import useRvfContext from "../utils/hooks/useRvfContext";
|
|
9
|
+
|
|
10
|
+
export type RvfExportMenuButtonProps = JSX.HTMLAttributes<HTMLButtonElement> &
|
|
11
|
+
PreactDOMAttributes;
|
|
12
|
+
|
|
13
|
+
function RvfExportMenuButton({ ...props }: RvfExportMenuButtonProps) {
|
|
14
|
+
const { isExportMenuOpen, setIsExportMenuOpen } = useRvfContext();
|
|
15
|
+
|
|
16
|
+
const onClick = useCallback(() => {
|
|
17
|
+
setIsExportMenuOpen(!isExportMenuOpen);
|
|
18
|
+
}, [isExportMenuOpen, setIsExportMenuOpen]);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<RvfIconButton {...props} onClick={onClick} selected={isExportMenuOpen}>
|
|
22
|
+
<Download />
|
|
23
|
+
</RvfIconButton>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default memo(RvfExportMenuButton);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./RvfExportMenuButton";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { JSX, PreactDOMAttributes } from "preact";
|
|
2
|
+
|
|
3
|
+
import { memo } from "preact/compat";
|
|
4
|
+
|
|
5
|
+
import useRvfContext from "../utils/hooks/useRvfContext";
|
|
6
|
+
|
|
7
|
+
export type RvfFeatureDetailsProps = JSX.HTMLAttributes<HTMLDivElement> &
|
|
8
|
+
PreactDOMAttributes;
|
|
9
|
+
|
|
10
|
+
function RvfFeatureDetails(props: RvfFeatureDetailsProps) {
|
|
11
|
+
const { selectedFeature } = useRvfContext();
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div {...props}>
|
|
15
|
+
{Object.entries(selectedFeature.getProperties()).map(([key, value]) => {
|
|
16
|
+
return (
|
|
17
|
+
<div className="flex gap-2" key={key}>
|
|
18
|
+
<span>
|
|
19
|
+
<b>{key}:</b>
|
|
20
|
+
</span>
|
|
21
|
+
<div>{value}</div>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
})}
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default memo(RvfFeatureDetails);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./RvfFeatureDetails";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { JSX, PreactDOMAttributes } from "preact";
|
|
2
|
+
|
|
3
|
+
import { memo, SVGProps, useMemo } from "preact/compat";
|
|
4
|
+
|
|
5
|
+
import { RvfButtonProps, themes } from "../RvfButton/RvfButton";
|
|
6
|
+
|
|
7
|
+
export type RvfIconButtonProps = {
|
|
8
|
+
Icon?: (props: SVGProps<SVGSVGElement>) => preact.JSX.Element;
|
|
9
|
+
} & JSX.ButtonHTMLAttributes<HTMLButtonElement> &
|
|
10
|
+
PreactDOMAttributes &
|
|
11
|
+
RvfButtonProps;
|
|
12
|
+
|
|
13
|
+
const baseClasses =
|
|
14
|
+
"flex h-8 w-8 md:h-9 md:w-9 lg:w-10 lg:h-10 p-1.75 max-w-button max-h-button items-center justify-center rounded-full border";
|
|
15
|
+
|
|
16
|
+
function RvfIconButton({
|
|
17
|
+
children,
|
|
18
|
+
className,
|
|
19
|
+
Icon,
|
|
20
|
+
selected = false,
|
|
21
|
+
theme = "secondary",
|
|
22
|
+
...props
|
|
23
|
+
}: RvfIconButtonProps) {
|
|
24
|
+
const classes = useMemo(() => {
|
|
25
|
+
return `${baseClasses} ${themes[theme].classes} ${selected ? themes[theme].selectedClasses : ""} ${className || ""}`;
|
|
26
|
+
}, [className, selected, theme]);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<button className={classes} {...props}>
|
|
30
|
+
{children || <Icon height={"100%"} width={"100%"} />}
|
|
31
|
+
</button>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default memo(RvfIconButton);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./RvfIconButton";
|