@backmatter/studio 0.0.4 → 0.0.6
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/chunks/{EmbedPublishPage-hx1xoAhI.js → EmbedPublishPage-DazYJLaD.js} +13 -13
- package/dist/chunks/{UiKitPage-BOunq6mr.js → UiKitPage-DyVyBp0I.js} +9 -9
- package/dist/chunks/{WorkspaceRoutes-CTFTWu3L.js → WorkspaceRoutes-CPvkgvxe.js} +10869 -10957
- package/dist/chunks/{dashboard-upmiawx5.js → dashboard-6aSS8oyj.js} +194 -194
- package/dist/chunks/{index-CBvevwfT.js → index-DgTNL4t3.js} +2 -2
- package/dist/chunks/{status-bar-action-DiXhfcj3.js → status-bar-action-RNBujSgk.js} +5655 -5427
- package/dist/dashboard.js +2 -2
- package/dist/index.js +18 -18
- package/dist/site-widget.js +790 -234
- package/dist/studio.css +4 -4
- package/package.json +2 -2
- package/src/WorkspaceRoutes.tsx +2 -0
- package/src/api.ts +24 -0
- package/src/chat/ChatPanel.tsx +1 -1
- package/src/chrome/icons.tsx +13 -0
- package/src/pages/SettingsLayout.tsx +7 -1
- package/src/pages/SettingsUsagePage.tsx +168 -0
- package/src/preview-frame.tsx +78 -0
- package/src/site-bar.tsx +769 -0
- package/src/site-widget.tsx +38 -163
package/src/site-widget.tsx
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
// packages/studio/src/site-widget.tsx
|
|
2
|
-
// The on-site bar:
|
|
2
|
+
// The on-site bar: Live/Preview, the current page, the branch, then Agent and Publish. The host page mounts this
|
|
3
3
|
// after the site session verifies. Calls go through the host's same-origin
|
|
4
4
|
// CMS proxy.
|
|
5
|
-
import { useEffect, useLayoutEffect, useRef, useState, type CSSProperties
|
|
5
|
+
import { useEffect, useLayoutEffect, useRef, useState, type CSSProperties } from "react";
|
|
6
6
|
import * as stylex from "@stylexjs/stylex";
|
|
7
7
|
import { ChatPanel } from "./chat/ChatPanel";
|
|
8
|
-
import { PublishIcon, SparkIcon } from "./chat/icons";
|
|
9
8
|
import { chatPointerFromGrab } from "./chat/chat-context";
|
|
10
9
|
import { POINTER_ARM_EVENT } from "./chat/Composer";
|
|
11
10
|
import { ChatProvider, ChatSessionScope, useChatUI } from "./chat/ChatProvider";
|
|
12
11
|
import { isPanelVisible } from "./chat/chat-state";
|
|
13
12
|
import { DOC_CHANGED_EVENT, EditorFocusProvider, useEditorFocus } from "./chrome/EditorFocusContext";
|
|
14
|
-
import { matchAppHotkey
|
|
13
|
+
import { matchAppHotkey } from "./chrome/hotkeys";
|
|
15
14
|
import { EmbedPublishPage } from "./pages/EmbedPublishPage";
|
|
15
|
+
import { PreviewFrame } from "./preview-frame";
|
|
16
|
+
import { DEVBAR_CLASS, SiteBar } from "./site-bar";
|
|
16
17
|
import { installSitePointer } from "./site-pointer";
|
|
17
18
|
import { lightTheme } from "./styles/themes";
|
|
18
19
|
import { configureStudio } from "./studio-config";
|
|
@@ -30,28 +31,36 @@ export type SiteWidgetProps = {
|
|
|
30
31
|
doc: SiteWidgetDoc | null;
|
|
31
32
|
branch?: string;
|
|
32
33
|
tree?: string;
|
|
34
|
+
siteMode?: "preview" | "live";
|
|
33
35
|
exiting?: boolean;
|
|
34
36
|
onExit: () => void;
|
|
37
|
+
onEnterPreview?: () => void;
|
|
35
38
|
/** The host re-renders the page after a write. */
|
|
36
39
|
onDocChanged?: () => void;
|
|
37
40
|
/** The site session was rejected. The host drops the widget. */
|
|
38
41
|
onSessionExpired?: () => void;
|
|
39
42
|
/** Same-origin CMS proxy. Default `/api/backmatter/cms`. */
|
|
40
43
|
proxyPath?: string;
|
|
44
|
+
/** Host route that turns a preview ticket into the site session. */
|
|
45
|
+
previewEntryPath?: string;
|
|
46
|
+
/** Full-viewport preview ring and top pill (see `devBar.previewFrame` in host config). */
|
|
47
|
+
previewFrame?: boolean;
|
|
41
48
|
version?: string;
|
|
42
49
|
};
|
|
43
50
|
|
|
44
|
-
const DEVBAR_CLASS = "backmatter-devbar";
|
|
45
|
-
|
|
46
51
|
export function SiteWidget({
|
|
47
52
|
doc,
|
|
48
53
|
branch,
|
|
49
54
|
tree,
|
|
55
|
+
siteMode = "preview",
|
|
50
56
|
exiting,
|
|
51
57
|
onExit,
|
|
58
|
+
onEnterPreview,
|
|
52
59
|
onDocChanged,
|
|
53
60
|
onSessionExpired,
|
|
54
61
|
proxyPath = "/api/backmatter/cms",
|
|
62
|
+
previewEntryPath,
|
|
63
|
+
previewFrame,
|
|
55
64
|
version,
|
|
56
65
|
}: SiteWidgetProps) {
|
|
57
66
|
const expiredRef = useRef(onSessionExpired);
|
|
@@ -94,50 +103,27 @@ export function SiteWidget({
|
|
|
94
103
|
}, []);
|
|
95
104
|
|
|
96
105
|
const bar = (
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<span>Publish{changeCount ? ` ${changeCount}` : ""}</span>
|
|
114
|
-
</button>
|
|
115
|
-
<button
|
|
116
|
-
type="button"
|
|
117
|
-
className={`${DEVBAR_CLASS}-btn ${DEVBAR_CLASS}-agent${chatOpen ? ` ${DEVBAR_CLASS}-on` : ""}`}
|
|
118
|
-
aria-pressed={chatOpen}
|
|
119
|
-
aria-keyshortcuts="Meta+J Control+J"
|
|
120
|
-
disabled={!doc}
|
|
121
|
-
onClick={() => {
|
|
122
|
-
setPublishOpen(false);
|
|
123
|
-
setChatOpen((open) => !open);
|
|
124
|
-
}}
|
|
125
|
-
>
|
|
126
|
-
<SparkIcon />
|
|
127
|
-
<span>Agent</span>
|
|
128
|
-
<kbd>
|
|
129
|
-
{modifierSymbol()}J
|
|
130
|
-
</kbd>
|
|
131
|
-
</button>
|
|
132
|
-
<button type="button" aria-label="Exit preview" disabled={exiting} onClick={onExit} style={barButton}>
|
|
133
|
-
Exit
|
|
134
|
-
</button>
|
|
135
|
-
</footer>
|
|
106
|
+
<SiteBar
|
|
107
|
+
label={label}
|
|
108
|
+
branch={branch}
|
|
109
|
+
tree={tree}
|
|
110
|
+
doc={doc}
|
|
111
|
+
siteMode={siteMode}
|
|
112
|
+
exiting={exiting}
|
|
113
|
+
chatOpen={chatOpen}
|
|
114
|
+
publishOpen={publishOpen}
|
|
115
|
+
changeCount={changeCount}
|
|
116
|
+
previewEntryPath={previewEntryPath}
|
|
117
|
+
onExit={onExit}
|
|
118
|
+
onEnterPreview={onEnterPreview}
|
|
119
|
+
onToggleChat={() => setChatOpen((open) => !open)}
|
|
120
|
+
onTogglePublish={() => setPublishOpen((open) => !open)}
|
|
121
|
+
/>
|
|
136
122
|
);
|
|
137
123
|
|
|
138
124
|
return (
|
|
139
125
|
<>
|
|
140
|
-
<
|
|
126
|
+
{previewFrame ? <PreviewFrame /> : null}
|
|
141
127
|
{doc ? (
|
|
142
128
|
<TooltipProvider>
|
|
143
129
|
<EditorFocusProvider>
|
|
@@ -240,7 +226,11 @@ function SitePointer({ doc }: { doc: SiteWidgetDoc }) {
|
|
|
240
226
|
},
|
|
241
227
|
onGrab: (grab) => {
|
|
242
228
|
const next = chatPointerFromGrab(docRef.current, grab);
|
|
243
|
-
if (next)
|
|
229
|
+
if (!next) return;
|
|
230
|
+
addPointer(next);
|
|
231
|
+
requestAnimationFrame(() => {
|
|
232
|
+
window.dispatchEvent(new Event("backmatter:chat-focus"));
|
|
233
|
+
});
|
|
244
234
|
},
|
|
245
235
|
onEscape: () => {
|
|
246
236
|
window.dispatchEvent(new CustomEvent(POINTER_ARM_EVENT, { detail: { on: false } }));
|
|
@@ -261,69 +251,10 @@ function SitePointer({ doc }: { doc: SiteWidgetDoc }) {
|
|
|
261
251
|
return null;
|
|
262
252
|
}
|
|
263
253
|
|
|
264
|
-
function BarText({ children }: { children: ReactNode }) {
|
|
265
|
-
return <span style={mutedStyle}>{children}</span>;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const barStyle: CSSProperties = {
|
|
269
|
-
position: "fixed",
|
|
270
|
-
right: "max(16px, env(safe-area-inset-right, 0px))",
|
|
271
|
-
bottom: 0,
|
|
272
|
-
zIndex: 2147483000,
|
|
273
|
-
isolation: "isolate",
|
|
274
|
-
display: "flex",
|
|
275
|
-
alignItems: "center",
|
|
276
|
-
gap: 2,
|
|
277
|
-
width: "max-content",
|
|
278
|
-
maxWidth: "calc(100vw - 32px)",
|
|
279
|
-
minHeight: 36,
|
|
280
|
-
padding: "0 6px 0 10px",
|
|
281
|
-
boxSizing: "border-box",
|
|
282
|
-
border: "1px solid #e4e4e7",
|
|
283
|
-
borderRadius: "12px 12px 0 0",
|
|
284
|
-
background: "#ffffff",
|
|
285
|
-
color: "#71717a",
|
|
286
|
-
boxShadow: "0 10px 28px rgba(24, 24, 27, 0.12), 0 1px 2px rgba(24, 24, 27, 0.06)",
|
|
287
|
-
font: '12px/1 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
288
|
-
WebkitFontSmoothing: "antialiased",
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
const barButton: CSSProperties = {
|
|
292
|
-
border: 0,
|
|
293
|
-
borderRadius: 8,
|
|
294
|
-
background: "transparent",
|
|
295
|
-
color: "#18181b",
|
|
296
|
-
font: "inherit",
|
|
297
|
-
cursor: "pointer",
|
|
298
|
-
padding: "0 8px",
|
|
299
|
-
minHeight: 28,
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
const docLabel: CSSProperties = {
|
|
303
|
-
fontWeight: 600,
|
|
304
|
-
color: "#18181b",
|
|
305
|
-
maxWidth: 200,
|
|
306
|
-
overflow: "hidden",
|
|
307
|
-
textOverflow: "ellipsis",
|
|
308
|
-
whiteSpace: "nowrap",
|
|
309
|
-
padding: "0 6px",
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
const mutedStyle: CSSProperties = {
|
|
313
|
-
color: "#71717a",
|
|
314
|
-
fontSize: 12,
|
|
315
|
-
margin: 0,
|
|
316
|
-
padding: "0 6px",
|
|
317
|
-
maxWidth: 140,
|
|
318
|
-
overflow: "hidden",
|
|
319
|
-
textOverflow: "ellipsis",
|
|
320
|
-
whiteSpace: "nowrap",
|
|
321
|
-
};
|
|
322
|
-
|
|
323
254
|
const publishStyle: CSSProperties = {
|
|
324
255
|
position: "fixed",
|
|
325
256
|
right: "max(16px, env(safe-area-inset-right, 0px))",
|
|
326
|
-
bottom: "calc(env(safe-area-inset-bottom, 0px)
|
|
257
|
+
bottom: "calc(48px + env(safe-area-inset-bottom, 0px))",
|
|
327
258
|
zIndex: 2147483001,
|
|
328
259
|
width: "min(320px, calc(100vw - 32px))",
|
|
329
260
|
maxHeight: "min(420px, calc(100vh - 80px))",
|
|
@@ -333,59 +264,3 @@ const publishStyle: CSSProperties = {
|
|
|
333
264
|
background: "#ffffff",
|
|
334
265
|
boxShadow: "0 16px 40px rgba(24, 24, 27, 0.14), 0 2px 8px rgba(24, 24, 27, 0.06)",
|
|
335
266
|
};
|
|
336
|
-
|
|
337
|
-
const BAR_CSS = `
|
|
338
|
-
@keyframes backmatter-devbar-in {
|
|
339
|
-
from { opacity: 0; transform: translateY(10px) scale(0.98); }
|
|
340
|
-
to { opacity: 1; transform: none; }
|
|
341
|
-
}
|
|
342
|
-
.${DEVBAR_CLASS} { animation: backmatter-devbar-in 240ms cubic-bezier(0.23, 1, 0.32, 1) both; }
|
|
343
|
-
@media (prefers-reduced-motion: reduce) {
|
|
344
|
-
.${DEVBAR_CLASS} { animation: none; }
|
|
345
|
-
}
|
|
346
|
-
.${DEVBAR_CLASS}-btn {
|
|
347
|
-
display: inline-flex;
|
|
348
|
-
align-items: center;
|
|
349
|
-
gap: 6px;
|
|
350
|
-
height: 26px;
|
|
351
|
-
margin-inline: 4px;
|
|
352
|
-
padding: 0 8px;
|
|
353
|
-
border: 1px solid #e4e4e7;
|
|
354
|
-
border-radius: 6px;
|
|
355
|
-
background: #ffffff;
|
|
356
|
-
color: #18181b;
|
|
357
|
-
font-size: 11px;
|
|
358
|
-
font-weight: 500;
|
|
359
|
-
line-height: 1;
|
|
360
|
-
cursor: pointer;
|
|
361
|
-
}
|
|
362
|
-
.${DEVBAR_CLASS}-agent kbd {
|
|
363
|
-
font-family: Geist Mono, ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
364
|
-
font-size: 11px;
|
|
365
|
-
font-weight: 400;
|
|
366
|
-
opacity: 0.7;
|
|
367
|
-
}
|
|
368
|
-
.${DEVBAR_CLASS} button.${DEVBAR_CLASS}-on,
|
|
369
|
-
.${DEVBAR_CLASS} button.${DEVBAR_CLASS}-on:hover:not(:disabled) {
|
|
370
|
-
background: #18181b;
|
|
371
|
-
border-color: #18181b;
|
|
372
|
-
color: #fafafa;
|
|
373
|
-
}
|
|
374
|
-
@media (hover: hover) {
|
|
375
|
-
.${DEVBAR_CLASS} button:hover:not(:disabled) { background: #f4f4f5; }
|
|
376
|
-
.${DEVBAR_CLASS} button.${DEVBAR_CLASS}-btn:hover:not(:disabled) {
|
|
377
|
-
background: rgba(24, 24, 27, 0.05);
|
|
378
|
-
}
|
|
379
|
-
.${DEVBAR_CLASS} button.${DEVBAR_CLASS}-on:hover:not(:disabled) {
|
|
380
|
-
background: #18181b;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
.${DEVBAR_CLASS} button:focus-visible { outline: 2px solid #18181b; outline-offset: 2px; }
|
|
384
|
-
.${DEVBAR_CLASS} button:disabled { cursor: default; opacity: 0.5; }
|
|
385
|
-
html.backmatter-pointing, html.backmatter-pointing * { cursor: crosshair !important; }
|
|
386
|
-
html.backmatter-pointing .${DEVBAR_CLASS},
|
|
387
|
-
html.backmatter-pointing .${DEVBAR_CLASS} *,
|
|
388
|
-
html.backmatter-pointing [data-backmatter-panel],
|
|
389
|
-
html.backmatter-pointing [data-backmatter-panel] * { cursor: pointer !important; }
|
|
390
|
-
html.backmatter-pointing .${DEVBAR_CLASS} button:disabled { cursor: default !important; }
|
|
391
|
-
`;
|