@satanwagen/reviewkit 0.1.3 → 0.1.5

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/lazy.cjs CHANGED
@@ -1044,6 +1044,8 @@ input, textarea, select {
1044
1044
  .rk-sync-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--rk-fg-faint); }
1045
1045
  .rk-sync-online .rk-sync-dot { background: var(--rk-success); }
1046
1046
  .rk-sync-connecting .rk-sync-dot { background: var(--rk-warn); }
1047
+ .rk-sync-reason-token-short .rk-sync-dot, .rk-sync-reason-bad-token .rk-sync-dot { background: var(--rk-danger); }
1048
+ .rk-sync[title] { cursor: help; }
1047
1049
  /* Automatic Emblema push hint (same quiet language) */
1048
1050
  .rk-epush-ok .rk-sync-dot { background: var(--rk-success); }
1049
1051
  .rk-epush-sending .rk-sync-dot { background: var(--rk-warn); }
@@ -2644,7 +2646,8 @@ function reducer(state, action) {
2644
2646
  panelOpen: false,
2645
2647
  confirm: null,
2646
2648
  cheatsheetOpen: false,
2647
- emblemaConnectOpen: false
2649
+ emblemaConnectOpen: false,
2650
+ terminalConnectOpen: false
2648
2651
  } : { ...state, hidden: false };
2649
2652
  case "SELECT":
2650
2653
  return { ...state, selection: action.selection };
@@ -2754,12 +2757,16 @@ function reducer(state, action) {
2754
2757
  return { ...state, cheatsheetOpen: action.open };
2755
2758
  case "SET_EMBLEMA_CONNECT":
2756
2759
  return { ...state, emblemaConnectOpen: action.open };
2760
+ case "SET_TERMINAL_CONNECT":
2761
+ return { ...state, terminalConnectOpen: action.open };
2757
2762
  case "SET_COACH":
2758
2763
  return { ...state, coachOpen: action.open };
2759
2764
  case "SET_CORNER":
2760
2765
  return { ...state, badgeCorner: action.corner };
2761
- case "SYNC_STATUS":
2762
- return state.syncStatus === action.status ? state : { ...state, syncStatus: action.status };
2766
+ case "SYNC_STATUS": {
2767
+ const reason = action.reason === void 0 ? action.status === "online" ? null : state.syncReason : action.reason;
2768
+ return state.syncStatus === action.status && state.syncReason === reason ? state : { ...state, syncStatus: action.status, syncReason: reason };
2769
+ }
2763
2770
  case "EMBLEMA_PUSH_STATUS":
2764
2771
  return state.emblemaPush === action.status ? state : { ...state, emblemaPush: action.status };
2765
2772
  /*
@@ -2887,9 +2894,11 @@ function initialState() {
2887
2894
  confirm: null,
2888
2895
  cheatsheetOpen: false,
2889
2896
  emblemaConnectOpen: false,
2897
+ terminalConnectOpen: false,
2890
2898
  coachOpen: false,
2891
2899
  undoStack: [],
2892
2900
  syncStatus: "disabled",
2901
+ syncReason: null,
2893
2902
  emblemaPush: "idle",
2894
2903
  peers: [],
2895
2904
  quick: null,
@@ -2901,7 +2910,7 @@ function StoreProvider({ config, children }) {
2901
2910
  const configValue = (0, import_react.useMemo)(
2902
2911
  () => config,
2903
2912
  // eslint-disable-next-line react-hooks/exhaustive-deps -- config object identity is per-render; depend on its fields
2904
- [config.enabled, config.token, config.devAutoOn, config.syncToken, config.syncUrl, config.defaultAuthor, config.fxAssetsUrl, config.position, config.storageKey, config.onSessionChange, config.emblema]
2913
+ [config.enabled, config.token, config.devAutoOn, config.sync, config.syncToken, config.syncUrl, config.defaultAuthor, config.fxAssetsUrl, config.position, config.storageKey, config.onSessionChange, config.emblema]
2905
2914
  );
2906
2915
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConfigContext.Provider, { value: configValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StateContext.Provider, { value: state, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DispatchContext.Provider, { value: dispatch, children }) }) });
2907
2916
  }
@@ -4837,9 +4846,13 @@ function createRkSync(options) {
4837
4846
  pongTimer = null;
4838
4847
  }
4839
4848
  break;
4840
- case "error":
4849
+ case "error": {
4841
4850
  log("server error:", msg.code, msg.message);
4851
+ const code = typeof msg.code === "string" ? msg.code : "error";
4852
+ const message = typeof msg.message === "string" ? msg.message : "";
4853
+ safely(() => handlers.onError?.(code, message));
4842
4854
  break;
4855
+ }
4843
4856
  case "presence:join": {
4844
4857
  const peer = msg.peer;
4845
4858
  if (peer && typeof peer.id === "string") safely(() => handlers.onPeerJoin?.(peer));
@@ -5061,6 +5074,20 @@ var init_identity = __esm({
5061
5074
  });
5062
5075
 
5063
5076
  // src/client/sync.ts
5077
+ function normalizeRoute(route) {
5078
+ let r = String(route ?? "/");
5079
+ if (!r.startsWith("/")) r = "/" + r;
5080
+ return r.length > 1 ? r.replace(/\/+$/, "") : r;
5081
+ }
5082
+ function resolveSyncUrl(config) {
5083
+ return typeof config.syncUrl === "string" && config.syncUrl !== "" ? config.syncUrl : DEFAULT_SYNC_URL;
5084
+ }
5085
+ function resolveSyncToken(config) {
5086
+ if (config.sync === false) return null;
5087
+ const explicit = typeof config.syncToken === "string" && config.syncToken !== "" ? config.syncToken : null;
5088
+ const fallback = typeof config.token === "string" && config.token !== "" ? config.token : null;
5089
+ return explicit ?? fallback;
5090
+ }
5064
5091
  function toPeerState(peer) {
5065
5092
  return {
5066
5093
  id: peer.id,
@@ -5086,20 +5113,43 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
5086
5113
  const stateRef = (0, import_react4.useRef)(state);
5087
5114
  stateRef.current = state;
5088
5115
  const myIdRef = (0, import_react4.useRef)("");
5089
- const enabled = typeof config.syncToken === "string" && config.syncToken !== "" && typeof config.syncUrl === "string" && config.syncUrl !== "";
5116
+ const syncToken = resolveSyncToken(config);
5117
+ const syncUrl = resolveSyncUrl(config);
5118
+ const enabled = syncToken !== null;
5090
5119
  const author = state.session?.author ?? "";
5091
5120
  const hasSession = state.session !== null;
5092
5121
  (0, import_react4.useEffect)(() => {
5093
5122
  if (!enabled || !hasSession) return;
5123
+ const dispatchGuard = rawDispatch;
5124
+ if (syncToken.length < MIN_SYNC_TOKEN_LENGTH) {
5125
+ dispatchGuard({ type: "SYNC_STATUS", status: "offline", reason: "token-short" });
5126
+ if (!warnedShortToken) {
5127
+ warnedShortToken = true;
5128
+ console.warn(
5129
+ `[review-kit] live sync is off: the token has ${syncToken.length} characters, the sync server needs at least ${MIN_SYNC_TOKEN_LENGTH}. Use a longer \`token\` (or \`syncToken\`) \u2014 it is the secret of your private rooms.`
5130
+ );
5131
+ }
5132
+ return () => dispatchGuard({ type: "SYNC_STATUS", status: "disabled", reason: null });
5133
+ }
5094
5134
  const id = reviewerId();
5095
5135
  myIdRef.current = id;
5096
5136
  const dispatch = rawDispatch;
5097
5137
  const sync = createRkSync({
5098
- token: config.syncToken,
5099
- url: config.syncUrl,
5138
+ token: syncToken,
5139
+ url: syncUrl,
5100
5140
  user: { id, name: author || "Reviewer", color: colorForReviewer(id) },
5101
5141
  handlers: {
5102
- onStatus: (status) => dispatch({ type: "SYNC_STATUS", status }),
5142
+ onStatus: (status) => dispatch({
5143
+ type: "SYNC_STATUS",
5144
+ status,
5145
+ // Offline with no server verdict = the socket never got through
5146
+ // (server down, CSP connect-src, network); a verdict keeps its reason.
5147
+ ...status === "offline" ? { reason: stateRef.current.syncReason ?? "unreachable" } : {}
5148
+ }),
5149
+ onError: (code) => {
5150
+ if (code === "bad-token") dispatch({ type: "SYNC_STATUS", status: "offline", reason: "bad-token" });
5151
+ else if (code === "room-full") dispatch({ type: "SYNC_STATUS", status: "offline", reason: "room-full" });
5152
+ },
5103
5153
  onSnapshot: (items, peers, deletedIds = []) => {
5104
5154
  const safeItems = items.map(sanitizeRemoteItem).filter((item) => item !== null);
5105
5155
  dispatch({ type: "SYNC_SNAPSHOT", items: safeItems });
@@ -5107,8 +5157,11 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
5107
5157
  for (const id2 of deletedIds) dispatch({ type: "REMOTE_DELETE", id: id2 });
5108
5158
  dispatch({ type: "PEERS_SET", peers: peers.filter((peer) => peer.id !== id).map(toPeerState) });
5109
5159
  const serverIds = new Set(items.map((item) => item.id));
5160
+ const here = normalizeRoute(window.location.pathname);
5110
5161
  for (const item of stateRef.current.session?.items ?? []) {
5111
- if (!serverIds.has(item.id) && !deleted.has(item.id)) sync.addItem(item);
5162
+ if (serverIds.has(item.id) || deleted.has(item.id)) continue;
5163
+ if (normalizeRoute(item.route) !== here) continue;
5164
+ sync.addItem(item);
5112
5165
  }
5113
5166
  },
5114
5167
  onPeerJoin: (peer) => dispatch({
@@ -5156,10 +5209,10 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
5156
5209
  if (activeSyncRef === sync) activeSyncRef = null;
5157
5210
  setEffectBroadcaster2(null);
5158
5211
  sync.stop();
5159
- dispatch({ type: "SYNC_STATUS", status: "disabled" });
5212
+ dispatch({ type: "SYNC_STATUS", status: "disabled", reason: null });
5160
5213
  dispatch({ type: "PEERS_SET", peers: [] });
5161
5214
  };
5162
- }, [enabled, hasSession, config.syncToken, config.syncUrl, author, rawDispatch]);
5215
+ }, [enabled, hasSession, syncToken, syncUrl, author, rawDispatch]);
5163
5216
  const wrapped = (0, import_react4.useMemo)(() => {
5164
5217
  return (action) => {
5165
5218
  const prev = stateRef.current;
@@ -5222,7 +5275,7 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
5222
5275
  }, [enabled, editorOpen]);
5223
5276
  return enabled ? wrapped : rawDispatch;
5224
5277
  }
5225
- var import_react4, activeSyncRef, MIRRORED_EXCLUDED;
5278
+ var import_react4, DEFAULT_SYNC_URL, MIN_SYNC_TOKEN_LENGTH, warnedShortToken, activeSyncRef, MIRRORED_EXCLUDED;
5226
5279
  var init_sync = __esm({
5227
5280
  "src/client/sync.ts"() {
5228
5281
  "use strict";
@@ -5234,6 +5287,9 @@ var init_sync = __esm({
5234
5287
  init_schema();
5235
5288
  init_store();
5236
5289
  init_identity();
5290
+ DEFAULT_SYNC_URL = "wss://2-59-219-26.sslip.io/rk-sync";
5291
+ MIN_SYNC_TOKEN_LENGTH = 8;
5292
+ warnedShortToken = false;
5237
5293
  activeSyncRef = null;
5238
5294
  MIRRORED_EXCLUDED = /* @__PURE__ */ new Set(["SYNC_SNAPSHOT", "REMOTE_ADD", "REMOTE_PATCH", "REMOTE_STATUS", "REMOTE_DELETE", "INIT_SESSION"]);
5239
5295
  }
@@ -5716,10 +5772,10 @@ function EmblemaConnect() {
5716
5772
  state === null && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "rk-modal-text", children: [
5717
5773
  "The local sync agent isn't running. In the project repo run:",
5718
5774
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("code", { className: "rk-connect-cmd", children: [
5719
- "npx @satanwagen/reviewkit-cli init --origin ",
5775
+ "npx -p @satanwagen/reviewkit-cli reviewkit-emblema init --origin ",
5720
5776
  window.location.origin
5721
5777
  ] }),
5722
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "rk-connect-cmd", children: "npx @satanwagen/reviewkit-cli serve" }),
5778
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "rk-connect-cmd", children: "npx -p @satanwagen/reviewkit-cli reviewkit-emblema serve" }),
5723
5779
  "then reopen this dialog."
5724
5780
  ] }),
5725
5781
  state !== null && state !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
@@ -5817,12 +5873,247 @@ var init_EmblemaConnect = __esm({
5817
5873
  }
5818
5874
  });
5819
5875
 
