camox 0.45.0 → 0.47.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 +24 -9
- 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 +16 -31
- package/dist/features/canvas/useCanvasFrame.js +5 -6
- package/dist/features/preview/CamoxPreview.js +137 -120
- 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/components/PreviewToolbar.js +74 -85
- package/dist/features/preview/previewStore.js +9 -9
- package/dist/features/provider/CamoxProvider.js +8 -16
- package/dist/features/provider/CoreCamoxProvider.js +10 -12
- package/dist/features/provider/signInShortcut.js +60 -0
- package/dist/features/routes/pageRuntime.js +8 -8
- package/dist/features/runtime/RuntimeChrome.js +1 -1
- package/dist/features/runtime/pageApp.js +11 -39
- 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
- package/dist/features/provider/LocalhostPreviewProvider.js +0 -158
|
@@ -14,130 +14,116 @@ import * as Tooltip$1 from "@camox/ui/tooltip";
|
|
|
14
14
|
import { FloatingToolbar } from "@camox/ui/floating-toolbar";
|
|
15
15
|
|
|
16
16
|
//#region src/features/preview/components/PreviewToolbar.tsx
|
|
17
|
-
const PreviewToolbar = (
|
|
18
|
-
const $ = c(
|
|
19
|
-
const { onCanvasShownChange } = t0;
|
|
17
|
+
const PreviewToolbar = () => {
|
|
18
|
+
const $ = c(21);
|
|
20
19
|
const isCanvasShown = useSelector(previewStore, selectIsCanvasShown);
|
|
21
20
|
const isToolbarHidden = useSelector(previewStore, _temp);
|
|
22
21
|
const viewportMode = useSelector(previewStore, _temp2);
|
|
23
22
|
if (isToolbarHidden) return null;
|
|
24
|
-
let
|
|
25
|
-
if ($[0] !==
|
|
26
|
-
|
|
27
|
-
if (onCanvasShownChange) {
|
|
28
|
-
onCanvasShownChange(checked);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
previewStore.send({ type: checked ? "showCanvas" : "hideCanvas" });
|
|
32
|
-
};
|
|
33
|
-
$[0] = onCanvasShownChange;
|
|
34
|
-
$[1] = t1;
|
|
35
|
-
} else t1 = $[1];
|
|
36
|
-
let t2;
|
|
37
|
-
if ($[2] !== isCanvasShown || $[3] !== t1) {
|
|
38
|
-
t2 = /* @__PURE__ */ jsx(Switch, {
|
|
23
|
+
let t0;
|
|
24
|
+
if ($[0] !== isCanvasShown) {
|
|
25
|
+
t0 = /* @__PURE__ */ jsx(Switch, {
|
|
39
26
|
id: "show-canvas",
|
|
40
27
|
checked: isCanvasShown,
|
|
41
|
-
onCheckedChange:
|
|
28
|
+
onCheckedChange: _temp3
|
|
42
29
|
});
|
|
43
|
-
$[
|
|
44
|
-
$[
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
t3 = /* @__PURE__ */ jsxs(Label, {
|
|
30
|
+
$[0] = isCanvasShown;
|
|
31
|
+
$[1] = t0;
|
|
32
|
+
} else t0 = $[1];
|
|
33
|
+
let t1;
|
|
34
|
+
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
35
|
+
t1 = /* @__PURE__ */ jsxs(Label, {
|
|
50
36
|
htmlFor: "show-canvas",
|
|
51
37
|
className: "flex items-center gap-2",
|
|
52
38
|
children: ["Show canvas ", formatShortcut(TOGGLE_CANVAS_SHORTCUT)]
|
|
53
39
|
});
|
|
54
|
-
$[
|
|
55
|
-
} else
|
|
56
|
-
let
|
|
57
|
-
if ($[
|
|
58
|
-
|
|
40
|
+
$[2] = t1;
|
|
41
|
+
} else t1 = $[2];
|
|
42
|
+
let t2;
|
|
43
|
+
if ($[3] !== t0) {
|
|
44
|
+
t2 = /* @__PURE__ */ jsxs("div", {
|
|
59
45
|
className: "flex shrink-0 items-center gap-2 px-2",
|
|
60
46
|
onPointerEnter: prefetchCanvas,
|
|
61
47
|
onFocus: prefetchCanvas,
|
|
62
|
-
children: [
|
|
48
|
+
children: [t0, t1]
|
|
63
49
|
});
|
|
64
|
-
$[
|
|
65
|
-
$[
|
|
66
|
-
} else
|
|
67
|
-
const
|
|
68
|
-
let
|
|
69
|
-
if ($[
|
|
70
|
-
|
|
71
|
-
value:
|
|
50
|
+
$[3] = t0;
|
|
51
|
+
$[4] = t2;
|
|
52
|
+
} else t2 = $[4];
|
|
53
|
+
const t3 = viewportMode === "full" ? "desktop" : viewportMode;
|
|
54
|
+
let t4;
|
|
55
|
+
if ($[5] !== t3) {
|
|
56
|
+
t4 = /* @__PURE__ */ jsx(DeviceSelector, {
|
|
57
|
+
value: t3,
|
|
72
58
|
desktopLabel: "Full view",
|
|
73
|
-
onValueChange:
|
|
59
|
+
onValueChange: _temp4
|
|
74
60
|
});
|
|
75
|
-
$[
|
|
76
|
-
$[
|
|
77
|
-
} else
|
|
78
|
-
let
|
|
79
|
-
if ($[
|
|
80
|
-
|
|
61
|
+
$[5] = t3;
|
|
62
|
+
$[6] = t4;
|
|
63
|
+
} else t4 = $[6];
|
|
64
|
+
let t5;
|
|
65
|
+
if ($[7] !== isCanvasShown) {
|
|
66
|
+
t5 = /* @__PURE__ */ jsx(Button, {
|
|
81
67
|
type: "button",
|
|
82
68
|
variant: "ghost",
|
|
83
69
|
size: "icon",
|
|
84
70
|
disabled: isCanvasShown,
|
|
85
|
-
onClick:
|
|
71
|
+
onClick: _temp5,
|
|
86
72
|
"aria-label": "Hide toolbar",
|
|
87
73
|
className: "text-muted-foreground"
|
|
88
74
|
});
|
|
89
|
-
$[
|
|
75
|
+
$[7] = isCanvasShown;
|
|
76
|
+
$[8] = t5;
|
|
77
|
+
} else t5 = $[8];
|
|
78
|
+
let t6;
|
|
79
|
+
if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
|
|
80
|
+
t6 = /* @__PURE__ */ jsx(X, {});
|
|
81
|
+
$[9] = t6;
|
|
82
|
+
} else t6 = $[9];
|
|
83
|
+
let t7;
|
|
84
|
+
if ($[10] !== t5) {
|
|
85
|
+
t7 = /* @__PURE__ */ jsx(Tooltip$1.TooltipTrigger, {
|
|
86
|
+
render: t5,
|
|
87
|
+
children: t6
|
|
88
|
+
});
|
|
89
|
+
$[10] = t5;
|
|
90
90
|
$[11] = t7;
|
|
91
91
|
} else t7 = $[11];
|
|
92
92
|
let t8;
|
|
93
93
|
if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
|
|
94
|
-
t8 = /* @__PURE__ */ jsx(
|
|
94
|
+
t8 = /* @__PURE__ */ jsx(Tooltip$1.TooltipContent, { children: "Hide toolbar" });
|
|
95
95
|
$[12] = t8;
|
|
96
96
|
} else t8 = $[12];
|
|
97
97
|
let t9;
|
|
98
98
|
if ($[13] !== t7) {
|
|
99
|
-
t9 = /* @__PURE__ */ jsx(
|
|
100
|
-
|
|
101
|
-
children: t8
|
|
99
|
+
t9 = /* @__PURE__ */ jsx("div", {
|
|
100
|
+
className: "-ml-2 flex items-center gap-2",
|
|
101
|
+
children: /* @__PURE__ */ jsxs(Tooltip$1.Tooltip, { children: [t7, t8] })
|
|
102
102
|
});
|
|
103
103
|
$[13] = t7;
|
|
104
104
|
$[14] = t9;
|
|
105
105
|
} else t9 = $[14];
|
|
106
106
|
let t10;
|
|
107
|
-
if ($[15]
|
|
108
|
-
t10 = /* @__PURE__ */
|
|
109
|
-
$[15] = t10;
|
|
110
|
-
} else t10 = $[15];
|
|
111
|
-
let t11;
|
|
112
|
-
if ($[16] !== t9) {
|
|
113
|
-
t11 = /* @__PURE__ */ jsx("div", {
|
|
114
|
-
className: "-ml-2 flex items-center gap-2",
|
|
115
|
-
children: /* @__PURE__ */ jsxs(Tooltip$1.Tooltip, { children: [t9, t10] })
|
|
116
|
-
});
|
|
117
|
-
$[16] = t9;
|
|
118
|
-
$[17] = t11;
|
|
119
|
-
} else t11 = $[17];
|
|
120
|
-
let t12;
|
|
121
|
-
if ($[18] !== t11 || $[19] !== t6) {
|
|
122
|
-
t12 = /* @__PURE__ */ jsxs("div", {
|
|
107
|
+
if ($[15] !== t4 || $[16] !== t9) {
|
|
108
|
+
t10 = /* @__PURE__ */ jsxs("div", {
|
|
123
109
|
className: "flex shrink-0 items-center gap-6 self-stretch",
|
|
124
|
-
children: [
|
|
110
|
+
children: [t4, t9]
|
|
125
111
|
});
|
|
126
|
-
$[
|
|
127
|
-
$[
|
|
128
|
-
$[
|
|
129
|
-
} else
|
|
130
|
-
let
|
|
131
|
-
if ($[
|
|
132
|
-
|
|
112
|
+
$[15] = t4;
|
|
113
|
+
$[16] = t9;
|
|
114
|
+
$[17] = t10;
|
|
115
|
+
} else t10 = $[17];
|
|
116
|
+
let t11;
|
|
117
|
+
if ($[18] !== t10 || $[19] !== t2) {
|
|
118
|
+
t11 = /* @__PURE__ */ jsxs(FloatingToolbar, {
|
|
133
119
|
className: "fixed bottom-2 w-max justify-between gap-6 transition-none",
|
|
134
|
-
children: [
|
|
120
|
+
children: [t2, t10]
|
|
135
121
|
});
|
|
136
|
-
$[
|
|
137
|
-
$[
|
|
138
|
-
$[
|
|
139
|
-
} else
|
|
140
|
-
return
|
|
122
|
+
$[18] = t10;
|
|
123
|
+
$[19] = t2;
|
|
124
|
+
$[20] = t11;
|
|
125
|
+
} else t11 = $[20];
|
|
126
|
+
return t11;
|
|
141
127
|
};
|
|
142
128
|
function _temp(state) {
|
|
143
129
|
return state.context.isToolbarHidden;
|
|
@@ -145,13 +131,16 @@ function _temp(state) {
|
|
|
145
131
|
function _temp2(state_0) {
|
|
146
132
|
return state_0.context.viewportMode;
|
|
147
133
|
}
|
|
148
|
-
function _temp3(
|
|
134
|
+
function _temp3(checked) {
|
|
135
|
+
return previewStore.send({ type: checked ? "showCanvas" : "hideCanvas" });
|
|
136
|
+
}
|
|
137
|
+
function _temp4(device) {
|
|
149
138
|
return previewStore.send({
|
|
150
139
|
type: "setViewportMode",
|
|
151
140
|
mode: device === "desktop" ? "full" : device
|
|
152
141
|
});
|
|
153
142
|
}
|
|
154
|
-
function
|
|
143
|
+
function _temp5() {
|
|
155
144
|
return previewStore.send({ type: "hideToolbar" });
|
|
156
145
|
}
|
|
157
146
|
|
|
@@ -97,7 +97,7 @@ const selectIsCanvasShown = (state) => state.context.view === "canvas";
|
|
|
97
97
|
const initialPreviewContext = {
|
|
98
98
|
view: "preview",
|
|
99
99
|
isToolbarHidden: false,
|
|
100
|
-
|
|
100
|
+
addBlockSheet: null,
|
|
101
101
|
isCreatePageModalOpen: false,
|
|
102
102
|
editingPageId: null,
|
|
103
103
|
viewportMode: "full",
|
|
@@ -150,7 +150,7 @@ const previewStore = createStore({
|
|
|
150
150
|
return {
|
|
151
151
|
...context,
|
|
152
152
|
editingContext: owner ? targetContext(owner, null) : null,
|
|
153
|
-
|
|
153
|
+
addBlockSheet: null
|
|
154
154
|
};
|
|
155
155
|
},
|
|
156
156
|
activateLayout: (context, event) => {
|
|
@@ -162,7 +162,7 @@ const previewStore = createStore({
|
|
|
162
162
|
return {
|
|
163
163
|
...context,
|
|
164
164
|
editingContext: targetContext(owner, null),
|
|
165
|
-
|
|
165
|
+
addBlockSheet: null
|
|
166
166
|
};
|
|
167
167
|
},
|
|
168
168
|
selectTarget: (context, event) => ({
|
|
@@ -175,7 +175,7 @@ const previewStore = createStore({
|
|
|
175
175
|
type: "block",
|
|
176
176
|
blockId: event.blockId
|
|
177
177
|
}),
|
|
178
|
-
|
|
178
|
+
addBlockSheet: null
|
|
179
179
|
}),
|
|
180
180
|
selectItem: (context, event) => ({
|
|
181
181
|
...context,
|
|
@@ -312,13 +312,13 @@ const previewStore = createStore({
|
|
|
312
312
|
selection: null
|
|
313
313
|
} : null
|
|
314
314
|
}),
|
|
315
|
-
|
|
315
|
+
openAddBlockSheet: (context, event) => ({
|
|
316
316
|
...context,
|
|
317
|
-
|
|
317
|
+
addBlockSheet: { afterPosition: event.afterPosition }
|
|
318
318
|
}),
|
|
319
|
-
|
|
319
|
+
closeAddBlockSheet: (context) => ({
|
|
320
320
|
...context,
|
|
321
|
-
|
|
321
|
+
addBlockSheet: null
|
|
322
322
|
}),
|
|
323
323
|
focusCreatedBlock: (context, event) => ({
|
|
324
324
|
...context,
|
|
@@ -326,7 +326,7 @@ const previewStore = createStore({
|
|
|
326
326
|
type: "block",
|
|
327
327
|
blockId: event.blockId
|
|
328
328
|
}),
|
|
329
|
-
|
|
329
|
+
addBlockSheet: null
|
|
330
330
|
}),
|
|
331
331
|
openCreatePageModal: (context) => ({
|
|
332
332
|
...context,
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { useSignInRedirect } from "../../lib/auth.js";
|
|
2
2
|
import { useLocation } from "../navigation/navigation.js";
|
|
3
|
+
import { useSignInShortcut } from "./signInShortcut.js";
|
|
3
4
|
import { STUDIO_BASE_PATH } from "../studio/routes.js";
|
|
4
5
|
import { AuthGate } from "../../components/AuthGate.js";
|
|
5
6
|
import { AuthenticatedCamoxProvider } from "./AuthenticatedCamoxProvider.js";
|
|
6
|
-
import { CoreCamoxProvider
|
|
7
|
-
import { LocalhostPreviewProvider } from "./LocalhostPreviewProvider.js";
|
|
7
|
+
import { CoreCamoxProvider } from "./CoreCamoxProvider.js";
|
|
8
8
|
import { c } from "react/compiler-runtime";
|
|
9
9
|
import * as React from "react";
|
|
10
10
|
import { jsx } from "react/jsx-runtime";
|
|
11
11
|
|
|
12
12
|
//#region src/features/provider/CamoxProvider.tsx
|
|
13
13
|
function UnauthenticatedExperience(t0) {
|
|
14
|
-
const $ = c(
|
|
14
|
+
const $ = c(10);
|
|
15
15
|
const { children } = t0;
|
|
16
16
|
const { pathname } = useLocation();
|
|
17
17
|
let t1;
|
|
@@ -48,25 +48,17 @@ function UnauthenticatedExperience(t0) {
|
|
|
48
48
|
t4 = $[7];
|
|
49
49
|
}
|
|
50
50
|
React.useEffect(t3, t4);
|
|
51
|
+
useSignInShortcut(!isStudio);
|
|
51
52
|
if (isStudio) return null;
|
|
52
|
-
if (isLocalhostPreview()) {
|
|
53
|
-
let t5;
|
|
54
|
-
if ($[8] !== children) {
|
|
55
|
-
t5 = /* @__PURE__ */ jsx(LocalhostPreviewProvider, { children });
|
|
56
|
-
$[8] = children;
|
|
57
|
-
$[9] = t5;
|
|
58
|
-
} else t5 = $[9];
|
|
59
|
-
return t5;
|
|
60
|
-
}
|
|
61
53
|
let t5;
|
|
62
|
-
if ($[
|
|
54
|
+
if ($[8] !== children) {
|
|
63
55
|
t5 = /* @__PURE__ */ jsx("div", {
|
|
64
56
|
className: "bg-background min-h-screen",
|
|
65
57
|
children
|
|
66
58
|
});
|
|
67
|
-
$[
|
|
68
|
-
$[
|
|
69
|
-
} else t5 = $[
|
|
59
|
+
$[8] = children;
|
|
60
|
+
$[9] = t5;
|
|
61
|
+
} else t5 = $[9];
|
|
70
62
|
return t5;
|
|
71
63
|
}
|
|
72
64
|
function CamoxProvider(props) {
|
|
@@ -9,11 +9,6 @@ import { jsx } from "react/jsx-runtime";
|
|
|
9
9
|
import { replaceEqualDeep, useQueryClient } from "@tanstack/react-query";
|
|
10
10
|
|
|
11
11
|
//#region src/features/provider/CoreCamoxProvider.tsx
|
|
12
|
-
function isLocalhostPreview() {
|
|
13
|
-
if (typeof window === "undefined") return false;
|
|
14
|
-
const { hostname } = window.location;
|
|
15
|
-
return hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1";
|
|
16
|
-
}
|
|
17
12
|
function CoreCamoxProvider({ apiUrl, authenticationUrl, camoxApp, children, projectUuid, initialAuthenticated = false, initialProject }) {
|
|
18
13
|
const queryClient = useQueryClient();
|
|
19
14
|
const authClient = React.useMemo(() => createCamoxAuthClient(apiUrl), [apiUrl]);
|
|
@@ -42,23 +37,26 @@ function CoreCamoxProvider({ apiUrl, authenticationUrl, camoxApp, children, proj
|
|
|
42
37
|
if (!cached || replaceEqualDeep(cached, initialProject) !== cached) studioCache.set(read, initialProject);
|
|
43
38
|
seededProject.current = initialProject;
|
|
44
39
|
}
|
|
40
|
+
const { ready, error } = useProcessOtt(authClient, {
|
|
41
|
+
projectUuid,
|
|
42
|
+
apiUrl
|
|
43
|
+
}, initialAuthenticated);
|
|
44
|
+
const exchangingToken = !ready;
|
|
45
45
|
const authContext = React.useMemo(() => ({
|
|
46
46
|
authClient,
|
|
47
47
|
authenticationUrl,
|
|
48
48
|
apiUrl,
|
|
49
49
|
projectUuid,
|
|
50
|
-
initialAuthenticated
|
|
50
|
+
initialAuthenticated,
|
|
51
|
+
exchangingToken
|
|
51
52
|
}), [
|
|
52
53
|
authClient,
|
|
53
54
|
authenticationUrl,
|
|
54
55
|
apiUrl,
|
|
55
56
|
projectUuid,
|
|
56
|
-
initialAuthenticated
|
|
57
|
+
initialAuthenticated,
|
|
58
|
+
exchangingToken
|
|
57
59
|
]);
|
|
58
|
-
const { ready, error } = useProcessOtt(authClient, {
|
|
59
|
-
projectUuid,
|
|
60
|
-
apiUrl
|
|
61
|
-
}, initialAuthenticated);
|
|
62
60
|
const [isPreviewHandoff, setIsPreviewHandoff] = React.useState(false);
|
|
63
61
|
React.useEffect(() => {
|
|
64
62
|
setIsPreviewHandoff(new URL(window.location.href).searchParams.has("camox-preview"));
|
|
@@ -91,4 +89,4 @@ function createWindowDraftScope(queryClient) {
|
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
//#endregion
|
|
94
|
-
export { CoreCamoxProvider
|
|
92
|
+
export { CoreCamoxProvider };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useSignInRedirect } from "../../lib/auth.js";
|
|
2
|
+
import { TOGGLE_CANVAS_SHORTCUT } from "../preview/previewConstants.js";
|
|
3
|
+
import { c } from "react/compiler-runtime";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
//#region src/features/provider/signInShortcut.ts
|
|
7
|
+
/** Marks the URL a sign-in returns to, so the Studio opens on the Canvas there. */
|
|
8
|
+
const SHOW_CANVAS_PARAM = "camox-show-canvas";
|
|
9
|
+
function showCanvasCallbackHref() {
|
|
10
|
+
const url = new URL(window.location.href);
|
|
11
|
+
url.searchParams.set(SHOW_CANVAS_PARAM, "");
|
|
12
|
+
return url.href;
|
|
13
|
+
}
|
|
14
|
+
function isTyping() {
|
|
15
|
+
const element = document.activeElement;
|
|
16
|
+
return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLElement && element.isContentEditable;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* While signed out, the shortcut that shows the Canvas signs in instead, then shows the Canvas
|
|
20
|
+
* on the page it was pressed on. Fields keep it, since sites often submit forms with it.
|
|
21
|
+
*/
|
|
22
|
+
function useSignInShortcut(enabled) {
|
|
23
|
+
const $ = c(4);
|
|
24
|
+
const signIn = useSignInRedirect(showCanvasCallbackHref);
|
|
25
|
+
let t0;
|
|
26
|
+
let t1;
|
|
27
|
+
if ($[0] !== enabled || $[1] !== signIn) {
|
|
28
|
+
t0 = () => {
|
|
29
|
+
if (!enabled) return;
|
|
30
|
+
const handleKeyDown = (event) => {
|
|
31
|
+
if (event.key !== TOGGLE_CANVAS_SHORTCUT.key || !(event.metaKey || event.ctrlKey)) return;
|
|
32
|
+
if (event.altKey || event.shiftKey || event.defaultPrevented || isTyping()) return;
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
signIn();
|
|
35
|
+
};
|
|
36
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
37
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
38
|
+
};
|
|
39
|
+
t1 = [enabled, signIn];
|
|
40
|
+
$[0] = enabled;
|
|
41
|
+
$[1] = signIn;
|
|
42
|
+
$[2] = t0;
|
|
43
|
+
$[3] = t1;
|
|
44
|
+
} else {
|
|
45
|
+
t0 = $[2];
|
|
46
|
+
t1 = $[3];
|
|
47
|
+
}
|
|
48
|
+
React.useEffect(t0, t1);
|
|
49
|
+
}
|
|
50
|
+
/** Whether a sign-in from the shortcut led here. Removes the mark, so it shows the Canvas once. */
|
|
51
|
+
function takeShowCanvasRequest() {
|
|
52
|
+
const url = new URL(window.location.href);
|
|
53
|
+
if (!url.searchParams.has(SHOW_CANVAS_PARAM)) return false;
|
|
54
|
+
url.searchParams.delete(SHOW_CANVAS_PARAM);
|
|
55
|
+
window.history.replaceState(window.history.state, "", url);
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
export { takeShowCanvasRequest, useSignInShortcut };
|
|
@@ -174,16 +174,16 @@ async function resolveMemberProject({ apiUrl, authCookieHeader, projectUuid }) {
|
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
/**
|
|
177
|
-
* The project's favicon, which falls back to the
|
|
178
|
-
* `
|
|
177
|
+
* The project's favicon, which falls back to the default favicon when none was uploaded.
|
|
178
|
+
* Pass `withDefault: false` to get a 404 instead, to learn whether there is one.
|
|
179
179
|
*/
|
|
180
|
-
function buildFaviconUrl(apiUrl, project, {
|
|
180
|
+
function buildFaviconUrl(apiUrl, project, { withDefault = true } = {}) {
|
|
181
181
|
const url = `${apiUrl}/favicons/${project.id}?v=${project.updatedAt}`;
|
|
182
|
-
return
|
|
182
|
+
return withDefault ? `${url}&default=camox` : url;
|
|
183
183
|
}
|
|
184
|
-
/** The
|
|
185
|
-
function
|
|
186
|
-
return `${apiUrl}/favicons/
|
|
184
|
+
/** The default favicon, shown by a project without its own. */
|
|
185
|
+
function buildDefaultFaviconUrl(apiUrl) {
|
|
186
|
+
return `${apiUrl}/favicons/default`;
|
|
187
187
|
}
|
|
188
188
|
function buildCamoxPageLoaderData(apiUrl, page, origin) {
|
|
189
189
|
return {
|
|
@@ -340,4 +340,4 @@ function buildCamoxPageHead(camoxApp, loaderData, locale) {
|
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
//#endregion
|
|
343
|
-
export { buildCamoxPageHead, buildCamoxPageLoaderData,
|
|
343
|
+
export { buildCamoxPageHead, buildCamoxPageLoaderData, buildDefaultFaviconUrl, buildFaviconUrl, buildPageHead, buildPageMeta, createMarkdownResponse, createServerApiClient, createServerStudioCache, getMarkdownPath, isAuthSessionError, isNotFoundError, loadCamoxPage, loadCamoxPageForRequest, parseMarkdownPath, parseQuality, prefersMarkdown, readDraftOrLive, readScopeLocales, renderedHref, resolveMemberProject, withFrontMatter };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { previewStore, selectIsCanvasShown } from "../preview/previewStore.js";
|
|
2
2
|
import { shownRecordPage } from "../preview/pageRecord.js";
|
|
3
3
|
import { Navbar } from "../studio/components/Navbar.js";
|
|
4
|
-
import { PreviewToolbar } from "../preview/components/PreviewToolbar.js";
|
|
5
4
|
import { EditingFallbackContext } from "./editingFallback.js";
|
|
5
|
+
import { PreviewToolbar } from "../preview/components/PreviewToolbar.js";
|
|
6
6
|
import { StudioEditingFallback } from "../preview/components/StudioEditingFallback.js";
|
|
7
7
|
import { ChatSidebar } from "../studio/components/ChatSidebar.js";
|
|
8
8
|
import { FollowAgentProvider } from "../studio/FollowAgentProvider.js";
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { useAuthState, useSignInRedirect } from "../../lib/auth.js";
|
|
2
2
|
import { DraftScopeContext } from "../../lib/draft-scope.js";
|
|
3
3
|
import { DerivedPageContent } from "../page/DerivedPageContent.js";
|
|
4
|
+
import { useSignInShortcut } from "../provider/signInShortcut.js";
|
|
4
5
|
import { PreviewDocumentContext } from "./PreviewDocumentContext.js";
|
|
5
6
|
import { PreviewActivation } from "../preview/components/PreviewActivation.js";
|
|
6
7
|
import { Frame } from "../preview/components/Frame.js";
|
|
7
8
|
import { PreviewSignInPage } from "../provider/PreviewSignInPage.js";
|
|
8
|
-
import { CoreCamoxProvider
|
|
9
|
+
import { CoreCamoxProvider } from "../provider/CoreCamoxProvider.js";
|
|
9
10
|
import { CuratedPageContent } from "../page/CuratedPageContent.js";
|
|
10
11
|
import { EditingFallbackSlot } from "./editingFallback.js";
|
|
11
12
|
import { PageNavigationProvider } from "./pageNavigation.js";
|
|
@@ -96,7 +97,6 @@ function PageApp(t0) {
|
|
|
96
97
|
return t6;
|
|
97
98
|
}
|
|
98
99
|
const LazyEditablePageExperience = React.lazy(() => import("../preview/EditablePageExperience.js").then((module) => ({ default: module.EditablePageExperience })));
|
|
99
|
-
const LazyLocalhostPreviewProvider = React.lazy(() => import("../provider/LocalhostPreviewProvider.js").then((module) => ({ default: module.LocalhostPreviewProvider })));
|
|
100
100
|
/** Editing lists and adds any block, so it waits for every definition, not only the page's. */
|
|
101
101
|
function AllBlocks({ camoxApp, children }) {
|
|
102
102
|
React.use(camoxApp.loadAllBlocks());
|
|
@@ -116,7 +116,7 @@ var EditingActivationBoundary = class extends React.Component {
|
|
|
116
116
|
};
|
|
117
117
|
const subscribeToHydration = () => () => {};
|
|
118
118
|
function PageExperience(t0) {
|
|
119
|
-
const $ = c(
|
|
119
|
+
const $ = c(38);
|
|
120
120
|
const { camoxApp, input, queryClient, studioDocument } = t0;
|
|
121
121
|
const { isAuthenticated, isLoading } = useAuthState();
|
|
122
122
|
const hasHydrated = React.useSyncExternalStore(subscribeToHydration, _temp, _temp2);
|
|
@@ -145,6 +145,7 @@ function PageExperience(t0) {
|
|
|
145
145
|
t2 = $[5];
|
|
146
146
|
}
|
|
147
147
|
React.useEffect(t1, t2);
|
|
148
|
+
useSignInShortcut(hasHydrated && !studioOnly && !isAuthenticated && !isLoading);
|
|
148
149
|
let t3;
|
|
149
150
|
if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
|
|
150
151
|
t3 = /* @__PURE__ */ jsx("div", {
|
|
@@ -248,50 +249,21 @@ function PageExperience(t0) {
|
|
|
248
249
|
return t11;
|
|
249
250
|
}
|
|
250
251
|
if (studioOnly) return null;
|
|
251
|
-
if (hasHydrated && isLocalhostPreview()) {
|
|
252
|
-
let t7;
|
|
253
|
-
if ($[35] !== readOnlyPage) {
|
|
254
|
-
t7 = /* @__PURE__ */ jsx(LazyLocalhostPreviewProvider, { children: readOnlyPage });
|
|
255
|
-
$[35] = readOnlyPage;
|
|
256
|
-
$[36] = t7;
|
|
257
|
-
} else t7 = $[36];
|
|
258
|
-
let t8;
|
|
259
|
-
if ($[37] !== camoxApp || $[38] !== t7) {
|
|
260
|
-
t8 = /* @__PURE__ */ jsx(AllBlocks, {
|
|
261
|
-
camoxApp,
|
|
262
|
-
children: t7
|
|
263
|
-
});
|
|
264
|
-
$[37] = camoxApp;
|
|
265
|
-
$[38] = t7;
|
|
266
|
-
$[39] = t8;
|
|
267
|
-
} else t8 = $[39];
|
|
268
|
-
let t9;
|
|
269
|
-
if ($[40] !== readOnlyPage || $[41] !== t8) {
|
|
270
|
-
t9 = /* @__PURE__ */ jsx(React.Suspense, {
|
|
271
|
-
fallback: readOnlyPage,
|
|
272
|
-
children: t8
|
|
273
|
-
});
|
|
274
|
-
$[40] = readOnlyPage;
|
|
275
|
-
$[41] = t8;
|
|
276
|
-
$[42] = t9;
|
|
277
|
-
} else t9 = $[42];
|
|
278
|
-
return t9;
|
|
279
|
-
}
|
|
280
252
|
if (studioDocument) {
|
|
281
253
|
let t7;
|
|
282
|
-
if ($[
|
|
254
|
+
if ($[35] === Symbol.for("react.memo_cache_sentinel")) {
|
|
283
255
|
t7 = { height: "100vh" };
|
|
284
|
-
$[
|
|
285
|
-
} else t7 = $[
|
|
256
|
+
$[35] = t7;
|
|
257
|
+
} else t7 = $[35];
|
|
286
258
|
let t8;
|
|
287
|
-
if ($[
|
|
259
|
+
if ($[36] !== isolatedPage) {
|
|
288
260
|
t8 = /* @__PURE__ */ jsx("div", {
|
|
289
261
|
style: t7,
|
|
290
262
|
children: isolatedPage
|
|
291
263
|
});
|
|
292
|
-
$[
|
|
293
|
-
$[
|
|
294
|
-
} else t8 = $[
|
|
264
|
+
$[36] = isolatedPage;
|
|
265
|
+
$[37] = t8;
|
|
266
|
+
} else t8 = $[37];
|
|
295
267
|
return t8;
|
|
296
268
|
}
|
|
297
269
|
return readOnlyPage;
|
|
@@ -33,13 +33,8 @@ export interface PageRenderInput extends DraftRead {
|
|
|
33
33
|
previewHandoff?: boolean;
|
|
34
34
|
previewDocument?: string;
|
|
35
35
|
routeKind?: "studio" | "studio-content" | "studio-nested";
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
* with nothing selected, or with a block of the Block Catalog selected.
|
|
39
|
-
*/
|
|
40
|
-
canvasOnly?: {
|
|
41
|
-
blockId?: string;
|
|
42
|
-
};
|
|
36
|
+
/** Whether the location is the Canvas with nothing selected, which only the Canvas shows. */
|
|
37
|
+
canvasOnly?: boolean;
|
|
43
38
|
project?: MemberProject;
|
|
44
39
|
presentation?: "public" | "studio";
|
|
45
40
|
derived?: {
|
|
@@ -7,7 +7,7 @@ import { RUNTIME_ROUTE_PATHS, matchRuntimeOwnedRoute } from "./runtimeRoutes.js"
|
|
|
7
7
|
import { reads } from "../../lib/studio-reads.js";
|
|
8
8
|
import { asCollectionItem, recordMarkdownTemplate, recordPlainText } from "../../core/recordItem.js";
|
|
9
9
|
import { PLATFORM_SCRIPT } from "../../lib/platform.js";
|
|
10
|
-
import { STUDIO_ASSETS_PATH,
|
|
10
|
+
import { STUDIO_ASSETS_PATH, STUDIO_CANVAS_PATH, STUDIO_CONTENT_PATH, matchCollectionContentPath } from "../studio/routes.js";
|
|
11
11
|
import { STUDIO_THEME_SCRIPT } from "../studio/studioTheme.js";
|
|
12
12
|
import { discoverLayoutPages, matchDerivedLayout } from "../../core/derivedRoutes.js";
|
|
13
13
|
import { buildCamoxPageHead, buildFaviconUrl, buildPageHead, buildPageMeta, createMarkdownResponse, createServerApiClient, createServerStudioCache, isNotFoundError, loadCamoxPageForRequest, parseMarkdownPath, prefersMarkdown, readDraftOrLive, readScopeLocales, renderedHref, resolveMemberProject, withFrontMatter } from "../routes/pageRuntime.js";
|
|
@@ -76,7 +76,7 @@ function matchRuntimeRoute(pathname) {
|
|
|
76
76
|
kind: "studio",
|
|
77
77
|
pathname
|
|
78
78
|
};
|
|
79
|
-
if (
|
|
79
|
+
if (pathname === "/camox/canvas") return {
|
|
80
80
|
kind: "canvas",
|
|
81
81
|
pathname
|
|
82
82
|
};
|
|
@@ -872,22 +872,10 @@ ${renderClientEntryScript(options.studioClientEntryUrl)}
|
|
|
872
872
|
} });
|
|
873
873
|
}
|
|
874
874
|
/**
|
|
875
|
-
* The Canvas with nothing selected
|
|
876
|
-
*
|
|
877
|
-
* without a page-content block of that id redirects home.
|
|
875
|
+
* The Canvas with nothing selected renders the page app, like a Page, so
|
|
876
|
+
* selecting it keeps the Canvas mounted.
|
|
878
877
|
*/
|
|
879
878
|
async function createCanvasOnlyResponse({ options, pathname, located, request, dataOnly = false }) {
|
|
880
|
-
const { blockId } = matchCanvasOnlyPath(located.path);
|
|
881
|
-
const app = blockId ? await options.getCamoxApp?.() : void 0;
|
|
882
|
-
const block = blockId ? app?.getBlockById(blockId) : void 0;
|
|
883
|
-
if (blockId && (!block || block._internal.layoutOnly)) {
|
|
884
|
-
if (dataOnly) return Response.json({
|
|
885
|
-
kind: "canvas",
|
|
886
|
-
message: "No block of the Block Catalog on this path",
|
|
887
|
-
pathname
|
|
888
|
-
}, { status: 404 });
|
|
889
|
-
return Response.redirect(new URL(withRuntimeBasePath(localizedPath("/", located.locale), options.runtimeBasePath), request.url), 302);
|
|
890
|
-
}
|
|
891
879
|
if (!options.apiUrl || !options.authenticationUrl || !options.projectUuid || !dataOnly && !options.renderPage) return Response.json({
|
|
892
880
|
message: "Camox page renderer is not configured.",
|
|
893
881
|
kind: "canvas",
|
|
@@ -895,7 +883,7 @@ async function createCanvasOnlyResponse({ options, pathname, located, request, d
|
|
|
895
883
|
}, { status: 500 });
|
|
896
884
|
const { project, clearAuthCookie } = await resolveRequestMember(request, options);
|
|
897
885
|
const studio = project !== void 0;
|
|
898
|
-
const title =
|
|
886
|
+
const title = "Canvas";
|
|
899
887
|
const input = {
|
|
900
888
|
project,
|
|
901
889
|
presentation: studio ? "studio" : "public",
|
|
@@ -911,10 +899,9 @@ async function createCanvasOnlyResponse({ options, pathname, located, request, d
|
|
|
911
899
|
layoutIdentity: null,
|
|
912
900
|
loaderData: null,
|
|
913
901
|
dehydratedState: dehydrate(new QueryClient()),
|
|
914
|
-
canvasOnly:
|
|
902
|
+
canvasOnly: true,
|
|
915
903
|
draftId: studio ? getRequestDraftId(request, options) : void 0
|
|
916
904
|
};
|
|
917
|
-
await preparePreviewDocument(input, options, await options.getDocument?.() ?? {}, "");
|
|
918
905
|
const headers = {
|
|
919
906
|
"Cache-Control": "private, no-store",
|
|
920
907
|
Vary: "Cookie",
|