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.
Files changed (45) hide show
  1. package/dist/core/hooks/useArtifactHost.js +2 -2
  2. package/dist/features/canvas/CamoxCanvas.js +438 -771
  3. package/dist/features/canvas/CanvasPageFrame.js +1 -3
  4. package/dist/features/canvas/CanvasPreviewPageSlot.js +26 -6
  5. package/dist/features/canvas/canvasCamera.js +24 -9
  6. package/dist/features/canvas/canvasFrameDocument.js +4 -19
  7. package/dist/features/canvas/canvasItems.js +12 -102
  8. package/dist/features/canvas/canvasStore.js +3 -92
  9. package/dist/features/canvas/sidebar/CanvasNavigator.js +81 -183
  10. package/dist/features/canvas/sidebar/CanvasSidebar.js +22 -28
  11. package/dist/features/canvas/sidebar/CuratedPageInspector.js +2 -2
  12. package/dist/features/canvas/useCanvasCamera.js +16 -31
  13. package/dist/features/canvas/useCanvasFrame.js +5 -6
  14. package/dist/features/preview/CamoxPreview.js +137 -120
  15. package/dist/features/preview/components/{AddBlockDialog.js → AddBlockSheet.js} +35 -32
  16. package/dist/features/preview/components/BlockActionsPopover.js +6 -6
  17. package/dist/features/preview/components/BlockThumbnail.js +31 -33
  18. package/dist/features/preview/components/Overlays.js +1 -1
  19. package/dist/features/preview/components/PageTree.js +1 -1
  20. package/dist/features/preview/components/PreviewPanel.js +1 -1
  21. package/dist/features/preview/components/PreviewToolbar.js +74 -85
  22. package/dist/features/preview/previewStore.js +9 -9
  23. package/dist/features/provider/CamoxProvider.js +8 -16
  24. package/dist/features/provider/CoreCamoxProvider.js +10 -12
  25. package/dist/features/provider/signInShortcut.js +60 -0
  26. package/dist/features/routes/pageRuntime.js +8 -8
  27. package/dist/features/runtime/RuntimeChrome.js +1 -1
  28. package/dist/features/runtime/pageApp.js +11 -39
  29. package/dist/features/runtime/runtime.d.ts +2 -7
  30. package/dist/features/runtime/runtime.js +6 -19
  31. package/dist/features/studio/FollowAgentProvider.js +11 -22
  32. package/dist/features/studio/components/FaviconDialog.js +3 -3
  33. package/dist/features/studio/followAgent.js +5 -14
  34. package/dist/features/studio/routes.js +1 -23
  35. package/dist/lib/auth.js +36 -24
  36. package/dist/lib/studio-reads.js +0 -20
  37. package/dist/package.js +1 -1
  38. package/dist/studio.css +1 -1
  39. package/package.json +4 -4
  40. package/skills/camox-expand/SKILL.md +5 -4
  41. package/dist/features/canvas/CanvasBlockFrame.js +0 -353
  42. package/dist/features/canvas/CanvasBlockHeader.js +0 -55
  43. package/dist/features/canvas/CanvasShelfMarker.js +0 -255
  44. package/dist/features/canvas/sidebar/CatalogBlockInspector.js +0 -189
  45. 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 = (t0) => {
18
- const $ = c(24);
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 t1;
25
- if ($[0] !== onCanvasShownChange) {
26
- t1 = (checked) => {
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: t1
28
+ onCheckedChange: _temp3
42
29
  });
43
- $[2] = isCanvasShown;
44
- $[3] = t1;
45
- $[4] = t2;
46
- } else t2 = $[4];
47
- let t3;
48
- if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
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
- $[5] = t3;
55
- } else t3 = $[5];
56
- let t4;
57
- if ($[6] !== t2) {
58
- t4 = /* @__PURE__ */ jsxs("div", {
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: [t2, t3]
48
+ children: [t0, t1]
63
49
  });
64
- $[6] = t2;
65
- $[7] = t4;
66
- } else t4 = $[7];
67
- const t5 = viewportMode === "full" ? "desktop" : viewportMode;
68
- let t6;
69
- if ($[8] !== t5) {
70
- t6 = /* @__PURE__ */ jsx(DeviceSelector, {
71
- value: t5,
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: _temp3
59
+ onValueChange: _temp4
74
60
  });
75
- $[8] = t5;
76
- $[9] = t6;
77
- } else t6 = $[9];
78
- let t7;
79
- if ($[10] !== isCanvasShown) {
80
- t7 = /* @__PURE__ */ jsx(Button, {
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: _temp4,
71
+ onClick: _temp5,
86
72
  "aria-label": "Hide toolbar",
87
73
  className: "text-muted-foreground"
88
74
  });
89
- $[10] = isCanvasShown;
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(X, {});
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(Tooltip$1.TooltipTrigger, {
100
- render: t7,
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] === Symbol.for("react.memo_cache_sentinel")) {
108
- t10 = /* @__PURE__ */ jsx(Tooltip$1.TooltipContent, { children: "Hide toolbar" });
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: [t6, t11]
110
+ children: [t4, t9]
125
111
  });