5876
+ // src/integrations/terminal.ts
5877
+ async function fetchJson2(url, init, timeoutMs) {
5878
+ const abort = new AbortController();
5879
+ const timer = window.setTimeout(() => abort.abort(), timeoutMs);
5880
+ try {
5881
+ return await fetch(url, { ...init, signal: abort.signal });
5882
+ } finally {
5883
+ window.clearTimeout(timer);
5884
+ }
5885
+ }
5886
+ async function probeTerminal() {
5887
+ for (const port of TERMINAL_PAIR_PORTS) {
5888
+ try {
5889
+ const res = await fetchJson2(`http://127.0.0.1:${port}/pair`, { method: "GET" }, 900);
5890
+ if (!res.ok) continue;
5891
+ const body = await res.json();
5892
+ if (typeof body === "object" && body !== null && body.app === "reviewkit-cli") {
5893
+ const b = body;
5894
+ return {
5895
+ port,
5896
+ cwd: typeof b.cwd === "string" ? b.cwd : void 0,
5897
+ projects: Array.isArray(b.projects) ? b.projects.filter((p) => typeof p === "string") : []
5898
+ };
5899
+ }
5900
+ } catch {
5901
+ }
5902
+ }
5903
+ return null;
5904
+ }
5905
+ async function pairTerminal(port, key) {
5906
+ try {
5907
+ const res = await fetchJson2(
5908
+ `http://127.0.0.1:${port}/pair`,
5909
+ { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ key }) },
5910
+ 5e3
5911
+ );
5912
+ const body = await res.json().catch(() => null);
5913
+ if (res.ok && body?.ok) return { ok: true, name: body.name ?? "", repo: body.repo ?? null };
5914
+ return { ok: false, error: body?.error ?? `HTTP ${res.status}` };
5915
+ } catch {
5916
+ return { ok: false, error: "the terminal stopped answering" };
5917
+ }
5918
+ }
5919
+ var TERMINAL_PAIR_PORTS;
5920
+ var init_terminal = __esm({
5921
+ "src/integrations/terminal.ts"() {
5922
+ "use strict";
5923
+ TERMINAL_PAIR_PORTS = [48780, 48781, 48782, 48783];
5924
+ }
5925
+ });
5926
+
5927
+ // src/client/terminalKey.ts
5928
+ function base64url(text) {
5929
+ const bytes = new TextEncoder().encode(text);
5930
+ let binary = "";
5931
+ for (const byte of bytes) binary += String.fromCharCode(byte);
5932
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
5933
+ }
5934
+ function encodeTerminalKey(fields) {
5935
+ const payload = { v: TERMINAL_KEY_VERSION, ...fields };
5936
+ return TERMINAL_KEY_PREFIX + base64url(JSON.stringify(payload));
5937
+ }
5938
+ function currentTerminalKey(syncUrl, syncToken) {
5939
+ const origin = window.location.origin;
5940
+ let route = "/";
5941
+ try {
5942
+ route = window.location.pathname || "/";
5943
+ } catch {
5944
+ }
5945
+ return encodeTerminalKey({ name: window.location.hostname, origin, syncUrl, syncToken, route });
5946
+ }
5947
+ var TERMINAL_KEY_PREFIX, TERMINAL_KEY_VERSION;
5948
+ var init_terminalKey = __esm({
5949
+ "src/client/terminalKey.ts"() {
5950
+ "use strict";
5951
+ TERMINAL_KEY_PREFIX = "rkc_";
5952
+ TERMINAL_KEY_VERSION = 1;
5953
+ }
5954
+ });
5955
+
5956
+ // src/client/components/TerminalConnect.tsx
5957
+ function shortKey2(key) {
5958
+ return `${key.slice(0, 8)}\u2026${key.slice(-6)}`;
5959
+ }
5960
+ function shortPath(path) {
5961
+ if (!path) return "";
5962
+ const parts = path.split("/").filter(Boolean);
5963
+ return parts.length > 2 ? `\u2026/${parts.slice(-2).join("/")}` : path;
5964
+ }
5965
+ function TerminalConnect() {
5966
+ const { terminalConnectOpen } = useStore();
5967
+ const config = useConfig();
5968
+ const dispatch = useDispatch();
5969
+ const [phase, setPhase] = (0, import_react7.useState)("probing");
5970
+ const [probe, setProbe] = (0, import_react7.useState)(null);
5971
+ const [paired, setPaired] = (0, import_react7.useState)(null);
5972
+ const [showManual, setShowManual] = (0, import_react7.useState)(false);
5973
+ const syncToken = resolveSyncToken(config);
5974
+ const key = terminalConnectOpen && syncToken ? currentTerminalKey(resolveSyncUrl(config), syncToken) : null;
5975
+ (0, import_react7.useEffect)(() => {
5976
+ if (!terminalConnectOpen) return;
5977
+ let cancelled = false;
5978
+ setPhase("probing");
5979
+ setProbe(null);
5980
+ setPaired(null);
5981
+ setShowManual(false);
5982
+ const look = () => void probeTerminal().then((found) => {
5983
+ if (cancelled) return;
5984
+ setProbe(found);
5985
+ setPhase((current) => current === "pairing" || current === "paired" ? current : found ? "found" : "missing");
5986
+ });
5987
+ look();
5988
+ const timer = window.setInterval(look, 2e3);
5989
+ return () => {
5990
+ cancelled = true;
5991
+ window.clearInterval(timer);
5992
+ };
5993
+ }, [terminalConnectOpen]);
5994
+ if (!terminalConnectOpen) return null;
5995
+ const close = () => dispatch({ type: "SET_TERMINAL_CONNECT", open: false });
5996
+ const copy = async (value, what) => {
5997
+ try {
5998
+ await navigator.clipboard.writeText(value);
5999
+ toast(dispatch, `${what} copied`, "success");
6000
+ } catch {
6001
+ toast(dispatch, "Copy failed \u2014 select the text manually", "error");
6002
+ }
6003
+ };
6004
+ const connect = () => {
6005
+ if (!probe || !key) return;
6006
+ setPhase("pairing");
6007
+ void pairTerminal(probe.port, key).then((result) => {
6008
+ if (result.ok) {
6009
+ setPaired({ name: result.name, repo: result.repo });
6010
+ setPhase("paired");
6011
+ toast(dispatch, `Terminal paired as \u201C${result.name}\u201D`, "success");
6012
+ } else {
6013
+ setPhase("found");
6014
+ toast(dispatch, `Pairing failed: ${result.error}`, "error");
6015
+ }
6016
+ });
6017
+ };
6018
+ const connectCmd = key ? `npx -y @satanwagen/reviewkit-cli connect ${key}` : "";
6019
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6020
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "rk-backdrop", onClick: close }),
6021
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "rk-modal", role: "dialog", "aria-modal": "true", "aria-label": "Connect terminal or agent", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-body", children: [
6022
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
6023
+ "Connect terminal / agent",
6024
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { flex: 1 } }),
6025
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "rk-icon-btn", "aria-label": "Close", onClick: close, autoFocus: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(IconClose, { size: 13 }) })
6026
+ ] }),
6027
+ !key && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
6028
+ "Live sync is off on this page (",
6029
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "sync=false" }),
6030
+ " or no token), so there is no shared room a terminal could read."
6031
+ ] }),
6032
+ key && phase === "paired" && paired && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
6033
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-emblema-dot", "data-state": "live" }),
6034
+ " Paired as ",
6035
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: paired.name }),
6036
+ paired.repo ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6037
+ " in ",
6038
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: shortPath(paired.repo) })
6039
+ ] }) : null,
6040
+ ". The terminal shows this page's comments live, and Claude Code / Cursor can read and resolve them through the ",
6041
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "reviewkit" }),
6042
+ " MCP tools."
6043
+ ] }),
6044
+ key && phase !== "paired" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6045
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
6046
+ phase === "probing" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6047
+ "Looking for a ",
6048
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "reviewkit" }),
6049
+ " terminal on this machine\u2026"
6050
+ ] }),
6051
+ phase === "missing" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6052
+ "No terminal is listening yet. In the site's repo run",
6053
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: "rk-connect-cmd", children: "npx -y @satanwagen/reviewkit-cli setup" }),
6054
+ "and this dialog will pick it up by itself."
6055
+ ] }),
6056
+ (phase === "found" || phase === "pairing") && probe && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6057
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-emblema-dot", "data-state": "live" }),
6058
+ " Terminal found",
6059
+ probe.cwd ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6060
+ " in ",
6061
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: shortPath(probe.cwd) })
6062
+ ] }) : null,
6063
+ ".",
6064
+ probe.projects.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6065
+ " Already paired: ",
6066
+ probe.projects.join(", "),
6067
+ "."
6068
+ ] }) : null
6069
+ ] })
6070
+ ] }),
6071
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-connect-actions", children: [
6072
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6073
+ "button",
6074
+ {
6075
+ type: "button",
6076
+ className: "rk-btn rk-btn-primary",
6077
+ disabled: phase !== "found",
6078
+ onClick: connect,
6079
+ title: "Send this site's connection to the terminal \u2014 nothing to copy",
6080
+ children: phase === "pairing" ? "Connecting\u2026" : "Connect this terminal"
6081
+ }
6082
+ ),
6083
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => setShowManual((v) => !v), children: showManual ? "Hide manual option" : "Another machine\u2026" })
6084
+ ] }),
6085
+ showManual && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6086
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "rk-modal-text", style: { marginTop: 10 }, children: "On a machine without a listening terminal, run this once (the key carries the sync server and its token \u2014 treat it like a review link):" }),
6087
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("code", { className: "rk-connect-cmd", title: connectCmd, children: [
6088
+ "npx -y @satanwagen/reviewkit-cli connect ",
6089
+ shortKey2(key)
6090
+ ] }),
6091
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "rk-connect-actions", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void copy(connectCmd, "Command"), children: "Copy command" }) })
6092
+ ] })
6093
+ ] })
6094
+ ] }) })
6095
+ ] });
6096
+ }
6097
+ var import_react7, import_jsx_runtime6;
6098
+ var init_TerminalConnect = __esm({
6099
+ "src/client/components/TerminalConnect.tsx"() {
6100
+ "use strict";
6101
+ import_react7 = require("react");
6102
+ init_terminal();
6103
+ init_store();
6104
+ init_terminalKey();
6105
+ init_sync();
6106
+ init_icons();
6107
+ import_jsx_runtime6 = require("react/jsx-runtime");
6108
+ }
6109
+ });
6110
+
5820
6111
  // src/client/components/CoachMark.tsx
5821
6112
  function CoachMark() {
5822
6113
  const { coachOpen, session } = useStore();
5823
6114
  const dispatch = useDispatch();
5824
6115
  const config = useConfig();
5825
- const [name, setName] = (0, import_react7.useState)(session?.author ?? config.defaultAuthor ?? "");
6116
+ const [name, setName] = (0, import_react8.useState)(session?.author ?? config.defaultAuthor ?? "");
5826
6117
  if (!coachOpen) return null;
5827
6118
  const done = (startPicking) => {
5828
6119
  if (name.trim() !== "") dispatch({ type: "SET_AUTHOR", author: name.trim() });
@@ -5833,39 +6124,39 @@ function CoachMark() {
5833
6124
  }
5834
6125
  if (startPicking) dispatch({ type: "SET_MODE", mode: "pick" });
5835
6126
  };
5836
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-coach", role: "dialog", "aria-label": "Welcome to review mode", children: [
5837
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "rk-coach-accent" }),
5838
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-coach-body", children: [
5839
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
5840
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(IconTarget, { size: 16 }),
6127
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach", role: "dialog", "aria-label": "Welcome to review mode", children: [
6128
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rk-coach-accent" }),
6129
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach-body", children: [
6130
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
6131
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconTarget, { size: 16 }),
5841
6132
  " Review mode"
5842
6133
  ] }),
5843
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "rk-modal-text", children: "Click anything on the page to suggest a change \u2014 rewrite the copy, swap an image, or leave a note. The live site stays untouched; everything you add is collected for the team." }),
5844
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-coach-keys", "aria-label": "Key shortcuts", children: [
5845
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
5846
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-kbd", children: "T" }),
6134
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rk-modal-text", children: "Click anything on the page to suggest a change \u2014 rewrite the copy, swap an image, or leave a note. The live site stays untouched; everything you add is collected for the team." }),
6135
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach-keys", "aria-label": "Key shortcuts", children: [
6136
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
6137
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "T" }),
5847
6138
  " rewrite"
5848
6139
  ] }),
5849
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
5850
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-kbd", children: "C" }),
6140
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
6141
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "C" }),
5851
6142
  " comment"
5852
6143
  ] }),
5853
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
5854
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-kbd", children: "I" }),
6144
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
6145
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "I" }),
5855
6146
  " image"
5856
6147
  ] }),
5857
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
5858
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-kbd", children: "V" }),
6148
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
6149
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "V" }),
5859
6150
  " select"
5860
6151
  ] }),
5861
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
5862
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-kbd", children: "?" }),
6152
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
6153
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "?" }),
5863
6154
  " all shortcuts"
5864
6155
  ] })
5865
6156
  ] }),
5866
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
5867
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: "rk-label", htmlFor: "rk-author", children: "Your name" }),
5868
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6157
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
6158
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "rk-label", htmlFor: "rk-author", children: "Your name" }),
6159
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5869
6160
  "input",
5870
6161
  {
5871
6162
  id: "rk-author",
@@ -5879,21 +6170,21 @@ function CoachMark() {
5879
6170
  }
5880
6171
  )
5881
6172
  ] }),
5882
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 4 }, children: [
5883
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => done(false), children: "Not now" }),
5884
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: () => done(true), children: "Start reviewing" })
6173
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 4 }, children: [
6174
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => done(false), children: "Not now" }),
6175
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: () => done(true), children: "Start reviewing" })
5885
6176
  ] })
5886
6177
  ] })
5887
6178
  ] });
5888
6179
  }
5889
- var import_react7, import_jsx_runtime6, COACH_KEY;
6180
+ var import_react8, import_jsx_runtime7, COACH_KEY;
5890
6181
  var init_CoachMark = __esm({
5891
6182
  "src/client/components/CoachMark.tsx"() {
5892
6183
  "use strict";
5893
- import_react7 = require("react");
6184
+ import_react8 = require("react");
5894
6185
  init_store();
5895
6186
  init_icons();
5896
- import_jsx_runtime6 = require("react/jsx-runtime");
6187
+ import_jsx_runtime7 = require("react/jsx-runtime");
5897
6188
  COACH_KEY = "review-kit:coach-dismissed";
5898
6189
  }
5899
6190
  });
@@ -5902,22 +6193,22 @@ var init_CoachMark = __esm({
5902
6193
  function ConfirmHost() {
5903
6194
  const { confirm } = useStore();
5904
6195
  const dispatch = useDispatch();
5905
- const cancelRef = (0, import_react8.useRef)(null);
5906
- (0, import_react8.useEffect)(() => {
6196
+ const cancelRef = (0, import_react9.useRef)(null);
6197
+ (0, import_react9.useEffect)(() => {
5907
6198
  if (confirm) cancelRef.current?.focus();
5908
6199
  }, [confirm]);
5909
6200
  if (!confirm) return null;
5910
6201
  const close = () => dispatch({ type: "SET_CONFIRM", confirm: null });
5911
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
5912
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rk-backdrop", onClick: close }),
5913
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-modal", role: "alertdialog", "aria-modal": "true", "aria-label": confirm.title, children: [
5914
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-modal-body", children: [
5915
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rk-modal-title", children: confirm.title }),
5916
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rk-modal-text", children: confirm.message })
6202
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
6203
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-backdrop", onClick: close }),
6204
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal", role: "alertdialog", "aria-modal": "true", "aria-label": confirm.title, children: [
6205
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal-body", children: [
6206
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-modal-title", children: confirm.title }),
6207
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-modal-text", children: confirm.message })
5917
6208
  ] }),
5918
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-modal-actions", children: [
5919
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { ref: cancelRef, type: "button", className: "rk-btn rk-btn-ghost", onClick: close, children: "Cancel" }),
5920
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
6209
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal-actions", children: [
6210
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { ref: cancelRef, type: "button", className: "rk-btn rk-btn-ghost", onClick: close, children: "Cancel" }),
6211
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5921
6212
  "button",
5922
6213
  {
5923
6214
  type: "button",
@@ -5934,13 +6225,13 @@ function ConfirmHost() {
5934
6225
  ] })
5935
6226
  ] });
5936
6227
  }
5937
- var import_react8, import_jsx_runtime7;
6228
+ var import_react9, import_jsx_runtime8;
5938
6229
  var init_Confirm = __esm({
5939
6230
  "src/client/components/Confirm.tsx"() {
5940
6231
  "use strict";
5941
- import_react8 = require("react");
6232
+ import_react9 = require("react");
5942
6233
  init_store();
5943
- import_jsx_runtime7 = require("react/jsx-runtime");
6234
+ import_jsx_runtime8 = require("react/jsx-runtime");
5944
6235
  }
5945
6236
  });
5946
6237
 
