dune-react 0.0.16 → 0.0.18
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/dist/components/puck-base/core/fields.d.ts +23 -0
- package/dist/components/puck-base/core/fields.js +24 -15
- package/dist/components/puck-base/core/styles.d.ts +1 -5
- package/dist/components/puck-base/core/styles.js +1 -5
- package/dist/components/puck-base/editor-context.d.ts +2 -0
- package/dist/components/puck-base/fields/index.d.ts +1 -0
- package/dist/components/puck-base/fields/location-field.d.ts +44 -0
- package/dist/components/puck-base/fields/location-field.js +207 -0
- package/dist/components/puck-block/location-sections/location-1/index.js +17 -22
- package/dist/components/puck-block/location-sections/location-1/location.d.ts +5 -7
- package/dist/components/puck-block/location-sections/location-1/location.js +15 -12
- package/dist/components/puck-block/location-sections/location-2/index.js +28 -24
- package/dist/components/puck-block/location-sections/location-2/location.d.ts +6 -8
- package/dist/components/puck-block/location-sections/location-2/location.js +18 -15
- package/dist/components/puck-block/location-sections/location-3/index.js +43 -20
- package/dist/components/puck-block/location-sections/location-3/location.d.ts +5 -6
- package/dist/components/puck-block/location-sections/location-3/location.js +96 -86
- package/dist/components/puck-block/location-sections/props.d.ts +9 -10
- package/package.json +3 -2
|
@@ -801,4 +801,27 @@ export declare const form: {
|
|
|
801
801
|
};
|
|
802
802
|
};
|
|
803
803
|
export declare const formDefaults: CompoundFormProps;
|
|
804
|
+
/** 地图定位的核心数据:地址 + 坐标 */
|
|
805
|
+
export interface MapLocation {
|
|
806
|
+
/** 用户可读的完整地址(显示 & 搜索用) */
|
|
807
|
+
address: string;
|
|
808
|
+
/** 纬度 */
|
|
809
|
+
lat: number;
|
|
810
|
+
/** 经度 */
|
|
811
|
+
lng: number;
|
|
812
|
+
/** 地图缩放级别,默认 14 */
|
|
813
|
+
zoom?: number;
|
|
814
|
+
/** Google Place ID(可选,便于精确定位) */
|
|
815
|
+
placeId?: string;
|
|
816
|
+
}
|
|
817
|
+
/** 从 MapLocation 生成 Google Maps embed URL */
|
|
818
|
+
export declare function getMapEmbedUrl(loc: MapLocation): string;
|
|
819
|
+
/** 从 MapLocation 生成 Google Maps 导航 URL */
|
|
820
|
+
export declare function getDirectionsUrl(loc: MapLocation): string;
|
|
821
|
+
export declare const locationDefaults: MapLocation;
|
|
822
|
+
export declare const location: {
|
|
823
|
+
type: "custom";
|
|
824
|
+
label: string;
|
|
825
|
+
render: any;
|
|
826
|
+
};
|
|
804
827
|
export * from "./styles";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fieldTypes } from "../field.js";
|
|
2
2
|
import { ActionField } from "../fields/action-field.js";
|
|
3
3
|
import { IconPickerField } from "../icon-picker-field.js";
|
|
4
|
-
import {
|
|
4
|
+
import { LocationField } from "../fields/location-field.js";
|
|
5
5
|
const formMethods = ["get", "post", "put", "patch", "delete"];
|
|
6
6
|
const icon = {
|
|
7
7
|
type: "custom",
|
|
@@ -241,42 +241,51 @@ const formDefaults = {
|
|
|
241
241
|
icon: "move-right"
|
|
242
242
|
}
|
|
243
243
|
};
|
|
244
|
+
function getMapEmbedUrl(loc) {
|
|
245
|
+
const { lat, lng, zoom = 14 } = loc;
|
|
246
|
+
return `https://maps.google.com/maps?q=${lat},${lng}&z=${zoom}&output=embed`;
|
|
247
|
+
}
|
|
248
|
+
function getDirectionsUrl(loc) {
|
|
249
|
+
return `https://www.google.com/maps/dir/?api=1&destination=${loc.lat},${loc.lng}`;
|
|
250
|
+
}
|
|
251
|
+
const locationDefaults = {
|
|
252
|
+
address: "San Francisco, CA, USA",
|
|
253
|
+
lat: 37.7749,
|
|
254
|
+
lng: -122.4194,
|
|
255
|
+
zoom: 13
|
|
256
|
+
};
|
|
257
|
+
const location = {
|
|
258
|
+
type: "custom",
|
|
259
|
+
label: "Location",
|
|
260
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
261
|
+
render: LocationField
|
|
262
|
+
};
|
|
244
263
|
export {
|
|
245
264
|
action,
|
|
246
265
|
actionDefaults,
|
|
247
|
-
backgroundColor,
|
|
248
|
-
backgroundImage,
|
|
249
266
|
badge,
|
|
250
|
-
bannerStylesDefaults,
|
|
251
|
-
bannerStylesField,
|
|
252
267
|
button,
|
|
253
268
|
buttons,
|
|
254
269
|
card,
|
|
255
270
|
cards,
|
|
256
271
|
contentFields,
|
|
257
272
|
contentFieldsWithFeatures,
|
|
258
|
-
createStylesDefaults,
|
|
259
|
-
createStylesField,
|
|
260
273
|
description,
|
|
261
274
|
features,
|
|
262
275
|
field,
|
|
263
276
|
fieldDefaults,
|
|
264
277
|
form,
|
|
265
278
|
formDefaults,
|
|
279
|
+
getDirectionsUrl,
|
|
280
|
+
getMapEmbedUrl,
|
|
266
281
|
getPlaceholderImageUrl,
|
|
267
282
|
heading,
|
|
268
|
-
heroStylesDefaults,
|
|
269
283
|
icon,
|
|
270
284
|
image,
|
|
271
285
|
image16x9Placeholder,
|
|
272
286
|
image1x1Placeholder,
|
|
273
287
|
image9x16Placeholder,
|
|
274
288
|
images,
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
paddingLevel,
|
|
278
|
-
sectionBaseStyleDefaults,
|
|
279
|
-
sectionBaseStyleFields,
|
|
280
|
-
sectionOverlay,
|
|
281
|
-
sectionStyle
|
|
289
|
+
location,
|
|
290
|
+
locationDefaults
|
|
282
291
|
};
|
|
@@ -1394,11 +1394,7 @@ export declare const contactStylesDefaults: {
|
|
|
1394
1394
|
readonly bottom: "medium";
|
|
1395
1395
|
};
|
|
1396
1396
|
};
|
|
1397
|
-
export
|
|
1398
|
-
mapHeight?: number;
|
|
1399
|
-
mapFilter?: string;
|
|
1400
|
-
mapTintColor?: string;
|
|
1401
|
-
}
|
|
1397
|
+
export type LocationSectionStyles = SectionBaseStyles;
|
|
1402
1398
|
export declare const locationStylesField: {
|
|
1403
1399
|
type: "object";
|
|
1404
1400
|
label: string;
|
|
@@ -216,11 +216,7 @@ createStylesField({
|
|
|
216
216
|
}
|
|
217
217
|
});
|
|
218
218
|
createStylesDefaults();
|
|
219
|
-
createStylesField(
|
|
220
|
-
mapHeight: { type: "number", label: "Map Height", min: 200, max: 800 },
|
|
221
|
-
mapFilter: { type: "text", label: "Map Filter (CSS)" },
|
|
222
|
-
mapTintColor: { type: "text", label: "Map Tint Color" }
|
|
223
|
-
});
|
|
219
|
+
createStylesField();
|
|
224
220
|
createStylesDefaults();
|
|
225
221
|
createStylesField();
|
|
226
222
|
createStylesDefaults();
|
|
@@ -17,6 +17,8 @@ type EditorContextValue = {
|
|
|
17
17
|
domain?: string;
|
|
18
18
|
/** 站内可选页面列表,用于 url 字段快捷选择 */
|
|
19
19
|
sitePages?: SitePage[];
|
|
20
|
+
/** Google Maps API Key,用于 LocationField 地址搜索 */
|
|
21
|
+
googleMapsApiKey?: string;
|
|
20
22
|
};
|
|
21
23
|
export declare const EditorContextProvider: import("react").Provider<EditorContextValue>;
|
|
22
24
|
export declare const useEditorContext: () => EditorContextValue;
|
|
@@ -4,4 +4,5 @@ export { ColorField } from "./color-field";
|
|
|
4
4
|
export { RadioToggleField } from "./radio-toggle-field";
|
|
5
5
|
export { ObjectField } from "./object-field";
|
|
6
6
|
export { VirtualizedSelectField, LARGE_SELECT_THRESHOLD, } from "./virtualized-select-field";
|
|
7
|
+
export { LocationField } from "./location-field";
|
|
7
8
|
export { ActionField, ACTION_TYPE_FIELD_MAP, ACTION_TYPE_OPTIONS, PageActionFields, ExternalActionFields, EmailActionFields, PhoneActionFields, SectionActionFields, DownloadActionFields, type ActionTypeFieldProps, } from "./action-field";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { MapLocation } from "../core/fields";
|
|
2
|
+
interface GLatLng {
|
|
3
|
+
lat(): number;
|
|
4
|
+
lng(): number;
|
|
5
|
+
}
|
|
6
|
+
interface GGeometry {
|
|
7
|
+
location?: GLatLng;
|
|
8
|
+
}
|
|
9
|
+
interface GPlaceResult {
|
|
10
|
+
formatted_address?: string;
|
|
11
|
+
geometry?: GGeometry;
|
|
12
|
+
place_id?: string;
|
|
13
|
+
address_components?: unknown[];
|
|
14
|
+
}
|
|
15
|
+
interface GAutocomplete {
|
|
16
|
+
getPlace(): GPlaceResult;
|
|
17
|
+
addListener(event: string, handler: () => void): void;
|
|
18
|
+
}
|
|
19
|
+
interface GAutocompleteConstructor {
|
|
20
|
+
new (input: HTMLInputElement, opts?: Record<string, unknown>): GAutocomplete;
|
|
21
|
+
}
|
|
22
|
+
interface GGoogleMaps {
|
|
23
|
+
places: {
|
|
24
|
+
Autocomplete: GAutocompleteConstructor;
|
|
25
|
+
};
|
|
26
|
+
event: {
|
|
27
|
+
clearInstanceListeners(instance: unknown): void;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
interface GGoogle {
|
|
31
|
+
maps: GGoogleMaps;
|
|
32
|
+
}
|
|
33
|
+
declare global {
|
|
34
|
+
interface Window {
|
|
35
|
+
google?: GGoogle;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export interface LocationFieldProps {
|
|
39
|
+
name: string;
|
|
40
|
+
value: MapLocation | undefined;
|
|
41
|
+
onChange: (value: MapLocation) => void;
|
|
42
|
+
}
|
|
43
|
+
export declare const LocationField: import("react").NamedExoticComponent<LocationFieldProps>;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { memo, useState, useRef, useEffect, useCallback } from "react";
|
|
4
|
+
import { Input } from "../../shadcn/input.js";
|
|
5
|
+
import { Label } from "../../shadcn/label.js";
|
|
6
|
+
import { Loader2, Search, X, MapPin } from "lucide-react";
|
|
7
|
+
import { useEditorContext } from "../editor-context.js";
|
|
8
|
+
let googleLoadPromise = null;
|
|
9
|
+
function loadGooglePlaces(apiKey) {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
if (googleLoadPromise) return googleLoadPromise;
|
|
12
|
+
if (typeof window !== "undefined" && ((_b = (_a = window.google) == null ? void 0 : _a.maps) == null ? void 0 : _b.places)) {
|
|
13
|
+
return Promise.resolve();
|
|
14
|
+
}
|
|
15
|
+
googleLoadPromise = new Promise((resolve, reject) => {
|
|
16
|
+
const script = document.createElement("script");
|
|
17
|
+
script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places`;
|
|
18
|
+
script.async = true;
|
|
19
|
+
script.onload = () => resolve();
|
|
20
|
+
script.onerror = () => {
|
|
21
|
+
googleLoadPromise = null;
|
|
22
|
+
reject(new Error("Failed to load Google Maps API"));
|
|
23
|
+
};
|
|
24
|
+
document.head.appendChild(script);
|
|
25
|
+
});
|
|
26
|
+
return googleLoadPromise;
|
|
27
|
+
}
|
|
28
|
+
const LocationField = memo(function LocationField2({
|
|
29
|
+
value,
|
|
30
|
+
onChange
|
|
31
|
+
}) {
|
|
32
|
+
const { googleMapsApiKey } = useEditorContext();
|
|
33
|
+
const apiKey = googleMapsApiKey || "";
|
|
34
|
+
const [inputValue, setInputValue] = useState((value == null ? void 0 : value.address) || "");
|
|
35
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
36
|
+
const [loadError, setLoadError] = useState(false);
|
|
37
|
+
const inputRef = useRef(null);
|
|
38
|
+
const autocompleteRef = useRef(null);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if ((value == null ? void 0 : value.address) && value.address !== inputValue) {
|
|
41
|
+
setInputValue(value.address);
|
|
42
|
+
}
|
|
43
|
+
}, [value == null ? void 0 : value.address]);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!apiKey) {
|
|
46
|
+
setLoadError(true);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
loadGooglePlaces(apiKey).then(() => setIsLoaded(true)).catch(() => setLoadError(true));
|
|
50
|
+
}, [apiKey]);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!isLoaded || !inputRef.current || autocompleteRef.current) return;
|
|
53
|
+
const G = window.google;
|
|
54
|
+
const autocomplete = new G.maps.places.Autocomplete(inputRef.current, {
|
|
55
|
+
fields: [
|
|
56
|
+
"formatted_address",
|
|
57
|
+
"geometry",
|
|
58
|
+
"place_id",
|
|
59
|
+
"address_components"
|
|
60
|
+
]
|
|
61
|
+
});
|
|
62
|
+
autocomplete.addListener("place_changed", () => {
|
|
63
|
+
var _a;
|
|
64
|
+
const place = autocomplete.getPlace();
|
|
65
|
+
if (!((_a = place.geometry) == null ? void 0 : _a.location)) return;
|
|
66
|
+
const lat = place.geometry.location.lat();
|
|
67
|
+
const lng = place.geometry.location.lng();
|
|
68
|
+
const address = place.formatted_address || "";
|
|
69
|
+
const newLocation = {
|
|
70
|
+
address,
|
|
71
|
+
lat,
|
|
72
|
+
lng,
|
|
73
|
+
zoom: (value == null ? void 0 : value.zoom) ?? 14,
|
|
74
|
+
placeId: place.place_id || ""
|
|
75
|
+
};
|
|
76
|
+
setInputValue(address);
|
|
77
|
+
onChange(newLocation);
|
|
78
|
+
});
|
|
79
|
+
autocompleteRef.current = autocomplete;
|
|
80
|
+
return () => {
|
|
81
|
+
var _a;
|
|
82
|
+
(_a = window.google) == null ? void 0 : _a.maps.event.clearInstanceListeners(autocomplete);
|
|
83
|
+
autocompleteRef.current = null;
|
|
84
|
+
};
|
|
85
|
+
}, [isLoaded]);
|
|
86
|
+
const handleClear = useCallback(() => {
|
|
87
|
+
var _a;
|
|
88
|
+
setInputValue("");
|
|
89
|
+
onChange({
|
|
90
|
+
address: "",
|
|
91
|
+
lat: 0,
|
|
92
|
+
lng: 0,
|
|
93
|
+
zoom: 14,
|
|
94
|
+
placeId: ""
|
|
95
|
+
});
|
|
96
|
+
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
97
|
+
}, [onChange]);
|
|
98
|
+
const handleZoomChange = useCallback(
|
|
99
|
+
(e) => {
|
|
100
|
+
if (!value) return;
|
|
101
|
+
onChange({ ...value, zoom: Number(e.target.value) });
|
|
102
|
+
},
|
|
103
|
+
[value, onChange]
|
|
104
|
+
);
|
|
105
|
+
const embedUrl = value && value.lat !== 0 ? `https://maps.google.com/maps?q=${value.lat},${value.lng}&z=${value.zoom ?? 14}&output=embed` : null;
|
|
106
|
+
return /* @__PURE__ */ jsxs("div", { className: "mb-4 space-y-3", children: [
|
|
107
|
+
/* @__PURE__ */ jsx(Label, { children: "Location" }),
|
|
108
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
109
|
+
/* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3", children: !isLoaded && !loadError ? /* @__PURE__ */ jsx(Loader2, { className: "text-muted-foreground size-4 animate-spin" }) : /* @__PURE__ */ jsx(Search, { className: "text-muted-foreground size-4" }) }),
|
|
110
|
+
/* @__PURE__ */ jsx(
|
|
111
|
+
Input,
|
|
112
|
+
{
|
|
113
|
+
ref: inputRef,
|
|
114
|
+
value: inputValue,
|
|
115
|
+
onChange: (e) => setInputValue(e.target.value),
|
|
116
|
+
placeholder: loadError ? "Enter address manually..." : "Search address or place...",
|
|
117
|
+
className: "pl-9 pr-8"
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
inputValue && /* @__PURE__ */ jsx(
|
|
121
|
+
"button",
|
|
122
|
+
{
|
|
123
|
+
type: "button",
|
|
124
|
+
onClick: handleClear,
|
|
125
|
+
className: "text-muted-foreground hover:text-foreground absolute inset-y-0 right-0 flex items-center pr-3",
|
|
126
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
] }),
|
|
130
|
+
loadError && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
131
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
132
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Latitude" }),
|
|
133
|
+
/* @__PURE__ */ jsx(
|
|
134
|
+
Input,
|
|
135
|
+
{
|
|
136
|
+
type: "number",
|
|
137
|
+
step: "any",
|
|
138
|
+
value: (value == null ? void 0 : value.lat) ?? "",
|
|
139
|
+
onChange: (e) => onChange({
|
|
140
|
+
...value || { address: "", lng: 0, zoom: 14 },
|
|
141
|
+
lat: Number(e.target.value)
|
|
142
|
+
}),
|
|
143
|
+
placeholder: "37.7749",
|
|
144
|
+
className: "h-8 text-xs"
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
] }),
|
|
148
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
149
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Longitude" }),
|
|
150
|
+
/* @__PURE__ */ jsx(
|
|
151
|
+
Input,
|
|
152
|
+
{
|
|
153
|
+
type: "number",
|
|
154
|
+
step: "any",
|
|
155
|
+
value: (value == null ? void 0 : value.lng) ?? "",
|
|
156
|
+
onChange: (e) => onChange({
|
|
157
|
+
...value || { address: "", lat: 0, zoom: 14 },
|
|
158
|
+
lng: Number(e.target.value)
|
|
159
|
+
}),
|
|
160
|
+
placeholder: "-122.4194",
|
|
161
|
+
className: "h-8 text-xs"
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
] })
|
|
165
|
+
] }),
|
|
166
|
+
value && value.lat !== 0 && /* @__PURE__ */ jsxs("div", { className: "border-border bg-muted/50 space-y-2 rounded-lg border p-3", children: [
|
|
167
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
168
|
+
/* @__PURE__ */ jsx(MapPin, { className: "text-primary mt-0.5 size-3.5 shrink-0" }),
|
|
169
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium leading-tight", children: value.address })
|
|
170
|
+
] }),
|
|
171
|
+
/* @__PURE__ */ jsxs("div", { className: "text-muted-foreground pl-5.5 text-xs", children: [
|
|
172
|
+
value.lat.toFixed(4),
|
|
173
|
+
", ",
|
|
174
|
+
value.lng.toFixed(4)
|
|
175
|
+
] })
|
|
176
|
+
] }),
|
|
177
|
+
embedUrl && /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-lg border", children: /* @__PURE__ */ jsx(
|
|
178
|
+
"iframe",
|
|
179
|
+
{
|
|
180
|
+
src: embedUrl,
|
|
181
|
+
title: "Location preview",
|
|
182
|
+
className: "h-[160px] w-full border-0",
|
|
183
|
+
loading: "lazy",
|
|
184
|
+
referrerPolicy: "no-referrer-when-downgrade"
|
|
185
|
+
}
|
|
186
|
+
) }),
|
|
187
|
+
value && value.lat !== 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
188
|
+
/* @__PURE__ */ jsx(Label, { className: "shrink-0 text-xs", children: "Zoom" }),
|
|
189
|
+
/* @__PURE__ */ jsx(
|
|
190
|
+
"input",
|
|
191
|
+
{
|
|
192
|
+
type: "range",
|
|
193
|
+
min: 1,
|
|
194
|
+
max: 20,
|
|
195
|
+
step: 1,
|
|
196
|
+
value: value.zoom ?? 14,
|
|
197
|
+
onChange: handleZoomChange,
|
|
198
|
+
className: "h-1.5 flex-1 cursor-pointer appearance-none rounded-full bg-gray-200 accent-current"
|
|
199
|
+
}
|
|
200
|
+
),
|
|
201
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground w-6 text-right text-xs tabular-nums", children: value.zoom ?? 14 })
|
|
202
|
+
] })
|
|
203
|
+
] });
|
|
204
|
+
});
|
|
205
|
+
export {
|
|
206
|
+
LocationField
|
|
207
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { button } from "../../../puck-base/core/fields.js";
|
|
1
|
+
import { locationDefaults, button, location } from "../../../puck-base/core/fields.js";
|
|
2
2
|
import { LocationSection } from "./location.js";
|
|
3
3
|
import { createStylesDefaults, createStylesField } from "../../../puck-base/core/styles.js";
|
|
4
4
|
const locationButtonFields = {
|
|
@@ -40,26 +40,24 @@ const conf = {
|
|
|
40
40
|
{ label: "Map Left / Text Right", value: "right" }
|
|
41
41
|
]
|
|
42
42
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
location,
|
|
44
|
+
mapStyle: {
|
|
45
|
+
type: "radio",
|
|
46
|
+
label: "Map Style",
|
|
47
|
+
options: [
|
|
48
|
+
{ label: "Default", value: "default" },
|
|
49
|
+
{ label: "Grayscale", value: "grayscale" },
|
|
50
|
+
{ label: "Dark", value: "dark" }
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
mapTint: {
|
|
54
|
+
type: "radio",
|
|
55
|
+
label: "Map Tint",
|
|
49
56
|
options: [
|
|
50
57
|
{ label: "Theme", value: "theme" },
|
|
51
|
-
{ label: "Custom", value: "custom" },
|
|
52
58
|
{ label: "None", value: "none" }
|
|
53
59
|
]
|
|
54
60
|
},
|
|
55
|
-
mapTintColor: { type: "text", label: "Map Tint Color" },
|
|
56
|
-
mapTintOpacity: {
|
|
57
|
-
type: "number",
|
|
58
|
-
label: "Map Tint Opacity",
|
|
59
|
-
min: 0,
|
|
60
|
-
max: 1,
|
|
61
|
-
step: 0.01
|
|
62
|
-
},
|
|
63
61
|
buttons: {
|
|
64
62
|
type: "array",
|
|
65
63
|
max: 3,
|
|
@@ -74,12 +72,9 @@ const conf = {
|
|
|
74
72
|
description: "We have offices around the globe. Visit us or get in touch with a local team near you.",
|
|
75
73
|
contentAlign: "left",
|
|
76
74
|
contentPosition: "left",
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
mapTintMode: "theme",
|
|
81
|
-
mapTintColor: "var(--primary)",
|
|
82
|
-
mapTintOpacity: 0.21,
|
|
75
|
+
location: locationDefaults,
|
|
76
|
+
mapStyle: "grayscale",
|
|
77
|
+
mapTint: "theme",
|
|
83
78
|
buttons: [
|
|
84
79
|
{
|
|
85
80
|
label: "Contact us",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CompoundContainerProps } from "@/components/puck-base/container";
|
|
2
2
|
import { CompoundButtonProps } from "@/components/puck-base/button";
|
|
3
|
+
import type { MapLocation } from "@/components/puck-base/core/fields";
|
|
3
4
|
interface LocationButton extends Omit<CompoundButtonProps, "label"> {
|
|
4
5
|
label?: string;
|
|
5
6
|
url?: string;
|
|
@@ -12,12 +13,9 @@ export interface LocationSectionProps {
|
|
|
12
13
|
description?: string;
|
|
13
14
|
contentAlign?: "left" | "right";
|
|
14
15
|
contentPosition?: "left" | "right";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
mapTintMode?: "theme" | "custom" | "none";
|
|
19
|
-
mapTintColor?: string;
|
|
20
|
-
mapTintOpacity?: number;
|
|
16
|
+
location?: MapLocation;
|
|
17
|
+
mapStyle?: "default" | "grayscale" | "dark";
|
|
18
|
+
mapTint?: "none" | "theme";
|
|
21
19
|
buttons?: LocationButton[];
|
|
22
20
|
styles?: {
|
|
23
21
|
padding?: CompoundContainerProps["padding"];
|
|
@@ -25,5 +23,5 @@ export interface LocationSectionProps {
|
|
|
25
23
|
backgroundColor?: string;
|
|
26
24
|
};
|
|
27
25
|
}
|
|
28
|
-
export declare const LocationSection: ({ heading, description, contentAlign, contentPosition,
|
|
26
|
+
export declare const LocationSection: ({ heading, description, contentAlign, contentPosition, location: loc, mapStyle, mapTint, buttons, styles, }: LocationSectionProps) => import("react/jsx-runtime").JSX.Element;
|
|
29
27
|
export {};
|
|
@@ -2,6 +2,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { CompoundContainer } from "../../../puck-base/container.js";
|
|
3
3
|
import { CompoundButton } from "../../../puck-base/button.js";
|
|
4
4
|
import { cn } from "../../../../utils/css-utils.js";
|
|
5
|
+
import { getMapEmbedUrl } from "../../../puck-base/core/fields.js";
|
|
5
6
|
const LocationActionButton = ({
|
|
6
7
|
label,
|
|
7
8
|
url,
|
|
@@ -35,24 +36,27 @@ const LocationActionButton = ({
|
|
|
35
36
|
}
|
|
36
37
|
) });
|
|
37
38
|
};
|
|
39
|
+
const MAP_STYLE_FILTERS = {
|
|
40
|
+
default: "",
|
|
41
|
+
grayscale: "grayscale(45%) contrast(1.06) brightness(0.98) saturate(0.9)",
|
|
42
|
+
dark: "grayscale(100%) invert(1) contrast(1.1) brightness(0.8)"
|
|
43
|
+
};
|
|
38
44
|
const LocationSection = ({
|
|
39
45
|
heading,
|
|
40
46
|
description,
|
|
41
47
|
contentAlign = "left",
|
|
42
48
|
contentPosition = "left",
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
mapTintMode = "theme",
|
|
47
|
-
mapTintColor,
|
|
48
|
-
mapTintOpacity = 0.2,
|
|
49
|
+
location: loc,
|
|
50
|
+
mapStyle = "default",
|
|
51
|
+
mapTint = "theme",
|
|
49
52
|
buttons = [],
|
|
50
53
|
styles
|
|
51
54
|
}) => {
|
|
52
55
|
const isTextRight = contentAlign === "right";
|
|
53
56
|
const isContentRight = contentPosition === "right";
|
|
54
|
-
const showMapTint =
|
|
55
|
-
const
|
|
57
|
+
const showMapTint = mapTint === "theme";
|
|
58
|
+
const mapEmbedUrl = loc && loc.lat !== 0 ? getMapEmbedUrl(loc) : void 0;
|
|
59
|
+
const mapFilter = MAP_STYLE_FILTERS[mapStyle] || "";
|
|
56
60
|
return /* @__PURE__ */ jsx(
|
|
57
61
|
CompoundContainer,
|
|
58
62
|
{
|
|
@@ -105,12 +109,12 @@ const LocationSection = ({
|
|
|
105
109
|
"iframe",
|
|
106
110
|
{
|
|
107
111
|
src: mapEmbedUrl,
|
|
108
|
-
title:
|
|
112
|
+
title: (loc == null ? void 0 : loc.address) || "Google Maps",
|
|
109
113
|
className: "h-full w-full border-0",
|
|
110
114
|
loading: "lazy",
|
|
111
115
|
referrerPolicy: "no-referrer-when-downgrade",
|
|
112
116
|
allowFullScreen: true,
|
|
113
|
-
style: { filter: mapFilter }
|
|
117
|
+
style: mapFilter ? { filter: mapFilter } : void 0
|
|
114
118
|
}
|
|
115
119
|
) : /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center bg-muted text-muted-foreground", children: "Map address not configured" }),
|
|
116
120
|
showMapTint ? /* @__PURE__ */ jsx(
|
|
@@ -118,8 +122,7 @@ const LocationSection = ({
|
|
|
118
122
|
{
|
|
119
123
|
className: "bg-primary pointer-events-none absolute inset-0",
|
|
120
124
|
style: {
|
|
121
|
-
|
|
122
|
-
opacity: mapTintOpacity,
|
|
125
|
+
opacity: 0.2,
|
|
123
126
|
mixBlendMode: "color"
|
|
124
127
|
}
|
|
125
128
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { button } from "../../../puck-base/core/fields.js";
|
|
1
|
+
import { button, location } from "../../../puck-base/core/fields.js";
|
|
2
2
|
import { Location2 } from "./location.js";
|
|
3
3
|
import { createStylesDefaults, createStylesField } from "../../../puck-base/core/styles.js";
|
|
4
4
|
const locationButtonFields = {
|
|
@@ -43,7 +43,11 @@ const conf = {
|
|
|
43
43
|
fields: {
|
|
44
44
|
heading: { type: "textarea", contentEditable: true },
|
|
45
45
|
description: { type: "textarea", contentEditable: true },
|
|
46
|
-
|
|
46
|
+
displayAddress: {
|
|
47
|
+
type: "textarea",
|
|
48
|
+
label: "Display Address",
|
|
49
|
+
contentEditable: true
|
|
50
|
+
},
|
|
47
51
|
contentPosition: {
|
|
48
52
|
type: "radio",
|
|
49
53
|
label: "Card Position",
|
|
@@ -52,26 +56,24 @@ const conf = {
|
|
|
52
56
|
{ label: "Right", value: "right" }
|
|
53
57
|
]
|
|
54
58
|
},
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
location,
|
|
60
|
+
mapStyle: {
|
|
61
|
+
type: "radio",
|
|
62
|
+
label: "Map Style",
|
|
63
|
+
options: [
|
|
64
|
+
{ label: "Default", value: "default" },
|
|
65
|
+
{ label: "Grayscale", value: "grayscale" },
|
|
66
|
+
{ label: "Dark", value: "dark" }
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
mapTint: {
|
|
70
|
+
type: "radio",
|
|
60
71
|
label: "Map Tint",
|
|
61
72
|
options: [
|
|
62
73
|
{ label: "None", value: "none" },
|
|
63
|
-
{ label: "Theme", value: "theme" }
|
|
64
|
-
{ label: "Custom", value: "custom" }
|
|
74
|
+
{ label: "Theme", value: "theme" }
|
|
65
75
|
]
|
|
66
76
|
},
|
|
67
|
-
mapTintColor: { type: "text", label: "Map Tint Color" },
|
|
68
|
-
mapTintOpacity: {
|
|
69
|
-
type: "number",
|
|
70
|
-
label: "Map Tint Opacity",
|
|
71
|
-
min: 0,
|
|
72
|
-
max: 1,
|
|
73
|
-
step: 0.01
|
|
74
|
-
},
|
|
75
77
|
buttons: {
|
|
76
78
|
type: "array",
|
|
77
79
|
max: 3,
|
|
@@ -84,14 +86,16 @@ const conf = {
|
|
|
84
86
|
defaultProps: {
|
|
85
87
|
heading: "Our Offices",
|
|
86
88
|
description: "Visit our headquarters in London or reach out to one of our regional offices worldwide.",
|
|
87
|
-
|
|
89
|
+
displayAddress: "10 Finsbury Square\nLondon, UK EC2A 1AF",
|
|
88
90
|
contentPosition: "left",
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
location: {
|
|
92
|
+
address: "London, United Kingdom",
|
|
93
|
+
lat: 51.5074,
|
|
94
|
+
lng: -0.1278,
|
|
95
|
+
zoom: 13
|
|
96
|
+
},
|
|
97
|
+
mapStyle: "grayscale",
|
|
98
|
+
mapTint: "none",
|
|
95
99
|
buttons: [
|
|
96
100
|
{
|
|
97
101
|
label: "Get Directions",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CompoundContainerProps } from "@/components/puck-base/container";
|
|
2
2
|
import { CompoundButtonProps } from "@/components/puck-base/button";
|
|
3
|
+
import type { MapLocation } from "@/components/puck-base/core/fields";
|
|
3
4
|
interface LocationButton extends Omit<CompoundButtonProps, "label"> {
|
|
4
5
|
label?: string;
|
|
5
6
|
url?: string;
|
|
@@ -10,14 +11,11 @@ interface LocationButton extends Omit<CompoundButtonProps, "label"> {
|
|
|
10
11
|
export interface Location2Props {
|
|
11
12
|
heading?: string;
|
|
12
13
|
description?: string;
|
|
13
|
-
|
|
14
|
+
displayAddress?: string;
|
|
14
15
|
contentPosition?: "left" | "right";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
mapTintMode?: "none" | "theme" | "custom";
|
|
19
|
-
mapTintColor?: string;
|
|
20
|
-
mapTintOpacity?: number;
|
|
16
|
+
location?: MapLocation;
|
|
17
|
+
mapStyle?: "default" | "grayscale" | "dark";
|
|
18
|
+
mapTint?: "none" | "theme";
|
|
21
19
|
buttons?: LocationButton[];
|
|
22
20
|
styles?: {
|
|
23
21
|
padding?: CompoundContainerProps["padding"];
|
|
@@ -27,5 +25,5 @@ export interface Location2Props {
|
|
|
27
25
|
sectionHeight?: "sm" | "md" | "lg";
|
|
28
26
|
};
|
|
29
27
|
}
|
|
30
|
-
export declare const Location2: ({ heading, description,
|
|
28
|
+
export declare const Location2: ({ heading, description, displayAddress, contentPosition, location: loc, mapStyle, mapTint, buttons, styles, }: Location2Props) => import("react/jsx-runtime").JSX.Element;
|
|
31
29
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { CompoundButton } from "../../../puck-base/button.js";
|
|
3
3
|
import { cn } from "../../../../utils/css-utils.js";
|
|
4
|
+
import { getMapEmbedUrl } from "../../../puck-base/core/fields.js";
|
|
4
5
|
const ActionButton = ({
|
|
5
6
|
label,
|
|
6
7
|
url,
|
|
@@ -34,24 +35,27 @@ const ActionButton = ({
|
|
|
34
35
|
}
|
|
35
36
|
) });
|
|
36
37
|
};
|
|
38
|
+
const MAP_STYLE_FILTERS = {
|
|
39
|
+
default: "",
|
|
40
|
+
grayscale: "grayscale(40%) contrast(1.05) brightness(1.0) saturate(0.85)",
|
|
41
|
+
dark: "grayscale(100%) invert(1) contrast(1.1) brightness(0.8)"
|
|
42
|
+
};
|
|
37
43
|
const Location2 = ({
|
|
38
44
|
heading,
|
|
39
45
|
description,
|
|
40
|
-
|
|
46
|
+
displayAddress,
|
|
41
47
|
contentPosition = "left",
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
mapTintMode = "none",
|
|
46
|
-
mapTintColor,
|
|
47
|
-
mapTintOpacity = 0.15,
|
|
48
|
+
location: loc,
|
|
49
|
+
mapStyle = "default",
|
|
50
|
+
mapTint = "none",
|
|
48
51
|
buttons = [],
|
|
49
52
|
styles
|
|
50
53
|
}) => {
|
|
51
54
|
const isRight = contentPosition === "right";
|
|
52
55
|
const isGlass = (styles == null ? void 0 : styles.cardStyle) === "glass";
|
|
53
|
-
const showMapTint =
|
|
54
|
-
const
|
|
56
|
+
const showMapTint = mapTint === "theme";
|
|
57
|
+
const mapEmbedUrl = loc && loc.lat !== 0 ? getMapEmbedUrl(loc) : void 0;
|
|
58
|
+
const mapFilter = MAP_STYLE_FILTERS[mapStyle] || "";
|
|
55
59
|
const heightClass = (styles == null ? void 0 : styles.sectionHeight) === "sm" ? "h-[480px]" : (styles == null ? void 0 : styles.sectionHeight) === "lg" ? "h-[75vh] min-h-[520px]" : "h-[600px]";
|
|
56
60
|
return /* @__PURE__ */ jsxs("div", { className: cn("relative w-full overflow-hidden", heightClass), children: [
|
|
57
61
|
/* @__PURE__ */ jsxs("div", { className: "absolute inset-0", children: [
|
|
@@ -59,12 +63,12 @@ const Location2 = ({
|
|
|
59
63
|
"iframe",
|
|
60
64
|
{
|
|
61
65
|
src: mapEmbedUrl,
|
|
62
|
-
title:
|
|
66
|
+
title: (loc == null ? void 0 : loc.address) || "Google Maps",
|
|
63
67
|
className: "h-full w-full border-0",
|
|
64
68
|
loading: "lazy",
|
|
65
69
|
referrerPolicy: "no-referrer-when-downgrade",
|
|
66
70
|
allowFullScreen: true,
|
|
67
|
-
style: { filter: mapFilter }
|
|
71
|
+
style: mapFilter ? { filter: mapFilter } : void 0
|
|
68
72
|
}
|
|
69
73
|
) : /* @__PURE__ */ jsx("div", { className: "bg-muted text-muted-foreground flex h-full w-full items-center justify-center text-sm", children: "Map address not configured" }),
|
|
70
74
|
showMapTint && /* @__PURE__ */ jsx(
|
|
@@ -72,8 +76,7 @@ const Location2 = ({
|
|
|
72
76
|
{
|
|
73
77
|
className: "bg-primary pointer-events-none absolute inset-0",
|
|
74
78
|
style: {
|
|
75
|
-
|
|
76
|
-
opacity: mapTintOpacity,
|
|
79
|
+
opacity: 0.15,
|
|
77
80
|
mixBlendMode: "color"
|
|
78
81
|
}
|
|
79
82
|
}
|
|
@@ -96,7 +99,7 @@ const Location2 = ({
|
|
|
96
99
|
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
97
100
|
heading && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: /* @__PURE__ */ jsx("h2", { className: "text-foreground whitespace-pre-line font-serif text-3xl leading-tight tracking-tighter md:text-4xl", children: heading }) }),
|
|
98
101
|
description && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm leading-relaxed", children: description }),
|
|
99
|
-
|
|
102
|
+
displayAddress && /* @__PURE__ */ jsxs("div", { className: "text-foreground flex items-start gap-2 text-sm", children: [
|
|
100
103
|
/* @__PURE__ */ jsxs(
|
|
101
104
|
"svg",
|
|
102
105
|
{
|
|
@@ -115,7 +118,7 @@ const Location2 = ({
|
|
|
115
118
|
]
|
|
116
119
|
}
|
|
117
120
|
),
|
|
118
|
-
/* @__PURE__ */ jsx("span", { className: "whitespace-pre-line", children:
|
|
121
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-pre-line", children: displayAddress })
|
|
119
122
|
] }),
|
|
120
123
|
buttons.some((button) => button == null ? void 0 : button.label) && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 pt-1", children: buttons.map((button, index) => /* @__PURE__ */ jsx(ActionButton, { ...button }, index)) })
|
|
121
124
|
] })
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import { location } from "../../../puck-base/core/fields.js";
|
|
1
2
|
import { Location3 } from "./location.js";
|
|
2
3
|
import { createStylesDefaults, createStylesField } from "../../../puck-base/core/styles.js";
|
|
3
|
-
const
|
|
4
|
+
const defaultLocationEntry = {
|
|
4
5
|
name: "San Francisco, CA",
|
|
5
|
-
|
|
6
|
+
location: {
|
|
7
|
+
address: "123 Market Street, San Francisco, CA 94105",
|
|
8
|
+
lat: 37.7749,
|
|
9
|
+
lng: -122.4194,
|
|
10
|
+
zoom: 14
|
|
11
|
+
},
|
|
6
12
|
phone: "+1 (415) 555-0100",
|
|
7
|
-
hours: "Mon–Fri: 9am–6pm\nSat: 10am–4pm"
|
|
8
|
-
directionsUrl: "https://maps.google.com"
|
|
13
|
+
hours: "Mon–Fri: 9am–6pm\nSat: 10am–4pm"
|
|
9
14
|
};
|
|
10
15
|
const location3ExtraStyleFields = {
|
|
11
16
|
mapHeight: {
|
|
@@ -30,9 +35,16 @@ const conf = {
|
|
|
30
35
|
fields: {
|
|
31
36
|
heading: { type: "textarea", contentEditable: true },
|
|
32
37
|
description: { type: "textarea", contentEditable: true },
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
mapLocation: { ...location, label: "Map Location" },
|
|
39
|
+
mapStyle: {
|
|
40
|
+
type: "radio",
|
|
41
|
+
label: "Map Style",
|
|
42
|
+
options: [
|
|
43
|
+
{ label: "Default", value: "default" },
|
|
44
|
+
{ label: "Grayscale", value: "grayscale" },
|
|
45
|
+
{ label: "Dark", value: "dark" }
|
|
46
|
+
]
|
|
47
|
+
},
|
|
36
48
|
locations: {
|
|
37
49
|
type: "array",
|
|
38
50
|
min: 1,
|
|
@@ -40,37 +52,48 @@ const conf = {
|
|
|
40
52
|
getItemSummary: (item, index = 0) => item.name || `Location ${index + 1}`,
|
|
41
53
|
arrayFields: {
|
|
42
54
|
name: { type: "text", contentEditable: true },
|
|
43
|
-
|
|
55
|
+
location,
|
|
44
56
|
phone: { type: "text" },
|
|
45
57
|
hours: { type: "textarea", label: "Business Hours" },
|
|
46
|
-
directionsUrl: { type: "text", label: "Directions URL" },
|
|
47
58
|
directionsLabel: { type: "text", label: "Directions Button Label" }
|
|
48
59
|
},
|
|
49
|
-
defaultItemProps:
|
|
60
|
+
defaultItemProps: defaultLocationEntry
|
|
50
61
|
},
|
|
51
62
|
styles: createStylesField(location3ExtraStyleFields)
|
|
52
63
|
},
|
|
53
64
|
defaultProps: {
|
|
54
65
|
heading: "Our Offices",
|
|
55
66
|
description: "We have teams around the world ready to help you succeed.",
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
mapLocation: {
|
|
68
|
+
address: "New York, NY, United States",
|
|
69
|
+
lat: 40.7128,
|
|
70
|
+
lng: -74.006,
|
|
71
|
+
zoom: 11
|
|
72
|
+
},
|
|
73
|
+
mapStyle: "grayscale",
|
|
59
74
|
locations: [
|
|
60
|
-
|
|
75
|
+
defaultLocationEntry,
|
|
61
76
|
{
|
|
62
77
|
name: "London, UK",
|
|
63
|
-
|
|
78
|
+
location: {
|
|
79
|
+
address: "10 Finsbury Square, London, EC2A 1AF",
|
|
80
|
+
lat: 51.5207,
|
|
81
|
+
lng: -0.0876,
|
|
82
|
+
zoom: 14
|
|
83
|
+
},
|
|
64
84
|
phone: "+44 20 7946 0200",
|
|
65
|
-
hours: "Mon–Fri: 9am–6pm\nSat: 10am–3pm"
|
|
66
|
-
directionsUrl: "https://maps.google.com"
|
|
85
|
+
hours: "Mon–Fri: 9am–6pm\nSat: 10am–3pm"
|
|
67
86
|
},
|
|
68
87
|
{
|
|
69
88
|
name: "Tokyo, Japan",
|
|
70
|
-
|
|
89
|
+
location: {
|
|
90
|
+
address: "1-1-2 Marunouchi, Chiyoda-ku, Tokyo 100-0005",
|
|
91
|
+
lat: 35.6812,
|
|
92
|
+
lng: 139.7671,
|
|
93
|
+
zoom: 14
|
|
94
|
+
},
|
|
71
95
|
phone: "+81 3-1234-5678",
|
|
72
|
-
hours: "Mon–Fri: 9am–6pm"
|
|
73
|
-
directionsUrl: "https://maps.google.com"
|
|
96
|
+
hours: "Mon–Fri: 9am–6pm"
|
|
74
97
|
}
|
|
75
98
|
],
|
|
76
99
|
styles: createStylesDefaults({
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { CompoundContainerProps } from "@/components/puck-base/container";
|
|
2
2
|
import type { Action } from "@/components/puck-base/core/types";
|
|
3
|
+
import type { MapLocation } from "@/components/puck-base/core/fields";
|
|
3
4
|
export interface LocationEntry {
|
|
4
5
|
name: string;
|
|
5
|
-
|
|
6
|
+
location?: MapLocation;
|
|
6
7
|
phone?: string;
|
|
7
8
|
hours?: string;
|
|
8
|
-
directionsUrl?: string;
|
|
9
9
|
directionsLabel?: string;
|
|
10
10
|
directionsAction?: Action;
|
|
11
11
|
}
|
|
12
12
|
export interface Location3Props {
|
|
13
13
|
heading?: string;
|
|
14
14
|
description?: string;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
mapFilter?: string;
|
|
15
|
+
mapLocation?: MapLocation;
|
|
16
|
+
mapStyle?: "default" | "grayscale" | "dark";
|
|
18
17
|
locations: LocationEntry[];
|
|
19
18
|
styles?: {
|
|
20
19
|
padding?: CompoundContainerProps["padding"];
|
|
@@ -24,4 +23,4 @@ export interface Location3Props {
|
|
|
24
23
|
columns?: "2" | "3";
|
|
25
24
|
};
|
|
26
25
|
}
|
|
27
|
-
export declare const Location3: ({ heading, description,
|
|
26
|
+
export declare const Location3: ({ heading, description, mapLocation, mapStyle, locations, styles, }: Location3Props) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,15 +2,22 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { CompoundContainer } from "../../../puck-base/container.js";
|
|
3
3
|
import { CompoundButton } from "../../../puck-base/button.js";
|
|
4
4
|
import { cn } from "../../../../utils/css-utils.js";
|
|
5
|
+
import { getMapEmbedUrl, getDirectionsUrl } from "../../../puck-base/core/fields.js";
|
|
6
|
+
const MAP_STYLE_FILTERS = {
|
|
7
|
+
default: "",
|
|
8
|
+
grayscale: "grayscale(35%) contrast(1.05) brightness(1.0)",
|
|
9
|
+
dark: "grayscale(100%) invert(1) contrast(1.1) brightness(0.8)"
|
|
10
|
+
};
|
|
5
11
|
const Location3 = ({
|
|
6
12
|
heading,
|
|
7
13
|
description,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
mapFilter,
|
|
14
|
+
mapLocation,
|
|
15
|
+
mapStyle = "default",
|
|
11
16
|
locations = [],
|
|
12
17
|
styles
|
|
13
18
|
}) => {
|
|
19
|
+
const mapEmbedUrl = mapLocation && mapLocation.lat !== 0 ? getMapEmbedUrl(mapLocation) : void 0;
|
|
20
|
+
const mapFilter = MAP_STYLE_FILTERS[mapStyle] || "";
|
|
14
21
|
const mapHeight = (styles == null ? void 0 : styles.mapHeight) ?? "md";
|
|
15
22
|
const columns = (styles == null ? void 0 : styles.columns) ?? "3";
|
|
16
23
|
const mapHeightClass = mapHeight === "sm" ? "h-[220px] md:h-[260px]" : mapHeight === "lg" ? "h-[360px] md:h-[440px]" : "h-[280px] md:h-[340px]";
|
|
@@ -30,97 +37,100 @@ const Location3 = ({
|
|
|
30
37
|
"iframe",
|
|
31
38
|
{
|
|
32
39
|
src: mapEmbedUrl,
|
|
33
|
-
title:
|
|
40
|
+
title: (mapLocation == null ? void 0 : mapLocation.address) || "Google Maps",
|
|
34
41
|
className: "h-full w-full border-0",
|
|
35
42
|
loading: "lazy",
|
|
36
43
|
referrerPolicy: "no-referrer-when-downgrade",
|
|
37
44
|
allowFullScreen: true,
|
|
38
|
-
style: { filter: mapFilter }
|
|
45
|
+
style: mapFilter ? { filter: mapFilter } : void 0
|
|
39
46
|
}
|
|
40
47
|
) : /* @__PURE__ */ jsx("div", { className: "bg-muted text-muted-foreground flex h-full w-full items-center justify-center text-sm", children: "Map address not configured" }) }),
|
|
41
|
-
locations.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-1 gap-5", colClass), children: locations.map((loc, i) =>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
/* @__PURE__ */
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
48
|
+
locations.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-1 gap-5", colClass), children: locations.map((loc, i) => {
|
|
49
|
+
var _a;
|
|
50
|
+
return /* @__PURE__ */ jsxs(
|
|
51
|
+
"div",
|
|
52
|
+
{
|
|
53
|
+
className: "bg-card border-border flex flex-col gap-3 rounded-xl border p-6",
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsx("h3", { className: "text-foreground text-lg font-semibold", children: loc.name }),
|
|
56
|
+
((_a = loc.location) == null ? void 0 : _a.address) && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground flex items-start gap-2 text-sm", children: [
|
|
57
|
+
/* @__PURE__ */ jsxs(
|
|
58
|
+
"svg",
|
|
59
|
+
{
|
|
60
|
+
className: "text-primary mt-0.5 shrink-0",
|
|
61
|
+
width: "14",
|
|
62
|
+
height: "14",
|
|
63
|
+
viewBox: "0 0 24 24",
|
|
64
|
+
fill: "none",
|
|
65
|
+
stroke: "currentColor",
|
|
66
|
+
strokeWidth: "2",
|
|
67
|
+
strokeLinecap: "round",
|
|
68
|
+
strokeLinejoin: "round",
|
|
69
|
+
children: [
|
|
70
|
+
/* @__PURE__ */ jsx("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }),
|
|
71
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "10", r: "3" })
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
),
|
|
75
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-pre-line", children: loc.location.address })
|
|
76
|
+
] }),
|
|
77
|
+
loc.phone && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [
|
|
78
|
+
/* @__PURE__ */ jsx(
|
|
79
|
+
"svg",
|
|
80
|
+
{
|
|
81
|
+
className: "text-primary shrink-0",
|
|
82
|
+
width: "14",
|
|
83
|
+
height: "14",
|
|
84
|
+
viewBox: "0 0 24 24",
|
|
85
|
+
fill: "none",
|
|
86
|
+
stroke: "currentColor",
|
|
87
|
+
strokeWidth: "2",
|
|
88
|
+
strokeLinecap: "round",
|
|
89
|
+
strokeLinejoin: "round",
|
|
90
|
+
children: /* @__PURE__ */ jsx("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.69 14a19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 3.62 3h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 10.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 17.92Z" })
|
|
91
|
+
}
|
|
92
|
+
),
|
|
93
|
+
/* @__PURE__ */ jsx("span", { children: loc.phone })
|
|
94
|
+
] }),
|
|
95
|
+
loc.hours && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground flex items-start gap-2 text-sm", children: [
|
|
96
|
+
/* @__PURE__ */ jsxs(
|
|
97
|
+
"svg",
|
|
98
|
+
{
|
|
99
|
+
className: "text-primary mt-0.5 shrink-0",
|
|
100
|
+
width: "14",
|
|
101
|
+
height: "14",
|
|
102
|
+
viewBox: "0 0 24 24",
|
|
103
|
+
fill: "none",
|
|
104
|
+
stroke: "currentColor",
|
|
105
|
+
strokeWidth: "2",
|
|
106
|
+
strokeLinecap: "round",
|
|
107
|
+
strokeLinejoin: "round",
|
|
108
|
+
children: [
|
|
109
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
110
|
+
/* @__PURE__ */ jsx("polyline", { points: "12 6 12 12 16 14" })
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
),
|
|
114
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-pre-line", children: loc.hours })
|
|
115
|
+
] }),
|
|
116
|
+
(loc.directionsAction || loc.location && loc.location.lat !== 0) && /* @__PURE__ */ jsx("div", { className: "mt-auto pt-2", children: /* @__PURE__ */ jsx(
|
|
117
|
+
CompoundButton,
|
|
89
118
|
{
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
strokeLinejoin: "round",
|
|
99
|
-
children: [
|
|
100
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
101
|
-
/* @__PURE__ */ jsx("polyline", { points: "12 6 12 12 16 14" })
|
|
102
|
-
]
|
|
119
|
+
label: loc.directionsLabel || "Get Directions",
|
|
120
|
+
action: loc.directionsAction ?? (loc.location ? {
|
|
121
|
+
type: "external",
|
|
122
|
+
externalUrl: getDirectionsUrl(loc.location)
|
|
123
|
+
} : void 0),
|
|
124
|
+
variant: "outline",
|
|
125
|
+
size: "sm",
|
|
126
|
+
icon: "map-pin"
|
|
103
127
|
}
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
label: loc.directionsLabel || "Get Directions",
|
|
111
|
-
action: loc.directionsAction ?? (loc.directionsUrl ? {
|
|
112
|
-
type: "external",
|
|
113
|
-
externalUrl: loc.directionsUrl
|
|
114
|
-
} : void 0),
|
|
115
|
-
variant: "outline",
|
|
116
|
-
size: "sm",
|
|
117
|
-
icon: "map-pin"
|
|
118
|
-
}
|
|
119
|
-
) })
|
|
120
|
-
]
|
|
121
|
-
},
|
|
122
|
-
i
|
|
123
|
-
)) })
|
|
128
|
+
) })
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
i
|
|
132
|
+
);
|
|
133
|
+
}) })
|
|
124
134
|
] })
|
|
125
135
|
}
|
|
126
136
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MapLocation } from "@/components/puck-base/core/fields";
|
|
1
2
|
type LocationVariant = "location-1" | "location-2" | "location-3";
|
|
2
3
|
type LocationPadding = {
|
|
3
4
|
top?: "none" | "small" | "medium" | "large";
|
|
@@ -13,22 +14,19 @@ type LocationButton = {
|
|
|
13
14
|
};
|
|
14
15
|
type LocationItem = {
|
|
15
16
|
name: string;
|
|
16
|
-
|
|
17
|
+
location?: MapLocation;
|
|
17
18
|
phone?: string;
|
|
18
19
|
hours?: string;
|
|
19
|
-
directionsUrl?: string;
|
|
20
20
|
};
|
|
21
|
-
type LocationSectionProps = {
|
|
21
|
+
export type LocationSectionProps = {
|
|
22
22
|
variant?: LocationVariant;
|
|
23
23
|
heading?: string;
|
|
24
24
|
description?: string;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
mapTintColor?: string;
|
|
31
|
-
mapTintOpacity?: number;
|
|
25
|
+
displayAddress?: string;
|
|
26
|
+
location?: MapLocation;
|
|
27
|
+
mapLocation?: MapLocation;
|
|
28
|
+
mapStyle?: "default" | "grayscale" | "dark";
|
|
29
|
+
mapTint?: "none" | "theme";
|
|
32
30
|
buttons?: LocationButton[];
|
|
33
31
|
locations?: LocationItem[];
|
|
34
32
|
contentPosition?: "left" | "right";
|
|
@@ -43,3 +41,4 @@ type LocationSectionProps = {
|
|
|
43
41
|
sectionHeight?: "sm" | "md" | "lg";
|
|
44
42
|
};
|
|
45
43
|
};
|
|
44
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dune-react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"build-storybook": "storybook build && cp -r skills storybook-static/skills",
|
|
17
17
|
"deploy-storybook": "storybook-to-ghpages -- --existing-output-dir=storybook-static",
|
|
18
18
|
"ondeploy": "pnpm build-storybook && pnpm deploy-storybook",
|
|
19
|
-
"postpublish": "bash scripts/postpublish.sh"
|
|
19
|
+
"postpublish": "bash scripts/postpublish.sh",
|
|
20
|
+
"upload:previews": "tsx scripts/upload-previews-r2.ts"
|
|
20
21
|
},
|
|
21
22
|
"sideEffects": [
|
|
22
23
|
"*.css"
|