camox 0.45.0 → 0.46.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/hooks/useArtifactHost.js +2 -2
- package/dist/features/canvas/CamoxCanvas.js +438 -771
- package/dist/features/canvas/CanvasPageFrame.js +1 -3
- package/dist/features/canvas/CanvasPreviewPageSlot.js +26 -6
- package/dist/features/canvas/canvasCamera.js +3 -3
- package/dist/features/canvas/canvasFrameDocument.js +4 -19
- package/dist/features/canvas/canvasItems.js +12 -102
- package/dist/features/canvas/canvasStore.js +3 -92
- package/dist/features/canvas/sidebar/CanvasNavigator.js +81 -183
- package/dist/features/canvas/sidebar/CanvasSidebar.js +22 -28
- package/dist/features/canvas/sidebar/CuratedPageInspector.js +2 -2
- package/dist/features/canvas/useCanvasCamera.js +0 -20
- package/dist/features/canvas/useCanvasFrame.js +5 -6
- package/dist/features/preview/CamoxPreview.js +3 -3
- package/dist/features/preview/components/{AddBlockDialog.js → AddBlockSheet.js} +35 -32
- package/dist/features/preview/components/BlockActionsPopover.js +6 -6
- package/dist/features/preview/components/BlockThumbnail.js +31 -33
- package/dist/features/preview/components/Overlays.js +1 -1
- package/dist/features/preview/components/PageTree.js +1 -1
- package/dist/features/preview/components/PreviewPanel.js +1 -1
- package/dist/features/preview/previewStore.js +9 -9
- package/dist/features/provider/CoreCamoxProvider.js +9 -6
- package/dist/features/routes/pageRuntime.js +8 -8
- package/dist/features/runtime/runtime.d.ts +2 -7
- package/dist/features/runtime/runtime.js +6 -19
- package/dist/features/studio/FollowAgentProvider.js +11 -22
- package/dist/features/studio/components/FaviconDialog.js +3 -3
- package/dist/features/studio/followAgent.js +5 -14
- package/dist/features/studio/routes.js +1 -23
- package/dist/lib/auth.js +36 -24
- package/dist/lib/studio-reads.js +0 -20
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +4 -4
- package/skills/camox-expand/SKILL.md +5 -4
- package/dist/features/canvas/CanvasBlockFrame.js +0 -353
- package/dist/features/canvas/CanvasBlockHeader.js +0 -55
- package/dist/features/canvas/CanvasShelfMarker.js +0 -255
- package/dist/features/canvas/sidebar/CatalogBlockInspector.js +0 -189
|
@@ -1,224 +1,122 @@
|
|
|
1
|
-
import { cn } from "../../../lib/utils.js";
|
|
2
1
|
import { previewStore } from "../../preview/previewStore.js";
|
|
3
2
|
import { canvasPagePath } from "../canvasPages.js";
|
|
4
3
|
import { c } from "react/compiler-runtime";
|
|
5
4
|
import * as React from "react";
|
|
6
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
6
|
import { Button } from "@camox/ui/button";
|
|
8
|
-
import {
|
|
7
|
+
import { Plus } from "lucide-react";
|
|
9
8
|
import { Command as Command$1, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, commandFilter } from "@camox/ui/command";
|
|
10
9
|
|
|
11
10
|
//#region src/features/canvas/sidebar/CanvasNavigator.tsx
|
|
12
|
-
/** Blocks behind a bordered toggle, collapsed until opened. */
|
|
13
|
-
function CollapsedBlocks(t0) {
|
|
14
|
-
const $ = c(14);
|
|
15
|
-
const { label, children } = t0;
|
|
16
|
-
const [expanded, setExpanded] = React.useState(false);
|
|
17
|
-
let t1;
|
|
18
|
-
let t2;
|
|
19
|
-
let t3;
|
|
20
|
-
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
21
|
-
t1 = cn("hover:bg-accent/75 flex w-full cursor-default items-center gap-2 px-3 py-2 text-left text-sm", "focus-visible:rounded-none focus-visible:ring-inset");
|
|
22
|
-
t2 = () => setExpanded(_temp);
|
|
23
|
-
t3 = /* @__PURE__ */ jsx(ChevronsUpDown, { className: "text-muted-foreground size-4 shrink-0" });
|
|
24
|
-
$[0] = t1;
|
|
25
|
-
$[1] = t2;
|
|
26
|
-
$[2] = t3;
|
|
27
|
-
} else {
|
|
28
|
-
t1 = $[0];
|
|
29
|
-
t2 = $[1];
|
|
30
|
-
t3 = $[2];
|
|
31
|
-
}
|
|
32
|
-
let t4;
|
|
33
|
-
if ($[3] !== label) {
|
|
34
|
-
t4 = /* @__PURE__ */ jsx("span", {
|
|
35
|
-
className: "truncate",
|
|
36
|
-
children: label
|
|
37
|
-
});
|
|
38
|
-
$[3] = label;
|
|
39
|
-
$[4] = t4;
|
|
40
|
-
} else t4 = $[4];
|
|
41
|
-
let t5;
|
|
42
|
-
if ($[5] !== expanded || $[6] !== t4) {
|
|
43
|
-
t5 = /* @__PURE__ */ jsxs("button", {
|
|
44
|
-
type: "button",
|
|
45
|
-
"aria-expanded": expanded,
|
|
46
|
-
className: t1,
|
|
47
|
-
onClick: t2,
|
|
48
|
-
children: [t3, t4]
|
|
49
|
-
});
|
|
50
|
-
$[5] = expanded;
|
|
51
|
-
$[6] = t4;
|
|
52
|
-
$[7] = t5;
|
|
53
|
-
} else t5 = $[7];
|
|
54
|
-
let t6;
|
|
55
|
-
if ($[8] !== children || $[9] !== expanded) {
|
|
56
|
-
t6 = expanded && /* @__PURE__ */ jsx("div", {
|
|
57
|
-
className: "border-input border-t p-1",
|
|
58
|
-
children
|
|
59
|
-
});
|
|
60
|
-
$[8] = children;
|
|
61
|
-
$[9] = expanded;
|
|
62
|
-
$[10] = t6;
|
|
63
|
-
} else t6 = $[10];
|
|
64
|
-
let t7;
|
|
65
|
-
if ($[11] !== t5 || $[12] !== t6) {
|
|
66
|
-
t7 = /* @__PURE__ */ jsxs("div", {
|
|
67
|
-
className: "border-input flex flex-col overflow-hidden rounded-lg border shadow-xs",
|
|
68
|
-
children: [t5, t6]
|
|
69
|
-
});
|
|
70
|
-
$[11] = t5;
|
|
71
|
-
$[12] = t6;
|
|
72
|
-
$[13] = t7;
|
|
73
|
-
} else t7 = $[13];
|
|
74
|
-
return t7;
|
|
75
|
-
}
|
|
76
|
-
function _temp(value) {
|
|
77
|
-
return !value;
|
|
78
|
-
}
|
|
79
|
-
function canvasItemLabel(item) {
|
|
80
|
-
return item.kind === "page" ? item.page.title : item.block._internal.title;
|
|
81
|
-
}
|
|
82
|
-
/** Search an item by its label, and a Page by its path too, never by its key. */
|
|
83
|
-
function canvasItemKeywords(item) {
|
|
84
|
-
const label = canvasItemLabel(item);
|
|
85
|
-
const path = item.kind === "page" ? canvasPagePath(item.page) : null;
|
|
86
|
-
return path ? [label, path] : [label];
|
|
87
|
-
}
|
|
88
11
|
/**
|
|
89
|
-
* The Canvas Navigator, shown while nothing is selected: every
|
|
90
|
-
* in Canvas order,
|
|
91
|
-
*
|
|
92
|
-
* finds them. Picking an item shows it: the camera goes to it.
|
|
12
|
+
* The Canvas Navigator, shown while nothing is selected: every Page of the Canvas,
|
|
13
|
+
* in Canvas order, with its path, and a search that takes focus. Picking a Page
|
|
14
|
+
* shows it: the camera goes to it.
|
|
93
15
|
*/
|
|
94
16
|
function CanvasNavigator(t0) {
|
|
95
|
-
const $ = c(
|
|
96
|
-
const {
|
|
17
|
+
const $ = c(17);
|
|
18
|
+
const { pages, selectedKey, onShowPage } = t0;
|
|
97
19
|
const [search, setSearch] = React.useState("");
|
|
98
20
|
let t1;
|
|
99
21
|
if ($[0] !== search) {
|
|
100
|
-
t1 =
|
|
101
|
-
|
|
102
|
-
$[1] = t1;
|
|
103
|
-
} else t1 = $[1];
|
|
104
|
-
const searching = t1 !== "";
|
|
105
|
-
let t2;
|
|
106
|
-
if ($[2] !== onShowItem || $[3] !== selectedKey) {
|
|
107
|
-
t2 = (item) => {
|
|
108
|
-
const selected = item.key === selectedKey;
|
|
109
|
-
const path = item.kind === "page" ? canvasPagePath(item.page) : null;
|
|
110
|
-
return /* @__PURE__ */ jsx(CommandItem, {
|
|
111
|
-
value: item.key,
|
|
112
|
-
keywords: canvasItemKeywords(item),
|
|
113
|
-
"data-checked": selected,
|
|
114
|
-
"aria-current": selected ? "true" : void 0,
|
|
115
|
-
onSelect: () => onShowItem(item.key),
|
|
116
|
-
children: item.kind === "page" ? /* @__PURE__ */ jsxs("div", {
|
|
117
|
-
className: "flex min-w-0 flex-col py-0.5",
|
|
118
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
119
|
-
className: "truncate font-medium",
|
|
120
|
-
children: canvasItemLabel(item)
|
|
121
|
-
}), path && /* @__PURE__ */ jsx("span", {
|
|
122
|
-
className: "text-muted-foreground truncate font-mono text-xs",
|
|
123
|
-
children: path
|
|
124
|
-
})]
|
|
125
|
-
}) : /* @__PURE__ */ jsx("span", {
|
|
126
|
-
className: "truncate",
|
|
127
|
-
children: canvasItemLabel(item)
|
|
128
|
-
})
|
|
129
|
-
}, item.key);
|
|
130
|
-
};
|
|
131
|
-
$[2] = onShowItem;
|
|
132
|
-
$[3] = selectedKey;
|
|
133
|
-
$[4] = t2;
|
|
134
|
-
} else t2 = $[4];
|
|
135
|
-
const renderItem = t2;
|
|
136
|
-
let t3;
|
|
137
|
-
if ($[5] !== search) {
|
|
138
|
-
t3 = /* @__PURE__ */ jsx(CommandInput, {
|
|
139
|
-
placeholder: "Search the Canvas…",
|
|
22
|
+
t1 = /* @__PURE__ */ jsx(CommandInput, {
|
|
23
|
+
placeholder: "Search pages…",
|
|
140
24
|
autoFocus: true,
|
|
141
25
|
value: search,
|
|
142
26
|
onValueChange: setSearch
|
|
143
27
|
});
|
|
144
|
-
$[
|
|
145
|
-
$[
|
|
146
|
-
} else
|
|
28
|
+
$[0] = search;
|
|
29
|
+
$[1] = t1;
|
|
30
|
+
} else t1 = $[1];
|
|
31
|
+
let t2;
|
|
32
|
+
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
33
|
+
t2 = /* @__PURE__ */ jsx(CommandEmpty, { children: "Nothing found." });
|
|
34
|
+
$[2] = t2;
|
|
35
|
+
} else t2 = $[2];
|
|
36
|
+
const t3 = `Pages (${pages.length})`;
|
|
147
37
|
let t4;
|
|
148
|
-
if ($[
|
|
149
|
-
|
|
150
|
-
$[7]
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
children:
|
|
161
|
-
className: "
|
|
162
|
-
children: /* @__PURE__ */
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
children:
|
|
168
|
-
})
|
|
169
|
-
})]
|
|
170
|
-
}, shelf.key);
|
|
171
|
-
return /* @__PURE__ */ jsx(CommandGroup, {
|
|
172
|
-
heading: searching ? heading : void 0,
|
|
173
|
-
children: searching || shelf.items.length === 0 ? shelf.items.map(renderItem) : /* @__PURE__ */ jsx("div", {
|
|
174
|
-
className: "p-1",
|
|
175
|
-
children: /* @__PURE__ */ jsx(CollapsedBlocks, {
|
|
176
|
-
label: `${shelf.items.length} ${shelf.items.length === 1 ? "block" : "blocks"}`,
|
|
177
|
-
children: shelf.items.map(renderItem)
|
|
178
|
-
})
|
|
38
|
+
if ($[3] !== onShowPage || $[4] !== pages || $[5] !== selectedKey) {
|
|
39
|
+
let t5;
|
|
40
|
+
if ($[7] !== onShowPage || $[8] !== selectedKey) {
|
|
41
|
+
t5 = (page) => {
|
|
42
|
+
const selected = page.key === selectedKey;
|
|
43
|
+
const path = canvasPagePath(page);
|
|
44
|
+
return /* @__PURE__ */ jsx(CommandItem, {
|
|
45
|
+
value: page.key,
|
|
46
|
+
keywords: path ? [page.title, path] : [page.title],
|
|
47
|
+
"data-checked": selected,
|
|
48
|
+
"aria-current": selected ? "true" : void 0,
|
|
49
|
+
onSelect: () => onShowPage(page.key),
|
|
50
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
51
|
+
className: "flex min-w-0 flex-col py-0.5",
|
|
52
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
53
|
+
className: "truncate font-medium",
|
|
54
|
+
children: page.title
|
|
55
|
+
}), path && /* @__PURE__ */ jsx("span", {
|
|
56
|
+
className: "text-muted-foreground truncate font-mono text-xs",
|
|
57
|
+
children: path
|
|
58
|
+
})]
|
|
179
59
|
})
|
|
180
|
-
},
|
|
60
|
+
}, page.key);
|
|
181
61
|
};
|
|
182
|
-
$[
|
|
183
|
-
$[
|
|
184
|
-
$[
|
|
185
|
-
} else
|
|
186
|
-
|
|
187
|
-
$[
|
|
188
|
-
$[
|
|
189
|
-
$[
|
|
190
|
-
$[
|
|
191
|
-
} else
|
|
62
|
+
$[7] = onShowPage;
|
|
63
|
+
$[8] = selectedKey;
|
|
64
|
+
$[9] = t5;
|
|
65
|
+
} else t5 = $[9];
|
|
66
|
+
t4 = pages.map(t5);
|
|
67
|
+
$[3] = onShowPage;
|
|
68
|
+
$[4] = pages;
|
|
69
|
+
$[5] = selectedKey;
|
|
70
|
+
$[6] = t4;
|
|
71
|
+
} else t4 = $[6];
|
|
72
|
+
let t5;
|
|
73
|
+
if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
|
|
74
|
+
t5 = /* @__PURE__ */ jsx("div", {
|
|
75
|
+
className: "p-1",
|
|
76
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
77
|
+
type: "button",
|
|
78
|
+
variant: "secondary",
|
|
79
|
+
className: "w-full",
|
|
80
|
+
onClick: _temp2,
|
|
81
|
+
children: [/* @__PURE__ */ jsx(Plus, {}), "Create page"]
|
|
82
|
+
})
|
|
83
|
+
});
|
|
84
|
+
$[10] = t5;
|
|
85
|
+
} else t5 = $[10];
|
|
192
86
|
let t6;
|
|
193
|
-
if ($[
|
|
87
|
+
if ($[11] !== t3 || $[12] !== t4) {
|
|
194
88
|
t6 = /* @__PURE__ */ jsxs(CommandList, {
|
|
195
89
|
className: "max-h-none flex-1",
|
|
196
|
-
children: [
|
|
90
|
+
children: [t2, /* @__PURE__ */ jsxs(CommandGroup, {
|
|
91
|
+
heading: t3,
|
|
92
|
+
children: [t4, t5]
|
|
93
|
+
})]
|
|
197
94
|
});
|
|
198
|
-
$[
|
|
199
|
-
$[
|
|
200
|
-
|
|
95
|
+
$[11] = t3;
|
|
96
|
+
$[12] = t4;
|
|
97
|
+
$[13] = t6;
|
|
98
|
+
} else t6 = $[13];
|
|
201
99
|
let t7;
|
|
202
|
-
if ($[
|
|
100
|
+
if ($[14] !== t1 || $[15] !== t6) {
|
|
203
101
|
t7 = /* @__PURE__ */ jsx("div", {
|
|
204
102
|
"data-canvas-navigator": true,
|
|
205
103
|
className: "flex min-h-0 flex-1 flex-col",
|
|
206
104
|
children: /* @__PURE__ */ jsxs(Command$1, {
|
|
207
105
|
className: "rounded-none! bg-transparent",
|
|
208
|
-
filter:
|
|
209
|
-
children: [
|
|
106
|
+
filter: _temp,
|
|
107
|
+
children: [t1, t6]
|
|
210
108
|
})
|
|
211
109
|
});
|
|
212
|
-
$[
|
|
213
|
-
$[
|
|
214
|
-
$[
|
|
215
|
-
} else t7 = $[
|
|
110
|
+
$[14] = t1;
|
|
111
|
+
$[15] = t6;
|
|
112
|
+
$[16] = t7;
|
|
113
|
+
} else t7 = $[16];
|
|
216
114
|
return t7;
|
|
217
115
|
}
|
|
218
|
-
function
|
|
116
|
+
function _temp2() {
|
|
219
117
|
return previewStore.send({ type: "openCreatePageModal" });
|
|
220
118
|
}
|
|
221
|
-
function
|
|
119
|
+
function _temp(_value, search_0, keywords) {
|
|
222
120
|
return commandFilter(keywords?.join(" ") ?? "", search_0);
|
|
223
121
|
}
|
|
224
122
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { CanvasSidebarFrame } from "./CanvasSidebarFrame.js";
|
|
2
2
|
import { CreatePageModal } from "../../preview/components/CreatePageModal.js";
|
|
3
3
|
import { CanvasNavigator } from "./CanvasNavigator.js";
|
|
4
|
-
import { CatalogBlockInspector } from "./CatalogBlockInspector.js";
|
|
5
4
|
import { PageInspector } from "./PageInspector.js";
|
|
6
5
|
import { c } from "react/compiler-runtime";
|
|
7
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -9,50 +8,45 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
9
8
|
//#region src/features/canvas/sidebar/CanvasSidebar.tsx
|
|
10
9
|
/**
|
|
11
10
|
* The sidebar beside the Canvas. Without a selection, it shows the Canvas Navigator;
|
|
12
|
-
* with one, the Canvas Inspector of the selected Page
|
|
11
|
+
* with one, the Canvas Inspector of the selected Page.
|
|
13
12
|
*/
|
|
14
13
|
function CanvasSidebar(t0) {
|
|
15
|
-
const $ = c(
|
|
16
|
-
const { page,
|
|
14
|
+
const $ = c(11);
|
|
15
|
+
const { page, navigator, onShowWholeCanvas, onRenamePage, owner: t1, pageRecord } = t0;
|
|
17
16
|
const owner = t1 === void 0 ? null : t1;
|
|
18
|
-
const t2 =
|
|
17
|
+
const t2 = page?.title ?? "Canvas navigator";
|
|
19
18
|
let t3;
|
|
20
|
-
if ($[0] !==
|
|
21
|
-
t3 =
|
|
22
|
-
block: catalog.block,
|
|
23
|
-
projectId: catalog.projectId,
|
|
24
|
-
onBack: onShowWholeCanvas
|
|
25
|
-
}) : page ? /* @__PURE__ */ jsx(PageInspector, {
|
|
19
|
+
if ($[0] !== navigator || $[1] !== onRenamePage || $[2] !== onShowWholeCanvas || $[3] !== owner || $[4] !== page || $[5] !== pageRecord) {
|
|
20
|
+
t3 = page ? /* @__PURE__ */ jsx(PageInspector, {
|
|
26
21
|
page,
|
|
27
22
|
owner,
|
|
28
23
|
pageRecord,
|
|
29
24
|
onBack: onShowWholeCanvas,
|
|
30
25
|
onRenamePage
|
|
31
26
|
}) : /* @__PURE__ */ jsx(CanvasNavigator, { ...navigator });
|
|
32
|
-
$[0] =
|
|
33
|
-
$[1] =
|
|
34
|
-
$[2] =
|
|
35
|
-
$[3] =
|
|
36
|
-
$[4] =
|
|
37
|
-
$[5] =
|
|
38
|
-
$[6] =
|
|
39
|
-
|
|
40
|
-
} else t3 = $[7];
|
|
27
|
+
$[0] = navigator;
|
|
28
|
+
$[1] = onRenamePage;
|
|
29
|
+
$[2] = onShowWholeCanvas;
|
|
30
|
+
$[3] = owner;
|
|
31
|
+
$[4] = page;
|
|
32
|
+
$[5] = pageRecord;
|
|
33
|
+
$[6] = t3;
|
|
34
|
+
} else t3 = $[6];
|
|
41
35
|
let t4;
|
|
42
|
-
if ($[
|
|
36
|
+
if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
|
|
43
37
|
t4 = /* @__PURE__ */ jsx(CreatePageModal, {});
|
|
44
|
-
$[
|
|
45
|
-
} else t4 = $[
|
|
38
|
+
$[7] = t4;
|
|
39
|
+
} else t4 = $[7];
|
|
46
40
|
let t5;
|
|
47
|
-
if ($[
|
|
41
|
+
if ($[8] !== t2 || $[9] !== t3) {
|
|
48
42
|
t5 = /* @__PURE__ */ jsxs(CanvasSidebarFrame, {
|
|
49
43
|
label: t2,
|
|
50
44
|
children: [t3, t4]
|
|
51
45
|
});
|
|
52
|
-
$[
|
|
53
|
-
$[
|
|
54
|
-
$[
|
|
55
|
-
} else t5 = $[
|
|
46
|
+
$[8] = t2;
|
|
47
|
+
$[9] = t3;
|
|
48
|
+
$[10] = t5;
|
|
49
|
+
} else t5 = $[10];
|
|
56
50
|
return t5;
|
|
57
51
|
}
|
|
58
52
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useProjectUuid } from "../../../lib/auth.js";
|
|
2
2
|
import { reads, useRead } from "../../../lib/studio-reads.js";
|
|
3
3
|
import { useLocalePath } from "../../../lib/view-locale.js";
|
|
4
|
-
import {
|
|
4
|
+
import { AddBlockSheet } from "../../preview/components/AddBlockSheet.js";
|
|
5
5
|
import { PreviewEditingOwnerContext } from "../../preview/previewSelection.js";
|
|
6
6
|
import { PageInfo } from "../../preview/components/PageInfo.js";
|
|
7
7
|
import { PageTree } from "../../preview/components/PageTree.js";
|
|
@@ -51,7 +51,7 @@ function CuratedPageInspector() {
|
|
|
51
51
|
const t3 = owner?.kind === "page" && owner.pageId === pageId;
|
|
52
52
|
let t4;
|
|
53
53
|
if ($[6] !== t3) {
|
|
54
|
-
t4 = /* @__PURE__ */ jsx(
|
|
54
|
+
t4 = /* @__PURE__ */ jsx(AddBlockSheet, { focusCreatedBlock: t3 });
|
|
55
55
|
$[6] = t3;
|
|
56
56
|
$[7] = t4;
|
|
57
57
|
} else t4 = $[7];
|
|
@@ -71,13 +71,6 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
71
71
|
};
|
|
72
72
|
}, []);
|
|
73
73
|
/**
|
|
74
|
-
* Pan immediately so a world x sits at or right of a screen x; never pans
|
|
75
|
-
* otherwise, nor while a selection holds the camera.
|
|
76
|
-
*/
|
|
77
|
-
const keepInView = React.useCallback((worldX, screenX) => {
|
|
78
|
-
flightControls.current?.keepInView(worldX, screenX);
|
|
79
|
-
}, []);
|
|
80
|
-
/**
|
|
81
74
|
* Pan vertically to an element inside a Canvas frame, such as a selected block,
|
|
82
75
|
* unless enough of it already shows. A page flight or a drag in progress keeps the camera.
|
|
83
76
|
*/
|
|
@@ -433,18 +426,6 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
433
426
|
};
|
|
434
427
|
flightControls.current = {
|
|
435
428
|
flyTo: startFlight,
|
|
436
|
-
keepInView: (worldX, screenX) => {
|
|
437
|
-
const x = screenX - worldX * camera.scale;
|
|
438
|
-
if (selection || camera.x >= x) return;
|
|
439
|
-
cancelCameraFlight();
|
|
440
|
-
restoredCamera = void 0;
|
|
441
|
-
fittingInitialPage = false;
|
|
442
|
-
gesture = void 0;
|
|
443
|
-
applyCamera({
|
|
444
|
-
...camera,
|
|
445
|
-
x
|
|
446
|
-
}, true);
|
|
447
|
-
},
|
|
448
429
|
reveal: (element, immediate) => {
|
|
449
430
|
const frame = element.ownerDocument.defaultView?.frameElement;
|
|
450
431
|
if (!frame || flight && !flight.pan || pointers.size) return;
|
|
@@ -793,7 +774,6 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
793
774
|
contentRef,
|
|
794
775
|
flyTo,
|
|
795
776
|
mirrorCamera,
|
|
796
|
-
keepInView,
|
|
797
777
|
reveal,
|
|
798
778
|
fitAll
|
|
799
779
|
};
|
|
@@ -20,7 +20,7 @@ function toError(error) {
|
|
|
20
20
|
* Unless live, the frame's document is paused. A resting frame keeps its size:
|
|
21
21
|
* its content is hidden, and must not shrink the frame and move the Canvas.
|
|
22
22
|
*/
|
|
23
|
-
function useCanvasFrame({ previewDocument, href, width, viewportHeight,
|
|
23
|
+
function useCanvasFrame({ previewDocument, href, width, viewportHeight, mode }) {
|
|
24
24
|
const iframeRef = React.useRef(null);
|
|
25
25
|
const [srcDoc, setSrcDoc] = React.useState();
|
|
26
26
|
const [mount, setMount] = React.useState(null);
|
|
@@ -44,7 +44,7 @@ function useCanvasFrame({ previewDocument, href, width, viewportHeight, fit, sub
|
|
|
44
44
|
React.useLayoutEffect(() => {
|
|
45
45
|
const iframe = iframeRef.current;
|
|
46
46
|
if (!iframe || !mount) return;
|
|
47
|
-
const stop = observeCanvasDocument(iframe, mount, viewportHeight,
|
|
47
|
+
const stop = observeCanvasDocument(iframe, mount, viewportHeight, () => restingRef.current);
|
|
48
48
|
sizing.current = stop;
|
|
49
49
|
return () => {
|
|
50
50
|
stop();
|
|
@@ -53,8 +53,7 @@ function useCanvasFrame({ previewDocument, href, width, viewportHeight, fit, sub
|
|
|
53
53
|
}, [
|
|
54
54
|
mount,
|
|
55
55
|
viewportHeight,
|
|
56
|
-
width
|
|
57
|
-
fit
|
|
56
|
+
width
|
|
58
57
|
]);
|
|
59
58
|
React.useEffect(() => {
|
|
60
59
|
if (!mount || live) return;
|
|
@@ -73,7 +72,7 @@ function useCanvasFrame({ previewDocument, href, width, viewportHeight, fit, sub
|
|
|
73
72
|
try {
|
|
74
73
|
const loaded = iframeRef.current;
|
|
75
74
|
const root = (loaded?.contentDocument)?.querySelector("[data-camox-preview-root]");
|
|
76
|
-
if (!root) throw new Error(
|
|
75
|
+
if (!root) throw new Error("The page preview document has no content root.");
|
|
77
76
|
if (root === mount) return;
|
|
78
77
|
root.replaceChildren();
|
|
79
78
|
setMount(root);
|
|
@@ -82,7 +81,7 @@ function useCanvasFrame({ previewDocument, href, width, viewportHeight, fit, sub
|
|
|
82
81
|
setFailure(toError(error));
|
|
83
82
|
}
|
|
84
83
|
},
|
|
85
|
-
onError: () => setFailure(/* @__PURE__ */ new Error(
|
|
84
|
+
onError: () => setFailure(/* @__PURE__ */ new Error("The page preview document could not load."))
|
|
86
85
|
}
|
|
87
86
|
};
|
|
88
87
|
}
|
|
@@ -20,7 +20,7 @@ import { DerivedPageContent } from "../page/DerivedPageContent.js";
|
|
|
20
20
|
import { STUDIO_CANVAS_PATH } from "../studio/routes.js";
|
|
21
21
|
import { studioStore } from "../studio/studioStore.js";
|
|
22
22
|
import { previewStore, selectIsCanvasShown } from "./previewStore.js";
|
|
23
|
-
import {
|
|
23
|
+
import { AddBlockSheet } from "./components/AddBlockSheet.js";
|
|
24
24
|
import { CanvasPreview, prefetchCanvas } from "./components/CanvasPreview.js";
|
|
25
25
|
import { CreatePageModal } from "./components/CreatePageModal.js";
|
|
26
26
|
import { PreviewEditingOwnerContext } from "./previewSelection.js";
|
|
@@ -667,7 +667,7 @@ const PreviewShell = (t0) => {
|
|
|
667
667
|
t3 = () => {
|
|
668
668
|
if (!isMobileStudio) return;
|
|
669
669
|
previewStore.send({ type: "hideCanvas" });
|
|
670
|
-
previewStore.send({ type: "
|
|
670
|
+
previewStore.send({ type: "closeAddBlockSheet" });
|
|
671
671
|
};
|
|
672
672
|
t4 = [isMobileStudio];
|
|
673
673
|
$[4] = isMobileStudio;
|
|
@@ -823,7 +823,7 @@ const PreviewShell = (t0) => {
|
|
|
823
823
|
} else t18 = $[33];
|
|
824
824
|
let t19;
|
|
825
825
|
if ($[34] !== isCanvasEnabled || $[35] !== pageId) {
|
|
826
|
-
t19 = !isCanvasEnabled && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CreatePageModal, {}), pageId != null && /* @__PURE__ */ jsx(
|
|
826
|
+
t19 = !isCanvasEnabled && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CreatePageModal, {}), pageId != null && /* @__PURE__ */ jsx(AddBlockSheet, {})] });
|
|
827
827
|
$[34] = isCanvasEnabled;
|
|
828
828
|
$[35] = pageId;
|
|
829
829
|
$[36] = t19;
|
|
@@ -14,12 +14,12 @@ import { generateKeyBetween } from "fractional-indexing";
|
|
|
14
14
|
import { useSelector } from "@xstate/store-react";
|
|
15
15
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
16
|
import { useMutation } from "@tanstack/react-query";
|
|
17
|
-
import {
|
|
17
|
+
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@camox/ui/sheet";
|
|
18
18
|
import { Badge } from "@camox/ui/badge";
|
|
19
19
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, commandFilter } from "@camox/ui/command";
|
|
20
20
|
|
|
21
|
-
//#region src/features/preview/components/
|
|
22
|
-
const
|
|
21
|
+
//#region src/features/preview/components/AddBlockSheet.tsx
|
|
22
|
+
const AddBlockSheet = ({ focusCreatedBlock = true }) => {
|
|
23
23
|
const [highlightedValue, setHighlightedValue] = React.useState("");
|
|
24
24
|
const [search, setSearch] = React.useState("");
|
|
25
25
|
const [error, setError] = React.useState(null);
|
|
@@ -32,7 +32,7 @@ const AddBlockDialog = ({ focusCreatedBlock = true }) => {
|
|
|
32
32
|
};
|
|
33
33
|
}, []);
|
|
34
34
|
const gridRef = React.useRef(null);
|
|
35
|
-
const
|
|
35
|
+
const sheet = useSelector(previewStore, (state) => state.context.addBlockSheet);
|
|
36
36
|
const studioCache = useStudioCache();
|
|
37
37
|
const projectUuid = useProjectUuid();
|
|
38
38
|
const pathname = useLocalePath();
|
|
@@ -117,15 +117,15 @@ const AddBlockDialog = ({ focusCreatedBlock = true }) => {
|
|
|
117
117
|
for (const block of pageBlocks) counts[block.type] = (counts[block.type] ?? 0) + 1;
|
|
118
118
|
return counts;
|
|
119
119
|
}, [page, pageBlocks]);
|
|
120
|
-
const [
|
|
121
|
-
if (
|
|
122
|
-
|
|
120
|
+
const [previousSheet, setPreviousSheet] = React.useState(sheet);
|
|
121
|
+
if (sheet !== previousSheet) {
|
|
122
|
+
setPreviousSheet(sheet);
|
|
123
123
|
setHighlightedValue("");
|
|
124
124
|
setSearch("");
|
|
125
125
|
setError(null);
|
|
126
126
|
}
|
|
127
127
|
const handleAddBlock = async (block) => {
|
|
128
|
-
if (!page || !
|
|
128
|
+
if (!page || !sheet || submitting.current) return;
|
|
129
129
|
submitting.current = true;
|
|
130
130
|
setError(null);
|
|
131
131
|
const owner = {
|
|
@@ -140,21 +140,21 @@ const AddBlockDialog = ({ focusCreatedBlock = true }) => {
|
|
|
140
140
|
type: block._internal.id,
|
|
141
141
|
content: bundle.content,
|
|
142
142
|
settings: bundle.settings,
|
|
143
|
-
afterPosition:
|
|
143
|
+
afterPosition: sheet.afterPosition,
|
|
144
144
|
repeatableItems: bundle.repeatableItems
|
|
145
145
|
});
|
|
146
146
|
const context = previewStore.getSnapshot().context;
|
|
147
147
|
if (!mounted.current) return;
|
|
148
148
|
if (focusCreatedBlock && !sameEditingOwner(context.editingContext, owner)) return;
|
|
149
|
-
if (context.
|
|
150
|
-
previewStore.send({ type: "
|
|
149
|
+
if (context.addBlockSheet !== sheet) return;
|
|
150
|
+
previewStore.send({ type: "closeAddBlockSheet" });
|
|
151
151
|
if (focusCreatedBlock) previewStore.send({
|
|
152
152
|
type: "focusCreatedBlock",
|
|
153
153
|
...owner,
|
|
154
154
|
blockId
|
|
155
155
|
});
|
|
156
156
|
} catch {
|
|
157
|
-
if (previewStore.getSnapshot().context.
|
|
157
|
+
if (previewStore.getSnapshot().context.addBlockSheet === sheet) setError("Could not add this block. Please try again.");
|
|
158
158
|
} finally {
|
|
159
159
|
submitting.current = false;
|
|
160
160
|
}
|
|
@@ -165,24 +165,25 @@ const AddBlockDialog = ({ focusCreatedBlock = true }) => {
|
|
|
165
165
|
const page = pageCounts[blockId] ?? "none";
|
|
166
166
|
return `${total} use${total > 1 ? "s" : ""} (${page} here)`;
|
|
167
167
|
};
|
|
168
|
-
return /* @__PURE__ */ jsx(
|
|
169
|
-
open:
|
|
168
|
+
return /* @__PURE__ */ jsx(Sheet, {
|
|
169
|
+
open: sheet != null,
|
|
170
170
|
onOpenChange: (open) => {
|
|
171
|
-
if (!open && !submitting.current) previewStore.send({ type: "
|
|
171
|
+
if (!open && !submitting.current) previewStore.send({ type: "closeAddBlockSheet" });
|
|
172
172
|
},
|
|
173
|
-
children: /* @__PURE__ */ jsxs(
|
|
174
|
-
|
|
173
|
+
children: /* @__PURE__ */ jsxs(SheetContent, {
|
|
174
|
+
side: "right",
|
|
175
|
+
className: "gap-0 overflow-hidden data-[side=right]:w-full data-[side=right]:sm:max-w-4xl",
|
|
175
176
|
children: [
|
|
176
|
-
/* @__PURE__ */ jsxs(
|
|
177
|
-
className: "pr-
|
|
178
|
-
children: [/* @__PURE__ */ jsx(
|
|
177
|
+
/* @__PURE__ */ jsxs(SheetHeader, {
|
|
178
|
+
className: "pr-12",
|
|
179
|
+
children: [/* @__PURE__ */ jsx(SheetTitle, { children: "Add a block" }), /* @__PURE__ */ jsx(SheetDescription, { children: "Search blocks, use the arrow keys to browse, and press Enter to add." })]
|
|
179
180
|
}),
|
|
180
181
|
/* @__PURE__ */ jsxs(Command, {
|
|
181
182
|
label: "Search blocks",
|
|
182
183
|
shouldFilter: false,
|
|
183
184
|
value: selectedValue,
|
|
184
185
|
onValueChange: setHighlightedValue,
|
|
185
|
-
className: "h-0 min-h-0 flex-1 rounded-none! bg-transparent!
|
|
186
|
+
className: "h-0 min-h-0 flex-1 rounded-none! bg-transparent! px-4! pt-0! pb-0!",
|
|
186
187
|
onKeyDown: (e) => {
|
|
187
188
|
if (e.nativeEvent.isComposing || e.altKey || e.ctrlKey || e.metaKey) return;
|
|
188
189
|
if (![
|
|
@@ -214,11 +215,11 @@ const AddBlockDialog = ({ focusCreatedBlock = true }) => {
|
|
|
214
215
|
autoFocus: true
|
|
215
216
|
}), /* @__PURE__ */ jsxs(CommandList, {
|
|
216
217
|
label: "Available blocks",
|
|
217
|
-
className: "mt-4 max-h-none min-h-0 flex-1 pb-
|
|
218
|
+
className: "mt-4 max-h-none min-h-0 flex-1 pb-4",
|
|
218
219
|
"aria-busy": createBlock.isPending,
|
|
219
220
|
children: [/* @__PURE__ */ jsx(CommandEmpty, { children: "No blocks found." }), /* @__PURE__ */ jsx(CommandGroup, {
|
|
220
221
|
ref: gridRef,
|
|
221
|
-
className: "p-0 [&>[cmdk-group-items]]:grid [&>[cmdk-group-items]]:grid-cols-1 [&>[cmdk-group-items]]:gap-4
|
|
222
|
+
className: "@container p-0 [&>[cmdk-group-items]]:grid [&>[cmdk-group-items]]:grid-cols-1 [&>[cmdk-group-items]]:gap-4 @xl:[&>[cmdk-group-items]]:grid-cols-2 @3xl:[&>[cmdk-group-items]]:grid-cols-3",
|
|
222
223
|
children: filteredBlocks.map((block) => /* @__PURE__ */ jsxs(CommandItem, {
|
|
223
224
|
value: block._internal.id,
|
|
224
225
|
keywords: [block._internal.title, block._internal.description ?? ""],
|
|
@@ -252,14 +253,16 @@ const AddBlockDialog = ({ focusCreatedBlock = true }) => {
|
|
|
252
253
|
})]
|
|
253
254
|
})]
|
|
254
255
|
}),
|
|
255
|
-
createBlock.isPending && /* @__PURE__ */
|
|
256
|
-
|
|
257
|
-
children: "
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
256
|
+
(createBlock.isPending || error) && /* @__PURE__ */ jsxs("div", {
|
|
257
|
+
className: "border-border border-t p-4",
|
|
258
|
+
children: [createBlock.isPending && /* @__PURE__ */ jsx("p", {
|
|
259
|
+
role: "status",
|
|
260
|
+
children: "Adding block…"
|
|
261
|
+
}), error && /* @__PURE__ */ jsx("p", {
|
|
262
|
+
role: "alert",
|
|
263
|
+
className: "text-destructive",
|
|
264
|
+
children: error
|
|
265
|
+
})]
|
|
263
266
|
})
|
|
264
267
|
]
|
|
265
268
|
})
|
|
@@ -267,4 +270,4 @@ const AddBlockDialog = ({ focusCreatedBlock = true }) => {
|
|
|
267
270
|
};
|
|
268
271
|
|
|
269
272
|
//#endregion
|
|
270
|
-
export {
|
|
273
|
+
export { AddBlockSheet };
|