@@ -5993,9 +6284,9 @@ var init_position = __esm({
5993
6284
 
5994
6285
  // src/client/useAnchored.ts
5995
6286
  function useAnchored(anchorEl, side = "bottom", offset = 8) {
5996
- const ref = (0, import_react9.useRef)(null);
5997
- const [pos, setPos] = (0, import_react9.useState)(null);
5998
- (0, import_react9.useLayoutEffect)(() => {
6287
+ const ref = (0, import_react10.useRef)(null);
6288
+ const [pos, setPos] = (0, import_react10.useState)(null);
6289
+ (0, import_react10.useLayoutEffect)(() => {
5999
6290
  if (!anchorEl) {
6000
6291
  setPos(null);
6001
6292
  return;
@@ -6024,11 +6315,11 @@ function anchoredStyle(pos) {
6024
6315
  if (!pos) return { visibility: "hidden", transform: "translate3d(-9999px, -9999px, 0)" };
6025
6316
  return { transform: `translate3d(${pos.x}px, ${pos.y}px, 0)`, top: 0, left: 0 };
6026
6317
  }
6027
- var import_react9;
6318
+ var import_react10;
6028
6319
  var init_useAnchored = __esm({
6029
6320
  "src/client/useAnchored.ts"() {
6030
6321
  "use strict";
6031
- import_react9 = require("react");
6322
+ import_react10 = require("react");
6032
6323
  init_position();
6033
6324
  }
6034
6325
  });
@@ -6088,15 +6379,15 @@ function urlFromDataTransfer(dt) {
6088
6379
  function ImageEditor({ editor }) {
6089
6380
  const dispatch = useDispatch();
6090
6381
  const { route, session } = useStore();
6091
- const [replacement, setReplacement] = (0, import_react10.useState)(null);
6092
- const [urlValue, setUrlValue] = (0, import_react10.useState)("");
6093
- const [loading2, setLoading] = (0, import_react10.useState)(false);
6094
- const [description, setDescription] = (0, import_react10.useState)("");
6095
- const [priority, setPriority] = (0, import_react10.useState)("nice");
6096
- const [over, setOver] = (0, import_react10.useState)(false);
6097
- const fileInput = (0, import_react10.useRef)(null);
6098
- const abortRef = (0, import_react10.useRef)(null);
6099
- const debounceRef = (0, import_react10.useRef)(null);
6382
+ const [replacement, setReplacement] = (0, import_react11.useState)(null);
6383
+ const [urlValue, setUrlValue] = (0, import_react11.useState)("");
6384
+ const [loading2, setLoading] = (0, import_react11.useState)(false);
6385
+ const [description, setDescription] = (0, import_react11.useState)("");
6386
+ const [priority, setPriority] = (0, import_react11.useState)("nice");
6387
+ const [over, setOver] = (0, import_react11.useState)(false);
6388
+ const fileInput = (0, import_react11.useRef)(null);
6389
+ const abortRef = (0, import_react11.useRef)(null);
6390
+ const debounceRef = (0, import_react11.useRef)(null);
6100
6391
  const { ref, pos } = useAnchored(editor.element, "bottom", 12);
6101
6392
  const image = findImage(editor.element);
6102
6393
  const beforeSrc = image?.currentSrc || image?.src || "";
@@ -6160,7 +6451,7 @@ function ImageEditor({ editor }) {
6160
6451
  }
6161
6452
  }
6162
6453
  };
6163
- (0, import_react10.useEffect)(() => {
6454
+ (0, import_react11.useEffect)(() => {
6164
6455
  if (debounceRef.current !== null) window.clearTimeout(debounceRef.current);
6165
6456
  if (urlValue.trim() === "" || replacement !== null) return;
6166
6457
  debounceRef.current = window.setTimeout(() => {
@@ -6170,8 +6461,8 @@ function ImageEditor({ editor }) {
6170
6461
  if (debounceRef.current !== null) window.clearTimeout(debounceRef.current);
6171
6462
  };
6172
6463
  }, [urlValue, replacement]);
6173
- (0, import_react10.useEffect)(() => () => abortRef.current?.abort(), []);
6174
- (0, import_react10.useEffect)(() => {
6464
+ (0, import_react11.useEffect)(() => () => abortRef.current?.abort(), []);
6465
+ (0, import_react11.useEffect)(() => {
6175
6466
  const onPaste = (event) => {
6176
6467
  const data = event.clipboardData;
6177
6468
  if (!data) return;
@@ -6249,23 +6540,23 @@ function ImageEditor({ editor }) {
6249
6540
  toast(dispatch, "Image proposal saved", "success");
6250
6541
  };
6251
6542
  const previewSrc = replacement?.kind === "data" ? replacement.dataUrl : replacement?.url;
6252
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Replace image", children: [
6253
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-card-head", children: [
6254
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconImage, { size: 14 }),
6543
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Replace image", children: [
6544
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-head", children: [
6545
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconImage, { size: 14 }),
6255
6546
  "Replace image"
6256
6547
  ] }),
6257
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-card-body", children: [
6258
- replacement && previewSrc ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-thumbs", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-thumb-pair", title: "Hover to compare with the current image", children: [
6259
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("figure", { className: "rk-thumb", children: [
6260
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("img", { src: beforeSrc, alt: "Current" }),
6261
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("figcaption", { children: "Before" })
6548
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-body", children: [
6549
+ replacement && previewSrc ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "rk-thumbs", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-thumb-pair", title: "Hover to compare with the current image", children: [
6550
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { className: "rk-thumb", children: [
6551
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: beforeSrc, alt: "Current" }),
6552
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { children: "Before" })
6262
6553
  ] }),
6263
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("figure", { className: "rk-thumb", children: [
6264
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("img", { src: previewSrc, alt: "Proposed replacement" }),
6265
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("figcaption", { children: replacement.kind === "url" ? "After \xB7 linked" : "After" })
6554
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { className: "rk-thumb", children: [
6555
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: previewSrc, alt: "Proposed replacement" }),
6556
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { children: replacement.kind === "url" ? "After \xB7 linked" : "After" })
6266
6557
  ] })
6267
- ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
6268
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
6558
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
6559
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
6269
6560
  "button",
6270
6561
  {
6271
6562
  type: "button",
@@ -6278,18 +6569,18 @@ function ImageEditor({ editor }) {
6278
6569
  onDragLeave: () => setOver(false),
6279
6570
  onDrop,
6280
6571
  children: [
6281
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconUpload, { size: 18 }),
6282
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
6572
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconUpload, { size: 18 }),
6573
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
6283
6574
  "Drop an image \u2014 from your disk or another tab \u2014",
6284
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("br", {}),
6575
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("br", {}),
6285
6576
  "or click to browse (max 2 MB)"
6286
6577
  ] })
6287
6578
  ]
6288
6579
  }
6289
6580
  ),
6290
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-url", children: [
6291
- loading2 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "rk-spinner", "aria-label": "Loading image" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconLink, { size: 13 }),
6292
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
6581
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-url", children: [
6582
+ loading2 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-spinner", "aria-label": "Loading image" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconLink, { size: 13 }),
6583
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6293
6584
  "input",
6294
6585
  {
6295
6586
  className: "rk-input",
@@ -6304,9 +6595,9 @@ function ImageEditor({ editor }) {
6304
6595
  )
6305
6596
  ] })
6306
6597
  ] }),
6307
- replacement && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: clearReplacement, children: "Remove replacement" }),
6308
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { ref: fileInput, type: "file", accept: "image/*", hidden: true, onChange: onPick }),
6309
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
6598
+ replacement && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: clearReplacement, children: "Remove replacement" }),
6599
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { ref: fileInput, type: "file", accept: "image/*", hidden: true, onChange: onPick }),
6600
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6310
6601
  "textarea",
6311
6602
  {
6312
6603
  className: "rk-textarea",
@@ -6316,35 +6607,35 @@ function ImageEditor({ editor }) {
6316
6607
  rows: 2
6317
6608
  }
6318
6609
  ),
6319
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
6320
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
6321
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
6610
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
6611
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
6612
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
6322
6613
  ] })
6323
6614
  ] }),
6324
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-card-foot", children: [
6325
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "rk-hint", children: [
6326
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "rk-kbd", children: "esc" }),
6615
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-foot", children: [
6616
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "rk-hint", children: [
6617
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-kbd", children: "esc" }),
6327
6618
  " cancel"
6328
6619
  ] }),
6329
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-actions", children: [
6330
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
6331
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
6620
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-actions", children: [
6621
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
6622
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
6332
6623
  ] })
6333
6624
  ] })
6334
6625
  ] });
6335
6626
  }
6336
- var import_react10, import_jsx_runtime8, MAX_BYTES, FETCH_TIMEOUT_MS, PROBE_TIMEOUT_MS;
6627
+ var import_react11, import_jsx_runtime9, MAX_BYTES, FETCH_TIMEOUT_MS, PROBE_TIMEOUT_MS;
6337
6628
  var init_ImageEditor = __esm({
6338
6629
  "src/client/components/ImageEditor.tsx"() {
6339
6630
  "use strict";
6340
- import_react10 = require("react");
6631
+ import_react11 = require("react");
6341
6632
  init_store();
6342
6633
  init_id();
6343
6634
  init_identity();
6344
6635
  init_target();
6345
6636
  init_useAnchored();
6346
6637
  init_icons();
6347
- import_jsx_runtime8 = require("react/jsx-runtime");
6638
+ import_jsx_runtime9 = require("react/jsx-runtime");
6348
6639
  MAX_BYTES = 2 * 1024 * 1024;
6349
6640
  FETCH_TIMEOUT_MS = 12e3;
6350
6641
  PROBE_TIMEOUT_MS = 8e3;
@@ -6355,19 +6646,19 @@ var init_ImageEditor = __esm({
6355
6646
  function InlineEditor({ editor }) {
6356
6647
  const dispatch = useDispatch();
6357
6648
  const { route, session } = useStore();
6358
- const [after, setAfter] = (0, import_react11.useState)(() => editor.element.innerText);
6359
- const [priority, setPriority] = (0, import_react11.useState)("nice");
6360
- const [note, setNote] = (0, import_react11.useState)("");
6361
- const original = (0, import_react11.useRef)(null);
6362
- const baseline = (0, import_react11.useRef)(null);
6363
- const [sizeDelta, setSizeDelta] = (0, import_react11.useState)(0);
6364
- const [widthDelta, setWidthDelta] = (0, import_react11.useState)(0);
6365
- const [clipped, setClipped] = (0, import_react11.useState)(false);
6366
- const ringRef = (0, import_react11.useRef)(null);
6367
- const afterRef = (0, import_react11.useRef)(null);
6649
+ const [after, setAfter] = (0, import_react12.useState)(() => editor.element.innerText);
6650
+ const [priority, setPriority] = (0, import_react12.useState)("nice");
6651
+ const [note, setNote] = (0, import_react12.useState)("");
6652
+ const original = (0, import_react12.useRef)(null);
6653
+ const baseline = (0, import_react12.useRef)(null);
6654
+ const [sizeDelta, setSizeDelta] = (0, import_react12.useState)(0);
6655
+ const [widthDelta, setWidthDelta] = (0, import_react12.useState)(0);
6656
+ const [clipped, setClipped] = (0, import_react12.useState)(false);
6657
+ const ringRef = (0, import_react12.useRef)(null);
6658
+ const afterRef = (0, import_react12.useRef)(null);
6368
6659
  const { ref, pos } = useAnchored(editor.element, "bottom", 12);
6369
6660
  const element = editor.element;
6370
- (0, import_react11.useEffect)(() => {
6661
+ (0, import_react12.useEffect)(() => {
6371
6662
  const el = element;
6372
6663
  original.current = { html: el.innerHTML, text: el.innerText, styleAttr: el.getAttribute("style") };
6373
6664
  const rect = el.getBoundingClientRect();
@@ -6397,8 +6688,8 @@ function InlineEditor({ editor }) {
6397
6688
  }
6398
6689
  };
6399
6690
  }, [element]);
6400
- const focusedOnce = (0, import_react11.useRef)(false);
6401
- (0, import_react11.useEffect)(() => {
6691
+ const focusedOnce = (0, import_react12.useRef)(false);
6692
+ (0, import_react12.useEffect)(() => {
6402
6693
  const field = afterRef.current;
6403
6694
  if (pos === null || focusedOnce.current || !field) return;
6404
6695
  focusedOnce.current = true;
@@ -6406,7 +6697,7 @@ function InlineEditor({ editor }) {
6406
6697
  const end = field.value.length;
6407
6698
  field.setSelectionRange(end, end);
6408
6699
  }, [pos]);
6409
- (0, import_react11.useEffect)(() => {
6700
+ (0, import_react12.useEffect)(() => {
6410
6701
  const field = afterRef.current;
6411
6702
  if (!field) return;
6412
6703
  field.style.height = "auto";
@@ -6416,7 +6707,7 @@ function InlineEditor({ editor }) {
6416
6707
  setAfter(value);
6417
6708
  if (element.innerText !== value) setElementText(element, value);
6418
6709
  };
6419
- (0, import_react11.useEffect)(() => {
6710
+ (0, import_react12.useEffect)(() => {
6420
6711
  let raf = 0;
6421
6712
  let lastDelta = 0;
6422
6713
  let lastWidth = 0;
@@ -6486,7 +6777,7 @@ function InlineEditor({ editor }) {
6486
6777
  cancel();
6487
6778
  }
6488
6779
  };
6489
- (0, import_react11.useEffect)(() => {
6780
+ (0, import_react12.useEffect)(() => {
6490
6781
  const el = element;
6491
6782
  const onKeyDown = (event) => {
6492
6783
  if (event.key === "Enter" && !event.shiftKey) {
@@ -6504,19 +6795,19 @@ function InlineEditor({ editor }) {
6504
6795
  });
6505
6796
  const before = original.current?.text ?? "";
6506
6797
  const delta = after.length - before.length;
6507
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
6508
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { ref: ringRef, className: "rk-edit-ring" }),
6509
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Rewrite text", children: [
6510
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-head", children: [
6511
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconText, { size: 14 }),
6798
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
6799
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: ringRef, className: "rk-edit-ring" }),
6800
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Rewrite text", children: [
6801
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-head", children: [
6802
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconText, { size: 14 }),
6512
6803
  "Rewrite text",
6513
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-spacer" }),
6514
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "rk-delta", "aria-live": "polite", children: [
6804
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-spacer" }),
6805
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-delta", "aria-live": "polite", children: [
6515
6806
  before.length,
6516
6807
  " \u2192 ",
6517
6808
  after.length,
6518
6809
  " ",
6519
- delta !== 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: delta > 0 ? "rk-plus" : "rk-minus", children: [
6810
+ delta !== 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: delta > 0 ? "rk-plus" : "rk-minus", children: [
6520
6811
  "(",
6521
6812
  delta > 0 ? "+" : "",
6522
6813
  delta,
@@ -6524,15 +6815,15 @@ function InlineEditor({ editor }) {
6524
6815
  ] })
6525
6816
  ] })
6526
6817
  ] }),
6527
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-body", children: [
6528
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-diff", "aria-label": "Before and after", children: [
6529
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
6530
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
6531
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-diff-text", children: before })
6818
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-body", children: [
6819
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff", "aria-label": "Before and after", children: [
6820
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
6821
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
6822
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-text", children: before })
6532
6823
  ] }),
6533
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
6534
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-diff-tag", children: "After" }),
6535
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6824
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
6825
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-tag", children: "After" }),
6826
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6536
6827
  "textarea",
6537
6828
  {
6538
6829
  ref: afterRef,
@@ -6546,11 +6837,11 @@ function InlineEditor({ editor }) {
6546
6837
  )
6547
6838
  ] })
6548
6839
  ] }),
6549
- (Math.abs(sizeDelta) > 2 || Math.abs(widthDelta) > 4 || clipped) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-size-note", role: "status", children: [
6840
+ (Math.abs(sizeDelta) > 2 || Math.abs(widthDelta) > 4 || clipped) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-size-note", role: "status", children: [
6550
6841
  Math.abs(sizeDelta) > 2 && (() => {
6551
6842
  const lines = baseline.current ? Math.round(Math.abs(sizeDelta) / baseline.current.lineHeight) : 0;
6552
6843
  const lineNote = lines >= 1 ? ` (~${lines} line${lines === 1 ? "" : "s"})` : "";
6553
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
6844
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
6554
6845
  "Block ",
6555
6846
  sizeDelta > 0 ? "grew" : "shrank",
6556
6847
  " by ",
@@ -6560,16 +6851,16 @@ function InlineEditor({ editor }) {
6560
6851
  " \u2014 as it would with this text live."
6561
6852
  ] });
6562
6853
  })(),
6563
- Math.abs(sizeDelta) <= 2 && Math.abs(widthDelta) > 4 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
6854
+ Math.abs(sizeDelta) <= 2 && Math.abs(widthDelta) > 4 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
6564
6855
  "Block got ",
6565
6856
  widthDelta > 0 ? "wider" : "narrower",
6566
6857
  " by ",
6567
6858
  Math.abs(widthDelta),
6568
6859
  " px \u2014 as it would with this text live."
6569
6860
  ] }),
6570
- clipped && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-clip-note", children: "Text exceeds the visible crop here and will be cut off." })
6861
+ clipped && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-clip-note", children: "Text exceeds the visible crop here and will be cut off." })
6571
6862
  ] }),
6572
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6863
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6573
6864
  "input",
6574
6865
  {
6575
6866
  className: "rk-input",
@@ -6578,41 +6869,41 @@ function InlineEditor({ editor }) {
6578
6869
  onChange: (event) => setNote(event.target.value)
6579
6870
  }
6580
6871
  ),
6581
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
6582
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
6583
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
6872
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
6873
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
6874
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
6584
6875
  ] })
6585
6876
  ] }),
6586
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-foot", children: [
6587
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "rk-hint", children: [
6588
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
6877
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-foot", children: [
6878
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-hint", children: [
6879
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
6589
6880
  " save \xB7 ",
6590
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-kbd", children: "\u21E7\u21B5" }),
6881
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u21E7\u21B5" }),
6591
6882
  " newline \xB7",
6592
6883
  " ",
6593
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-kbd", children: "esc" }),
6884
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "esc" }),
6594
6885
  " cancel"
6595
6886
  ] }),
6596
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-actions", children: [
6597
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: cancel, children: "Cancel" }),
6598
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: commit, children: "Save" })
6887
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-actions", children: [
6888
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: cancel, children: "Cancel" }),
6889
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: commit, children: "Save" })
6599
6890
  ] })
6600
6891
  ] })
6601
6892
  ] })
6602
6893
  ] });
6603
6894
  }
6604
- var import_react11, import_jsx_runtime9;
6895
+ var import_react12, import_jsx_runtime10;
6605
6896
  var init_InlineEditor = __esm({
6606
6897
  "src/client/components/InlineEditor.tsx"() {
6607
6898
  "use strict";
6608
- import_react11 = require("react");
6899
+ import_react12 = require("react");
6609
6900
  init_store();
6610
6901
  init_id();
6611
6902
  init_identity();
6612
6903
  init_preview();
6613
6904
  init_useAnchored();
6614
6905
  init_icons();
6615
- import_jsx_runtime9 = require("react/jsx-runtime");
6906
+ import_jsx_runtime10 = require("react/jsx-runtime");
6616
6907
  }
6617
6908
  });
6618
6909
 