126
- $[18] = t11;
127
- $[19] = t6;
128
- $[20] = t12;
129
- } else t12 = $[20];
130
- let t13;
131
- if ($[21] !== t12 || $[22] !== t4) {
132
- t13 = /* @__PURE__ */ jsxs(FloatingToolbar, {
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: [t4, t12]
120
+ children: [t2, t10]
135
121
  });
136
- $[21] = t12;
137
- $[22] = t4;
138
- $[23] = t13;
139
- } else t13 = $[23];
140
- return t13;
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(device) {
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 _temp4() {
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
- addBlockDialog: null,
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
- addBlockDialog: null
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
- addBlockDialog: null
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
- addBlockDialog: null
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
- openAddBlockDialog: (context, event) => ({
315
+ openAddBlockSheet: (context, event) => ({
316
316
  ...context,
317
- addBlockDialog: { afterPosition: event.afterPosition }
317
+ addBlockSheet: { afterPosition: event.afterPosition }
318
318
  }),
319
- closeAddBlockDialog: (context) => ({
319
+ closeAddBlockSheet: (context) => ({
320
320
  ...context,
321
- addBlockDialog: null
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
- addBlockDialog: null
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, isLocalhostPreview } from "./CoreCamoxProvider.js";
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(12);
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 ($[10] !== children) {
54
+ if ($[8] !== children) {
63
55
  t5 = /* @__PURE__ */ jsx("div", {
64
56
  className: "bg-background min-h-screen",
65
57
  children
66
58
  });
67
- $[10] = children;
68
- $[11] = t5;
69
- } else t5 = $[11];
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, isLocalhostPreview };
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 Camox mark when none was uploaded. Pass
178
- * `placeholder: false` to get a 404 instead, to learn whether there is one.
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, { placeholder = true } = {}) {
180
+ function buildFaviconUrl(apiUrl, project, { withDefault = true } = {}) {
181
181
  const url = `${apiUrl}/favicons/${project.id}?v=${project.updatedAt}`;
182
- return placeholder ? `${url}&placeholder=camox` : url;
182
+ return withDefault ? `${url}&default=camox` : url;
183
183
  }
184
- /** The Camox mark a project without a favicon shows. */
185
- function buildFaviconPlaceholderUrl(apiUrl) {
186
- return `${apiUrl}/favicons/placeholder`;
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, buildFaviconPlaceholderUrl, buildFaviconUrl, buildPageHead, buildPageMeta, createMarkdownResponse, createServerApiClient, createServerStudioCache, getMarkdownPath, isAuthSessionError, isNotFoundError, loadCamoxPage, loadCamoxPageForRequest, parseMarkdownPath, parseQuality, prefersMarkdown, readDraftOrLive, readScopeLocales, renderedHref, resolveMemberProject, withFrontMatter };
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, isLocalhostPreview } from "../provider/CoreCamoxProvider.js";
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(46);
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 ($[43] === Symbol.for("react.memo_cache_sentinel")) {
254
+ if ($[35] === Symbol.for("react.memo_cache_sentinel")) {
283
255
  t7 = { height: "100vh" };
284
- $[43] = t7;
285
- } else t7 = $[43];
256
+ $[35] = t7;
257
+ } else t7 = $[35];
286
258
  let t8;
287
- if ($[44] !== isolatedPage) {
259
+ if ($[36] !== isolatedPage) {
288
260
  t8 = /* @__PURE__ */ jsx("div", {
289
261
  style: t7,
290
262
  children: isolatedPage
291
263
  });
292
- $[44] = isolatedPage;
293
- $[45] = t8;
294
- } else t8 = $[45];
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
- * A location only the Canvas shows, instead of a Page: the Canvas
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, STUDIO_CONTENT_PATH, matchCanvasOnlyPath, matchCollectionContentPath } from "../studio/routes.js";
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 (matchCanvasOnlyPath(pathname)) return {
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, or a block of the Block Catalog, renders the
876
- * page app, like a Page, so selecting it keeps the Canvas mounted. A block path
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 = block?._internal.title ?? "Canvas";
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: blockId ? { blockId } : {},
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",