camox 0.32.0 → 0.33.0
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/core/createBlock.d.ts +1 -1
- package/dist/core/createBlock.js +88 -108
- package/dist/core/hooks/useIsEditable.js +6 -10
- package/dist/core/lib/fieldTypes.js +10 -219
- package/dist/features/agent-chat/components/AgentChatSidebar.js +172 -0
- package/dist/features/agent-chat/components/AgentChatThread.js +9 -9
- package/dist/features/preview/CamoxPreview.js +137 -729
- package/dist/features/preview/components/{AddBlockSheet.js → AddBlockSidebar.js} +121 -131
- package/dist/features/preview/components/AssetFieldEditor.js +107 -82
- package/dist/features/preview/components/AssetLightbox.js +4 -4
- package/dist/features/preview/components/AssetPickerModal.js +277 -0
- package/dist/features/preview/components/BlockActionsPopover.js +18 -24
- package/dist/features/preview/components/CreatePageModal.js +6 -6
- package/dist/features/preview/components/FieldToolbar.js +64 -127
- package/dist/features/preview/components/ItemFieldsEditor.js +98 -125
- package/dist/features/preview/components/LeftSidebar.js +64 -0
- package/dist/features/preview/components/LinkFieldEditor.js +1 -1
- package/dist/features/preview/components/MultipleAssetFieldEditor.js +94 -56
- package/dist/features/preview/components/OverlayTracker.js +15 -15
- package/dist/features/preview/components/Overlays.js +12 -12
- package/dist/features/preview/components/PageEditorSidebar.js +563 -0
- package/dist/features/preview/components/PageInfoSidebar.js +1453 -0
- package/dist/features/preview/components/PageNavigatorSidebar.js +590 -0
- package/dist/features/preview/components/PagePicker.js +3 -3
- package/dist/features/preview/components/PageStatusBadge.js +1 -1
- package/dist/features/preview/components/PageTree.js +204 -564
- package/dist/features/preview/components/PreviewPanel.js +123 -158
- package/dist/features/preview/components/PreviewToolbar.js +260 -256
- package/dist/features/preview/components/PublishDialog.js +2 -2
- package/dist/features/preview/components/RepeatableItemsList.js +2 -2
- package/dist/features/preview/components/RightSidebar.js +109 -0
- package/dist/features/preview/components/UnlinkAssetButton.js +2 -2
- package/dist/features/preview/components/useRepeatableItemActions.js +3 -138
- package/dist/features/preview/components/useUpdateBlockPosition.js +1 -1
- package/dist/features/preview/previewQueryFns.js +23 -0
- package/dist/features/preview/previewStore.js +46 -63
- package/dist/features/provider/CamoxProvider.js +255 -70
- package/dist/features/provider/useAdminShortcuts.js +5 -48
- package/dist/features/routes/pageRoute.js +1 -1
- package/dist/features/studio/CamoxStudio.js +6 -5
- package/dist/features/studio/components/EnvironmentMenu.js +2 -2
- package/dist/features/studio/components/Navbar.js +53 -71
- package/dist/features/studio/components/ProjectMenu.js +1 -1
- package/dist/features/studio/components/UserButton.js +1 -1
- package/dist/features/studio/routes.js +7 -0
- package/dist/features/studio/useTheme.js +67 -33
- package/dist/features/vite/routeGeneration.js +68 -66
- package/dist/hooks/use-file-upload.js +1 -1
- package/dist/lib/auth.js +23 -22
- package/dist/lib/utils.js +1 -1
- package/dist/studio-overlays.css +1 -1
- package/dist/studio.css +1 -1
- package/package.json +4 -4
- package/dist/features/agent-chat/components/AgentChatSheet.js +0 -207
- package/dist/features/preview/components/AssetPickerGrid.js +0 -236
- package/dist/features/preview/components/PageContentSheet.js +0 -608
- package/dist/features/preview/components/PageMetadataModal.js +0 -908
- package/dist/features/preview/components/PreviewSideSheet.js +0 -76
|
@@ -1,608 +0,0 @@
|
|
|
1
|
-
import { trackClientEvent } from "../../../lib/telemetry-client.js";
|
|
2
|
-
import { previewStore, selectionBlockId, selectionField, selectionItemId } from "../previewStore.js";
|
|
3
|
-
import { PreviewSideSheet, Sheet } from "./PreviewSideSheet.js";
|
|
4
|
-
import { actionsStore } from "../../provider/actionsStore.js";
|
|
5
|
-
import { blockMutations, blockQueries, fileQueries, repeatableItemMutations } from "../../../lib/queries.js";
|
|
6
|
-
import { cn } from "../../../lib/utils.js";
|
|
7
|
-
import { isFileMarker } from "../../../lib/normalized-data.js";
|
|
8
|
-
import { useCamoxApp } from "../../provider/components/CamoxAppContext.js";
|
|
9
|
-
import { useRequireDraftSource } from "../../../core/hooks/useRequireDraftSource.js";
|
|
10
|
-
import { fieldTypesDictionary } from "../../../core/lib/fieldTypes.js";
|
|
11
|
-
import { SingleAssetFieldEditor } from "./AssetFieldEditor.js";
|
|
12
|
-
import { useRepeatableItemActions } from "./useRepeatableItemActions.js";
|
|
13
|
-
import { ItemFieldsEditor, formatFieldName } from "./ItemFieldsEditor.js";
|
|
14
|
-
import { LinkFieldEditor } from "./LinkFieldEditor.js";
|
|
15
|
-
import { MultipleAssetFieldEditor } from "./MultipleAssetFieldEditor.js";
|
|
16
|
-
import { Label } from "@camox/ui/label";
|
|
17
|
-
import { useMutation, useQueries, useQuery } from "@tanstack/react-query";
|
|
18
|
-
import { useSelector } from "@xstate/store-react";
|
|
19
|
-
import * as React from "react";
|
|
20
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
21
|
-
import { Button } from "@camox/ui/button";
|
|
22
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@camox/ui/dropdown-menu";
|
|
23
|
-
import { Switch } from "@camox/ui/switch";
|
|
24
|
-
import { CircleMinus, CirclePlus, CornerLeftUp } from "lucide-react";
|
|
25
|
-
import { Spinner } from "@camox/ui/spinner";
|
|
26
|
-
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@camox/ui/select";
|
|
27
|
-
import { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "@camox/ui/breadcrumb";
|
|
28
|
-
|
|
29
|
-
//#region src/features/preview/components/PageContentSheet.tsx
|
|
30
|
-
const getSettingsFields = (schema) => {
|
|
31
|
-
const properties = schema?.properties;
|
|
32
|
-
if (!properties) return [];
|
|
33
|
-
return Object.keys(properties).map((fieldName) => {
|
|
34
|
-
const prop = properties[fieldName];
|
|
35
|
-
return {
|
|
36
|
-
name: fieldName,
|
|
37
|
-
fieldType: prop.fieldType,
|
|
38
|
-
label: prop.title,
|
|
39
|
-
enumLabels: prop.enumLabels,
|
|
40
|
-
enumValues: prop.enum
|
|
41
|
-
};
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Builds the path of fieldNames from the block root to the given item,
|
|
46
|
-
* then walks the schema down that path to return the sub-schema for the item's fields.
|
|
47
|
-
*/
|
|
48
|
-
const getSchemaForItem = (contentSchema, itemId, itemsMap) => {
|
|
49
|
-
const path = [];
|
|
50
|
-
let current = itemsMap.get(itemId);
|
|
51
|
-
while (current) {
|
|
52
|
-
path.unshift(current.fieldName);
|
|
53
|
-
current = current.parentItemId ? itemsMap.get(current.parentItemId) : void 0;
|
|
54
|
-
}
|
|
55
|
-
let schema = contentSchema;
|
|
56
|
-
for (const fieldName of path) {
|
|
57
|
-
const prop = schema?.properties?.[fieldName];
|
|
58
|
-
if (!prop?.items) return null;
|
|
59
|
-
schema = prop.items;
|
|
60
|
-
}
|
|
61
|
-
return schema;
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Like `getSchemaForItem` but returns the **array** schema (one level above
|
|
65
|
-
* the items schema), where per-item settings metadata lives.
|
|
66
|
-
*/
|
|
67
|
-
const getArraySchemaForItem = (contentSchema, itemId, itemsMap) => {
|
|
68
|
-
const path = [];
|
|
69
|
-
let current = itemsMap.get(itemId);
|
|
70
|
-
while (current) {
|
|
71
|
-
path.unshift(current.fieldName);
|
|
72
|
-
current = current.parentItemId ? itemsMap.get(current.parentItemId) : void 0;
|
|
73
|
-
}
|
|
74
|
-
let schema = contentSchema;
|
|
75
|
-
for (let i = 0; i < path.length; i++) {
|
|
76
|
-
const prop = schema?.properties?.[path[i]];
|
|
77
|
-
if (!prop?.items) return null;
|
|
78
|
-
if (i === path.length - 1) return prop;
|
|
79
|
-
schema = prop.items;
|
|
80
|
-
}
|
|
81
|
-
return null;
|
|
82
|
-
};
|
|
83
|
-
/**
|
|
84
|
-
* Builds the ancestor chain from root to this item (inclusive).
|
|
85
|
-
* Returns items in order from root-most ancestor to the item itself.
|
|
86
|
-
*/
|
|
87
|
-
const buildAncestorChain = (itemId, itemsMap) => {
|
|
88
|
-
const chain = [];
|
|
89
|
-
let current = itemsMap.get(itemId);
|
|
90
|
-
while (current) {
|
|
91
|
-
chain.unshift(current);
|
|
92
|
-
current = current.parentItemId ? itemsMap.get(current.parentItemId) : void 0;
|
|
93
|
-
}
|
|
94
|
-
return chain;
|
|
95
|
-
};
|
|
96
|
-
const PageContentSheet = () => {
|
|
97
|
-
const camoxApp = useCamoxApp();
|
|
98
|
-
const updateContent = useMutation(blockMutations.updateContent());
|
|
99
|
-
const updateSettings = useMutation(blockMutations.updateSettings());
|
|
100
|
-
const updateRepeatableContent = useMutation(repeatableItemMutations.updateContent());
|
|
101
|
-
const updateRepeatableSettings = useMutation(repeatableItemMutations.updateSettings());
|
|
102
|
-
const requireDraft = useRequireDraftSource();
|
|
103
|
-
const isOpen = useSelector(previewStore, (state) => state.context.isPageContentSheetOpen);
|
|
104
|
-
const selection = useSelector(previewStore, (state_0) => state_0.context.selection);
|
|
105
|
-
const iframeElement = useSelector(previewStore, (state_1) => state_1.context.iframeElement);
|
|
106
|
-
const isReadOnly = useSelector(previewStore, (state_2) => state_2.context.previewSource) !== "draft";
|
|
107
|
-
const postToIframe = React.useCallback((message) => {
|
|
108
|
-
if (!iframeElement?.contentWindow) return;
|
|
109
|
-
iframeElement.contentWindow.postMessage(message, "*");
|
|
110
|
-
}, [iframeElement]);
|
|
111
|
-
const blockId = selectionBlockId(selection);
|
|
112
|
-
const currentItemId = selectionItemId(selection);
|
|
113
|
-
const fieldInfo = selectionField(selection);
|
|
114
|
-
const { data: blockBundle } = useQuery({
|
|
115
|
-
...blockQueries.get(blockId),
|
|
116
|
-
enabled: blockId != null
|
|
117
|
-
});
|
|
118
|
-
const block = blockBundle?.block ?? null;
|
|
119
|
-
const itemsMap = React.useMemo(() => new Map((blockBundle?.repeatableItems ?? []).map((i) => [i.id, i])), [blockBundle?.repeatableItems]);
|
|
120
|
-
const fileIds = React.useMemo(() => (blockBundle?.files ?? []).map((f) => f.id), [blockBundle?.files]);
|
|
121
|
-
const fileResults = useQueries({ queries: fileIds.map((id) => fileQueries.get(id)) });
|
|
122
|
-
const filesMap = React.useMemo(() => {
|
|
123
|
-
const map = new Map((blockBundle?.files ?? []).map((f_0) => [f_0.id, f_0]));
|
|
124
|
-
for (let i_0 = 0; i_0 < fileIds.length; i_0++) {
|
|
125
|
-
const data = fileResults[i_0]?.data;
|
|
126
|
-
if (data) map.set(data.id, data);
|
|
127
|
-
}
|
|
128
|
-
return map;
|
|
129
|
-
}, [
|
|
130
|
-
blockBundle?.files,
|
|
131
|
-
fileIds,
|
|
132
|
-
fileResults
|
|
133
|
-
]);
|
|
134
|
-
const blockDef = block ? camoxApp.getBlockById(block.type) : null;
|
|
135
|
-
const settingsFields = React.useMemo(() => {
|
|
136
|
-
return blockDef ? getSettingsFields(blockDef._internal.settingsSchema) : [];
|
|
137
|
-
}, [blockDef]);
|
|
138
|
-
const itemArraySchema = React.useMemo(() => {
|
|
139
|
-
if (!blockDef || currentItemId == null) return null;
|
|
140
|
-
return getArraySchemaForItem(blockDef._internal.contentSchema, currentItemId, itemsMap);
|
|
141
|
-
}, [
|
|
142
|
-
blockDef,
|
|
143
|
-
currentItemId,
|
|
144
|
-
itemsMap
|
|
145
|
-
]);
|
|
146
|
-
const itemSettingsFields = React.useMemo(() => {
|
|
147
|
-
return getSettingsFields(itemArraySchema?.itemSettingsSchema);
|
|
148
|
-
}, [itemArraySchema]);
|
|
149
|
-
const currentSchema = React.useMemo(() => {
|
|
150
|
-
if (!blockDef) return null;
|
|
151
|
-
if (currentItemId == null) return blockDef._internal.contentSchema;
|
|
152
|
-
return getSchemaForItem(blockDef._internal.contentSchema, currentItemId, itemsMap);
|
|
153
|
-
}, [
|
|
154
|
-
blockDef,
|
|
155
|
-
currentItemId,
|
|
156
|
-
itemsMap
|
|
157
|
-
]);
|
|
158
|
-
const currentItem = currentItemId != null ? itemsMap.get(currentItemId) : null;
|
|
159
|
-
const isItemLoading = currentItemId != null && !currentItem;
|
|
160
|
-
const siblingCount = React.useMemo(() => {
|
|
161
|
-
if (!currentItem) return 0;
|
|
162
|
-
let count = 0;
|
|
163
|
-
for (const it of itemsMap.values()) if (it.fieldName === currentItem.fieldName && it.parentItemId === currentItem.parentItemId) count++;
|
|
164
|
-
return count;
|
|
165
|
-
}, [currentItem, itemsMap]);
|
|
166
|
-
const { canAdd: canAddSibling, addItem: addSibling, canRemove: canRemoveCurrent, removeItem: removeCurrent } = useRepeatableItemActions({
|
|
167
|
-
blockId: block?.id ?? -1,
|
|
168
|
-
fieldName: currentItem?.fieldName ?? "",
|
|
169
|
-
parentItemId: currentItem?.parentItemId ?? null,
|
|
170
|
-
arraySchema: itemArraySchema,
|
|
171
|
-
siblingCount
|
|
172
|
-
});
|
|
173
|
-
const rawCurrentData = currentItem ? currentItem.content : block?.content ?? {};
|
|
174
|
-
const currentData = React.useMemo(() => {
|
|
175
|
-
const resolveFile = (marker) => {
|
|
176
|
-
const file = filesMap.get(marker._fileId);
|
|
177
|
-
return file ? {
|
|
178
|
-
url: file.url,
|
|
179
|
-
alt: file.alt,
|
|
180
|
-
filename: file.filename,
|
|
181
|
-
mimeType: file.mimeType,
|
|
182
|
-
_fileId: marker._fileId
|
|
183
|
-
} : {
|
|
184
|
-
url: "",
|
|
185
|
-
alt: "",
|
|
186
|
-
filename: "",
|
|
187
|
-
mimeType: ""
|
|
188
|
-
};
|
|
189
|
-
};
|
|
190
|
-
const resolveValue = (value) => {
|
|
191
|
-
if (isFileMarker(value)) return resolveFile(value);
|
|
192
|
-
if (Array.isArray(value)) return value.map(resolveValue);
|
|
193
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
194
|
-
const obj = value;
|
|
195
|
-
const resolved = {};
|
|
196
|
-
for (const [k, v] of Object.entries(obj)) resolved[k] = resolveValue(v);
|
|
197
|
-
return resolved;
|
|
198
|
-
}
|
|
199
|
-
return value;
|
|
200
|
-
};
|
|
201
|
-
const resolved_0 = {};
|
|
202
|
-
for (const [key, value_0] of Object.entries(rawCurrentData)) resolved_0[key] = resolveValue(value_0);
|
|
203
|
-
return resolved_0;
|
|
204
|
-
}, [rawCurrentData, filesMap]);
|
|
205
|
-
const isViewingLink = fieldInfo?.fieldType === "Link";
|
|
206
|
-
const linkFieldName = isViewingLink ? fieldInfo.fieldName : null;
|
|
207
|
-
const isViewingImage = fieldInfo?.fieldType === "Image";
|
|
208
|
-
const imageFieldName = isViewingImage ? fieldInfo.fieldName : null;
|
|
209
|
-
const isViewingFile = fieldInfo?.fieldType === "File";
|
|
210
|
-
const fileFieldName = isViewingFile ? fieldInfo.fieldName : null;
|
|
211
|
-
const isViewingAsset = isViewingImage || isViewingFile;
|
|
212
|
-
const assetFieldName = imageFieldName ?? fileFieldName;
|
|
213
|
-
const assetType = isViewingImage ? "Image" : "File";
|
|
214
|
-
const isMultipleAsset = React.useMemo(() => {
|
|
215
|
-
if (!isViewingAsset || !assetFieldName) return false;
|
|
216
|
-
const prop = currentSchema?.properties?.[assetFieldName];
|
|
217
|
-
return prop?.fieldType === "ImageList" || prop?.fieldType === "FileList";
|
|
218
|
-
}, [
|
|
219
|
-
isViewingAsset,
|
|
220
|
-
assetFieldName,
|
|
221
|
-
currentSchema
|
|
222
|
-
]);
|
|
223
|
-
const sessionDirtyRef = React.useRef(false);
|
|
224
|
-
const trackedOpenRef = React.useRef(false);
|
|
225
|
-
React.useEffect(() => {
|
|
226
|
-
if (!isOpen) {
|
|
227
|
-
trackedOpenRef.current = false;
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
if (trackedOpenRef.current) return;
|
|
231
|
-
if (!block) return;
|
|
232
|
-
trackedOpenRef.current = true;
|
|
233
|
-
sessionDirtyRef.current = false;
|
|
234
|
-
trackClientEvent("content_sheet_opened", { blockType: block.type });
|
|
235
|
-
}, [isOpen, block]);
|
|
236
|
-
const fieldIdPrefix = React.useId();
|
|
237
|
-
const autoFocusFieldName = React.useMemo(() => {
|
|
238
|
-
if ((selection?.type === "block-field" || selection?.type === "item-field") && (selection.fieldType === "String" || selection.fieldType === "Embed")) return selection.fieldName;
|
|
239
|
-
const properties = currentSchema?.properties;
|
|
240
|
-
if (!properties) return null;
|
|
241
|
-
for (const name of Object.keys(properties)) {
|
|
242
|
-
const ft = properties[name]?.fieldType;
|
|
243
|
-
if (ft === "String" || ft === "Embed") return name;
|
|
244
|
-
}
|
|
245
|
-
return null;
|
|
246
|
-
}, [selection, currentSchema]);
|
|
247
|
-
const getInitialFocus = React.useCallback(() => {
|
|
248
|
-
if (!autoFocusFieldName) return null;
|
|
249
|
-
return document.getElementById(`${fieldIdPrefix}-${autoFocusFieldName}`);
|
|
250
|
-
}, [autoFocusFieldName, fieldIdPrefix]);
|
|
251
|
-
React.useEffect(() => {
|
|
252
|
-
const action = {
|
|
253
|
-
id: "toggle-content-sheet",
|
|
254
|
-
label: isOpen ? "Close form" : "Open in form",
|
|
255
|
-
groupLabel: "Preview",
|
|
256
|
-
shortcut: {
|
|
257
|
-
key: "j",
|
|
258
|
-
withAlt: true
|
|
259
|
-
},
|
|
260
|
-
checkIfAvailable: () => blockId != null,
|
|
261
|
-
execute: () => {
|
|
262
|
-
previewStore.send({ type: "toggleContentSheet" });
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
actionsStore.send({
|
|
266
|
-
type: "registerAction",
|
|
267
|
-
action
|
|
268
|
-
});
|
|
269
|
-
return () => actionsStore.send({
|
|
270
|
-
type: "unregisterAction",
|
|
271
|
-
id: action.id
|
|
272
|
-
});
|
|
273
|
-
}, [blockId, isOpen]);
|
|
274
|
-
const handleBlockFieldChange = React.useCallback((fieldName, value_1) => {
|
|
275
|
-
if (!block) return;
|
|
276
|
-
if (!requireDraft()) return;
|
|
277
|
-
sessionDirtyRef.current = true;
|
|
278
|
-
updateContent.mutate({
|
|
279
|
-
id: block.id,
|
|
280
|
-
content: { [fieldName]: value_1 }
|
|
281
|
-
});
|
|
282
|
-
}, [
|
|
283
|
-
block,
|
|
284
|
-
updateContent,
|
|
285
|
-
requireDraft
|
|
286
|
-
]);
|
|
287
|
-
const handleItemFieldChange = React.useCallback((fieldName_0, value_2) => {
|
|
288
|
-
if (currentItemId == null) return;
|
|
289
|
-
if (!requireDraft()) return;
|
|
290
|
-
sessionDirtyRef.current = true;
|
|
291
|
-
updateRepeatableContent.mutate({
|
|
292
|
-
id: currentItemId,
|
|
293
|
-
content: { [fieldName_0]: value_2 }
|
|
294
|
-
});
|
|
295
|
-
}, [
|
|
296
|
-
currentItemId,
|
|
297
|
-
updateRepeatableContent,
|
|
298
|
-
requireDraft
|
|
299
|
-
]);
|
|
300
|
-
const activeFieldChangeHandler = currentItemId != null ? handleItemFieldChange : handleBlockFieldChange;
|
|
301
|
-
const handleOpenChange = (open) => {
|
|
302
|
-
if (open) return;
|
|
303
|
-
if (block && sessionDirtyRef.current) trackClientEvent("block_edited", {
|
|
304
|
-
via: "content-sheet",
|
|
305
|
-
blockType: block.type
|
|
306
|
-
});
|
|
307
|
-
sessionDirtyRef.current = false;
|
|
308
|
-
if (block && autoFocusFieldName) postToIframe({
|
|
309
|
-
type: "CAMOX_FOCUS_FIELD_END",
|
|
310
|
-
fieldId: currentItemId != null ? `${block.id}__${currentItemId}__${autoFocusFieldName}` : `${block.id}__${autoFocusFieldName}`
|
|
311
|
-
});
|
|
312
|
-
if (block && currentItemId != null) postToIframe({
|
|
313
|
-
type: "CAMOX_HOVER_REPEATER_ITEM_END",
|
|
314
|
-
blockId: String(block.id),
|
|
315
|
-
itemId: String(currentItemId)
|
|
316
|
-
});
|
|
317
|
-
previewStore.send({ type: "closeBlockContentSheet" });
|
|
318
|
-
};
|
|
319
|
-
const ancestorChain = React.useMemo(() => currentItemId != null ? buildAncestorChain(currentItemId, itemsMap) : [], [currentItemId, itemsMap]);
|
|
320
|
-
if (!block || !blockDef || !currentSchema) return null;
|
|
321
|
-
const fieldHasOwnView = fieldInfo ? fieldTypesDictionary[fieldInfo.fieldType].hasOwnView : false;
|
|
322
|
-
const isAtBlockLevel = ancestorChain.length === 0 && !fieldHasOwnView;
|
|
323
|
-
return /* @__PURE__ */ jsxs(PreviewSideSheet, {
|
|
324
|
-
open: isOpen,
|
|
325
|
-
onOpenChange: handleOpenChange,
|
|
326
|
-
initialFocus: getInitialFocus,
|
|
327
|
-
className: "flex flex-col gap-0",
|
|
328
|
-
children: [/* @__PURE__ */ jsxs(Sheet.SheetHeader, {
|
|
329
|
-
className: "border-border border-b",
|
|
330
|
-
children: [/* @__PURE__ */ jsx(Sheet.SheetTitle, { children: block.summary }), /* @__PURE__ */ jsx(Sheet.SheetDescription, {
|
|
331
|
-
render: /* @__PURE__ */ jsx(Breadcrumb, {}),
|
|
332
|
-
children: /* @__PURE__ */ jsxs(BreadcrumbList, {
|
|
333
|
-
className: "flex-nowrap",
|
|
334
|
-
children: [
|
|
335
|
-
/* @__PURE__ */ jsx(BreadcrumbItem, {
|
|
336
|
-
className: "min-w-0",
|
|
337
|
-
children: isAtBlockLevel ? /* @__PURE__ */ jsx(BreadcrumbPage, {
|
|
338
|
-
className: "truncate",
|
|
339
|
-
children: blockDef._internal.title
|
|
340
|
-
}) : /* @__PURE__ */ jsx(BreadcrumbLink, {
|
|
341
|
-
className: "cursor-pointer",
|
|
342
|
-
onClick: () => previewStore.send({
|
|
343
|
-
type: "setFocusedBlock",
|
|
344
|
-
blockId: block.id
|
|
345
|
-
}),
|
|
346
|
-
children: blockDef._internal.title
|
|
347
|
-
})
|
|
348
|
-
}),
|
|
349
|
-
ancestorChain.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
350
|
-
ancestorChain.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(BreadcrumbSeparator, {}), /* @__PURE__ */ jsx(BreadcrumbItem, { children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
351
|
-
className: "flex items-center gap-1",
|
|
352
|
-
children: /* @__PURE__ */ jsx(BreadcrumbEllipsis, { className: "size-5" })
|
|
353
|
-
}), /* @__PURE__ */ jsx(DropdownMenuContent, {
|
|
354
|
-
align: "start",
|
|
355
|
-
children: ancestorChain.slice(0, -1).map((ancestor) => /* @__PURE__ */ jsx(DropdownMenuItem, {
|
|
356
|
-
onClick: () => previewStore.send({
|
|
357
|
-
type: "selectItem",
|
|
358
|
-
blockId: block.id,
|
|
359
|
-
itemId: ancestor.id
|
|
360
|
-
}),
|
|
361
|
-
children: ancestor.summary || formatFieldName(ancestor.fieldName)
|
|
362
|
-
}, ancestor.id))
|
|
363
|
-
})] }) })] }),
|
|
364
|
-
/* @__PURE__ */ jsx(BreadcrumbSeparator, {}),
|
|
365
|
-
(() => {
|
|
366
|
-
const lastAncestor = ancestorChain[ancestorChain.length - 1];
|
|
367
|
-
const crumbLabel = lastAncestor.summary || formatFieldName(lastAncestor.fieldName);
|
|
368
|
-
if (fieldHasOwnView) return /* @__PURE__ */ jsx(BreadcrumbItem, {
|
|
369
|
-
className: "min-w-0",
|
|
370
|
-
children: /* @__PURE__ */ jsx(BreadcrumbLink, {
|
|
371
|
-
className: "cursor-pointer truncate",
|
|
372
|
-
onClick: () => previewStore.send({ type: "selectParent" }),
|
|
373
|
-
children: crumbLabel
|
|
374
|
-
})
|
|
375
|
-
});
|
|
376
|
-
return /* @__PURE__ */ jsx(BreadcrumbItem, {
|
|
377
|
-
className: "min-w-0",
|
|
378
|
-
children: /* @__PURE__ */ jsx(BreadcrumbPage, {
|
|
379
|
-
className: "truncate",
|
|
380
|
-
children: crumbLabel
|
|
381
|
-
})
|
|
382
|
-
});
|
|
383
|
-
})()
|
|
384
|
-
] }),
|
|
385
|
-
fieldHasOwnView && fieldInfo && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(BreadcrumbSeparator, {}), /* @__PURE__ */ jsx(BreadcrumbItem, {
|
|
386
|
-
className: "min-w-0",
|
|
387
|
-
children: /* @__PURE__ */ jsx(BreadcrumbPage, {
|
|
388
|
-
className: "truncate",
|
|
389
|
-
children: currentSchema?.properties?.[fieldInfo.fieldName]?.title ?? formatFieldName(fieldInfo.fieldName)
|
|
390
|
-
})
|
|
391
|
-
})] })
|
|
392
|
-
]
|
|
393
|
-
})
|
|
394
|
-
})]
|
|
395
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
396
|
-
className: "relative flex-1 overflow-auto",
|
|
397
|
-
children: [isReadOnly && /* @__PURE__ */ jsx("button", {
|
|
398
|
-
type: "button",
|
|
399
|
-
"aria-label": "Switch to draft to edit",
|
|
400
|
-
className: "absolute inset-0 z-10 h-full w-full cursor-not-allowed",
|
|
401
|
-
onClick: () => previewStore.send({ type: "requestDraftSwitch" })
|
|
402
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
403
|
-
className: cn(isReadOnly && "pointer-events-none opacity-50"),
|
|
404
|
-
children: isItemLoading ? /* @__PURE__ */ jsx("div", {
|
|
405
|
-
className: "flex h-full items-center justify-center py-12",
|
|
406
|
-
children: /* @__PURE__ */ jsx(Spinner, {})
|
|
407
|
-
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
408
|
-
currentItemId == null && !fieldHasOwnView && settingsFields.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
409
|
-
className: "border-border space-y-4 border-b px-4 py-4",
|
|
410
|
-
children: [/* @__PURE__ */ jsx(Label, {
|
|
411
|
-
className: "text-muted-foreground",
|
|
412
|
-
children: "Settings"
|
|
413
|
-
}), settingsFields.map((field) => {
|
|
414
|
-
const label = field.label ?? formatFieldName(field.name);
|
|
415
|
-
const settingsValues = block.settings ?? {};
|
|
416
|
-
if (field.fieldType === "Enum") {
|
|
417
|
-
const value_3 = settingsValues[field.name] ?? (blockDef._internal.settingsSchema?.properties?.[field.name])?.default ?? "";
|
|
418
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
419
|
-
className: "space-y-2",
|
|
420
|
-
children: [/* @__PURE__ */ jsx(Label, {
|
|
421
|
-
htmlFor: `setting-${field.name}`,
|
|
422
|
-
children: label
|
|
423
|
-
}), /* @__PURE__ */ jsxs(Select, {
|
|
424
|
-
value: value_3,
|
|
425
|
-
onValueChange: (newValue) => {
|
|
426
|
-
if (!requireDraft()) return;
|
|
427
|
-
sessionDirtyRef.current = true;
|
|
428
|
-
updateSettings.mutate({
|
|
429
|
-
id: block.id,
|
|
430
|
-
settings: { [field.name]: newValue }
|
|
431
|
-
});
|
|
432
|
-
},
|
|
433
|
-
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
434
|
-
id: `setting-${field.name}`,
|
|
435
|
-
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
436
|
-
}), /* @__PURE__ */ jsx(SelectContent, { children: field.enumValues?.map((enumValue) => /* @__PURE__ */ jsx(SelectItem, {
|
|
437
|
-
value: enumValue,
|
|
438
|
-
children: field.enumLabels?.[enumValue] ?? enumValue
|
|
439
|
-
}, enumValue)) })]
|
|
440
|
-
})]
|
|
441
|
-
}, field.name);
|
|
442
|
-
}
|
|
443
|
-
if (field.fieldType === "Boolean") {
|
|
444
|
-
const checked = settingsValues[field.name] ?? (blockDef._internal.settingsSchema?.properties?.[field.name])?.default ?? false;
|
|
445
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
446
|
-
className: "flex items-center justify-between",
|
|
447
|
-
children: [/* @__PURE__ */ jsx(Label, {
|
|
448
|
-
htmlFor: `setting-${field.name}`,
|
|
449
|
-
children: label
|
|
450
|
-
}), /* @__PURE__ */ jsx(Switch, {
|
|
451
|
-
id: `setting-${field.name}`,
|
|
452
|
-
checked,
|
|
453
|
-
onCheckedChange: (newValue_0) => {
|
|
454
|
-
if (!requireDraft()) return;
|
|
455
|
-
sessionDirtyRef.current = true;
|
|
456
|
-
updateSettings.mutate({
|
|
457
|
-
id: block.id,
|
|
458
|
-
settings: { [field.name]: newValue_0 }
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
})]
|
|
462
|
-
}, field.name);
|
|
463
|
-
}
|
|
464
|
-
return null;
|
|
465
|
-
})]
|
|
466
|
-
}),
|
|
467
|
-
currentItemId != null && !fieldHasOwnView && itemSettingsFields.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
468
|
-
className: "border-border space-y-4 border-b px-4 py-4",
|
|
469
|
-
children: [/* @__PURE__ */ jsx(Label, {
|
|
470
|
-
className: "text-muted-foreground",
|
|
471
|
-
children: "Settings"
|
|
472
|
-
}), itemSettingsFields.map((field_0) => {
|
|
473
|
-
const label_0 = field_0.label ?? formatFieldName(field_0.name);
|
|
474
|
-
const itemSettingsValues = currentItem?.settings ?? {};
|
|
475
|
-
const itemSettingsSchemaProps = itemArraySchema?.itemSettingsSchema?.properties;
|
|
476
|
-
if (field_0.fieldType === "Enum") {
|
|
477
|
-
const value_4 = itemSettingsValues[field_0.name] ?? itemSettingsSchemaProps?.[field_0.name]?.default ?? "";
|
|
478
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
479
|
-
className: "space-y-2",
|
|
480
|
-
children: [/* @__PURE__ */ jsx(Label, {
|
|
481
|
-
htmlFor: `item-setting-${field_0.name}`,
|
|
482
|
-
children: label_0
|
|
483
|
-
}), /* @__PURE__ */ jsxs(Select, {
|
|
484
|
-
value: value_4,
|
|
485
|
-
onValueChange: (newValue_1) => {
|
|
486
|
-
if (!requireDraft()) return;
|
|
487
|
-
sessionDirtyRef.current = true;
|
|
488
|
-
updateRepeatableSettings.mutate({
|
|
489
|
-
id: currentItemId,
|
|
490
|
-
settings: { [field_0.name]: newValue_1 }
|
|
491
|
-
});
|
|
492
|
-
},
|
|
493
|
-
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
494
|
-
id: `item-setting-${field_0.name}`,
|
|
495
|
-
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
496
|
-
}), /* @__PURE__ */ jsx(SelectContent, { children: field_0.enumValues?.map((enumValue_0) => /* @__PURE__ */ jsx(SelectItem, {
|
|
497
|
-
value: enumValue_0,
|
|
498
|
-
children: field_0.enumLabels?.[enumValue_0] ?? enumValue_0
|
|
499
|
-
}, enumValue_0)) })]
|
|
500
|
-
})]
|
|
501
|
-
}, field_0.name);
|
|
502
|
-
}
|
|
503
|
-
if (field_0.fieldType === "Boolean") {
|
|
504
|
-
const checked_0 = itemSettingsValues[field_0.name] ?? itemSettingsSchemaProps?.[field_0.name]?.default ?? false;
|
|
505
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
506
|
-
className: "flex items-center justify-between",
|
|
507
|
-
children: [/* @__PURE__ */ jsx(Label, {
|
|
508
|
-
htmlFor: `item-setting-${field_0.name}`,
|
|
509
|
-
children: label_0
|
|
510
|
-
}), /* @__PURE__ */ jsx(Switch, {
|
|
511
|
-
id: `item-setting-${field_0.name}`,
|
|
512
|
-
checked: checked_0,
|
|
513
|
-
onCheckedChange: (newValue_2) => {
|
|
514
|
-
if (!requireDraft()) return;
|
|
515
|
-
sessionDirtyRef.current = true;
|
|
516
|
-
updateRepeatableSettings.mutate({
|
|
517
|
-
id: currentItemId,
|
|
518
|
-
settings: { [field_0.name]: newValue_2 }
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
})]
|
|
522
|
-
}, field_0.name);
|
|
523
|
-
}
|
|
524
|
-
return null;
|
|
525
|
-
})]
|
|
526
|
-
}),
|
|
527
|
-
isViewingAsset && assetFieldName && isMultipleAsset && /* @__PURE__ */ jsx(MultipleAssetFieldEditor, {
|
|
528
|
-
fieldName: assetFieldName,
|
|
529
|
-
assetType,
|
|
530
|
-
currentData,
|
|
531
|
-
onFieldChange: activeFieldChangeHandler
|
|
532
|
-
}),
|
|
533
|
-
isViewingAsset && assetFieldName && !isMultipleAsset && /* @__PURE__ */ jsx(SingleAssetFieldEditor, {
|
|
534
|
-
fieldName: assetFieldName,
|
|
535
|
-
assetType,
|
|
536
|
-
currentData,
|
|
537
|
-
onFieldChange: activeFieldChangeHandler
|
|
538
|
-
}),
|
|
539
|
-
!isViewingAsset && isViewingLink && linkFieldName && /* @__PURE__ */ jsx("div", {
|
|
540
|
-
className: "px-4 py-4",
|
|
541
|
-
children: /* @__PURE__ */ jsx(LinkFieldEditor, {
|
|
542
|
-
fieldName: linkFieldName,
|
|
543
|
-
linkValue: currentData[linkFieldName] ?? {
|
|
544
|
-
type: "external",
|
|
545
|
-
text: "",
|
|
546
|
-
href: "",
|
|
547
|
-
newTab: false
|
|
548
|
-
},
|
|
549
|
-
onSave: (fieldName_1, value_5) => {
|
|
550
|
-
activeFieldChangeHandler(fieldName_1, value_5);
|
|
551
|
-
}
|
|
552
|
-
})
|
|
553
|
-
}),
|
|
554
|
-
!isViewingAsset && !isViewingLink && (currentItemId == null || currentItem) && /* @__PURE__ */ jsx(ItemFieldsEditor, {
|
|
555
|
-
schema: currentSchema,
|
|
556
|
-
data: currentData,
|
|
557
|
-
blockId: block.id,
|
|
558
|
-
itemId: currentItemId ?? void 0,
|
|
559
|
-
onFieldChange: activeFieldChangeHandler,
|
|
560
|
-
postToIframe,
|
|
561
|
-
filesMap,
|
|
562
|
-
itemsMap,
|
|
563
|
-
fieldIdPrefix,
|
|
564
|
-
autoFocusFieldName
|
|
565
|
-
}, currentItemId ?? `block-${block.id}`),
|
|
566
|
-
!isViewingAsset && !isViewingLink && currentItemId != null && currentItem && /* @__PURE__ */ jsxs("div", {
|
|
567
|
-
className: "border-border flex items-center gap-1 border-t px-4 py-4",
|
|
568
|
-
children: [
|
|
569
|
-
canAddSibling && /* @__PURE__ */ jsxs(Button, {
|
|
570
|
-
type: "button",
|
|
571
|
-
variant: "ghost",
|
|
572
|
-
size: "sm",
|
|
573
|
-
className: "text-muted-foreground justify-start",
|
|
574
|
-
onClick: () => {
|
|
575
|
-
if (!requireDraft()) return;
|
|
576
|
-
addSibling({ afterPosition: currentItem.position });
|
|
577
|
-
},
|
|
578
|
-
children: [/* @__PURE__ */ jsx(CirclePlus, { className: "h-4 w-4" }), "Add item"]
|
|
579
|
-
}),
|
|
580
|
-
canRemoveCurrent && /* @__PURE__ */ jsxs(Button, {
|
|
581
|
-
type: "button",
|
|
582
|
-
variant: "ghost",
|
|
583
|
-
size: "sm",
|
|
584
|
-
className: "text-muted-foreground justify-start",
|
|
585
|
-
onClick: () => {
|
|
586
|
-
if (!requireDraft()) return;
|
|
587
|
-
removeCurrent(currentItemId, { onSuccess: () => previewStore.send({ type: "selectParent" }) });
|
|
588
|
-
},
|
|
589
|
-
children: [/* @__PURE__ */ jsx(CircleMinus, { className: "h-4 w-4" }), "Remove item"]
|
|
590
|
-
}),
|
|
591
|
-
/* @__PURE__ */ jsxs(Button, {
|
|
592
|
-
type: "button",
|
|
593
|
-
variant: "ghost",
|
|
594
|
-
size: "sm",
|
|
595
|
-
className: "text-muted-foreground justify-start",
|
|
596
|
-
onClick: () => previewStore.send({ type: "selectParent" }),
|
|
597
|
-
children: [/* @__PURE__ */ jsx(CornerLeftUp, { className: "h-4 w-4" }), "Select parent"]
|
|
598
|
-
})
|
|
599
|
-
]
|
|
600
|
-
})
|
|
601
|
-
] })
|
|
602
|
-
})]
|
|
603
|
-
})]
|
|
604
|
-
});
|
|
605
|
-
};
|
|
606
|
-
|
|
607
|
-
//#endregion
|
|
608
|
-
export { PageContentSheet };
|