@@ -6620,14 +6911,14 @@ var init_InlineEditor = __esm({
6620
6911
  function NoteComposer({ editor }) {
6621
6912
  const dispatch = useDispatch();
6622
6913
  const { route, session } = useStore();
6623
- const [text, setText] = (0, import_react12.useState)("");
6624
- const [direction, setDirection] = (0, import_react12.useState)(void 0);
6625
- const [priority, setPriority] = (0, import_react12.useState)("nice");
6626
- const textareaRef = (0, import_react12.useRef)(null);
6914
+ const [text, setText] = (0, import_react13.useState)("");
6915
+ const [direction, setDirection] = (0, import_react13.useState)(void 0);
6916
+ const [priority, setPriority] = (0, import_react13.useState)("nice");
6917
+ const textareaRef = (0, import_react13.useRef)(null);
6627
6918
  const { ref, pos } = useAnchored(editor.element, "bottom", 12);
6628
6919
  const { kind } = editor;
6629
- const focusedOnce = (0, import_react12.useRef)(false);
6630
- (0, import_react12.useEffect)(() => {
6920
+ const focusedOnce = (0, import_react13.useRef)(false);
6921
+ (0, import_react13.useEffect)(() => {
6631
6922
  const field = textareaRef.current;
6632
6923
  if (pos === null || focusedOnce.current || !field) return;
6633
6924
  focusedOnce.current = true;
@@ -6686,13 +6977,13 @@ function NoteComposer({ editor }) {
6686
6977
  save();
6687
6978
  }
6688
6979
  };
6689
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": TITLES[kind], children: [
6690
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-head", children: [
6980
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": TITLES[kind], children: [
6981
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-head", children: [
6691
6982
  iconForType(kind),
6692
6983
  TITLES[kind]
6693
6984
  ] }),
6694
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-body", children: [
6695
- kind === "move" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "rk-seg", role: "group", "aria-label": "Direction", children: ["up", "down", "first", "last"].map((option) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6985
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-body", children: [
6986
+ kind === "move" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-seg", role: "group", "aria-label": "Direction", children: ["up", "down", "first", "last"].map((option) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6696
6987
  "button",
6697
6988
  {
6698
6989
  type: "button",
@@ -6702,7 +6993,7 @@ function NoteComposer({ editor }) {
6702
6993
  },
6703
6994
  option
6704
6995
  )) }),
6705
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6996
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6706
6997
  "textarea",
6707
6998
  {
6708
6999
  ref: textareaRef,
@@ -6714,36 +7005,36 @@ function NoteComposer({ editor }) {
6714
7005
  rows: 3
6715
7006
  }
6716
7007
  ),
6717
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
6718
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
6719
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
7008
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
7009
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
7010
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
6720
7011
  ] })
6721
7012
  ] }),
6722
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-foot", children: [
6723
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-hint", children: [
6724
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u2318\u21B5" }),
7013
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-foot", children: [
7014
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-hint", children: [
7015
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-kbd", children: "\u2318\u21B5" }),
6725
7016
  " save \xB7 ",
6726
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "esc" }),
7017
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-kbd", children: "esc" }),
6727
7018
  " cancel"
6728
7019
  ] }),
6729
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-actions", children: [
6730
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
6731
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
7020
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-actions", children: [
7021
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
7022
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
6732
7023
  ] })
6733
7024
  ] })
6734
7025
  ] });
6735
7026
  }
6736
- var import_react12, import_jsx_runtime10, TITLES, PLACEHOLDERS;
7027
+ var import_react13, import_jsx_runtime11, TITLES, PLACEHOLDERS;
6737
7028
  var init_NoteComposer = __esm({
6738
7029
  "src/client/components/NoteComposer.tsx"() {
6739
7030
  "use strict";
6740
- import_react12 = require("react");
7031
+ import_react13 = require("react");
6741
7032
  init_store();
6742
7033
  init_id();
6743
7034
  init_identity();
6744
7035
  init_useAnchored();
6745
7036
  init_icons();
6746
- import_jsx_runtime10 = require("react/jsx-runtime");
7037
+ import_jsx_runtime11 = require("react/jsx-runtime");
6747
7038
  TITLES = {
6748
7039
  comment: "Comment",
6749
7040
  delete: "Mark for deletion",
@@ -6837,24 +7128,24 @@ function formatBytes(bytes) {
6837
7128
  function CopyDiff({ before, after }) {
6838
7129
  const parts = diffParts(before, after);
6839
7130
  const delta = after.length - before.length;
6840
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-diffview", children: [
6841
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
6842
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
6843
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-diff-text", children: [
7131
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diffview", children: [
7132
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
7133
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
7134
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-diff-text", children: [
6844
7135
  parts.prefix,
6845
- parts.delMid && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("mark", { className: "rk-del", children: parts.delMid }),
7136
+ parts.delMid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("mark", { className: "rk-del", children: parts.delMid }),
6846
7137
  parts.suffix
6847
7138
  ] })
6848
7139
  ] }),
6849
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
6850
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-diff-tag", children: "After" }),
6851
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-diff-text", children: [
7140
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
7141
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-diff-tag", children: "After" }),
7142
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-diff-text", children: [
6852
7143
  parts.prefix,
6853
- parts.insMid && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("mark", { className: "rk-ins", children: parts.insMid }),
7144
+ parts.insMid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("mark", { className: "rk-ins", children: parts.insMid }),
6854
7145
  parts.suffix
6855
7146
  ] })
6856
7147
  ] }),
6857
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-diff-len", children: [
7148
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-len", children: [
6858
7149
  before.length,
6859
7150
  " \u2192 ",
6860
7151
  after.length,
@@ -6865,8 +7156,8 @@ function CopyDiff({ before, after }) {
6865
7156
  }
6866
7157
  function ImageDetail({ beforeSrc, afterSrc, afterDataUrl }) {
6867
7158
  const replacement = afterDataUrl ?? afterSrc;
6868
- const [dims, setDims] = (0, import_react13.useState)("");
6869
- (0, import_react13.useEffect)(() => {
7159
+ const [dims, setDims] = (0, import_react14.useState)("");
7160
+ (0, import_react14.useEffect)(() => {
6870
7161
  if (!replacement) return;
6871
7162
  const img = new Image();
6872
7163
  img.onload = () => setDims(`${img.naturalWidth}\xD7${img.naturalHeight}px`);
@@ -6891,55 +7182,55 @@ function ImageDetail({ beforeSrc, afterSrc, afterDataUrl }) {
6891
7182
  window.open(replacement, "_blank", "noopener");
6892
7183
  }
6893
7184
  };
6894
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-imgdetail", children: [
6895
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-thumbs", children: [
6896
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "rk-thumb", children: [
6897
- beforeSrc ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { src: beforeSrc, alt: "Current" }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-thumb-missing", children: "no image" }),
6898
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { children: "Before" })
7185
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail", children: [
7186
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-thumbs", children: [
7187
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "rk-thumb", children: [
7188
+ beforeSrc ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("img", { src: beforeSrc, alt: "Current" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-thumb-missing", children: "no image" }),
7189
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { children: "Before" })
6899
7190
  ] }),
6900
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "rk-thumb", children: [
6901
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { src: replacement, alt: "Proposed replacement" }),
6902
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figcaption", { children: [
7191
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "rk-thumb", children: [
7192
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("img", { src: replacement, alt: "Proposed replacement" }),
7193
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figcaption", { children: [
6903
7194
  "After",
6904
7195
  embedded ? "" : " \xB7 linked"
6905
7196
  ] })
6906
7197
  ] })
6907
7198
  ] }),
6908
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-imgdetail-meta", children: [
7199
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail-meta", children: [
6909
7200
  embedded ? "Embedded image" : "Linked image",
6910
7201
  dims ? ` \xB7 ${dims}` : "",
6911
7202
  bytes !== null ? ` \xB7 ${formatBytes(bytes)}` : ""
6912
7203
  ] }),
6913
- !embedded && afterSrc && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("a", { className: "rk-imgdetail-url", href: afterSrc, target: "_blank", rel: "noopener noreferrer", title: afterSrc, children: afterSrc }),
6914
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-imgdetail-actions", children: [
6915
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void download(), children: [
6916
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconDownload, { size: 12 }),
7204
+ !embedded && afterSrc && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { className: "rk-imgdetail-url", href: afterSrc, target: "_blank", rel: "noopener noreferrer", title: afterSrc, children: afterSrc }),
7205
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail-actions", children: [
7206
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void download(), children: [
7207
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconDownload, { size: 12 }),
6917
7208
  " Download"
6918
7209
  ] }),
6919
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => window.open(replacement, "_blank", "noopener"), children: "Open" })
7210
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => window.open(replacement, "_blank", "noopener"), children: "Open" })
6920
7211
  ] })
6921
7212
  ] });
6922
7213
  }
