@backmatter/studio 0.0.10 → 0.0.11
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/{UiKitApp-BxvTwsko.js → UiKitApp-Cu0CS1NU.js} +2 -2
- package/dist/chunks/{WorkspaceRoutes-BKKEkAq7.js → WorkspaceRoutes-Dzpaj8ov.js} +15186 -15183
- package/dist/chunks/{dashboard-8rjkfEXl.js → dashboard-kWmpeuAP.js} +2 -2
- package/dist/chunks/{index-laWAz5_p.js → index-Bryt_VJQ.js} +1 -1
- package/dist/dashboard.js +2 -2
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/src/api.ts +1 -1
- package/src/chrome/WorkspaceStatusBar.tsx +7 -6
- package/src/chrome/branch-head.ts +14 -0
- package/src/pages/DocEditorPage.tsx +26 -22
- package/src/pages/preview-url.ts +15 -0
|
@@ -3,7 +3,7 @@ var Xe = (e, t, n) => t in e ? Ke(e, t, { enumerable: !0, configurable: !0, writ
|
|
|
3
3
|
var D = (e, t, n) => Xe(e, typeof t != "symbol" ? t + "" : t, n);
|
|
4
4
|
import { jsxs as k, jsx as o, Fragment as be } from "react/jsx-runtime";
|
|
5
5
|
import { useRef as Ye, useCallback as Qe, useSyncExternalStore as Ze, useState as w, useEffect as V, lazy as et, Suspense as tt } from "react";
|
|
6
|
-
import { O as nt, ag as ye, ah as rt, K as _, ai as st, p as it, aj as at, ak as Ne, al as Ce, am as Ie, an as ot, ao as lt, N as qe, ap as ct, aq as ie, aa as J, Q as ze, ar as ut, as as Fe, ab as dt, ad as re, a4 as Q, a5 as Z, P as ae, at as ft, M as z, au as ht, z as ve, av as ee, ac as pt, aw as gt, ax as mt, ay as xt, f as yt, az as vt, a0 as bt, aA as wt, aB as kt, q as St, B as Et, y as Rt, aC as _t, aD as Ot, aE as Tt, A as Pt, aF as Lt, R as At, F as jt, G as Ut, H as Nt, I as F, L as Ct, J as It } from "./WorkspaceRoutes-
|
|
6
|
+
import { O as nt, ag as ye, ah as rt, K as _, ai as st, p as it, aj as at, ak as Ne, al as Ce, am as Ie, an as ot, ao as lt, N as qe, ap as ct, aq as ie, aa as J, Q as ze, ar as ut, as as Fe, ab as dt, ad as re, a4 as Q, a5 as Z, P as ae, at as ft, M as z, au as ht, z as ve, av as ee, ac as pt, aw as gt, ax as mt, ay as xt, f as yt, az as vt, a0 as bt, aA as wt, aB as kt, q as St, B as Et, y as Rt, aC as _t, aD as Ot, aE as Tt, A as Pt, aF as Lt, R as At, F as jt, G as Ut, H as Nt, I as F, L as Ct, J as It } from "./WorkspaceRoutes-Dzpaj8ov.js";
|
|
7
7
|
const te = /* @__PURE__ */ Object.create(null), W = (e) => {
|
|
8
8
|
var t, n;
|
|
9
9
|
return ((t = globalThis.process) == null ? void 0 : t.env) || ((n = globalThis.Deno) == null ? void 0 : n.env.toObject()) || globalThis.__env__ || (e ? te : globalThis);
|
|
@@ -1701,7 +1701,7 @@ function kr(e) {
|
|
|
1701
1701
|
const t = e.replace(/\/$/, "") || "/";
|
|
1702
1702
|
return t === "/__ui" || /^\/__ui\/[^/]+$/.test(t);
|
|
1703
1703
|
}
|
|
1704
|
-
const Sr = et(() => import("./UiKitApp-
|
|
1704
|
+
const Sr = et(() => import("./UiKitApp-Cu0CS1NU.js").then((e) => ({
|
|
1705
1705
|
default: e.UiKitApp
|
|
1706
1706
|
})));
|
|
1707
1707
|
function Pr() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var Rs = Object.defineProperty;
|
|
2
2
|
var Es = (r, e, t) => e in r ? Rs(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
|
|
3
3
|
var M = (r, e, t) => Es(r, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
-
import { aG as Bt, aH as Bs, aI as a0, aJ as ct, aK as xt, aL as ea, aM as Gn, aN as Is, aO as Ls, aP as Ds, aQ as La, aR as Ps, aS as Os, aT as Le, aU as qs } from "./WorkspaceRoutes-
|
|
4
|
+
import { aG as Bt, aH as Bs, aI as a0, aJ as ct, aK as xt, aL as ea, aM as Gn, aN as Is, aO as Ls, aP as Ds, aQ as La, aR as Ps, aS as Os, aT as Le, aU as qs } from "./WorkspaceRoutes-Dzpaj8ov.js";
|
|
5
5
|
function Fs() {
|
|
6
6
|
return {
|
|
7
7
|
enter: {
|
package/dist/dashboard.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as a, i as s } from "./chunks/dashboard-
|
|
2
|
-
import { w as t, x as f } from "./chunks/WorkspaceRoutes-
|
|
1
|
+
import { A as a, i as s } from "./chunks/dashboard-kWmpeuAP.js";
|
|
2
|
+
import { w as t, x as f } from "./chunks/WorkspaceRoutes-Dzpaj8ov.js";
|
|
3
3
|
export {
|
|
4
4
|
a as DashboardApp,
|
|
5
5
|
t as configureStudio,
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as t, jsxs as d } from "react/jsx-runtime";
|
|
2
2
|
import { useLayoutEffect as re, useEffect as f, useRef as W, useState as g, useMemo as oe } from "react";
|
|
3
|
-
import { i as J, T as ae, E as se, C as ce, a as le, b as de, u as ue, D as A, c as X, d as B, e as xe, f as Y, g as G, h as me, p as z, j as C, k as N, r as fe, n as he, s as pe, l as ge, m as we, o as be, q as ye, B as ve, t as ke, S as qe, v as Ee, w as Q, x as P, y as ze, z as Ce, A as Ne, R as Se, F as Re, G as Le, H as Pe, I as S, N as I, L as Ue, J as je, K as F, M as Te } from "./chunks/WorkspaceRoutes-
|
|
4
|
-
import { O as ot } from "./chunks/WorkspaceRoutes-
|
|
3
|
+
import { i as J, T as ae, E as se, C as ce, a as le, b as de, u as ue, D as A, c as X, d as B, e as xe, f as Y, g as G, h as me, p as z, j as C, k as N, r as fe, n as he, s as pe, l as ge, m as we, o as be, q as ye, B as ve, t as ke, S as qe, v as Ee, w as Q, x as P, y as ze, z as Ce, A as Ne, R as Se, F as Re, G as Le, H as Pe, I as S, N as I, L as Ue, J as je, K as F, M as Te } from "./chunks/WorkspaceRoutes-Dzpaj8ov.js";
|
|
4
|
+
import { O as ot } from "./chunks/WorkspaceRoutes-Dzpaj8ov.js";
|
|
5
5
|
import { u as Me, S as _e } from "./chunks/define-studio-BYtYDGLX.js";
|
|
6
6
|
import { d as st } from "./chunks/define-studio-BYtYDGLX.js";
|
|
7
7
|
const R = {
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -501,7 +501,7 @@ export function notifyTreeChanged(detail?: TreeChangeDetail) {
|
|
|
501
501
|
);
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
-
/** Branch HEAD moved (teammate push, pull, commit)
|
|
504
|
+
/** Branch HEAD moved (teammate push, pull, commit). Clean docs reload their fields. The preview frame stays up. */
|
|
505
505
|
export function notifyHeadChanged() {
|
|
506
506
|
window.dispatchEvent(new Event("backmatter:head-changed"));
|
|
507
507
|
}
|
|
@@ -35,9 +35,11 @@ import { replicaStore } from "../replica/instance";
|
|
|
35
35
|
import { useReplicaSession } from "../replica/ReplicaProvider";
|
|
36
36
|
import { useReplicaState } from "../replica/useReplica";
|
|
37
37
|
import { useWorkspaceNav } from "./WorkspaceNavContext";
|
|
38
|
+
import { branchHeadMoved } from "./branch-head";
|
|
38
39
|
import { commitTriggerDisabled, statusBarAction } from "./status-bar-action";
|
|
39
40
|
|
|
40
41
|
const hover = "@media (hover: hover)";
|
|
42
|
+
/** Status bar only. The preview frame follows HEAD on its SSE stream, not on this poll. */
|
|
41
43
|
const POLL_MS = 8000;
|
|
42
44
|
|
|
43
45
|
export const STATUS_LABEL: Record<ChangeStatus, string> = {
|
|
@@ -181,7 +183,8 @@ export function WorkspaceStatusBar({ workspaceId }: { workspaceId: string }) {
|
|
|
181
183
|
const [resolvingKey, setResolvingKey] = useState<string | null>(null);
|
|
182
184
|
const [message, setMessage] = useState("");
|
|
183
185
|
const [error, setError] = useState<string | null>(null);
|
|
184
|
-
//
|
|
186
|
+
// Commit sha from the last poll. A new sha means HEAD moved. The preview
|
|
187
|
+
// iframe does not reload for that; its page follows the SSE head event.
|
|
185
188
|
const lastHead = useRef<string | null | undefined>(undefined);
|
|
186
189
|
|
|
187
190
|
async function reloadGit() {
|
|
@@ -195,11 +198,9 @@ export function WorkspaceStatusBar({ workspaceId }: { workspaceId: string }) {
|
|
|
195
198
|
} else {
|
|
196
199
|
setError(null);
|
|
197
200
|
}
|
|
198
|
-
const
|
|
199
|
-
if (lastHead.current
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
lastHead.current = headKey;
|
|
201
|
+
const nextSha = next.head?.sha ?? null;
|
|
202
|
+
if (branchHeadMoved(lastHead.current, nextSha)) notifyHeadChanged();
|
|
203
|
+
lastHead.current = nextSha;
|
|
203
204
|
} catch (err) {
|
|
204
205
|
setError(err instanceof Error ? err.message : "Git status failed");
|
|
205
206
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// packages/studio/src/chrome/branch-head.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Whether a later git poll is a new commit.
|
|
5
|
+
* The first sample only records the sha. `updatedAt` is not part of the
|
|
6
|
+
* identity: rewriting the head row must not look like HEAD moved.
|
|
7
|
+
*/
|
|
8
|
+
export function branchHeadMoved(
|
|
9
|
+
previousSha: string | null | undefined,
|
|
10
|
+
nextSha: string | null,
|
|
11
|
+
): boolean {
|
|
12
|
+
if (previousSha === undefined) return false;
|
|
13
|
+
return previousSha !== nextSha;
|
|
14
|
+
}
|
|
@@ -49,9 +49,10 @@ import {
|
|
|
49
49
|
import {
|
|
50
50
|
editorPreviewPath,
|
|
51
51
|
modelForType,
|
|
52
|
-
previewSiteUrl,
|
|
53
|
-
primarySiteUrl,
|
|
54
52
|
onSitePreviewUrl,
|
|
53
|
+
previewEnableUrl,
|
|
54
|
+
previewFrameIdentity,
|
|
55
|
+
primarySiteUrl,
|
|
55
56
|
studioIsOnSite,
|
|
56
57
|
productionDocUrl,
|
|
57
58
|
} from "./preview-url";
|
|
@@ -255,31 +256,35 @@ export function DocEditorPage() {
|
|
|
255
256
|
fieldNames.find((name) => fieldKinds[name] === "blocks") ?? "blocks";
|
|
256
257
|
const siteUrl = primarySiteUrl(workspace.siteUrls ?? []);
|
|
257
258
|
const liveUrl = productionDocUrl(siteUrl, modelForType(models, type), locale, slug);
|
|
259
|
+
const previewPath = editorPreviewPath(
|
|
260
|
+
modelForType(models, type),
|
|
261
|
+
slug,
|
|
262
|
+
locale,
|
|
263
|
+
branch,
|
|
264
|
+
tree,
|
|
265
|
+
);
|
|
266
|
+
// Strings only. A replica refresh builds new models and siteUrls arrays
|
|
267
|
+
// with the same contents; that must not mint a ticket and reload the frame.
|
|
268
|
+
const frameIdentity = previewFrameIdentity({
|
|
269
|
+
siteUrl,
|
|
270
|
+
path: showPreview ? previewPath : null,
|
|
271
|
+
branch,
|
|
272
|
+
tree,
|
|
273
|
+
});
|
|
258
274
|
|
|
259
275
|
useEffect(() => {
|
|
260
|
-
if (!
|
|
261
|
-
setPreviewUrl(null);
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
const redirect = editorPreviewPath(
|
|
265
|
-
modelForType(models, type),
|
|
266
|
-
slug,
|
|
267
|
-
locale,
|
|
268
|
-
branch,
|
|
269
|
-
tree,
|
|
270
|
-
);
|
|
271
|
-
if (!redirect || !workspaceId || !siteUrl) {
|
|
276
|
+
if (!frameIdentity || !previewPath || !workspaceId || !siteUrl) {
|
|
272
277
|
setPreviewUrl(null);
|
|
273
278
|
return;
|
|
274
279
|
}
|
|
275
280
|
if (studioIsOnSite(siteUrl, window.location.origin)) {
|
|
276
|
-
setPreviewUrl(onSitePreviewUrl(siteUrl,
|
|
281
|
+
setPreviewUrl(onSitePreviewUrl(siteUrl, previewPath));
|
|
277
282
|
return;
|
|
278
283
|
}
|
|
279
284
|
let cancelled = false;
|
|
280
|
-
void createPreviewTicket(workspaceId, { redirect, branch, tree })
|
|
285
|
+
void createPreviewTicket(workspaceId, { redirect: previewPath, branch, tree })
|
|
281
286
|
.then((res) => {
|
|
282
|
-
if (!cancelled) setPreviewUrl(
|
|
287
|
+
if (!cancelled) setPreviewUrl(previewEnableUrl(siteUrl, res.ticket));
|
|
283
288
|
})
|
|
284
289
|
.catch(() => {
|
|
285
290
|
if (!cancelled) setPreviewUrl(null);
|
|
@@ -287,7 +292,7 @@ export function DocEditorPage() {
|
|
|
287
292
|
return () => {
|
|
288
293
|
cancelled = true;
|
|
289
294
|
};
|
|
290
|
-
}, [
|
|
295
|
+
}, [frameIdentity, previewPath, workspaceId, siteUrl, branch, tree]);
|
|
291
296
|
|
|
292
297
|
useEffect(() => {
|
|
293
298
|
setPreviewLoading(true);
|
|
@@ -539,13 +544,12 @@ export function DocEditorPage() {
|
|
|
539
544
|
setDocStatus(detail.status);
|
|
540
545
|
setSource(detail.status === "clean" ? "head" : "tree");
|
|
541
546
|
}
|
|
542
|
-
// Branch HEAD moved (teammate push / pull / commit). A clean doc reloads
|
|
543
|
-
//
|
|
544
|
-
//
|
|
547
|
+
// Branch HEAD moved (teammate push / pull / commit). A clean doc reloads its
|
|
548
|
+
// fields. The preview frame stays mounted: the page follows the same move
|
|
549
|
+
// on its SSE stream and refreshes in place.
|
|
545
550
|
function onHeadChanged() {
|
|
546
551
|
if (docStatusRef.current === "clean") {
|
|
547
552
|
onChanged();
|
|
548
|
-
remountPreview();
|
|
549
553
|
return;
|
|
550
554
|
}
|
|
551
555
|
void fetchDoc(workspaceId, locale, type, slug)
|
package/src/pages/preview-url.ts
CHANGED
|
@@ -32,6 +32,21 @@ export function editorPreviewPath(
|
|
|
32
32
|
return `${path}?${params.toString()}`;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Identity of the preview iframe. Equal results must keep the frame mounted.
|
|
37
|
+
* A replacement models array or siteUrls array is not a new target; the page
|
|
38
|
+
* inside the frame follows saves and HEAD on its SSE stream.
|
|
39
|
+
*/
|
|
40
|
+
export function previewFrameIdentity(input: {
|
|
41
|
+
siteUrl: string | null;
|
|
42
|
+
path: string | null;
|
|
43
|
+
branch: string | null;
|
|
44
|
+
tree: string | null;
|
|
45
|
+
}): string | null {
|
|
46
|
+
if (!input.siteUrl || !input.path || !input.branch?.trim() || !input.tree?.trim()) return null;
|
|
47
|
+
return `${input.siteUrl}\0${input.branch}\0${input.tree}\0${input.path}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
35
50
|
/**
|
|
36
51
|
* A Studio mounted on the site it previews already carries the site session
|
|
37
52
|
* cookie, so the preview frame loads the page directly — no ticket.
|