6923
7214
  function Panel() {
6924
- const { session, panelOpen, activeItemId, badgeCorner, undoStack, preview, unapplied, syncStatus, emblemaPush, peers } = useStore();
7215
+ const { session, panelOpen, activeItemId, badgeCorner, undoStack, preview, unapplied, syncStatus, syncReason, emblemaPush, peers } = useStore();
6925
7216
  const dispatch = useDispatch();
6926
7217
  const config = useConfig();
6927
- const [sticky, setStickyState] = (0, import_react13.useState)(() => isStickyEnabled(config.token));
6928
- const [query, setQuery] = (0, import_react13.useState)("");
6929
- const [typeFilter, setTypeFilter] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
6930
- const [prioFilter, setPrioFilter] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
6931
- const [statusFilter, setStatusFilter] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
6932
- const [filterOpen, setFilterOpen] = (0, import_react13.useState)(false);
6933
- const [settingsOpen, setSettingsOpen] = (0, import_react13.useState)(false);
6934
- const [emblemaAlive, setEmblemaAlive] = (0, import_react13.useState)(null);
6935
- const [emblemaSending, setEmblemaSending] = (0, import_react13.useState)(false);
6936
- const [emblemaSync, setEmblemaSync] = (0, import_react13.useState)("unknown");
6937
- const panelRef = (0, import_react13.useRef)(null);
6938
- const searchRef = (0, import_react13.useRef)(null);
6939
- const importRef = (0, import_react13.useRef)(null);
6940
- const sheetDrag = (0, import_react13.useRef)(null);
6941
- const items = (0, import_react13.useMemo)(() => session?.items ?? [], [session]);
6942
- const { orphanIds, hiddenIds } = (0, import_react13.useMemo)(() => {
7218
+ const [sticky, setStickyState] = (0, import_react14.useState)(() => isStickyEnabled(config.token));
7219
+ const [query, setQuery] = (0, import_react14.useState)("");
7220
+ const [typeFilter, setTypeFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
7221
+ const [prioFilter, setPrioFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
7222
+ const [statusFilter, setStatusFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
7223
+ const [filterOpen, setFilterOpen] = (0, import_react14.useState)(false);
7224
+ const [settingsOpen, setSettingsOpen] = (0, import_react14.useState)(false);
7225
+ const [emblemaAlive, setEmblemaAlive] = (0, import_react14.useState)(null);
7226
+ const [emblemaSending, setEmblemaSending] = (0, import_react14.useState)(false);
7227
+ const [emblemaSync, setEmblemaSync] = (0, import_react14.useState)("unknown");
7228
+ const panelRef = (0, import_react14.useRef)(null);
7229
+ const searchRef = (0, import_react14.useRef)(null);
7230
+ const importRef = (0, import_react14.useRef)(null);
7231
+ const sheetDrag = (0, import_react14.useRef)(null);
7232
+ const items = (0, import_react14.useMemo)(() => session?.items ?? [], [session]);
7233
+ const { orphanIds, hiddenIds } = (0, import_react14.useMemo)(() => {
6943
7234
  const orphans = /* @__PURE__ */ new Set();
6944
7235
  const hiddens = /* @__PURE__ */ new Set();
6945
7236
  for (const item of items) {
@@ -6950,15 +7241,15 @@ function Panel() {
6950
7241
  }
6951
7242
  return { orphanIds: orphans, hiddenIds: hiddens };
6952
7243
  }, [items, panelOpen]);
6953
- const activeFilter = (0, import_react13.useMemo)(
7244
+ const activeFilter = (0, import_react14.useMemo)(
6954
7245
  () => typeFilter.size + prioFilter.size + statusFilter.size > 0 ? { types: [...typeFilter], priorities: [...prioFilter], statuses: [...statusFilter] } : null,
6955
7246
  [typeFilter, prioFilter, statusFilter]
6956
7247
  );
6957
- (0, import_react13.useEffect)(() => {
7248
+ (0, import_react14.useEffect)(() => {
6958
7249
  dispatch({ type: "SET_FILTER", filter: activeFilter });
6959
7250
  return () => dispatch({ type: "SET_FILTER", filter: null });
6960
7251
  }, [activeFilter, dispatch]);
6961
- const filtered = (0, import_react13.useMemo)(() => {
7252
+ const filtered = (0, import_react14.useMemo)(() => {
6962
7253
  const q = query.trim().toLowerCase();
6963
7254
  return items.map((item, index) => ({ item, number: index + 1 })).filter(({ item }) => {
6964
7255
  if (!itemMatchesFilter(item, activeFilter)) return false;
@@ -6967,22 +7258,22 @@ function Panel() {
6967
7258
  return haystack.includes(q);
6968
7259
  });
6969
7260
  }, [items, query, activeFilter]);
6970
- const typeCounts = (0, import_react13.useMemo)(() => {
7261
+ const typeCounts = (0, import_react14.useMemo)(() => {
6971
7262
  const counts = /* @__PURE__ */ new Map();
6972
7263
  for (const item of items) counts.set(item.type, (counts.get(item.type) ?? 0) + 1);
6973
7264
  return counts;
6974
7265
  }, [items]);
6975
- const prioCounts = (0, import_react13.useMemo)(() => {
7266
+ const prioCounts = (0, import_react14.useMemo)(() => {
6976
7267
  const counts = /* @__PURE__ */ new Map();
6977
7268
  for (const item of items) counts.set(item.priority, (counts.get(item.priority) ?? 0) + 1);
6978
7269
  return counts;
6979
7270
  }, [items]);
6980
- const statusCounts = (0, import_react13.useMemo)(() => {
7271
+ const statusCounts = (0, import_react14.useMemo)(() => {
6981
7272
  const counts = /* @__PURE__ */ new Map();
6982
7273
  for (const item of items) counts.set(item.status, (counts.get(item.status) ?? 0) + 1);
6983
7274
  return counts;
6984
7275
  }, [items]);
6985
- const groups = (0, import_react13.useMemo)(() => {
7276
+ const groups = (0, import_react14.useMemo)(() => {
6986
7277
  const map = /* @__PURE__ */ new Map();
6987
7278
  for (const entry of filtered) {
6988
7279
  const list = map.get(entry.item.route) ?? [];
@@ -6991,7 +7282,7 @@ function Panel() {
6991
7282
  }
6992
7283
  return Array.from(map.entries());
6993
7284
  }, [filtered]);
6994
- (0, import_react13.useEffect)(() => {
7285
+ (0, import_react14.useEffect)(() => {
6995
7286
  if (!filterOpen && !settingsOpen) return;
6996
7287
  const onDown = (event) => {
6997
7288
  const path = event.composedPath();
@@ -7002,7 +7293,7 @@ function Panel() {
7002
7293
  document.addEventListener("pointerdown", onDown, true);
7003
7294
  return () => document.removeEventListener("pointerdown", onDown, true);
7004
7295
  }, [filterOpen, settingsOpen]);
7005
- (0, import_react13.useEffect)(() => {
7296
+ (0, import_react14.useEffect)(() => {
7006
7297
  if (!settingsOpen) return;
7007
7298
  let alive = true;
7008
7299
  const probe = () => {
@@ -7026,7 +7317,7 @@ function Panel() {
7026
7317
  live: "paired",
7027
7318
  off: "not paired"
7028
7319
  }[emblemaPairState];
7029
- (0, import_react13.useEffect)(() => {
7320
+ (0, import_react14.useEffect)(() => {
7030
7321
  if (!panelOpen || activeItemId === null) return;
7031
7322
  const row = panelRef.current?.querySelector(`[data-item-id="${activeItemId}"]`);
7032
7323
  row?.scrollIntoView({ block: "nearest" });
@@ -7142,7 +7433,7 @@ function Panel() {
7142
7433
  panel.style.transform = "";
7143
7434
  if (dy > 110) dispatch({ type: "SET_PANEL", open: false });
7144
7435
  };
7145
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7436
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7146
7437
  "div",
7147
7438
  {
7148
7439
  ref: panelRef,
@@ -7152,7 +7443,7 @@ function Panel() {
7152
7443
  "aria-label": "Review feedback panel",
7153
7444
  onKeyDown,
7154
7445
  children: [
7155
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7446
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7156
7447
  "div",
7157
7448
  {
7158
7449
  className: "rk-sheet-handle",
@@ -7163,34 +7454,41 @@ function Panel() {
7163
7454
  onPointerCancel: onSheetHandleUp
7164
7455
  }
7165
7456
  ),
7166
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-panel-head", children: [
7167
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
7168
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-panel-title", children: "Feedback" }),
7169
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-panel-sub", children: [
7457
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-head", children: [
7458
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
7459
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-panel-title", children: "Feedback" }),
7460
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-sub", children: [
7170
7461
  items.length,
7171
7462
  " item",
7172
7463
  items.length === 1 ? "" : "s",
7173
7464
  session.author ? ` \xB7 ${session.author}` : "",
7174
- syncStatus !== "disabled" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: `rk-sync rk-sync-${syncStatus}`, children: [
7175
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-sync-dot" }),
7176
- syncStatus === "online" ? `live${peers.length > 0 ? ` \xB7 ${peers.length} other${peers.length === 1 ? "" : "s"}` : ""}` : syncStatus === "connecting" ? "connecting\u2026" : "local only"
7177
- ] }),
7178
- config.emblema && emblemaPush !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7465
+ syncStatus !== "disabled" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7466
+ "span",
7467
+ {
7468
+ className: `rk-sync rk-sync-${syncStatus}${syncReason ? ` rk-sync-reason-${syncReason}` : ""}`,
7469
+ title: syncStatus === "online" ? "Live: everyone with this review link shares these items in real time" : syncStatus === "connecting" ? "Connecting to the sync server\u2026" : SYNC_REASON_HELP[syncReason ?? "unreachable"],
7470
+ children: [
7471
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-sync-dot" }),
7472
+ syncStatus === "online" ? `live${peers.length > 0 ? ` \xB7 ${peers.length} other${peers.length === 1 ? "" : "s"}` : ""}` : syncStatus === "connecting" ? "connecting\u2026" : `local only \xB7 ${SYNC_REASON_LABEL[syncReason ?? "unreachable"]}`
7473
+ ]
7474
+ }
7475
+ ),
7476
+ config.emblema && emblemaPush !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7179
7477
  "span",
7180
7478
  {
7181
7479
  className: `rk-sync rk-epush-${emblemaPush}`,
7182
7480
  title: emblemaPush === "ok" ? "Review items stream to Emblema automatically" : emblemaPush === "sending" ? "Sending items to Emblema\u2026" : "Emblema isn't reachable \u2014 items resend on the next change, or use Resend all in the menu",
7183
7481
  children: [
7184
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-sync-dot" }),
7482
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-sync-dot" }),
7185
7483
  emblemaPush === "ok" ? "emblema" : emblemaPush === "sending" ? "emblema\u2026" : emblemaPush === "rejected" ? "emblema rejected" : "emblema offline"
7186
7484
  ]
7187
7485
  }
7188
7486
  )
7189
7487
  ] })
7190
7488
  ] }),
7191
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-spacer" }),
7192
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
7193
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7489
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-spacer" }),
7490
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
7491
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7194
7492
  "button",
7195
7493
  {
7196
7494
  type: "button",
@@ -7206,11 +7504,11 @@ function Panel() {
7206
7504
  void pingEmblema(config.emblema).then((port) => setEmblemaAlive(port !== null));
7207
7505
  }
7208
7506
  },
7209
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconGear, { size: 15 })
7507
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconGear, { size: 15 })
7210
7508
  }
7211
7509
  ),
7212
- settingsOpen && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Session settings", children: [
7213
- config.token && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7510
+ settingsOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Session settings", children: [
7511
+ config.token && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7214
7512
  "button",
7215
7513
  {
7216
7514
  type: "button",
@@ -7225,12 +7523,12 @@ function Panel() {
7225
7523
  toast(dispatch, next ? "Review stays on in this tab" : "Review active only via the link", "info");
7226
7524
  },
7227
7525
  children: [
7228
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `rk-menu-check${sticky ? " rk-on" : ""}` }),
7526
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${sticky ? " rk-on" : ""}` }),
7229
7527
  "Keep review on in this tab"
7230
7528
  ]
7231
7529
  }
7232
7530
  ),
7233
- config.emblema && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7531
+ config.emblema && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7234
7532
  "button",
7235
7533
  {
7236
7534
  type: "button",
@@ -7260,7 +7558,7 @@ function Panel() {
7260
7558
  }).finally(() => setEmblemaSending(false));
7261
7559
  },
7262
7560
  children: [
7263
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7561
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7264
7562
  "span",
7265
7563
  {
7266
7564
  className: "rk-emblema-dot",
@@ -7271,25 +7569,40 @@ function Panel() {
7271
7569
  ]
7272
7570
  }
7273
7571
  ),
7274
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7572
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7275
7573
  "button",
7276
7574
  {
7277
7575
  type: "button",
7278
7576
  role: "menuitem",
7279
7577
  className: "rk-menu-item",
7280
- title: emblemaPairState === "stale" ? "The local sync agent is not answering \u2014 run `npx @satanwagen/reviewkit-cli serve` in the project" : "Pair this project with the Emblema app via a sync key",
7578
+ title: emblemaPairState === "stale" ? "The local sync agent is not answering \u2014 run `npx -p @satanwagen/reviewkit-cli reviewkit-emblema serve` in the project" : "Pair this project with the Emblema app via a sync key",
7281
7579
  onClick: () => {
7282
7580
  setSettingsOpen(false);
7283
7581
  dispatch({ type: "SET_EMBLEMA_CONNECT", open: true });
7284
7582
  },
7285
7583
  children: [
7286
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-emblema-dot", "data-state": emblemaPairState }),
7584
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-emblema-dot", "data-state": emblemaPairState }),
7287
7585
  "Connect to Emblema\u2026",
7288
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-menu-count", children: emblemaPairLabel })
7586
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: emblemaPairLabel })
7289
7587
  ]
7290
7588
  }
7291
7589
  ),
7292
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7590
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7591
+ "button",
7592
+ {
7593
+ type: "button",
7594
+ role: "menuitem",
7595
+ className: "rk-menu-item",
7596
+ title: resolveSyncToken(config) ? "Pair the reviewkit terminal CLI / Claude Code MCP bridge with this site" : "Needs live sync (sync is off on this page) \u2014 the terminal reads the shared room",
7597
+ disabled: !resolveSyncToken(config),
7598
+ onClick: () => {
7599
+ setSettingsOpen(false);
7600
+ dispatch({ type: "SET_TERMINAL_CONNECT", open: true });
7601
+ },
7602
+ children: "Connect terminal / agent\u2026"
7603
+ }
7604
+ ),
7605
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7293
7606
  "button",
7294
7607
  {
7295
7608
  type: "button",
@@ -7302,31 +7615,31 @@ function Panel() {
7302
7615
  )
7303
7616
  ] })
7304
7617
  ] }),
7305
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7618
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7306
7619
  "button",
7307
7620
  {
7308
7621
  type: "button",
7309
7622
  className: "rk-icon-btn",
7310
7623
  "aria-label": "Keyboard shortcuts",
7311
7624
  onClick: () => dispatch({ type: "SET_CHEATSHEET", open: true }),
7312
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconKeyboard, { size: 15 })
7625
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconKeyboard, { size: 15 })
7313
7626
  }
7314
7627
  ),
7315
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7628
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7316
7629
  "button",
7317
7630
  {
7318
7631
  type: "button",
7319
7632
  className: "rk-icon-btn",
7320
7633
  "aria-label": "Close panel",
7321
7634
  onClick: () => dispatch({ type: "SET_PANEL", open: false }),
7322
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconClose, { size: 14 })
7635
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconClose, { size: 14 })
7323
7636
  }
7324
7637
  )
7325
7638
  ] }),
7326
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-view-row", children: [
7327
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-view-info", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-view-title", children: "Page view" }) }),
7328
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-seg rk-view-toggle", role: "group", "aria-label": "Page view (P to toggle)", children: [
7329
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7639
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-view-row", children: [
7640
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-view-info", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-view-title", children: "Page view" }) }),
7641
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-seg rk-view-toggle", role: "group", "aria-label": "Page view (P to toggle)", children: [
7642
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7330
7643
  "button",
7331
7644
  {
7332
7645
  type: "button",
@@ -7336,7 +7649,7 @@ function Panel() {
7336
7649
  children: "Original"
7337
7650
  }
7338
7651
  ),
7339
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7652
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7340
7653
  "button",
7341
7654
  {
7342
7655
  type: "button",
@@ -7348,8 +7661,8 @@ function Panel() {
7348
7661
  )
7349
7662
  ] })
7350
7663
  ] }),
7351
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-panel-tools", children: [
7352
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7664
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-tools", children: [
7665
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7353
7666
  "button",
7354
7667
  {
7355
7668
  type: "button",
@@ -7360,15 +7673,15 @@ function Panel() {
7360
7673
  dispatch({ type: "SET_MODE", mode: "pick" });
7361
7674
  },
7362
7675
  children: [
7363
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconTarget, { size: 14 }),
7676
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTarget, { size: 14 }),
7364
7677
  " Pick an element"
7365
7678
  ]
7366
7679
  }
7367
7680
  ),
7368
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-search-row", children: [
7369
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-search", children: [
7370
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconSearch, { size: 13 }),
7371
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7681
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-search-row", children: [
7682
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-search", children: [
7683
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconSearch, { size: 13 }),
7684
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7372
7685
  "input",
7373
7686
  {
7374
7687
  ref: searchRef,
@@ -7380,8 +7693,8 @@ function Panel() {
7380
7693
  }
7381
7694
  )
7382
7695
  ] }),
7383
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
7384
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7696
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
7697
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7385
7698
  "button",
7386
7699
  {
7387
7700
  type: "button",
@@ -7393,15 +7706,15 @@ function Panel() {
7393
7706
  setSettingsOpen(false);
7394
7707
  },
7395
7708
  children: [
7396
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconFilter, { size: 13 }),
7709
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFilter, { size: 13 }),
7397
7710
  "Filter",
7398
- typeFilter.size + prioFilter.size + statusFilter.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-badge-count", children: typeFilter.size + prioFilter.size + statusFilter.size })
7711
+ typeFilter.size + prioFilter.size + statusFilter.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-count", children: typeFilter.size + prioFilter.size + statusFilter.size })
7399
7712
  ]
7400
7713
  }
7401
7714
  ),
7402
- filterOpen && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Filter items", children: [
7403
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-menu-title", children: "Type" }),
7404
- TYPE_FILTERS.map((type) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7715
+ filterOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Filter items", children: [
7716
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Type" }),
7717
+ TYPE_FILTERS.map((type) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7405
7718
  "button",
7406
7719
  {
7407
7720
  type: "button",
@@ -7415,16 +7728,16 @@ function Panel() {
7415
7728
  setTypeFilter(next);
7416
7729
  },
7417
7730
  children: [
7418
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `rk-menu-check${typeFilter.has(type) ? " rk-on" : ""}` }),
7731
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${typeFilter.has(type) ? " rk-on" : ""}` }),
7419
7732
  iconForType(type, 12),
7420
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-menu-label", children: type }),
7421
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-menu-count", children: typeCounts.get(type) ?? 0 })
7733
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: type }),
7734
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: typeCounts.get(type) ?? 0 })
7422
7735
  ]
7423
7736
  },
7424
7737
  type
7425
7738
  )),
7426
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-menu-title", children: "Priority" }),
7427
- PRIORITY_FILTERS.map((priority) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7739
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Priority" }),
7740
+ PRIORITY_FILTERS.map((priority) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7428
7741
  "button",
7429
7742
  {
7430
7743
  type: "button",
@@ -7438,15 +7751,15 @@ function Panel() {
7438
7751
  setPrioFilter(next);
7439
7752
  },
7440
7753
  children: [
7441
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `rk-menu-check${prioFilter.has(priority) ? " rk-on" : ""}` }),
7442
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-menu-label", children: PRIORITY_LABELS[priority] }),
7443
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-menu-count", children: prioCounts.get(priority) ?? 0 })
7754
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${prioFilter.has(priority) ? " rk-on" : ""}` }),
7755
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: PRIORITY_LABELS[priority] }),
7756
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: prioCounts.get(priority) ?? 0 })
7444
7757
  ]
7445
7758
  },
7446
7759
  priority
7447
7760
  )),
7448
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-menu-title", children: "Status" }),
7449
- STATUSES.map((status) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7761
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Status" }),
7762
+ STATUSES.map((status) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7450
7763
  "button",
7451
7764
  {
7452
7765
  type: "button",
@@ -7460,15 +7773,15 @@ function Panel() {
7460
7773
  setStatusFilter(next);
7461
7774
  },
7462
7775
  children: [
7463
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `rk-menu-check${statusFilter.has(status) ? " rk-on" : ""}` }),
7464
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `rk-status-dot rk-st-${status}` }),
7465
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-menu-label", children: status }),
7466
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-menu-count", children: statusCounts.get(status) ?? 0 })
7776
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${statusFilter.has(status) ? " rk-on" : ""}` }),
7777
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-status-dot rk-st-${status}` }),
7778
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: status }),
7779
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: statusCounts.get(status) ?? 0 })
7467
7780
  ]
7468
7781
  },
7469
7782
  status
7470
7783
  )),
7471
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7784
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7472
7785
  "button",
7473
7786
  {
7474
7787
  type: "button",
@@ -7488,24 +7801,24 @@ function Panel() {
7488
7801
  ] })
7489
7802
  ] })
7490
7803
  ] }),
7491
- preview && unapplied > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-unplaced", role: "status", children: [
7804
+ preview && unapplied > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-unplaced", role: "status", children: [
7492
7805
  unapplied,
7493
7806
  " saved change",
7494
7807
  unapplied === 1 ? "" : "s",
7495
7808
  " couldn\u2019t be placed on the current page \u2014 the page has changed since they were captured."
7496
7809
  ] }),
7497
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-panel-list", children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-empty", children: [
7498
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-empty-art", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconTarget, { size: 22 }) }),
7499
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-empty-title", children: items.length === 0 ? "Nothing here yet" : "No matches" }),
7500
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-empty-text", children: items.length === 0 ? "Choose \u201CPick an element\u201D, then click anything on the page. Your suggestions collect here, ready to hand off." : "Try a different search, or clear the filters." })
7501
- ] }) : groups.map(([route, entries]) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
7502
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-group-title", children: route }),
7810
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-panel-list", children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-empty", children: [
7811
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-art", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTarget, { size: 22 }) }),
7812
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-title", children: items.length === 0 ? "Nothing here yet" : "No matches" }),
7813
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-text", children: items.length === 0 ? "Choose \u201CPick an element\u201D, then click anything on the page. Your suggestions collect here, ready to hand off." : "Try a different search, or clear the filters." })
7814
+ ] }) : groups.map(([route, entries]) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
7815
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-group-title", children: route }),
7503
7816
  entries.map(({ item, number }) => {
7504
7817
  const active2 = item.id === activeItemId;
7505
7818
  const orphan = orphanIds.has(item.id);
7506
7819
  const hiddenEl = hiddenIds.has(item.id);
7507
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
7508
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7820
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
7821
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7509
7822
  "div",
7510
7823
  {
7511
7824
  "data-item-id": item.id,
@@ -7520,18 +7833,18 @@ function Panel() {
7520
7833
  }
7521
7834
  },
7522
7835
  children: [
7523
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-item-num", children: number }),
7524
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-item-icon", children: iconForType(item.type) }),
7525
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-item-body", children: [
7526
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-item-snippet", children: [
7836
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-num", children: number }),
7837
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-icon", children: iconForType(item.type) }),
7838
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-body", children: [
7839
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-snippet", children: [
7527
7840
  item.target.tagName,
7528
7841
  " \xB7 ",
7529
7842
  item.target.textSnippet || item.target.selector
7530
7843
  ] }),
7531
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-item-change", children: changeSummary(item) }),
7532
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-item-meta", children: [
7533
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-author", title: new Date(item.createdAt).toLocaleString(), children: [
7534
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7844
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-change", children: changeSummary(item) }),
7845
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-meta", children: [
7846
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-author", title: new Date(item.createdAt).toLocaleString(), children: [
7847
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7535
7848
  "span",
7536
7849
  {
7537
7850
  className: "rk-author-dot",
@@ -7539,15 +7852,15 @@ function Panel() {
7539
7852
  }
7540
7853
  ),
7541
7854
  item.author?.name ?? "Unknown",
7542
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-time", children: [
7855
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-time", children: [
7543
7856
  " \xB7 ",
7544
7857
  timeAgo(item.createdAt)
7545
7858
  ] })
7546
7859
  ] }),
7547
- item.priority === "must" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-badge-mini rk-must", children: "must" }),
7548
- item.status !== "open" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `rk-badge-mini rk-${item.status}`, children: item.status }),
7549
- orphan && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-badge-mini rk-orphaned", children: "unanchored" }),
7550
- hiddenEl && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7860
+ item.priority === "must" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini rk-must", children: "must" }),
7861
+ item.status !== "open" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-badge-mini rk-${item.status}`, children: item.status }),
7862
+ orphan && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini rk-orphaned", children: "unanchored" }),
7863
+ hiddenEl && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7551
7864
  "span",
7552
7865
  {
7553
7866
  className: "rk-badge-mini rk-hidden-el",
@@ -7555,14 +7868,14 @@ function Panel() {
7555
7868
  children: "hidden"
7556
7869
  }
7557
7870
  ),
7558
- item.note && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-badge-mini", children: "note" }),
7559
- peers.filter((peer) => peer.typingActive && peer.typingItemId === item.id).map((peer) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-badge-mini", style: { color: peer.color }, children: [
7871
+ item.note && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini", children: "note" }),
7872
+ peers.filter((peer) => peer.typingActive && peer.typingItemId === item.id).map((peer) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-badge-mini", style: { color: peer.color }, children: [
7560
7873
  peer.name || "peer",
7561
7874
  " is writing\u2026"
7562
7875
  ] }, peer.id))
7563
7876
  ] })
7564
7877
  ] }),
7565
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-item-actions", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7878
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-actions", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7566
7879
  "button",
7567
7880
  {
7568
7881
  type: "button",
@@ -7577,15 +7890,15 @@ function Panel() {
7577
7890
  "info"
7578
7891
  );
7579
7892
  },
7580
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconTrash, { size: 13 })
7893
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTrash, { size: 13 })
7581
7894
  }
7582
7895
  ) })
7583
7896
  ]
7584
7897
  }
7585
7898
  ),
7586
- active2 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-item-edit", children: [
7587
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-detail-byline", title: new Date(item.createdAt).toLocaleString(), children: [
7588
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7899
+ active2 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-item-edit", children: [
7900
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-detail-byline", title: new Date(item.createdAt).toLocaleString(), children: [
7901
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7589
7902
  "span",
7590
7903
  {
7591
7904
  className: "rk-author-dot",
@@ -7596,8 +7909,8 @@ function Panel() {
7596
7909
  " \xB7 ",
7597
7910
  timeAgo(item.createdAt)
7598
7911
  ] }),
7599
- isCopyItem(item) && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CopyDiff, { before: item.payload.before, after: item.payload.after }),
7600
- isImageItem(item) && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7912
+ isCopyItem(item) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CopyDiff, { before: item.payload.before, after: item.payload.after }),
7913
+ isImageItem(item) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7601
7914
  ImageDetail,
7602
7915
  {
7603
7916
  beforeSrc: item.payload.beforeSrc,
@@ -7605,7 +7918,7 @@ function Panel() {
7605
7918
  afterDataUrl: item.payload.afterDataUrl
7606
7919
  }
7607
7920
  ),
7608
- isKnownItemType(item.type) && item.type !== "move" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7921
+ isKnownItemType(item.type) && item.type !== "move" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7609
7922
  "textarea",
7610
7923
  {
7611
7924
  className: "rk-textarea",
@@ -7615,7 +7928,7 @@ function Panel() {
7615
7928
  onChange: (event) => dispatch({ type: "UPDATE_ITEM", id: item.id, patch: withPayloadText(item, event.target.value) })
7616
7929
  }
7617
7930
  ),
7618
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7931
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7619
7932
  "input",
7620
7933
  {
7621
7934
  className: "rk-input",
@@ -7625,9 +7938,9 @@ function Panel() {
7625
7938
  onChange: (event) => dispatch({ type: "UPDATE_ITEM", id: item.id, patch: { note: event.target.value } })
7626
7939
  }
7627
7940
  ),
7628
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
7629
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
7630
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7941
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
7942
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
7943
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7631
7944
  "button",
7632
7945
  {
7633
7946
  type: "button",
@@ -7636,7 +7949,7 @@ function Panel() {
7636
7949
  children: "Must"
7637
7950
  }
7638
7951
  ),
7639
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7952
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7640
7953
  "button",
7641
7954
  {
7642
7955
  type: "button",
@@ -7646,7 +7959,7 @@ function Panel() {
7646
7959
  }
7647
7960
  )
7648
7961
  ] }),
7649
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-seg", role: "group", "aria-label": "Status", children: STATUSES.map((status) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7962
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-seg", role: "group", "aria-label": "Status", children: STATUSES.map((status) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7650
7963
  "button",
7651
7964
  {
7652
7965
  type: "button",
@@ -7661,22 +7974,22 @@ function Panel() {
7661
7974
  ] }, item.id);
7662
7975
  })
7663
7976
  ] }, route)) }),
7664
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-panel-foot", children: [
7665
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: onExport, disabled: items.length === 0, children: [
7666
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconDownload, { size: 13 }),
7977
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-foot", children: [
7978
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: onExport, disabled: items.length === 0, children: [
7979
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconDownload, { size: 13 }),
7667
7980
  " Export"
7668
7981
  ] }),
7669
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void onCopy(), disabled: items.length === 0, children: [
7670
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconCopyClipboard, { size: 13 }),
7982
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void onCopy(), disabled: items.length === 0, children: [
7983
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconCopyClipboard, { size: 13 }),
7671
7984
  " Copy"
7672
7985
  ] }),
7673
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => importRef.current?.click(), children: [
7674
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconUpload, { size: 13 }),
7986
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => importRef.current?.click(), children: [
7987
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconUpload, { size: 13 }),
7675
7988
  " Import"
7676
7989
  ] }),
7677
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-spacer" }),
7678
- undoStack.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-icon-btn", "aria-label": "Undo last change (\u2318Z)", onClick: () => dispatch({ type: "UNDO" }), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconUndo, { size: 14 }) }),
7679
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7990
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-spacer" }),
7991
+ undoStack.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "rk-icon-btn", "aria-label": "Undo last change (\u2318Z)", onClick: () => dispatch({ type: "UNDO" }), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconUndo, { size: 14 }) }),
7992
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7680
7993
  "button",
7681
7994
  {
7682
7995
  type: "button",
@@ -7687,7 +8000,7 @@ function Panel() {
7687
8000
  children: "Clear"
7688
8001
  }
7689
8002
  ),
7690
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
8003
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7691
8004
  "button",
7692
8005
  {
7693
8006
  type: "button",
@@ -7697,7 +8010,7 @@ function Panel() {
7697
8010
  children: "Exit review"
7698
8011
  }
7699
8012
  ),
7700
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
8013
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7701
8014
  "input",
7702
8015
  {
7703
8016
  ref: importRef,
@@ -7716,13 +8029,14 @@ function Panel() {
7716
8029
  }
7717
8030
  );
7718
8031
  }
7719
- var import_react13, import_jsx_runtime11, TYPE_FILTERS, PRIORITY_FILTERS, STATUSES, PRIORITY_LABELS;
8032
+ var import_react14, import_jsx_runtime12, TYPE_FILTERS, PRIORITY_FILTERS, STATUSES, PRIORITY_LABELS, SYNC_REASON_LABEL, SYNC_REASON_HELP;
7720
8033
  var init_Panel = __esm({
7721
8034
  "src/client/components/Panel.tsx"() {
7722
8035
  "use strict";
7723
- import_react13 = require("react");
8036
+ import_react14 = require("react");
7724
8037
  init_schema();
7725
8038
  init_env();
8039
+ init_sync();
7726
8040
  init_emblema();
7727
8041
  init_exportSession();
7728
8042
  init_shortcuts();
@@ -7730,11 +8044,23 @@ var init_Panel = __esm({
7730
8044
  init_target();
7731
8045
  init_store();
7732
8046
  init_icons();
7733
- import_jsx_runtime11 = require("react/jsx-runtime");
8047
+ import_jsx_runtime12 = require("react/jsx-runtime");
7734
8048
  TYPE_FILTERS = ["copy", "image", "comment", "delete", "move", "style"];
7735
8049
  PRIORITY_FILTERS = ["must", "nice"];
7736
8050
  STATUSES = ["open", "accepted", "rejected", "applied"];
7737
8051
  PRIORITY_LABELS = { must: "Must", nice: "Nice to have" };
8052
+ SYNC_REASON_LABEL = {
8053
+ "token-short": "token too short",
8054
+ "bad-token": "token rejected",
8055
+ "room-full": "room full",
8056
+ unreachable: "server unreachable"
8057
+ };
8058
+ SYNC_REASON_HELP = {
8059
+ "token-short": "The sync server needs a token of at least 8 characters. Use a longer `token` (or `syncToken`) in <ReviewKit /> and everyone with the link shares items live.",
8060
+ "bad-token": "The sync server rejected the token. Check `syncToken` / `token` in <ReviewKit />.",
8061
+ "room-full": "This page already has the maximum number of reviewers online (16). Try again later.",
8062
+ unreachable: "Could not reach the sync server. Usually the page's Content-Security-Policy is missing the server in connect-src, or the server is down. Items stay on this device meanwhile."
8063
+ };
7738
8064
  }
7739
8065
  });
7740
8066
 
@@ -7748,8 +8074,8 @@ function initials(name) {
7748
8074
  function PresenceStrip() {
7749
8075
  const { peers, syncStatus } = useStore();
7750
8076
  if (syncStatus === "disabled" || peers.length === 0) return null;
7751
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-presence", "aria-label": `${peers.length} reviewer${peers.length === 1 ? "" : "s"} online`, children: [
7752
- peers.slice(0, 5).map((peer) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
8077
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rk-presence", "aria-label": `${peers.length} reviewer${peers.length === 1 ? "" : "s"} online`, children: [
8078
+ peers.slice(0, 5).map((peer) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7753
8079
  "span",
7754
8080
  {
7755
8081
  className: "rk-avatar",
@@ -7759,7 +8085,7 @@ function PresenceStrip() {
7759
8085
  },
7760
8086
  peer.id
7761
8087
  )),
7762
- peers.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-avatar rk-avatar-more", children: [
8088
+ peers.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "rk-avatar rk-avatar-more", children: [
7763
8089
  "+",
7764
8090
  peers.length - 5
7765
8091
  ] })
@@ -7767,13 +8093,13 @@ function PresenceStrip() {
7767
8093
  }
7768
8094
  function PeerCursors() {
7769
8095
  const { peers } = useStore();
7770
- const ringRefs = (0, import_react14.useRef)(/* @__PURE__ */ new Map());
7771
- const cursorRefs = (0, import_react14.useRef)(/* @__PURE__ */ new Map());
7772
- const motion = (0, import_react14.useRef)(
8096
+ const ringRefs = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
8097
+ const cursorRefs = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
8098
+ const motion = (0, import_react15.useRef)(
7773
8099
  /* @__PURE__ */ new Map()
7774
8100
  );
7775
- const peersRef = (0, import_react14.useRef)(peers);
7776
- const seen = (0, import_react14.useRef)(/* @__PURE__ */ new Map());
8101
+ const peersRef = (0, import_react15.useRef)(peers);
8102
+ const seen = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
7777
8103
  for (const peer of peers) {
7778
8104
  const sig = peer.cursor ? `${peer.cursor.x},${peer.cursor.y},${peer.cursor.ox},${peer.cursor.oy}` : "";
7779
8105
  if (seen.current.get(peer.id) !== sig) {
@@ -7783,7 +8109,7 @@ function PeerCursors() {
7783
8109
  }
7784
8110
  }
7785
8111
  peersRef.current = peers;
7786
- (0, import_react14.useEffect)(() => {
8112
+ (0, import_react15.useEffect)(() => {
7787
8113
  const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
7788
8114
  let raf = 0;
7789
8115
  let last = performance.now();
@@ -7888,8 +8214,8 @@ function PeerCursors() {
7888
8214
  return () => cancelAnimationFrame(raf);
7889
8215
  }, []);
7890
8216
  if (peers.length === 0) return null;
7891
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
7892
- peers.map((peer) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
8217
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
8218
+ peers.map((peer) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7893
8219
  "div",
7894
8220
  {
7895
8221
  ref: (el) => {
@@ -7901,7 +8227,7 @@ function PeerCursors() {
7901
8227
  },
7902
8228
  `ring-${peer.id}`
7903
8229
  )),
7904
- peers.map((peer, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
8230
+ peers.map((peer, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7905
8231
  "div",
7906
8232
  {
7907
8233
  ref: (el) => {
@@ -7911,8 +8237,8 @@ function PeerCursors() {
7911
8237
  className: "rk-peer-cursor",
7912
8238
  style: { opacity: 0 },
7913
8239
  children: [
7914
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { width: "14", height: "18", viewBox: "0 0 14 18", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M1 1l12 7.5-5.2 1.2L5 16z", fill: peer.color, stroke: "rgba(0,0,0,0.25)", strokeWidth: "1" }) }),
7915
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
8240
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { width: "14", height: "18", viewBox: "0 0 14 18", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M1 1l12 7.5-5.2 1.2L5 16z", fill: peer.color, stroke: "rgba(0,0,0,0.25)", strokeWidth: "1" }) }),
8241
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7916
8242
  "span",
7917
8243
  {
7918
8244
  className: "rk-peer-name",
@@ -7929,14 +8255,14 @@ function PeerCursors() {
7929
8255
  ))
7930
8256
  ] });
7931
8257
  }
7932
- var import_react14, import_jsx_runtime12;
8258
+ var import_react15, import_jsx_runtime13;
7933
8259
  var init_Presence = __esm({
7934
8260
  "src/client/components/Presence.tsx"() {
7935
8261
  "use strict";
7936
- import_react14 = require("react");
8262
+ import_react15 = require("react");
7937
8263
  init_store();
7938
8264
  init_target();
7939
- import_jsx_runtime12 = require("react/jsx-runtime");
8265
+ import_jsx_runtime13 = require("react/jsx-runtime");
7940
8266
  }
7941
8267
  });
7942
8268
 
@@ -7944,14 +8270,14 @@ var init_Presence = __esm({
7944
8270
  function QuickComment() {
7945
8271
  const { quick } = useStore();
7946
8272
  if (!quick) return null;
7947
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(QuickComposerCard, { quick }, quick.id);
8273
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(QuickComposerCard, { quick }, quick.id);
7948
8274
  }
7949
8275
  function QuickComposerCard({ quick }) {
7950
8276
  const { route, session } = useStore();
7951
8277
  const dispatch = useDispatch();
7952
- const [text, setText] = (0, import_react15.useState)("");
7953
- const fieldRef = (0, import_react15.useRef)(null);
7954
- (0, import_react15.useEffect)(() => {
8278
+ const [text, setText] = (0, import_react16.useState)("");
8279
+ const fieldRef = (0, import_react16.useRef)(null);
8280
+ (0, import_react16.useEffect)(() => {
7955
8281
  const field = fieldRef.current;
7956
8282
  if (!field) return;
7957
8283
  field.focus();
@@ -8004,18 +8330,18 @@ function QuickComposerCard({ quick }) {
8004
8330
  };
8005
8331
  const x = Math.min(Math.max(quick.x, 8), window.innerWidth - 288);
8006
8332
  const y = Math.min(Math.max(quick.y + 12, 8), window.innerHeight - 108);
8007
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rk-quick", style: { transform: `translate3d(${x}px, ${y}px, 0)` }, role: "dialog", "aria-label": "Quick comment", children: [
8008
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rk-quick-head", children: [
8009
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(IconComment, { size: 12 }),
8010
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Comment here" }),
8011
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "rk-hint", children: [
8012
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
8333
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rk-quick", style: { transform: `translate3d(${x}px, ${y}px, 0)` }, role: "dialog", "aria-label": "Quick comment", children: [
8334
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rk-quick-head", children: [
8335
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(IconComment, { size: 12 }),
8336
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Comment here" }),
8337
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "rk-hint", children: [
8338
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
8013
8339
  " save \xB7 ",
8014
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "rk-kbd", children: "esc" }),
8340
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-kbd", children: "esc" }),
8015
8341
  " cancel"
8016
8342
  ] })
8017
8343
  ] }),
8018
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
8344
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
8019
8345
  "textarea",
8020
8346
  {
8021
8347
  ref: fieldRef,
@@ -8029,11 +8355,11 @@ function QuickComposerCard({ quick }) {
8029
8355
  )
8030
8356
  ] });
8031
8357
  }
8032
- var import_react15, import_jsx_runtime13;
8358
+ var import_react16, import_jsx_runtime14;
8033
8359
  var init_QuickComment = __esm({
8034
8360
  "src/client/components/QuickComment.tsx"() {
8035
8361
  "use strict";
8036
- import_react15 = require("react");
8362
+ import_react16 = require("react");
8037
8363
  init_effectCatalog();
8038
8364
  init_effectsLazy();
8039
8365
  init_id();
@@ -8042,7 +8368,7 @@ var init_QuickComment = __esm({
8042
8368
  init_sync();
8043
8369
  init_store();
8044
8370
  init_icons();
8045
- import_jsx_runtime13 = require("react/jsx-runtime");
8371
+ import_jsx_runtime14 = require("react/jsx-runtime");
8046
8372
  }
8047
8373
  });
8048
8374
 
@@ -8061,14 +8387,14 @@ function applyRect(el, rect, pad2 = 3) {
8061
8387
  function PickLayer() {
8062
8388
  const { mode, selection, tool } = useStore();
8063
8389
  const dispatch = useDispatch();
8064
- const [hovered, setHovered] = (0, import_react16.useState)(null);
8065
- const outlineRef = (0, import_react16.useRef)(null);
8066
- const labelRef = (0, import_react16.useRef)(null);
8067
- const selectRef = (0, import_react16.useRef)(null);
8068
- const hoveredRef = (0, import_react16.useRef)(null);
8390
+ const [hovered, setHovered] = (0, import_react17.useState)(null);
8391
+ const outlineRef = (0, import_react17.useRef)(null);
8392
+ const labelRef = (0, import_react17.useRef)(null);
8393
+ const selectRef = (0, import_react17.useRef)(null);
8394
+ const hoveredRef = (0, import_react17.useRef)(null);
8069
8395
  hoveredRef.current = hovered;
8070
8396
  const picking = mode === "pick";
8071
- (0, import_react16.useEffect)(() => {
8397
+ (0, import_react17.useEffect)(() => {
8072
8398
  if (!picking) {
8073
8399
  setHovered(null);
8074
8400
  return;
@@ -8112,7 +8438,7 @@ function PickLayer() {
8112
8438
  document.removeEventListener("mousedown", swallow, true);
8113
8439
  };
8114
8440
  }, [picking, tool, dispatch]);
8115
- (0, import_react16.useEffect)(() => {
8441
+ (0, import_react17.useEffect)(() => {
8116
8442
  if (!picking) return;
8117
8443
  const body = document.body;
8118
8444
  const prev = body.style.cursor;
@@ -8122,7 +8448,7 @@ function PickLayer() {
8122
8448
  if (body.getAttribute("style") === "") body.removeAttribute("style");
8123
8449
  };
8124
8450
  }, [picking, tool]);
8125
- (0, import_react16.useEffect)(() => {
8451
+ (0, import_react17.useEffect)(() => {
8126
8452
  let raf = 0;
8127
8453
  const tick = () => {
8128
8454
  const hoverEl = hoveredRef.current;
@@ -8148,26 +8474,26 @@ function PickLayer() {
8148
8474
  raf = requestAnimationFrame(tick);
8149
8475
  return () => cancelAnimationFrame(raf);
8150
8476
  }, [picking, selection]);
8151
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
8152
- picking && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
8153
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { ref: outlineRef, className: "rk-outline", style: { opacity: 0 } }),
8154
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { ref: labelRef, className: "rk-outline-label", style: { opacity: 0 }, children: hovered ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
8155
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-tag", children: hovered.tagName.toLowerCase() }),
8156
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: describeElement(hovered).replace(/^[a-z0-9]+ · /, "") })
8157
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Pick an element" }) })
8477
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
8478
+ picking && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
8479
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: outlineRef, className: "rk-outline", style: { opacity: 0 } }),
8480
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: labelRef, className: "rk-outline-label", style: { opacity: 0 }, children: hovered ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
8481
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rk-tag", children: hovered.tagName.toLowerCase() }),
8482
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: describeElement(hovered).replace(/^[a-z0-9]+ · /, "") })
8483
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Pick an element" }) })
8158
8484
  ] }),
8159
- selection && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { ref: selectRef, className: "rk-select-ring", style: { opacity: 0 } })
8485
+ selection && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: selectRef, className: "rk-select-ring", style: { opacity: 0 } })
8160
8486
  ] });
8161
8487
  }
8162
- var import_react16, import_jsx_runtime14;
8488
+ var import_react17, import_jsx_runtime15;
8163
8489
  var init_PickLayer = __esm({
8164
8490
  "src/client/components/PickLayer.tsx"() {
8165
8491
  "use strict";
8166
- import_react16 = require("react");
8492
+ import_react17 = require("react");
8167
8493
  init_shortcuts();
8168
8494
  init_target();
8169
8495
  init_store();
8170
- import_jsx_runtime14 = require("react/jsx-runtime");
8496
+ import_jsx_runtime15 = require("react/jsx-runtime");
8171
8497
  }
8172
8498
  });
8173
8499
 
@@ -8175,22 +8501,22 @@ var init_PickLayer = __esm({
8175
8501
  function Pins() {
8176
8502
  const { session, route, activeItemId, editor, mode, filter } = useStore();
8177
8503
  const dispatch = useDispatch();
8178
- const [clusters, setClusters] = (0, import_react17.useState)([]);
8179
- const [orphanCount, setOrphanCount] = (0, import_react17.useState)(0);
8180
- const wrapRefs = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
8181
- const visibleCache = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
8182
- const highlightRef = (0, import_react17.useRef)(null);
8183
- const hoveredItems = (0, import_react17.useRef)(null);
8184
- const elementCache = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
8185
- const lastResolve = (0, import_react17.useRef)(0);
8186
- const [newestId, setNewestId] = (0, import_react17.useState)(null);
8187
- const prevCount = (0, import_react17.useRef)(0);
8188
- const items = (0, import_react17.useMemo)(() => {
8504
+ const [clusters, setClusters] = (0, import_react18.useState)([]);
8505
+ const [orphanCount, setOrphanCount] = (0, import_react18.useState)(0);
8506
+ const wrapRefs = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
8507
+ const visibleCache = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
8508
+ const highlightRef = (0, import_react18.useRef)(null);
8509
+ const hoveredItems = (0, import_react18.useRef)(null);
8510
+ const elementCache = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
8511
+ const lastResolve = (0, import_react18.useRef)(0);
8512
+ const [newestId, setNewestId] = (0, import_react18.useState)(null);
8513
+ const prevCount = (0, import_react18.useRef)(0);
8514
+ const items = (0, import_react18.useMemo)(() => {
8189
8515
  const all = session?.items ?? [];
8190
8516
  return all.map((item, index) => ({ item, number: index + 1 })).filter(({ item }) => item.route === route);
8191
8517
  }, [session, route]);
8192
8518
  const byId = new Map(items.map(({ item }) => [item.id, item]));
8193
- (0, import_react17.useEffect)(() => {
8519
+ (0, import_react18.useEffect)(() => {
8194
8520
  const count = session?.items.length ?? 0;
8195
8521
  if (count > prevCount.current && session && count > 0) {
8196
8522
  const id = session.items[count - 1].id;
@@ -8201,7 +8527,7 @@ function Pins() {
8201
8527
  }
8202
8528
  prevCount.current = count;
8203
8529
  }, [session]);
8204
- (0, import_react17.useEffect)(() => {
8530
+ (0, import_react18.useEffect)(() => {
8205
8531
  let raf = 0;
8206
8532
  let lastSignature = "";
8207
8533
  const tick = (time) => {
@@ -8285,8 +8611,8 @@ function Pins() {
8285
8611
  dispatch({ type: "SET_ACTIVE_ITEM", id });
8286
8612
  dispatch({ type: "SET_PANEL", open: true });
8287
8613
  };
8288
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
8289
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: highlightRef, className: "rk-hl-ring", style: { opacity: 0 } }),
8614
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
8615
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref: highlightRef, className: "rk-hl-ring", style: { opacity: 0 } }),
8290
8616
  clusters.map((cluster) => {
8291
8617
  const isCluster = cluster.ids.length > 1;
8292
8618
  const isActive = activeItemId !== null && cluster.ids.includes(activeItemId);
@@ -8296,7 +8622,7 @@ function Pins() {
8296
8622
  const status = statuses.size === 1 ? members[0]?.status : void 0;
8297
8623
  const dimmed = filter !== null && members.length > 0 && !members.some((item) => itemMatchesFilter(item, filter));
8298
8624
  const statusHint = isCluster ? status ? ` \xB7 all ${STATUS_LABELS[status] ?? status}` : "" : ` \xB7 ${STATUS_LABELS[members[0]?.status ?? "open"] ?? members[0]?.status}`;
8299
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8625
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8300
8626
  "div",
8301
8627
  {
8302
8628
  ref: (el) => {
@@ -8304,7 +8630,7 @@ function Pins() {
8304
8630
  else wrapRefs.current.delete(cluster.key);
8305
8631
  },
8306
8632
  className: `rk-pin-wrap${picking ? " rk-pin-ghost" : ""}`,
8307
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8633
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8308
8634
  "button",
8309
8635
  {
8310
8636
  type: "button",
@@ -8326,7 +8652,7 @@ function Pins() {
8326
8652
  cluster.key
8327
8653
  );
8328
8654
  }),
8329
- orphanCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
8655
+ orphanCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8330
8656
  "button",
8331
8657
  {
8332
8658
  type: "button",
@@ -8334,7 +8660,7 @@ function Pins() {
8334
8660
  style: { bottom: 16, left: "50%", transform: "translateX(-50%)" },
8335
8661
  onClick: () => dispatch({ type: "SET_PANEL", open: true }),
8336
8662
  children: [
8337
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IconUnlink, { size: 13 }),
8663
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconUnlink, { size: 13 }),
8338
8664
  orphanCount,
8339
8665
  " unanchored item",
8340
8666
  orphanCount === 1 ? "" : "s"
@@ -8343,15 +8669,15 @@ function Pins() {
8343
8669
  )
8344
8670
  ] });
8345
8671
  }
8346
- var import_react17, import_jsx_runtime15, STATUS_LABELS, CLUSTER_RADIUS, RERESOLVE_MS;
8672
+ var import_react18, import_jsx_runtime16, STATUS_LABELS, CLUSTER_RADIUS, RERESOLVE_MS;
8347
8673
  var init_Pins = __esm({
8348
8674
  "src/client/components/Pins.tsx"() {
8349
8675
  "use strict";
8350
- import_react17 = require("react");
8676
+ import_react18 = require("react");
8351
8677
  init_target();
8352
8678
  init_store();
8353
8679
  init_icons();
8354
- import_jsx_runtime15 = require("react/jsx-runtime");
8680
+ import_jsx_runtime16 = require("react/jsx-runtime");
8355
8681
  STATUS_LABELS = {
8356
8682
  open: "open",
8357
8683
  accepted: "accepted",
@@ -8368,24 +8694,24 @@ function Toolbar() {
8368
8694
  const { selection, editor, peers, syncStatus, mode, tool } = useStore();
8369
8695
  const hasPeers = syncStatus !== "disabled" && peers.length > 0;
8370
8696
  const dispatch = useDispatch();
8371
- const ref = (0, import_react18.useRef)(null);
8372
- const [pos, setPos] = (0, import_react18.useState)(() => readStoredPos(POS_KEY2));
8373
- const drag = (0, import_react18.useRef)(null);
8374
- const [dragging, setDragging] = (0, import_react18.useState)(false);
8375
- const justDragged = (0, import_react18.useRef)(false);
8697
+ const ref = (0, import_react19.useRef)(null);
8698
+ const [pos, setPos] = (0, import_react19.useState)(() => readStoredPos(POS_KEY2));
8699
+ const drag = (0, import_react19.useRef)(null);
8700
+ const [dragging, setDragging] = (0, import_react19.useState)(false);
8701
+ const justDragged = (0, import_react19.useRef)(false);
8376
8702
  const visible = editor === null || selection !== null;
8377
8703
  const applyPos = (next, persist) => {
8378
8704
  if (next === null && ref.current) ref.current.style.bottom = "";
8379
8705
  setPos(next);
8380
8706
  if (persist) storePos(POS_KEY2, next);
8381
8707
  };
8382
- (0, import_react18.useLayoutEffect)(() => {
8708
+ (0, import_react19.useLayoutEffect)(() => {
8383
8709
  const el = ref.current;
8384
8710
  if (!el || pos === null) return;
8385
8711
  const clamped = clampPos(pos.x, pos.y, el.offsetWidth, el.offsetHeight);
8386
8712
  if (clamped.x !== pos.x || clamped.y !== pos.y) applyPos(clamped, true);
8387
8713
  }, [pos, selection, hasPeers, visible]);
8388
- (0, import_react18.useEffect)(() => {
8714
+ (0, import_react19.useEffect)(() => {
8389
8715
  const onResize = () => {
8390
8716
  const el = ref.current;
8391
8717
  const current = readStoredPos(POS_KEY2);
@@ -8498,7 +8824,7 @@ function Toolbar() {
8498
8824
  mode === "pick" && selection === null ? "rk-ghost" : ""
8499
8825
  ].filter(Boolean).join(" ");
8500
8826
  const style = pos !== null ? { left: 0, top: 0, translate: `${pos.x}px ${pos.y}px` } : void 0;
8501
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8827
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8502
8828
  "div",
8503
8829
  {
8504
8830
  ref,
@@ -8509,7 +8835,7 @@ function Toolbar() {
8509
8835
  onPointerDown,
8510
8836
  onClickCapture,
8511
8837
  children: [
8512
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8838
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8513
8839
  "button",
8514
8840
  {
8515
8841
  type: "button",
@@ -8517,19 +8843,19 @@ function Toolbar() {
8517
8843
  "aria-label": "Move the toolbar \u2014 drag, or use arrow keys; double-click to reset its position",
8518
8844
  onKeyDown: onGripKeyDown,
8519
8845
  onDoubleClick: () => applyPos(null, true),
8520
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { width: "8", height: "14", viewBox: "0 0 8 14", "aria-hidden": "true", fill: "currentColor", children: [
8521
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "2", cy: "2", r: "1.1" }),
8522
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "6", cy: "2", r: "1.1" }),
8523
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "2", cy: "7", r: "1.1" }),
8524
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "6", cy: "7", r: "1.1" }),
8525
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "2", cy: "12", r: "1.1" }),
8526
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "6", cy: "12", r: "1.1" })
8846
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("svg", { width: "8", height: "14", viewBox: "0 0 8 14", "aria-hidden": "true", fill: "currentColor", children: [
8847
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "2", r: "1.1" }),
8848
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "2", r: "1.1" }),
8849
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "7", r: "1.1" }),
8850
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "7", r: "1.1" }),
8851
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "12", r: "1.1" }),
8852
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "12", r: "1.1" })
8527
8853
  ] })
8528
8854
  }
8529
8855
  ),
8530
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PresenceStrip, {}),
8531
- hasPeers && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "rk-toolbar-sep" }),
8532
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "rk-seg rk-tool-seg", role: "group", "aria-label": "Tools", children: TOOLS.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8856
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PresenceStrip, {}),
8857
+ hasPeers && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
8858
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "rk-seg rk-tool-seg", role: "group", "aria-label": "Tools", children: TOOLS.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8533
8859
  "button",
8534
8860
  {
8535
8861
  type: "button",
@@ -8541,9 +8867,9 @@ function Toolbar() {
8541
8867
  },
8542
8868
  entry.tool
8543
8869
  )) }),
8544
- selection && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "rk-toolbar-sep" }),
8545
- selection && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
8546
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8870
+ selection && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
8871
+ selection && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
8872
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8547
8873
  "button",
8548
8874
  {
8549
8875
  type: "button",
@@ -8552,12 +8878,12 @@ function Toolbar() {
8552
8878
  title: `Rewrite text${keyHint("tool-copy")}`,
8553
8879
  onClick: () => open("copy"),
8554
8880
  children: [
8555
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconText, { size: 14 }),
8881
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconText, { size: 14 }),
8556
8882
  " Rewrite"
8557
8883
  ]
8558
8884
  }
8559
8885
  ),
8560
- hasImage && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8886
+ hasImage && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8561
8887
  "button",
8562
8888
  {
8563
8889
  type: "button",
@@ -8566,12 +8892,12 @@ function Toolbar() {
8566
8892
  title: `Replace image${keyHint("tool-image")}`,
8567
8893
  onClick: () => open("image"),
8568
8894
  children: [
8569
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconImage, { size: 14 }),
8895
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconImage, { size: 14 }),
8570
8896
  " Image"
8571
8897
  ]
8572
8898
  }
8573
8899
  ),
8574
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8900
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8575
8901
  "button",
8576
8902
  {
8577
8903
  type: "button",
@@ -8580,32 +8906,32 @@ function Toolbar() {
8580
8906
  title: `Comment${keyHint("tool-comment")}`,
8581
8907
  onClick: () => open("comment"),
8582
8908
  children: [
8583
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconComment, { size: 14 }),
8909
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: 14 }),
8584
8910
  " Comment"
8585
8911
  ]
8586
8912
  }
8587
8913
  ),
8588
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("style"), children: [
8589
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconStyle, { size: 14 }),
8914
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("style"), children: [
8915
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconStyle, { size: 14 }),
8590
8916
  " Style"
8591
8917
  ] }),
8592
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("move"), children: [
8593
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconMove, { size: 14 }),
8918
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("move"), children: [
8919
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconMove, { size: 14 }),
8594
8920
  " Move"
8595
8921
  ] }),
8596
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn rk-danger", onClick: () => open("delete"), children: [
8597
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconTrash, { size: 14 }),
8922
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn rk-danger", onClick: () => open("delete"), children: [
8923
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconTrash, { size: 14 }),
8598
8924
  " Delete"
8599
8925
  ] }),
8600
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "rk-toolbar-sep" }),
8601
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8926
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
8927
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8602
8928
  "button",
8603
8929
  {
8604
8930
  type: "button",
8605
8931
  className: "rk-icon-btn",
8606
8932
  "aria-label": "Deselect",
8607
8933
  onClick: () => dispatch({ type: "SELECT", selection: null }),
8608
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconClose, { size: 13 })
8934
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconClose, { size: 13 })
8609
8935
  }
8610
8936
  )
8611
8937
  ] })
@@ -8613,11 +8939,11 @@ function Toolbar() {
8613
8939
  }
8614
8940
  );
8615
8941
  }
8616
- var import_react18, import_jsx_runtime16, TOOLS, POS_KEY2, DRAG_THRESHOLD2;
8942
+ var import_react19, import_jsx_runtime17, TOOLS, POS_KEY2, DRAG_THRESHOLD2;
8617
8943
  var init_Toolbar = __esm({
8618
8944
  "src/client/components/Toolbar.tsx"() {
8619
8945
  "use strict";
8620
- import_react18 = require("react");
8946
+ import_react19 = require("react");
8621
8947
  init_dragPosition();
8622
8948
  init_store();
8623
8949
  init_preview();
@@ -8625,12 +8951,12 @@ var init_Toolbar = __esm({
8625
8951
  init_target();
8626
8952
  init_Presence();
8627
8953
  init_icons();
8628
- import_jsx_runtime16 = require("react/jsx-runtime");
8954
+ import_jsx_runtime17 = require("react/jsx-runtime");
8629
8955
  TOOLS = [
8630
- { tool: "select", hintId: "tool-select", label: "Select", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconTarget, { size: n }) },
8631
- { tool: "copy", hintId: "tool-copy", label: "Rewrite text", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconText, { size: n }) },
8632
- { tool: "comment", hintId: "tool-comment", label: "Comment", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconComment, { size: n }) },
8633
- { tool: "image", hintId: "tool-image", label: "Replace image", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconImage, { size: n }) }
8956
+ { tool: "select", hintId: "tool-select", label: "Select", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconTarget, { size: n }) },
8957
+ { tool: "copy", hintId: "tool-copy", label: "Rewrite text", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconText, { size: n }) },
8958
+ { tool: "comment", hintId: "tool-comment", label: "Comment", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: n }) },
8959
+ { tool: "image", hintId: "tool-image", label: "Replace image", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconImage, { size: n }) }
8634
8960
  ];
8635
8961
  POS_KEY2 = "review-kit:toolbar-pos";
8636
8962
  DRAG_THRESHOLD2 = 6;
@@ -8640,28 +8966,28 @@ var init_Toolbar = __esm({
8640
8966
  // src/client/components/Toast.tsx
8641
8967
  function ToastRow({ toast: toast2 }) {
8642
8968
  const dispatch = useDispatch();
8643
- (0, import_react19.useEffect)(() => {
8969
+ (0, import_react20.useEffect)(() => {
8644
8970
  const timer = window.setTimeout(() => dispatch({ type: "DISMISS_TOAST", id: toast2.id }), 3500);
8645
8971
  return () => window.clearTimeout(timer);
8646
8972
  }, [toast2.id, dispatch]);
8647
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: `rk-toast rk-${toast2.tone}`, role: "status", children: [
8648
- toast2.tone === "success" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconCheck, { size: 13 }) : toast2.tone === "error" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconWarning, { size: 13 }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: 13 }),
8973
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `rk-toast rk-${toast2.tone}`, role: "status", children: [
8974
+ toast2.tone === "success" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconCheck, { size: 13 }) : toast2.tone === "error" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconWarning, { size: 13 }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconComment, { size: 13 }),
8649
8975
  toast2.message
8650
8976
  ] });
8651
8977
  }
8652
8978
  function ToastHost() {
8653
8979
  const { toasts } = useStore();
8654
8980
  if (toasts.length === 0) return null;
8655
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "rk-toasts", "aria-live": "polite", children: toasts.map((toast2) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ToastRow, { toast: toast2 }, toast2.id)) });
8981
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "rk-toasts", "aria-live": "polite", children: toasts.map((toast2) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ToastRow, { toast: toast2 }, toast2.id)) });
8656
8982
  }
8657
- var import_react19, import_jsx_runtime17;
8983
+ var import_react20, import_jsx_runtime18;
8658
8984
  var init_Toast = __esm({
8659
8985
  "src/client/components/Toast.tsx"() {
8660
8986
  "use strict";
8661
- import_react19 = require("react");
8987
+ import_react20 = require("react");
8662
8988
  init_store();
8663
8989
  init_icons();
8664
- import_jsx_runtime17 = require("react/jsx-runtime");
8990
+ import_jsx_runtime18 = require("react/jsx-runtime");
8665
8991
  }
8666
8992
  });
8667
8993
 
@@ -8671,14 +8997,14 @@ function App() {
8671
8997
  const rawDispatch = useDispatch();
8672
8998
  const config = useConfig();
8673
8999
  const dispatch = useRealtimeSync(state, rawDispatch, config, reducer);
8674
- const saveTimer = (0, import_react20.useRef)(null);
9000
+ const saveTimer = (0, import_react21.useRef)(null);
8675
9001
  const storageKey = config.storageKey ?? defaultStorageKey();
8676
9002
  useAppliedPreview(state, dispatch);
8677
9003
  useEmblemaAutoPush(state, dispatch, config);
8678
- (0, import_react20.useEffect)(() => {
9004
+ (0, import_react21.useEffect)(() => {
8679
9005
  setEffectAssetsUrl(config.fxAssetsUrl);
8680
9006
  }, [config.fxAssetsUrl]);
8681
- (0, import_react20.useEffect)(() => {
9007
+ (0, import_react21.useEffect)(() => {
8682
9008
  let cancelled = false;
8683
9009
  void loadSession(storageKey).then((stored) => {
8684
9010
  if (cancelled) return;
@@ -8696,7 +9022,7 @@ function App() {
8696
9022
  };
8697
9023
  }, [storageKey, config.defaultAuthor, dispatch]);
8698
9024
  const { session } = state;
8699
- (0, import_react20.useEffect)(() => {
9025
+ (0, import_react21.useEffect)(() => {
8700
9026
  if (!session) return;
8701
9027
  if (saveTimer.current !== null) window.clearTimeout(saveTimer.current);
8702
9028
  saveTimer.current = window.setTimeout(() => {
@@ -8707,9 +9033,9 @@ function App() {
8707
9033
  if (saveTimer.current !== null) window.clearTimeout(saveTimer.current);
8708
9034
  };
8709
9035
  }, [session, storageKey, config]);
8710
- (0, import_react20.useEffect)(() => trackPointer(), []);
8711
- const focusHandled = (0, import_react20.useRef)(false);
8712
- (0, import_react20.useEffect)(() => {
9036
+ (0, import_react21.useEffect)(() => trackPointer(), []);
9037
+ const focusHandled = (0, import_react21.useRef)(false);
9038
+ (0, import_react21.useEffect)(() => {
8713
9039
  if (!session || focusHandled.current) return;
8714
9040
  focusHandled.current = true;
8715
9041
  const id = takeFocusItem();
@@ -8734,7 +9060,7 @@ function App() {
8734
9060
  cancelled = true;
8735
9061
  };
8736
9062
  }, [session, dispatch]);
8737
- (0, import_react20.useEffect)(() => {
9063
+ (0, import_react21.useEffect)(() => {
8738
9064
  let last = window.location.pathname;
8739
9065
  const check = () => {
8740
9066
  if (window.location.pathname !== last) {
@@ -8749,9 +9075,9 @@ function App() {
8749
9075
  window.removeEventListener("popstate", check);
8750
9076
  };
8751
9077
  }, [dispatch]);
8752
- const stateRef = (0, import_react20.useRef)(state);
9078
+ const stateRef = (0, import_react21.useRef)(state);
8753
9079
  stateRef.current = state;
8754
- (0, import_react20.useEffect)(() => {
9080
+ (0, import_react21.useEffect)(() => {
8755
9081
  const onKeyDown = (event) => {
8756
9082
  const current = stateRef.current;
8757
9083
  for (const def of SHORTCUTS) {
@@ -8766,7 +9092,7 @@ function App() {
8766
9092
  document.addEventListener("keydown", onKeyDown);
8767
9093
  return () => document.removeEventListener("keydown", onKeyDown);
8768
9094
  }, [dispatch]);
8769
- (0, import_react20.useEffect)(() => {
9095
+ (0, import_react21.useEffect)(() => {
8770
9096
  if (!state.editor) return;
8771
9097
  const editorEl = state.editor.element;
8772
9098
  const onPointerDown = (event) => {
@@ -8779,31 +9105,32 @@ function App() {
8779
9105
  }, [state.editor, dispatch]);
8780
9106
  if (!session) return null;
8781
9107
  if (state.hidden) {
8782
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DispatchContext.Provider, { value: dispatch, children: null });
8783
- }
8784
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DispatchContext.Provider, { value: dispatch, children: [
8785
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PickLayer, {}),
8786
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PeerCursors, {}),
8787
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Toolbar, {}),
8788
- state.editor?.kind === "copy" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(InlineEditor, { editor: state.editor }),
8789
- state.editor?.kind === "image" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ImageEditor, { editor: state.editor }),
8790
- state.editor && state.editor.kind !== "copy" && state.editor.kind !== "image" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NoteComposer, { editor: state.editor }),
8791
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pins, {}),
8792
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(QuickComment, {}),
8793
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Panel, {}),
8794
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Badge, {}),
8795
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CoachMark, {}),
8796
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CheatSheet, {}),
8797
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(EmblemaConnect, {}),
8798
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ConfirmHost, {}),
8799
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ToastHost, {})
9108
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DispatchContext.Provider, { value: dispatch, children: null });
9109
+ }
9110
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DispatchContext.Provider, { value: dispatch, children: [
9111
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PickLayer, {}),
9112
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PeerCursors, {}),
9113
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Toolbar, {}),
9114
+ state.editor?.kind === "copy" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InlineEditor, { editor: state.editor }),
9115
+ state.editor?.kind === "image" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ImageEditor, { editor: state.editor }),
9116
+ state.editor && state.editor.kind !== "copy" && state.editor.kind !== "image" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NoteComposer, { editor: state.editor }),
9117
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pins, {}),
9118
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(QuickComment, {}),
9119
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Panel, {}),
9120
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Badge, {}),
9121
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CoachMark, {}),
9122
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CheatSheet, {}),
9123
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmblemaConnect, {}),
9124
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TerminalConnect, {}),
9125
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ConfirmHost, {}),
9126
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ToastHost, {})
8800
9127
  ] });
8801
9128
  }
8802
- var import_react20, import_jsx_runtime18;
9129
+ var import_react21, import_jsx_runtime19;
8803
9130
  var init_App = __esm({
8804
9131
  "src/client/App.tsx"() {
8805
9132
  "use strict";
8806
- import_react20 = require("react");
9133
+ import_react21 = require("react");
8807
9134
  init_env();
8808
9135
  init_persist();
8809
9136
  init_reveal();
@@ -8819,6 +9146,7 @@ var init_App = __esm({
8819
9146
  init_Badge();
8820
9147
  init_CheatSheet();
8821
9148
  init_EmblemaConnect();
9149
+ init_TerminalConnect();
8822
9150
  init_CoachMark();
8823
9151
  init_Confirm();
8824
9152
  init_ImageEditor();
@@ -8831,14 +9159,14 @@ var init_App = __esm({
8831
9159
  init_Pins();
8832
9160
  init_Toolbar();
8833
9161
  init_Toast();
8834
- import_jsx_runtime18 = require("react/jsx-runtime");
9162
+ import_jsx_runtime19 = require("react/jsx-runtime");
8835
9163
  }
8836
9164
  });
8837
9165
 
8838
9166
  // src/client/ReviewKit.tsx
8839
9167
  function ShadowHost({ config }) {
8840
- const [mount, setMount] = (0, import_react21.useState)(null);
8841
- (0, import_react21.useEffect)(() => {
9168
+ const [mount, setMount] = (0, import_react22.useState)(null);
9169
+ (0, import_react22.useEffect)(() => {
8842
9170
  const host = document.createElement("div");
8843
9171
  host.setAttribute(HOST_ATTR, "");
8844
9172
  host.style.position = "fixed";
@@ -8874,15 +9202,15 @@ function ShadowHost({ config }) {
8874
9202
  }, []);
8875
9203
  if (!mount) return null;
8876
9204
  return (0, import_react_dom.createPortal)(
8877
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StoreProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(App, {}) }),
9205
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StoreProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(App, {}) }),
8878
9206
  mount
8879
9207
  );
8880
9208
  }
8881
9209
  function ReviewKit(props) {
8882
- const [active2, setActive] = (0, import_react21.useState)(false);
9210
+ const [active2, setActive] = (0, import_react22.useState)(false);
8883
9211
  const { enabled, token, allowedHosts, devAutoOn } = props;
8884
9212
  const hostsKey = allowedHosts?.join("\0") ?? "";
8885
- (0, import_react21.useEffect)(() => {
9213
+ (0, import_react22.useEffect)(() => {
8886
9214
  if (enabled === false) {
8887
9215
  setActive(false);
8888
9216
  return;
@@ -8893,13 +9221,13 @@ function ReviewKit(props) {
8893
9221
  return () => window.removeEventListener(DEACTIVATE_EVENT, onDeactivate);
8894
9222
  }, [enabled, token, devAutoOn, hostsKey]);
8895
9223
  if (enabled === false || !active2) return null;
8896
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ShadowHost, { config: props });
9224
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ShadowHost, { config: props });
8897
9225
  }
8898
- var import_react21, import_react_dom, import_jsx_runtime19;
9226
+ var import_react22, import_react_dom, import_jsx_runtime20;
8899
9227
  var init_ReviewKit = __esm({
8900
9228
  "src/client/ReviewKit.tsx"() {
8901
9229
  "use strict";
8902
- import_react21 = require("react");
9230
+ import_react22 = require("react");
8903
9231
  import_react_dom = require("react-dom");
8904
9232
  init_env();
8905
9233
  init_pointer();
@@ -8907,7 +9235,7 @@ var init_ReviewKit = __esm({
8907
9235
  init_target();
8908
9236
  init_store();
8909
9237
  init_App();
8910
- import_jsx_runtime19 = require("react/jsx-runtime");
9238
+ import_jsx_runtime20 = require("react/jsx-runtime");
8911
9239
  }
8912
9240
  });
8913
9241
 
@@ -8954,19 +9282,19 @@ __export(lazy_exports, {
8954
9282
  module.exports = __toCommonJS(lazy_exports);
8955
9283
 
8956
9284
  // src/LazyReviewKit.tsx
8957
- var import_react22 = require("react");
9285
+ var import_react23 = require("react");
8958
9286
  init_activate();
8959
- var import_jsx_runtime20 = require("react/jsx-runtime");
9287
+ var import_jsx_runtime21 = require("react/jsx-runtime");
8960
9288
  var coreModule = null;
8961
9289
  function loadCore() {
8962
9290
  if (!coreModule) coreModule = Promise.resolve().then(() => (init_client(), client_exports)).then((mod) => mod.ReviewKit);
8963
9291
  return coreModule;
8964
9292
  }
8965
9293
  function LazyReviewKit(props) {
8966
- const [Core, setCore] = (0, import_react22.useState)(null);
9294
+ const [Core, setCore] = (0, import_react23.useState)(null);
8967
9295
  const { enabled, token, allowedHosts, devAutoOn } = props;
8968
9296
  const hostsKey = allowedHosts?.join(" ") ?? "";
8969
- (0, import_react22.useEffect)(() => {
9297
+ (0, import_react23.useEffect)(() => {
8970
9298
  if (!shouldActivate({ enabled, token, allowedHosts, devAutoOn })) return;
8971
9299
  let cancelled = false;
8972
9300
  loadCore().then((component) => {
@@ -8979,7 +9307,7 @@ function LazyReviewKit(props) {
8979
9307
  };
8980
9308
  }, [enabled, token, devAutoOn, hostsKey]);
8981
9309
  if (!Core || enabled === false) return null;
8982
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Core, { ...props });
9310
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Core, { ...props });
8983
9311
  }
8984
9312
  // Annotate the CommonJS export names for ESM import in node:
8985
9313
  0 && (module.exports = {