@satanwagen/reviewkit 0.1.3 → 0.1.4

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,15 @@ var init_identity = __esm({
5061
5074
  });
5062
5075
 
5063
5076
  // src/client/sync.ts
5077
+ function resolveSyncUrl(config) {
5078
+ return typeof config.syncUrl === "string" && config.syncUrl !== "" ? config.syncUrl : DEFAULT_SYNC_URL;
5079
+ }
5080
+ function resolveSyncToken(config) {
5081
+ if (config.sync === false) return null;
5082
+ const explicit = typeof config.syncToken === "string" && config.syncToken !== "" ? config.syncToken : null;
5083
+ const fallback = typeof config.token === "string" && config.token !== "" ? config.token : null;
5084
+ return explicit ?? fallback;
5085
+ }
5064
5086
  function toPeerState(peer) {
5065
5087
  return {
5066
5088
  id: peer.id,
@@ -5086,20 +5108,43 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
5086
5108
  const stateRef = (0, import_react4.useRef)(state);
5087
5109
  stateRef.current = state;
5088
5110
  const myIdRef = (0, import_react4.useRef)("");
5089
- const enabled = typeof config.syncToken === "string" && config.syncToken !== "" && typeof config.syncUrl === "string" && config.syncUrl !== "";
5111
+ const syncToken = resolveSyncToken(config);
5112
+ const syncUrl = resolveSyncUrl(config);
5113
+ const enabled = syncToken !== null;
5090
5114
  const author = state.session?.author ?? "";
5091
5115
  const hasSession = state.session !== null;
5092
5116
  (0, import_react4.useEffect)(() => {
5093
5117
  if (!enabled || !hasSession) return;
5118
+ const dispatchGuard = rawDispatch;
5119
+ if (syncToken.length < MIN_SYNC_TOKEN_LENGTH) {
5120
+ dispatchGuard({ type: "SYNC_STATUS", status: "offline", reason: "token-short" });
5121
+ if (!warnedShortToken) {
5122
+ warnedShortToken = true;
5123
+ console.warn(
5124
+ `[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.`
5125
+ );
5126
+ }
5127
+ return () => dispatchGuard({ type: "SYNC_STATUS", status: "disabled", reason: null });
5128
+ }
5094
5129
  const id = reviewerId();
5095
5130
  myIdRef.current = id;
5096
5131
  const dispatch = rawDispatch;
5097
5132
  const sync = createRkSync({
5098
- token: config.syncToken,
5099
- url: config.syncUrl,
5133
+ token: syncToken,
5134
+ url: syncUrl,
5100
5135
  user: { id, name: author || "Reviewer", color: colorForReviewer(id) },
5101
5136
  handlers: {
5102
- onStatus: (status) => dispatch({ type: "SYNC_STATUS", status }),
5137
+ onStatus: (status) => dispatch({
5138
+ type: "SYNC_STATUS",
5139
+ status,
5140
+ // Offline with no server verdict = the socket never got through
5141
+ // (server down, CSP connect-src, network); a verdict keeps its reason.
5142
+ ...status === "offline" ? { reason: stateRef.current.syncReason ?? "unreachable" } : {}
5143
+ }),
5144
+ onError: (code) => {
5145
+ if (code === "bad-token") dispatch({ type: "SYNC_STATUS", status: "offline", reason: "bad-token" });
5146
+ else if (code === "room-full") dispatch({ type: "SYNC_STATUS", status: "offline", reason: "room-full" });
5147
+ },
5103
5148
  onSnapshot: (items, peers, deletedIds = []) => {
5104
5149
  const safeItems = items.map(sanitizeRemoteItem).filter((item) => item !== null);
5105
5150
  dispatch({ type: "SYNC_SNAPSHOT", items: safeItems });
@@ -5156,10 +5201,10 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
5156
5201
  if (activeSyncRef === sync) activeSyncRef = null;
5157
5202
  setEffectBroadcaster2(null);
5158
5203
  sync.stop();
5159
- dispatch({ type: "SYNC_STATUS", status: "disabled" });
5204
+ dispatch({ type: "SYNC_STATUS", status: "disabled", reason: null });
5160
5205
  dispatch({ type: "PEERS_SET", peers: [] });
5161
5206
  };
5162
- }, [enabled, hasSession, config.syncToken, config.syncUrl, author, rawDispatch]);
5207
+ }, [enabled, hasSession, syncToken, syncUrl, author, rawDispatch]);
5163
5208
  const wrapped = (0, import_react4.useMemo)(() => {
5164
5209
  return (action) => {
5165
5210
  const prev = stateRef.current;
@@ -5222,7 +5267,7 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
5222
5267
  }, [enabled, editorOpen]);
5223
5268
  return enabled ? wrapped : rawDispatch;
5224
5269
  }
5225
- var import_react4, activeSyncRef, MIRRORED_EXCLUDED;
5270
+ var import_react4, DEFAULT_SYNC_URL, MIN_SYNC_TOKEN_LENGTH, warnedShortToken, activeSyncRef, MIRRORED_EXCLUDED;
5226
5271
  var init_sync = __esm({
5227
5272
  "src/client/sync.ts"() {
5228
5273
  "use strict";
@@ -5234,6 +5279,9 @@ var init_sync = __esm({
5234
5279
  init_schema();
5235
5280
  init_store();
5236
5281
  init_identity();
5282
+ DEFAULT_SYNC_URL = "wss://2-59-219-26.sslip.io/rk-sync";
5283
+ MIN_SYNC_TOKEN_LENGTH = 8;
5284
+ warnedShortToken = false;
5237
5285
  activeSyncRef = null;
5238
5286
  MIRRORED_EXCLUDED = /* @__PURE__ */ new Set(["SYNC_SNAPSHOT", "REMOTE_ADD", "REMOTE_PATCH", "REMOTE_STATUS", "REMOTE_DELETE", "INIT_SESSION"]);
5239
5287
  }
@@ -5716,10 +5764,10 @@ function EmblemaConnect() {
5716
5764
  state === null && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "rk-modal-text", children: [
5717
5765
  "The local sync agent isn't running. In the project repo run:",
5718
5766
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("code", { className: "rk-connect-cmd", children: [
5719
- "npx @satanwagen/reviewkit-cli init --origin ",
5767
+ "npx -p @satanwagen/reviewkit-cli reviewkit-emblema init --origin ",
5720
5768
  window.location.origin
5721
5769
  ] }),
5722
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "rk-connect-cmd", children: "npx @satanwagen/reviewkit-cli serve" }),
5770
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "rk-connect-cmd", children: "npx -p @satanwagen/reviewkit-cli reviewkit-emblema serve" }),
5723
5771
  "then reopen this dialog."
5724
5772
  ] }),
5725
5773
  state !== null && state !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
@@ -5817,12 +5865,247 @@ var init_EmblemaConnect = __esm({
5817
5865
  }
5818
5866
  });
5819
5867
 
5868
+ // src/integrations/terminal.ts
5869
+ async function fetchJson2(url, init, timeoutMs) {
5870
+ const abort = new AbortController();
5871
+ const timer = window.setTimeout(() => abort.abort(), timeoutMs);
5872
+ try {
5873
+ return await fetch(url, { ...init, signal: abort.signal });
5874
+ } finally {
5875
+ window.clearTimeout(timer);
5876
+ }
5877
+ }
5878
+ async function probeTerminal() {
5879
+ for (const port of TERMINAL_PAIR_PORTS) {
5880
+ try {
5881
+ const res = await fetchJson2(`http://127.0.0.1:${port}/pair`, { method: "GET" }, 900);
5882
+ if (!res.ok) continue;
5883
+ const body = await res.json();
5884
+ if (typeof body === "object" && body !== null && body.app === "reviewkit-cli") {
5885
+ const b = body;
5886
+ return {
5887
+ port,
5888
+ cwd: typeof b.cwd === "string" ? b.cwd : void 0,
5889
+ projects: Array.isArray(b.projects) ? b.projects.filter((p) => typeof p === "string") : []
5890
+ };
5891
+ }
5892
+ } catch {
5893
+ }
5894
+ }
5895
+ return null;
5896
+ }
5897
+ async function pairTerminal(port, key) {
5898
+ try {
5899
+ const res = await fetchJson2(
5900
+ `http://127.0.0.1:${port}/pair`,
5901
+ { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ key }) },
5902
+ 5e3
5903
+ );
5904
+ const body = await res.json().catch(() => null);
5905
+ if (res.ok && body?.ok) return { ok: true, name: body.name ?? "", repo: body.repo ?? null };
5906
+ return { ok: false, error: body?.error ?? `HTTP ${res.status}` };
5907
+ } catch {
5908
+ return { ok: false, error: "the terminal stopped answering" };
5909
+ }
5910
+ }
5911
+ var TERMINAL_PAIR_PORTS;
5912
+ var init_terminal = __esm({
5913
+ "src/integrations/terminal.ts"() {
5914
+ "use strict";
5915
+ TERMINAL_PAIR_PORTS = [48780, 48781, 48782, 48783];
5916
+ }
5917
+ });
5918
+
5919
+ // src/client/terminalKey.ts
5920
+ function base64url(text) {
5921
+ const bytes = new TextEncoder().encode(text);
5922
+ let binary = "";
5923
+ for (const byte of bytes) binary += String.fromCharCode(byte);
5924
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
5925
+ }
5926
+ function encodeTerminalKey(fields) {
5927
+ const payload = { v: TERMINAL_KEY_VERSION, ...fields };
5928
+ return TERMINAL_KEY_PREFIX + base64url(JSON.stringify(payload));
5929
+ }
5930
+ function currentTerminalKey(syncUrl, syncToken) {
5931
+ const origin = window.location.origin;
5932
+ let route = "/";
5933
+ try {
5934
+ route = window.location.pathname || "/";
5935
+ } catch {
5936
+ }
5937
+ return encodeTerminalKey({ name: window.location.hostname, origin, syncUrl, syncToken, route });
5938
+ }
5939
+ var TERMINAL_KEY_PREFIX, TERMINAL_KEY_VERSION;
5940
+ var init_terminalKey = __esm({
5941
+ "src/client/terminalKey.ts"() {
5942
+ "use strict";
5943
+ TERMINAL_KEY_PREFIX = "rkc_";
5944
+ TERMINAL_KEY_VERSION = 1;
5945
+ }
5946
+ });
5947
+
5948
+ // src/client/components/TerminalConnect.tsx
5949
+ function shortKey2(key) {
5950
+ return `${key.slice(0, 8)}\u2026${key.slice(-6)}`;
5951
+ }
5952
+ function shortPath(path) {
5953
+ if (!path) return "";
5954
+ const parts = path.split("/").filter(Boolean);
5955
+ return parts.length > 2 ? `\u2026/${parts.slice(-2).join("/")}` : path;
5956
+ }
5957
+ function TerminalConnect() {
5958
+ const { terminalConnectOpen } = useStore();
5959
+ const config = useConfig();
5960
+ const dispatch = useDispatch();
5961
+ const [phase, setPhase] = (0, import_react7.useState)("probing");
5962
+ const [probe, setProbe] = (0, import_react7.useState)(null);
5963
+ const [paired, setPaired] = (0, import_react7.useState)(null);
5964
+ const [showManual, setShowManual] = (0, import_react7.useState)(false);
5965
+ const syncToken = resolveSyncToken(config);
5966
+ const key = terminalConnectOpen && syncToken ? currentTerminalKey(resolveSyncUrl(config), syncToken) : null;
5967
+ (0, import_react7.useEffect)(() => {
5968
+ if (!terminalConnectOpen) return;
5969
+ let cancelled = false;
5970
+ setPhase("probing");
5971
+ setProbe(null);
5972
+ setPaired(null);
5973
+ setShowManual(false);
5974
+ const look = () => void probeTerminal().then((found) => {
5975
+ if (cancelled) return;
5976
+ setProbe(found);
5977
+ setPhase((current) => current === "pairing" || current === "paired" ? current : found ? "found" : "missing");
5978
+ });
5979
+ look();
5980
+ const timer = window.setInterval(look, 2e3);
5981
+ return () => {
5982
+ cancelled = true;
5983
+ window.clearInterval(timer);
5984
+ };
5985
+ }, [terminalConnectOpen]);
5986
+ if (!terminalConnectOpen) return null;
5987
+ const close = () => dispatch({ type: "SET_TERMINAL_CONNECT", open: false });
5988
+ const copy = async (value, what) => {
5989
+ try {
5990
+ await navigator.clipboard.writeText(value);
5991
+ toast(dispatch, `${what} copied`, "success");
5992
+ } catch {
5993
+ toast(dispatch, "Copy failed \u2014 select the text manually", "error");
5994
+ }
5995
+ };
5996
+ const connect = () => {
5997
+ if (!probe || !key) return;
5998
+ setPhase("pairing");
5999
+ void pairTerminal(probe.port, key).then((result) => {
6000
+ if (result.ok) {
6001
+ setPaired({ name: result.name, repo: result.repo });
6002
+ setPhase("paired");
6003
+ toast(dispatch, `Terminal paired as \u201C${result.name}\u201D`, "success");
6004
+ } else {
6005
+ setPhase("found");
6006
+ toast(dispatch, `Pairing failed: ${result.error}`, "error");
6007
+ }
6008
+ });
6009
+ };
6010
+ const connectCmd = key ? `npx -y @satanwagen/reviewkit-cli connect ${key}` : "";
6011
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6012
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "rk-backdrop", onClick: close }),
6013
+ /* @__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: [
6014
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
6015
+ "Connect terminal / agent",
6016
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { flex: 1 } }),
6017
+ /* @__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 }) })
6018
+ ] }),
6019
+ !key && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
6020
+ "Live sync is off on this page (",
6021
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "sync=false" }),
6022
+ " or no token), so there is no shared room a terminal could read."
6023
+ ] }),
6024
+ key && phase === "paired" && paired && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
6025
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-emblema-dot", "data-state": "live" }),
6026
+ " Paired as ",
6027
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: paired.name }),
6028
+ paired.repo ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6029
+ " in ",
6030
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: shortPath(paired.repo) })
6031
+ ] }) : null,
6032
+ ". The terminal shows this page's comments live, and Claude Code / Cursor can read and resolve them through the ",
6033
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "reviewkit" }),
6034
+ " MCP tools."
6035
+ ] }),
6036
+ key && phase !== "paired" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6037
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
6038
+ phase === "probing" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6039
+ "Looking for a ",
6040
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "reviewkit" }),
6041
+ " terminal on this machine\u2026"
6042
+ ] }),
6043
+ phase === "missing" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6044
+ "No terminal is listening yet. In the site's repo run",
6045
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: "rk-connect-cmd", children: "npx -y @satanwagen/reviewkit-cli setup" }),
6046
+ "and this dialog will pick it up by itself."
6047
+ ] }),
6048
+ (phase === "found" || phase === "pairing") && probe && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6049
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-emblema-dot", "data-state": "live" }),
6050
+ " Terminal found",
6051
+ probe.cwd ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6052
+ " in ",
6053
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: shortPath(probe.cwd) })
6054
+ ] }) : null,
6055
+ ".",
6056
+ probe.projects.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6057
+ " Already paired: ",
6058
+ probe.projects.join(", "),
6059
+ "."
6060
+ ] }) : null
6061
+ ] })
6062
+ ] }),
6063
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-connect-actions", children: [
6064
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6065
+ "button",
6066
+ {
6067
+ type: "button",
6068
+ className: "rk-btn rk-btn-primary",
6069
+ disabled: phase !== "found",
6070
+ onClick: connect,
6071
+ title: "Send this site's connection to the terminal \u2014 nothing to copy",
6072
+ children: phase === "pairing" ? "Connecting\u2026" : "Connect this terminal"
6073
+ }
6074
+ ),
6075
+ /* @__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" })
6076
+ ] }),
6077
+ showManual && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6078
+ /* @__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):" }),
6079
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("code", { className: "rk-connect-cmd", title: connectCmd, children: [
6080
+ "npx -y @satanwagen/reviewkit-cli connect ",
6081
+ shortKey2(key)
6082
+ ] }),
6083
+ /* @__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" }) })
6084
+ ] })
6085
+ ] })
6086
+ ] }) })
6087
+ ] });
6088
+ }
6089
+ var import_react7, import_jsx_runtime6;
6090
+ var init_TerminalConnect = __esm({
6091
+ "src/client/components/TerminalConnect.tsx"() {
6092
+ "use strict";
6093
+ import_react7 = require("react");
6094
+ init_terminal();
6095
+ init_store();
6096
+ init_terminalKey();
6097
+ init_sync();
6098
+ init_icons();
6099
+ import_jsx_runtime6 = require("react/jsx-runtime");
6100
+ }
6101
+ });
6102
+
5820
6103
  // src/client/components/CoachMark.tsx
5821
6104
  function CoachMark() {
5822
6105
  const { coachOpen, session } = useStore();
5823
6106
  const dispatch = useDispatch();
5824
6107
  const config = useConfig();
5825
- const [name, setName] = (0, import_react7.useState)(session?.author ?? config.defaultAuthor ?? "");
6108
+ const [name, setName] = (0, import_react8.useState)(session?.author ?? config.defaultAuthor ?? "");
5826
6109
  if (!coachOpen) return null;
5827
6110
  const done = (startPicking) => {
5828
6111
  if (name.trim() !== "") dispatch({ type: "SET_AUTHOR", author: name.trim() });
@@ -5833,39 +6116,39 @@ function CoachMark() {
5833
6116
  }
5834
6117
  if (startPicking) dispatch({ type: "SET_MODE", mode: "pick" });
5835
6118
  };
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 }),
6119
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach", role: "dialog", "aria-label": "Welcome to review mode", children: [
6120
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rk-coach-accent" }),
6121
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach-body", children: [
6122
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
6123
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconTarget, { size: 16 }),
5841
6124
  " Review mode"
5842
6125
  ] }),
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" }),
6126
+ /* @__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." }),
6127
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach-keys", "aria-label": "Key shortcuts", children: [
6128
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
6129
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "T" }),
5847
6130
  " rewrite"
5848
6131
  ] }),
5849
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
5850
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-kbd", children: "C" }),
6132
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
6133
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "C" }),
5851
6134
  " comment"
5852
6135
  ] }),
5853
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
5854
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-kbd", children: "I" }),
6136
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
6137
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "I" }),
5855
6138
  " image"
5856
6139
  ] }),
5857
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
5858
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-kbd", children: "V" }),
6140
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
6141
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "V" }),
5859
6142
  " select"
5860
6143
  ] }),
5861
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
5862
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-kbd", children: "?" }),
6144
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
6145
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "?" }),
5863
6146
  " all shortcuts"
5864
6147
  ] })
5865
6148
  ] }),
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)(
6149
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
6150
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "rk-label", htmlFor: "rk-author", children: "Your name" }),
6151
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5869
6152
  "input",
5870
6153
  {
5871
6154
  id: "rk-author",
@@ -5879,21 +6162,21 @@ function CoachMark() {
5879
6162
  }
5880
6163
  )
5881
6164
  ] }),
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" })
6165
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 4 }, children: [
6166
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => done(false), children: "Not now" }),
6167
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: () => done(true), children: "Start reviewing" })
5885
6168
  ] })
5886
6169
  ] })
5887
6170
  ] });
5888
6171
  }
5889
- var import_react7, import_jsx_runtime6, COACH_KEY;
6172
+ var import_react8, import_jsx_runtime7, COACH_KEY;
5890
6173
  var init_CoachMark = __esm({
5891
6174
  "src/client/components/CoachMark.tsx"() {
5892
6175
  "use strict";
5893
- import_react7 = require("react");
6176
+ import_react8 = require("react");
5894
6177
  init_store();
5895
6178
  init_icons();
5896
- import_jsx_runtime6 = require("react/jsx-runtime");
6179
+ import_jsx_runtime7 = require("react/jsx-runtime");
5897
6180
  COACH_KEY = "review-kit:coach-dismissed";
5898
6181
  }
5899
6182
  });
@@ -5902,22 +6185,22 @@ var init_CoachMark = __esm({
5902
6185
  function ConfirmHost() {
5903
6186
  const { confirm } = useStore();
5904
6187
  const dispatch = useDispatch();
5905
- const cancelRef = (0, import_react8.useRef)(null);
5906
- (0, import_react8.useEffect)(() => {
6188
+ const cancelRef = (0, import_react9.useRef)(null);
6189
+ (0, import_react9.useEffect)(() => {
5907
6190
  if (confirm) cancelRef.current?.focus();
5908
6191
  }, [confirm]);
5909
6192
  if (!confirm) return null;
5910
6193
  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 })
6194
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
6195
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-backdrop", onClick: close }),
6196
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal", role: "alertdialog", "aria-modal": "true", "aria-label": confirm.title, children: [
6197
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal-body", children: [
6198
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-modal-title", children: confirm.title }),
6199
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-modal-text", children: confirm.message })
5917
6200
  ] }),
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)(
6201
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal-actions", children: [
6202
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { ref: cancelRef, type: "button", className: "rk-btn rk-btn-ghost", onClick: close, children: "Cancel" }),
6203
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5921
6204
  "button",
5922
6205
  {
5923
6206
  type: "button",
@@ -5934,13 +6217,13 @@ function ConfirmHost() {
5934
6217
  ] })
5935
6218
  ] });
5936
6219
  }
5937
- var import_react8, import_jsx_runtime7;
6220
+ var import_react9, import_jsx_runtime8;
5938
6221
  var init_Confirm = __esm({
5939
6222
  "src/client/components/Confirm.tsx"() {
5940
6223
  "use strict";
5941
- import_react8 = require("react");
6224
+ import_react9 = require("react");
5942
6225
  init_store();
5943
- import_jsx_runtime7 = require("react/jsx-runtime");
6226
+ import_jsx_runtime8 = require("react/jsx-runtime");
5944
6227
  }
5945
6228
  });
5946
6229
 
@@ -5993,9 +6276,9 @@ var init_position = __esm({
5993
6276
 
5994
6277
  // src/client/useAnchored.ts
5995
6278
  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)(() => {
6279
+ const ref = (0, import_react10.useRef)(null);
6280
+ const [pos, setPos] = (0, import_react10.useState)(null);
6281
+ (0, import_react10.useLayoutEffect)(() => {
5999
6282
  if (!anchorEl) {
6000
6283
  setPos(null);
6001
6284
  return;
@@ -6024,11 +6307,11 @@ function anchoredStyle(pos) {
6024
6307
  if (!pos) return { visibility: "hidden", transform: "translate3d(-9999px, -9999px, 0)" };
6025
6308
  return { transform: `translate3d(${pos.x}px, ${pos.y}px, 0)`, top: 0, left: 0 };
6026
6309
  }
6027
- var import_react9;
6310
+ var import_react10;
6028
6311
  var init_useAnchored = __esm({
6029
6312
  "src/client/useAnchored.ts"() {
6030
6313
  "use strict";
6031
- import_react9 = require("react");
6314
+ import_react10 = require("react");
6032
6315
  init_position();
6033
6316
  }
6034
6317
  });
@@ -6088,15 +6371,15 @@ function urlFromDataTransfer(dt) {
6088
6371
  function ImageEditor({ editor }) {
6089
6372
  const dispatch = useDispatch();
6090
6373
  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);
6374
+ const [replacement, setReplacement] = (0, import_react11.useState)(null);
6375
+ const [urlValue, setUrlValue] = (0, import_react11.useState)("");
6376
+ const [loading2, setLoading] = (0, import_react11.useState)(false);
6377
+ const [description, setDescription] = (0, import_react11.useState)("");
6378
+ const [priority, setPriority] = (0, import_react11.useState)("nice");
6379
+ const [over, setOver] = (0, import_react11.useState)(false);
6380
+ const fileInput = (0, import_react11.useRef)(null);
6381
+ const abortRef = (0, import_react11.useRef)(null);
6382
+ const debounceRef = (0, import_react11.useRef)(null);
6100
6383
  const { ref, pos } = useAnchored(editor.element, "bottom", 12);
6101
6384
  const image = findImage(editor.element);
6102
6385
  const beforeSrc = image?.currentSrc || image?.src || "";
@@ -6160,7 +6443,7 @@ function ImageEditor({ editor }) {
6160
6443
  }
6161
6444
  }
6162
6445
  };
6163
- (0, import_react10.useEffect)(() => {
6446
+ (0, import_react11.useEffect)(() => {
6164
6447
  if (debounceRef.current !== null) window.clearTimeout(debounceRef.current);
6165
6448
  if (urlValue.trim() === "" || replacement !== null) return;
6166
6449
  debounceRef.current = window.setTimeout(() => {
@@ -6170,8 +6453,8 @@ function ImageEditor({ editor }) {
6170
6453
  if (debounceRef.current !== null) window.clearTimeout(debounceRef.current);
6171
6454
  };
6172
6455
  }, [urlValue, replacement]);
6173
- (0, import_react10.useEffect)(() => () => abortRef.current?.abort(), []);
6174
- (0, import_react10.useEffect)(() => {
6456
+ (0, import_react11.useEffect)(() => () => abortRef.current?.abort(), []);
6457
+ (0, import_react11.useEffect)(() => {
6175
6458
  const onPaste = (event) => {
6176
6459
  const data = event.clipboardData;
6177
6460
  if (!data) return;
@@ -6249,23 +6532,23 @@ function ImageEditor({ editor }) {
6249
6532
  toast(dispatch, "Image proposal saved", "success");
6250
6533
  };
6251
6534
  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 }),
6535
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Replace image", children: [
6536
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-head", children: [
6537
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconImage, { size: 14 }),
6255
6538
  "Replace image"
6256
6539
  ] }),
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" })
6540
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-body", children: [
6541
+ 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: [
6542
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { className: "rk-thumb", children: [
6543
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: beforeSrc, alt: "Current" }),
6544
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { children: "Before" })
6262
6545
  ] }),
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" })
6546
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { className: "rk-thumb", children: [
6547
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: previewSrc, alt: "Proposed replacement" }),
6548
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { children: replacement.kind === "url" ? "After \xB7 linked" : "After" })
6266
6549
  ] })
6267
- ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
6268
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
6550
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
6551
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
6269
6552
  "button",
6270
6553
  {
6271
6554
  type: "button",
@@ -6278,18 +6561,18 @@ function ImageEditor({ editor }) {
6278
6561
  onDragLeave: () => setOver(false),
6279
6562
  onDrop,
6280
6563
  children: [
6281
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconUpload, { size: 18 }),
6282
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
6564
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconUpload, { size: 18 }),
6565
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
6283
6566
  "Drop an image \u2014 from your disk or another tab \u2014",
6284
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("br", {}),
6567
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("br", {}),
6285
6568
  "or click to browse (max 2 MB)"
6286
6569
  ] })
6287
6570
  ]
6288
6571
  }
6289
6572
  ),
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)(
6573
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-url", children: [
6574
+ loading2 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-spinner", "aria-label": "Loading image" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconLink, { size: 13 }),
6575
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6293
6576
  "input",
6294
6577
  {
6295
6578
  className: "rk-input",
@@ -6304,9 +6587,9 @@ function ImageEditor({ editor }) {
6304
6587
  )
6305
6588
  ] })
6306
6589
  ] }),
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)(
6590
+ replacement && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: clearReplacement, children: "Remove replacement" }),
6591
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { ref: fileInput, type: "file", accept: "image/*", hidden: true, onChange: onPick }),
6592
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6310
6593
  "textarea",
6311
6594
  {
6312
6595
  className: "rk-textarea",
@@ -6316,35 +6599,35 @@ function ImageEditor({ editor }) {
6316
6599
  rows: 2
6317
6600
  }
6318
6601
  ),
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" })
6602
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
6603
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
6604
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
6322
6605
  ] })
6323
6606
  ] }),
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" }),
6607
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-foot", children: [
6608
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "rk-hint", children: [
6609
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-kbd", children: "esc" }),
6327
6610
  " cancel"
6328
6611
  ] }),
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" })
6612
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-actions", children: [
6613
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
6614
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
6332
6615
  ] })
6333
6616
  ] })
6334
6617
  ] });
6335
6618
  }
6336
- var import_react10, import_jsx_runtime8, MAX_BYTES, FETCH_TIMEOUT_MS, PROBE_TIMEOUT_MS;
6619
+ var import_react11, import_jsx_runtime9, MAX_BYTES, FETCH_TIMEOUT_MS, PROBE_TIMEOUT_MS;
6337
6620
  var init_ImageEditor = __esm({
6338
6621
  "src/client/components/ImageEditor.tsx"() {
6339
6622
  "use strict";
6340
- import_react10 = require("react");
6623
+ import_react11 = require("react");
6341
6624
  init_store();
6342
6625
  init_id();
6343
6626
  init_identity();
6344
6627
  init_target();
6345
6628
  init_useAnchored();
6346
6629
  init_icons();
6347
- import_jsx_runtime8 = require("react/jsx-runtime");
6630
+ import_jsx_runtime9 = require("react/jsx-runtime");
6348
6631
  MAX_BYTES = 2 * 1024 * 1024;
6349
6632
  FETCH_TIMEOUT_MS = 12e3;
6350
6633
  PROBE_TIMEOUT_MS = 8e3;
@@ -6355,19 +6638,19 @@ var init_ImageEditor = __esm({
6355
6638
  function InlineEditor({ editor }) {
6356
6639
  const dispatch = useDispatch();
6357
6640
  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);
6641
+ const [after, setAfter] = (0, import_react12.useState)(() => editor.element.innerText);
6642
+ const [priority, setPriority] = (0, import_react12.useState)("nice");
6643
+ const [note, setNote] = (0, import_react12.useState)("");
6644
+ const original = (0, import_react12.useRef)(null);
6645
+ const baseline = (0, import_react12.useRef)(null);
6646
+ const [sizeDelta, setSizeDelta] = (0, import_react12.useState)(0);
6647
+ const [widthDelta, setWidthDelta] = (0, import_react12.useState)(0);
6648
+ const [clipped, setClipped] = (0, import_react12.useState)(false);
6649
+ const ringRef = (0, import_react12.useRef)(null);
6650
+ const afterRef = (0, import_react12.useRef)(null);
6368
6651
  const { ref, pos } = useAnchored(editor.element, "bottom", 12);
6369
6652
  const element = editor.element;
6370
- (0, import_react11.useEffect)(() => {
6653
+ (0, import_react12.useEffect)(() => {
6371
6654
  const el = element;
6372
6655
  original.current = { html: el.innerHTML, text: el.innerText, styleAttr: el.getAttribute("style") };
6373
6656
  const rect = el.getBoundingClientRect();
@@ -6397,8 +6680,8 @@ function InlineEditor({ editor }) {
6397
6680
  }
6398
6681
  };
6399
6682
  }, [element]);
6400
- const focusedOnce = (0, import_react11.useRef)(false);
6401
- (0, import_react11.useEffect)(() => {
6683
+ const focusedOnce = (0, import_react12.useRef)(false);
6684
+ (0, import_react12.useEffect)(() => {
6402
6685
  const field = afterRef.current;
6403
6686
  if (pos === null || focusedOnce.current || !field) return;
6404
6687
  focusedOnce.current = true;
@@ -6406,7 +6689,7 @@ function InlineEditor({ editor }) {
6406
6689
  const end = field.value.length;
6407
6690
  field.setSelectionRange(end, end);
6408
6691
  }, [pos]);
6409
- (0, import_react11.useEffect)(() => {
6692
+ (0, import_react12.useEffect)(() => {
6410
6693
  const field = afterRef.current;
6411
6694
  if (!field) return;
6412
6695
  field.style.height = "auto";
@@ -6416,7 +6699,7 @@ function InlineEditor({ editor }) {
6416
6699
  setAfter(value);
6417
6700
  if (element.innerText !== value) setElementText(element, value);
6418
6701
  };
6419
- (0, import_react11.useEffect)(() => {
6702
+ (0, import_react12.useEffect)(() => {
6420
6703
  let raf = 0;
6421
6704
  let lastDelta = 0;
6422
6705
  let lastWidth = 0;
@@ -6486,7 +6769,7 @@ function InlineEditor({ editor }) {
6486
6769
  cancel();
6487
6770
  }
6488
6771
  };
6489
- (0, import_react11.useEffect)(() => {
6772
+ (0, import_react12.useEffect)(() => {
6490
6773
  const el = element;
6491
6774
  const onKeyDown = (event) => {
6492
6775
  if (event.key === "Enter" && !event.shiftKey) {
@@ -6504,19 +6787,19 @@ function InlineEditor({ editor }) {
6504
6787
  });
6505
6788
  const before = original.current?.text ?? "";
6506
6789
  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 }),
6790
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
6791
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: ringRef, className: "rk-edit-ring" }),
6792
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Rewrite text", children: [
6793
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-head", children: [
6794
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconText, { size: 14 }),
6512
6795
  "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: [
6796
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-spacer" }),
6797
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-delta", "aria-live": "polite", children: [
6515
6798
  before.length,
6516
6799
  " \u2192 ",
6517
6800
  after.length,
6518
6801
  " ",
6519
- delta !== 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: delta > 0 ? "rk-plus" : "rk-minus", children: [
6802
+ delta !== 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: delta > 0 ? "rk-plus" : "rk-minus", children: [
6520
6803
  "(",
6521
6804
  delta > 0 ? "+" : "",
6522
6805
  delta,
@@ -6524,15 +6807,15 @@ function InlineEditor({ editor }) {
6524
6807
  ] })
6525
6808
  ] })
6526
6809
  ] }),
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 })
6810
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-body", children: [
6811
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff", "aria-label": "Before and after", children: [
6812
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
6813
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
6814
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-text", children: before })
6532
6815
  ] }),
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)(
6816
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
6817
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-tag", children: "After" }),
6818
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6536
6819
  "textarea",
6537
6820
  {
6538
6821
  ref: afterRef,
@@ -6546,11 +6829,11 @@ function InlineEditor({ editor }) {
6546
6829
  )
6547
6830
  ] })
6548
6831
  ] }),
6549
- (Math.abs(sizeDelta) > 2 || Math.abs(widthDelta) > 4 || clipped) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-size-note", role: "status", children: [
6832
+ (Math.abs(sizeDelta) > 2 || Math.abs(widthDelta) > 4 || clipped) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-size-note", role: "status", children: [
6550
6833
  Math.abs(sizeDelta) > 2 && (() => {
6551
6834
  const lines = baseline.current ? Math.round(Math.abs(sizeDelta) / baseline.current.lineHeight) : 0;
6552
6835
  const lineNote = lines >= 1 ? ` (~${lines} line${lines === 1 ? "" : "s"})` : "";
6553
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
6836
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
6554
6837
  "Block ",
6555
6838
  sizeDelta > 0 ? "grew" : "shrank",
6556
6839
  " by ",
@@ -6560,16 +6843,16 @@ function InlineEditor({ editor }) {
6560
6843
  " \u2014 as it would with this text live."
6561
6844
  ] });
6562
6845
  })(),
6563
- Math.abs(sizeDelta) <= 2 && Math.abs(widthDelta) > 4 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
6846
+ Math.abs(sizeDelta) <= 2 && Math.abs(widthDelta) > 4 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
6564
6847
  "Block got ",
6565
6848
  widthDelta > 0 ? "wider" : "narrower",
6566
6849
  " by ",
6567
6850
  Math.abs(widthDelta),
6568
6851
  " px \u2014 as it would with this text live."
6569
6852
  ] }),
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." })
6853
+ 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
6854
  ] }),
6572
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6855
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6573
6856
  "input",
6574
6857
  {
6575
6858
  className: "rk-input",
@@ -6578,41 +6861,41 @@ function InlineEditor({ editor }) {
6578
6861
  onChange: (event) => setNote(event.target.value)
6579
6862
  }
6580
6863
  ),
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" })
6864
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
6865
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
6866
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
6584
6867
  ] })
6585
6868
  ] }),
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" }),
6869
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-foot", children: [
6870
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-hint", children: [
6871
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
6589
6872
  " save \xB7 ",
6590
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-kbd", children: "\u21E7\u21B5" }),
6873
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u21E7\u21B5" }),
6591
6874
  " newline \xB7",
6592
6875
  " ",
6593
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-kbd", children: "esc" }),
6876
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "esc" }),
6594
6877
  " cancel"
6595
6878
  ] }),
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" })
6879
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-actions", children: [
6880
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: cancel, children: "Cancel" }),
6881
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: commit, children: "Save" })
6599
6882
  ] })
6600
6883
  ] })
6601
6884
  ] })
6602
6885
  ] });
6603
6886
  }
6604
- var import_react11, import_jsx_runtime9;
6887
+ var import_react12, import_jsx_runtime10;
6605
6888
  var init_InlineEditor = __esm({
6606
6889
  "src/client/components/InlineEditor.tsx"() {
6607
6890
  "use strict";
6608
- import_react11 = require("react");
6891
+ import_react12 = require("react");
6609
6892
  init_store();
6610
6893
  init_id();
6611
6894
  init_identity();
6612
6895
  init_preview();
6613
6896
  init_useAnchored();
6614
6897
  init_icons();
6615
- import_jsx_runtime9 = require("react/jsx-runtime");
6898
+ import_jsx_runtime10 = require("react/jsx-runtime");
6616
6899
  }
6617
6900
  });
6618
6901
 
@@ -6620,14 +6903,14 @@ var init_InlineEditor = __esm({
6620
6903
  function NoteComposer({ editor }) {
6621
6904
  const dispatch = useDispatch();
6622
6905
  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);
6906
+ const [text, setText] = (0, import_react13.useState)("");
6907
+ const [direction, setDirection] = (0, import_react13.useState)(void 0);
6908
+ const [priority, setPriority] = (0, import_react13.useState)("nice");
6909
+ const textareaRef = (0, import_react13.useRef)(null);
6627
6910
  const { ref, pos } = useAnchored(editor.element, "bottom", 12);
6628
6911
  const { kind } = editor;
6629
- const focusedOnce = (0, import_react12.useRef)(false);
6630
- (0, import_react12.useEffect)(() => {
6912
+ const focusedOnce = (0, import_react13.useRef)(false);
6913
+ (0, import_react13.useEffect)(() => {
6631
6914
  const field = textareaRef.current;
6632
6915
  if (pos === null || focusedOnce.current || !field) return;
6633
6916
  focusedOnce.current = true;
@@ -6686,13 +6969,13 @@ function NoteComposer({ editor }) {
6686
6969
  save();
6687
6970
  }
6688
6971
  };
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: [
6972
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": TITLES[kind], children: [
6973
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-head", children: [
6691
6974
  iconForType(kind),
6692
6975
  TITLES[kind]
6693
6976
  ] }),
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)(
6977
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-body", children: [
6978
+ 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
6979
  "button",
6697
6980
  {
6698
6981
  type: "button",
@@ -6702,7 +6985,7 @@ function NoteComposer({ editor }) {
6702
6985
  },
6703
6986
  option
6704
6987
  )) }),
6705
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6988
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6706
6989
  "textarea",
6707
6990
  {
6708
6991
  ref: textareaRef,
@@ -6714,36 +6997,36 @@ function NoteComposer({ editor }) {
6714
6997
  rows: 3
6715
6998
  }
6716
6999
  ),
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" })
7000
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
7001
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
7002
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
6720
7003
  ] })
6721
7004
  ] }),
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" }),
7005
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-foot", children: [
7006
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-hint", children: [
7007
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-kbd", children: "\u2318\u21B5" }),
6725
7008
  " save \xB7 ",
6726
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "esc" }),
7009
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-kbd", children: "esc" }),
6727
7010
  " cancel"
6728
7011
  ] }),
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" })
7012
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-actions", children: [
7013
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
7014
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
6732
7015
  ] })
6733
7016
  ] })
6734
7017
  ] });
6735
7018
  }
6736
- var import_react12, import_jsx_runtime10, TITLES, PLACEHOLDERS;
7019
+ var import_react13, import_jsx_runtime11, TITLES, PLACEHOLDERS;
6737
7020
  var init_NoteComposer = __esm({
6738
7021
  "src/client/components/NoteComposer.tsx"() {
6739
7022
  "use strict";
6740
- import_react12 = require("react");
7023
+ import_react13 = require("react");
6741
7024
  init_store();
6742
7025
  init_id();
6743
7026
  init_identity();
6744
7027
  init_useAnchored();
6745
7028
  init_icons();
6746
- import_jsx_runtime10 = require("react/jsx-runtime");
7029
+ import_jsx_runtime11 = require("react/jsx-runtime");
6747
7030
  TITLES = {
6748
7031
  comment: "Comment",
6749
7032
  delete: "Mark for deletion",
@@ -6837,24 +7120,24 @@ function formatBytes(bytes) {
6837
7120
  function CopyDiff({ before, after }) {
6838
7121
  const parts = diffParts(before, after);
6839
7122
  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: [
7123
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diffview", children: [
7124
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
7125
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
7126
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-diff-text", children: [
6844
7127
  parts.prefix,
6845
- parts.delMid && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("mark", { className: "rk-del", children: parts.delMid }),
7128
+ parts.delMid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("mark", { className: "rk-del", children: parts.delMid }),
6846
7129
  parts.suffix
6847
7130
  ] })
6848
7131
  ] }),
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: [
7132
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
7133
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-diff-tag", children: "After" }),
7134
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-diff-text", children: [
6852
7135
  parts.prefix,
6853
- parts.insMid && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("mark", { className: "rk-ins", children: parts.insMid }),
7136
+ parts.insMid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("mark", { className: "rk-ins", children: parts.insMid }),
6854
7137
  parts.suffix
6855
7138
  ] })
6856
7139
  ] }),
6857
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-diff-len", children: [
7140
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-len", children: [
6858
7141
  before.length,
6859
7142
  " \u2192 ",
6860
7143
  after.length,
@@ -6865,8 +7148,8 @@ function CopyDiff({ before, after }) {
6865
7148
  }
6866
7149
  function ImageDetail({ beforeSrc, afterSrc, afterDataUrl }) {
6867
7150
  const replacement = afterDataUrl ?? afterSrc;
6868
- const [dims, setDims] = (0, import_react13.useState)("");
6869
- (0, import_react13.useEffect)(() => {
7151
+ const [dims, setDims] = (0, import_react14.useState)("");
7152
+ (0, import_react14.useEffect)(() => {
6870
7153
  if (!replacement) return;
6871
7154
  const img = new Image();
6872
7155
  img.onload = () => setDims(`${img.naturalWidth}\xD7${img.naturalHeight}px`);
@@ -6891,55 +7174,55 @@ function ImageDetail({ beforeSrc, afterSrc, afterDataUrl }) {
6891
7174
  window.open(replacement, "_blank", "noopener");
6892
7175
  }
6893
7176
  };
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" })
7177
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail", children: [
7178
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-thumbs", children: [
7179
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "rk-thumb", children: [
7180
+ 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" }),
7181
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { children: "Before" })
6899
7182
  ] }),
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: [
7183
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "rk-thumb", children: [
7184
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("img", { src: replacement, alt: "Proposed replacement" }),
7185
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figcaption", { children: [
6903
7186
  "After",
6904
7187
  embedded ? "" : " \xB7 linked"
6905
7188
  ] })
6906
7189
  ] })
6907
7190
  ] }),
6908
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-imgdetail-meta", children: [
7191
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail-meta", children: [
6909
7192
  embedded ? "Embedded image" : "Linked image",
6910
7193
  dims ? ` \xB7 ${dims}` : "",
6911
7194
  bytes !== null ? ` \xB7 ${formatBytes(bytes)}` : ""
6912
7195
  ] }),
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 }),
7196
+ !embedded && afterSrc && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { className: "rk-imgdetail-url", href: afterSrc, target: "_blank", rel: "noopener noreferrer", title: afterSrc, children: afterSrc }),
7197
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail-actions", children: [
7198
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void download(), children: [
7199
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconDownload, { size: 12 }),
6917
7200
  " Download"
6918
7201
  ] }),
6919
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => window.open(replacement, "_blank", "noopener"), children: "Open" })
7202
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => window.open(replacement, "_blank", "noopener"), children: "Open" })
6920
7203
  ] })
6921
7204
  ] });
6922
7205
  }
6923
7206
  function Panel() {
6924
- const { session, panelOpen, activeItemId, badgeCorner, undoStack, preview, unapplied, syncStatus, emblemaPush, peers } = useStore();
7207
+ const { session, panelOpen, activeItemId, badgeCorner, undoStack, preview, unapplied, syncStatus, syncReason, emblemaPush, peers } = useStore();
6925
7208
  const dispatch = useDispatch();
6926
7209
  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)(() => {
7210
+ const [sticky, setStickyState] = (0, import_react14.useState)(() => isStickyEnabled(config.token));
7211
+ const [query, setQuery] = (0, import_react14.useState)("");
7212
+ const [typeFilter, setTypeFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
7213
+ const [prioFilter, setPrioFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
7214
+ const [statusFilter, setStatusFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
7215
+ const [filterOpen, setFilterOpen] = (0, import_react14.useState)(false);
7216
+ const [settingsOpen, setSettingsOpen] = (0, import_react14.useState)(false);
7217
+ const [emblemaAlive, setEmblemaAlive] = (0, import_react14.useState)(null);
7218
+ const [emblemaSending, setEmblemaSending] = (0, import_react14.useState)(false);
7219
+ const [emblemaSync, setEmblemaSync] = (0, import_react14.useState)("unknown");
7220
+ const panelRef = (0, import_react14.useRef)(null);
7221
+ const searchRef = (0, import_react14.useRef)(null);
7222
+ const importRef = (0, import_react14.useRef)(null);
7223
+ const sheetDrag = (0, import_react14.useRef)(null);
7224
+ const items = (0, import_react14.useMemo)(() => session?.items ?? [], [session]);
7225
+ const { orphanIds, hiddenIds } = (0, import_react14.useMemo)(() => {
6943
7226
  const orphans = /* @__PURE__ */ new Set();
6944
7227
  const hiddens = /* @__PURE__ */ new Set();
6945
7228
  for (const item of items) {
@@ -6950,15 +7233,15 @@ function Panel() {
6950
7233
  }
6951
7234
  return { orphanIds: orphans, hiddenIds: hiddens };
6952
7235
  }, [items, panelOpen]);
6953
- const activeFilter = (0, import_react13.useMemo)(
7236
+ const activeFilter = (0, import_react14.useMemo)(
6954
7237
  () => typeFilter.size + prioFilter.size + statusFilter.size > 0 ? { types: [...typeFilter], priorities: [...prioFilter], statuses: [...statusFilter] } : null,
6955
7238
  [typeFilter, prioFilter, statusFilter]
6956
7239
  );
6957
- (0, import_react13.useEffect)(() => {
7240
+ (0, import_react14.useEffect)(() => {
6958
7241
  dispatch({ type: "SET_FILTER", filter: activeFilter });
6959
7242
  return () => dispatch({ type: "SET_FILTER", filter: null });
6960
7243
  }, [activeFilter, dispatch]);
6961
- const filtered = (0, import_react13.useMemo)(() => {
7244
+ const filtered = (0, import_react14.useMemo)(() => {
6962
7245
  const q = query.trim().toLowerCase();
6963
7246
  return items.map((item, index) => ({ item, number: index + 1 })).filter(({ item }) => {
6964
7247
  if (!itemMatchesFilter(item, activeFilter)) return false;
@@ -6967,22 +7250,22 @@ function Panel() {
6967
7250
  return haystack.includes(q);
6968
7251
  });
6969
7252
  }, [items, query, activeFilter]);
6970
- const typeCounts = (0, import_react13.useMemo)(() => {
7253
+ const typeCounts = (0, import_react14.useMemo)(() => {
6971
7254
  const counts = /* @__PURE__ */ new Map();
6972
7255
  for (const item of items) counts.set(item.type, (counts.get(item.type) ?? 0) + 1);
6973
7256
  return counts;
6974
7257
  }, [items]);
6975
- const prioCounts = (0, import_react13.useMemo)(() => {
7258
+ const prioCounts = (0, import_react14.useMemo)(() => {
6976
7259
  const counts = /* @__PURE__ */ new Map();
6977
7260
  for (const item of items) counts.set(item.priority, (counts.get(item.priority) ?? 0) + 1);
6978
7261
  return counts;
6979
7262
  }, [items]);
6980
- const statusCounts = (0, import_react13.useMemo)(() => {
7263
+ const statusCounts = (0, import_react14.useMemo)(() => {
6981
7264
  const counts = /* @__PURE__ */ new Map();
6982
7265
  for (const item of items) counts.set(item.status, (counts.get(item.status) ?? 0) + 1);
6983
7266
  return counts;
6984
7267
  }, [items]);
6985
- const groups = (0, import_react13.useMemo)(() => {
7268
+ const groups = (0, import_react14.useMemo)(() => {
6986
7269
  const map = /* @__PURE__ */ new Map();
6987
7270
  for (const entry of filtered) {
6988
7271
  const list = map.get(entry.item.route) ?? [];
@@ -6991,7 +7274,7 @@ function Panel() {
6991
7274
  }
6992
7275
  return Array.from(map.entries());
6993
7276
  }, [filtered]);
6994
- (0, import_react13.useEffect)(() => {
7277
+ (0, import_react14.useEffect)(() => {
6995
7278
  if (!filterOpen && !settingsOpen) return;
6996
7279
  const onDown = (event) => {
6997
7280
  const path = event.composedPath();
@@ -7002,7 +7285,7 @@ function Panel() {
7002
7285
  document.addEventListener("pointerdown", onDown, true);
7003
7286
  return () => document.removeEventListener("pointerdown", onDown, true);
7004
7287
  }, [filterOpen, settingsOpen]);
7005
- (0, import_react13.useEffect)(() => {
7288
+ (0, import_react14.useEffect)(() => {
7006
7289
  if (!settingsOpen) return;
7007
7290
  let alive = true;
7008
7291
  const probe = () => {
@@ -7026,7 +7309,7 @@ function Panel() {
7026
7309
  live: "paired",
7027
7310
  off: "not paired"
7028
7311
  }[emblemaPairState];
7029
- (0, import_react13.useEffect)(() => {
7312
+ (0, import_react14.useEffect)(() => {
7030
7313
  if (!panelOpen || activeItemId === null) return;
7031
7314
  const row = panelRef.current?.querySelector(`[data-item-id="${activeItemId}"]`);
7032
7315
  row?.scrollIntoView({ block: "nearest" });
@@ -7142,7 +7425,7 @@ function Panel() {
7142
7425
  panel.style.transform = "";
7143
7426
  if (dy > 110) dispatch({ type: "SET_PANEL", open: false });
7144
7427
  };
7145
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7428
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7146
7429
  "div",
7147
7430
  {
7148
7431
  ref: panelRef,
@@ -7152,7 +7435,7 @@ function Panel() {
7152
7435
  "aria-label": "Review feedback panel",
7153
7436
  onKeyDown,
7154
7437
  children: [
7155
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7438
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7156
7439
  "div",
7157
7440
  {
7158
7441
  className: "rk-sheet-handle",
@@ -7163,34 +7446,41 @@ function Panel() {
7163
7446
  onPointerCancel: onSheetHandleUp
7164
7447
  }
7165
7448
  ),
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: [
7449
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-head", children: [
7450
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
7451
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-panel-title", children: "Feedback" }),
7452
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-sub", children: [
7170
7453
  items.length,
7171
7454
  " item",
7172
7455
  items.length === 1 ? "" : "s",
7173
7456
  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)(
7457
+ syncStatus !== "disabled" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7458
+ "span",
7459
+ {
7460
+ className: `rk-sync rk-sync-${syncStatus}${syncReason ? ` rk-sync-reason-${syncReason}` : ""}`,
7461
+ 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"],
7462
+ children: [
7463
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-sync-dot" }),
7464
+ 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"]}`
7465
+ ]
7466
+ }
7467
+ ),
7468
+ config.emblema && emblemaPush !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7179
7469
  "span",
7180
7470
  {
7181
7471
  className: `rk-sync rk-epush-${emblemaPush}`,
7182
7472
  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
7473
  children: [
7184
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-sync-dot" }),
7474
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-sync-dot" }),
7185
7475
  emblemaPush === "ok" ? "emblema" : emblemaPush === "sending" ? "emblema\u2026" : emblemaPush === "rejected" ? "emblema rejected" : "emblema offline"
7186
7476
  ]
7187
7477
  }
7188
7478
  )
7189
7479
  ] })
7190
7480
  ] }),
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)(
7481
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-spacer" }),
7482
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
7483
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7194
7484
  "button",
7195
7485
  {
7196
7486
  type: "button",
@@ -7206,11 +7496,11 @@ function Panel() {
7206
7496
  void pingEmblema(config.emblema).then((port) => setEmblemaAlive(port !== null));
7207
7497
  }
7208
7498
  },
7209
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconGear, { size: 15 })
7499
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconGear, { size: 15 })
7210
7500
  }
7211
7501
  ),
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)(
7502
+ settingsOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Session settings", children: [
7503
+ config.token && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7214
7504
  "button",
7215
7505
  {
7216
7506
  type: "button",
@@ -7225,12 +7515,12 @@ function Panel() {
7225
7515
  toast(dispatch, next ? "Review stays on in this tab" : "Review active only via the link", "info");
7226
7516
  },
7227
7517
  children: [
7228
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `rk-menu-check${sticky ? " rk-on" : ""}` }),
7518
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${sticky ? " rk-on" : ""}` }),
7229
7519
  "Keep review on in this tab"
7230
7520
  ]
7231
7521
  }
7232
7522
  ),
7233
- config.emblema && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7523
+ config.emblema && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7234
7524
  "button",
7235
7525
  {
7236
7526
  type: "button",
@@ -7260,7 +7550,7 @@ function Panel() {
7260
7550
  }).finally(() => setEmblemaSending(false));
7261
7551
  },
7262
7552
  children: [
7263
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7553
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7264
7554
  "span",
7265
7555
  {
7266
7556
  className: "rk-emblema-dot",
@@ -7271,25 +7561,40 @@ function Panel() {
7271
7561
  ]
7272
7562
  }
7273
7563
  ),
7274
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7564
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7275
7565
  "button",
7276
7566
  {
7277
7567
  type: "button",
7278
7568
  role: "menuitem",
7279
7569
  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",
7570
+ 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
7571
  onClick: () => {
7282
7572
  setSettingsOpen(false);
7283
7573
  dispatch({ type: "SET_EMBLEMA_CONNECT", open: true });
7284
7574
  },
7285
7575
  children: [
7286
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-emblema-dot", "data-state": emblemaPairState }),
7576
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-emblema-dot", "data-state": emblemaPairState }),
7287
7577
  "Connect to Emblema\u2026",
7288
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-menu-count", children: emblemaPairLabel })
7578
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: emblemaPairLabel })
7289
7579
  ]
7290
7580
  }
7291
7581
  ),
7292
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7582
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7583
+ "button",
7584
+ {
7585
+ type: "button",
7586
+ role: "menuitem",
7587
+ className: "rk-menu-item",
7588
+ 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",
7589
+ disabled: !resolveSyncToken(config),
7590
+ onClick: () => {
7591
+ setSettingsOpen(false);
7592
+ dispatch({ type: "SET_TERMINAL_CONNECT", open: true });
7593
+ },
7594
+ children: "Connect terminal / agent\u2026"
7595
+ }
7596
+ ),
7597
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7293
7598
  "button",
7294
7599
  {
7295
7600
  type: "button",
@@ -7302,31 +7607,31 @@ function Panel() {
7302
7607
  )
7303
7608
  ] })
7304
7609
  ] }),
7305
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7610
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7306
7611
  "button",
7307
7612
  {
7308
7613
  type: "button",
7309
7614
  className: "rk-icon-btn",
7310
7615
  "aria-label": "Keyboard shortcuts",
7311
7616
  onClick: () => dispatch({ type: "SET_CHEATSHEET", open: true }),
7312
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconKeyboard, { size: 15 })
7617
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconKeyboard, { size: 15 })
7313
7618
  }
7314
7619
  ),
7315
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7620
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7316
7621
  "button",
7317
7622
  {
7318
7623
  type: "button",
7319
7624
  className: "rk-icon-btn",
7320
7625
  "aria-label": "Close panel",
7321
7626
  onClick: () => dispatch({ type: "SET_PANEL", open: false }),
7322
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconClose, { size: 14 })
7627
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconClose, { size: 14 })
7323
7628
  }
7324
7629
  )
7325
7630
  ] }),
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)(
7631
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-view-row", children: [
7632
+ /* @__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" }) }),
7633
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-seg rk-view-toggle", role: "group", "aria-label": "Page view (P to toggle)", children: [
7634
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7330
7635
  "button",
7331
7636
  {
7332
7637
  type: "button",
@@ -7336,7 +7641,7 @@ function Panel() {
7336
7641
  children: "Original"
7337
7642
  }
7338
7643
  ),
7339
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7644
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7340
7645
  "button",
7341
7646
  {
7342
7647
  type: "button",
@@ -7348,8 +7653,8 @@ function Panel() {
7348
7653
  )
7349
7654
  ] })
7350
7655
  ] }),
7351
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-panel-tools", children: [
7352
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7656
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-tools", children: [
7657
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7353
7658
  "button",
7354
7659
  {
7355
7660
  type: "button",
@@ -7360,15 +7665,15 @@ function Panel() {
7360
7665
  dispatch({ type: "SET_MODE", mode: "pick" });
7361
7666
  },
7362
7667
  children: [
7363
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconTarget, { size: 14 }),
7668
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTarget, { size: 14 }),
7364
7669
  " Pick an element"
7365
7670
  ]
7366
7671
  }
7367
7672
  ),
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)(
7673
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-search-row", children: [
7674
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-search", children: [
7675
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconSearch, { size: 13 }),
7676
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7372
7677
  "input",
7373
7678
  {
7374
7679
  ref: searchRef,
@@ -7380,8 +7685,8 @@ function Panel() {
7380
7685
  }
7381
7686
  )
7382
7687
  ] }),
7383
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
7384
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7688
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
7689
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7385
7690
  "button",
7386
7691
  {
7387
7692
  type: "button",
@@ -7393,15 +7698,15 @@ function Panel() {
7393
7698
  setSettingsOpen(false);
7394
7699
  },
7395
7700
  children: [
7396
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconFilter, { size: 13 }),
7701
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFilter, { size: 13 }),
7397
7702
  "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 })
7703
+ 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
7704
  ]
7400
7705
  }
7401
7706
  ),
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)(
7707
+ filterOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Filter items", children: [
7708
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Type" }),
7709
+ TYPE_FILTERS.map((type) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7405
7710
  "button",
7406
7711
  {
7407
7712
  type: "button",
@@ -7415,16 +7720,16 @@ function Panel() {
7415
7720
  setTypeFilter(next);
7416
7721
  },
7417
7722
  children: [
7418
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `rk-menu-check${typeFilter.has(type) ? " rk-on" : ""}` }),
7723
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${typeFilter.has(type) ? " rk-on" : ""}` }),
7419
7724
  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 })
7725
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: type }),
7726
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: typeCounts.get(type) ?? 0 })
7422
7727
  ]
7423
7728
  },
7424
7729
  type
7425
7730
  )),
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)(
7731
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Priority" }),
7732
+ PRIORITY_FILTERS.map((priority) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7428
7733
  "button",
7429
7734
  {
7430
7735
  type: "button",
@@ -7438,15 +7743,15 @@ function Panel() {
7438
7743
  setPrioFilter(next);
7439
7744
  },
7440
7745
  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 })
7746
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${prioFilter.has(priority) ? " rk-on" : ""}` }),
7747
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: PRIORITY_LABELS[priority] }),
7748
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: prioCounts.get(priority) ?? 0 })
7444
7749
  ]
7445
7750
  },
7446
7751
  priority
7447
7752
  )),
7448
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rk-menu-title", children: "Status" }),
7449
- STATUSES.map((status) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7753
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Status" }),
7754
+ STATUSES.map((status) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7450
7755
  "button",
7451
7756
  {
7452
7757
  type: "button",
@@ -7460,15 +7765,15 @@ function Panel() {
7460
7765
  setStatusFilter(next);
7461
7766
  },
7462
7767
  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 })
7768
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${statusFilter.has(status) ? " rk-on" : ""}` }),
7769
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-status-dot rk-st-${status}` }),
7770
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: status }),
7771
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: statusCounts.get(status) ?? 0 })
7467
7772
  ]
7468
7773
  },
7469
7774
  status
7470
7775
  )),
7471
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7776
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7472
7777
  "button",
7473
7778
  {
7474
7779
  type: "button",
@@ -7488,24 +7793,24 @@ function Panel() {
7488
7793
  ] })
7489
7794
  ] })
7490
7795
  ] }),
7491
- preview && unapplied > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-unplaced", role: "status", children: [
7796
+ preview && unapplied > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-unplaced", role: "status", children: [
7492
7797
  unapplied,
7493
7798
  " saved change",
7494
7799
  unapplied === 1 ? "" : "s",
7495
7800
  " couldn\u2019t be placed on the current page \u2014 the page has changed since they were captured."
7496
7801
  ] }),
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 }),
7802
+ /* @__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: [
7803
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-art", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTarget, { size: 22 }) }),
7804
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-title", children: items.length === 0 ? "Nothing here yet" : "No matches" }),
7805
+ /* @__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." })
7806
+ ] }) : groups.map(([route, entries]) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
7807
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-group-title", children: route }),
7503
7808
  entries.map(({ item, number }) => {
7504
7809
  const active2 = item.id === activeItemId;
7505
7810
  const orphan = orphanIds.has(item.id);
7506
7811
  const hiddenEl = hiddenIds.has(item.id);
7507
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
7508
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
7812
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
7813
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
7509
7814
  "div",
7510
7815
  {
7511
7816
  "data-item-id": item.id,
@@ -7520,18 +7825,18 @@ function Panel() {
7520
7825
  }
7521
7826
  },
7522
7827
  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: [
7828
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-num", children: number }),
7829
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-icon", children: iconForType(item.type) }),
7830
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-body", children: [
7831
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-snippet", children: [
7527
7832
  item.target.tagName,
7528
7833
  " \xB7 ",
7529
7834
  item.target.textSnippet || item.target.selector
7530
7835
  ] }),
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)(
7836
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-change", children: changeSummary(item) }),
7837
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-meta", children: [
7838
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-author", title: new Date(item.createdAt).toLocaleString(), children: [
7839
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7535
7840
  "span",
7536
7841
  {
7537
7842
  className: "rk-author-dot",
@@ -7539,15 +7844,15 @@ function Panel() {
7539
7844
  }
7540
7845
  ),
7541
7846
  item.author?.name ?? "Unknown",
7542
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-time", children: [
7847
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-time", children: [
7543
7848
  " \xB7 ",
7544
7849
  timeAgo(item.createdAt)
7545
7850
  ] })
7546
7851
  ] }),
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)(
7852
+ item.priority === "must" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini rk-must", children: "must" }),
7853
+ item.status !== "open" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-badge-mini rk-${item.status}`, children: item.status }),
7854
+ orphan && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini rk-orphaned", children: "unanchored" }),
7855
+ hiddenEl && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7551
7856
  "span",
7552
7857
  {
7553
7858
  className: "rk-badge-mini rk-hidden-el",
@@ -7555,14 +7860,14 @@ function Panel() {
7555
7860
  children: "hidden"
7556
7861
  }
7557
7862
  ),
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: [
7863
+ item.note && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini", children: "note" }),
7864
+ 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
7865
  peer.name || "peer",
7561
7866
  " is writing\u2026"
7562
7867
  ] }, peer.id))
7563
7868
  ] })
7564
7869
  ] }),
7565
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-item-actions", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7870
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-actions", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7566
7871
  "button",
7567
7872
  {
7568
7873
  type: "button",
@@ -7577,15 +7882,15 @@ function Panel() {
7577
7882
  "info"
7578
7883
  );
7579
7884
  },
7580
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconTrash, { size: 13 })
7885
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTrash, { size: 13 })
7581
7886
  }
7582
7887
  ) })
7583
7888
  ]
7584
7889
  }
7585
7890
  ),
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)(
7891
+ active2 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-item-edit", children: [
7892
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-detail-byline", title: new Date(item.createdAt).toLocaleString(), children: [
7893
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7589
7894
  "span",
7590
7895
  {
7591
7896
  className: "rk-author-dot",
@@ -7596,8 +7901,8 @@ function Panel() {
7596
7901
  " \xB7 ",
7597
7902
  timeAgo(item.createdAt)
7598
7903
  ] }),
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)(
7904
+ isCopyItem(item) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CopyDiff, { before: item.payload.before, after: item.payload.after }),
7905
+ isImageItem(item) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7601
7906
  ImageDetail,
7602
7907
  {
7603
7908
  beforeSrc: item.payload.beforeSrc,
@@ -7605,7 +7910,7 @@ function Panel() {
7605
7910
  afterDataUrl: item.payload.afterDataUrl
7606
7911
  }
7607
7912
  ),
7608
- isKnownItemType(item.type) && item.type !== "move" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7913
+ isKnownItemType(item.type) && item.type !== "move" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7609
7914
  "textarea",
7610
7915
  {
7611
7916
  className: "rk-textarea",
@@ -7615,7 +7920,7 @@ function Panel() {
7615
7920
  onChange: (event) => dispatch({ type: "UPDATE_ITEM", id: item.id, patch: withPayloadText(item, event.target.value) })
7616
7921
  }
7617
7922
  ),
7618
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7923
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7619
7924
  "input",
7620
7925
  {
7621
7926
  className: "rk-input",
@@ -7625,9 +7930,9 @@ function Panel() {
7625
7930
  onChange: (event) => dispatch({ type: "UPDATE_ITEM", id: item.id, patch: { note: event.target.value } })
7626
7931
  }
7627
7932
  ),
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)(
7933
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
7934
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
7935
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7631
7936
  "button",
7632
7937
  {
7633
7938
  type: "button",
@@ -7636,7 +7941,7 @@ function Panel() {
7636
7941
  children: "Must"
7637
7942
  }
7638
7943
  ),
7639
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7944
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7640
7945
  "button",
7641
7946
  {
7642
7947
  type: "button",
@@ -7646,7 +7951,7 @@ function Panel() {
7646
7951
  }
7647
7952
  )
7648
7953
  ] }),
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)(
7954
+ /* @__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
7955
  "button",
7651
7956
  {
7652
7957
  type: "button",
@@ -7661,22 +7966,22 @@ function Panel() {
7661
7966
  ] }, item.id);
7662
7967
  })
7663
7968
  ] }, 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 }),
7969
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-foot", children: [
7970
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: onExport, disabled: items.length === 0, children: [
7971
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconDownload, { size: 13 }),
7667
7972
  " Export"
7668
7973
  ] }),
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 }),
7974
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void onCopy(), disabled: items.length === 0, children: [
7975
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconCopyClipboard, { size: 13 }),
7671
7976
  " Copy"
7672
7977
  ] }),
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 }),
7978
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => importRef.current?.click(), children: [
7979
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconUpload, { size: 13 }),
7675
7980
  " Import"
7676
7981
  ] }),
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)(
7982
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-spacer" }),
7983
+ 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 }) }),
7984
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7680
7985
  "button",
7681
7986
  {
7682
7987
  type: "button",
@@ -7687,7 +7992,7 @@ function Panel() {
7687
7992
  children: "Clear"
7688
7993
  }
7689
7994
  ),
7690
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
7995
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7691
7996
  "button",
7692
7997
  {
7693
7998
  type: "button",
@@ -7697,7 +8002,7 @@ function Panel() {
7697
8002
  children: "Exit review"
7698
8003
  }
7699
8004
  ),
7700
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
8005
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
7701
8006
  "input",
7702
8007
  {
7703
8008
  ref: importRef,
@@ -7716,13 +8021,14 @@ function Panel() {
7716
8021
  }
7717
8022
  );
7718
8023
  }
7719
- var import_react13, import_jsx_runtime11, TYPE_FILTERS, PRIORITY_FILTERS, STATUSES, PRIORITY_LABELS;
8024
+ var import_react14, import_jsx_runtime12, TYPE_FILTERS, PRIORITY_FILTERS, STATUSES, PRIORITY_LABELS, SYNC_REASON_LABEL, SYNC_REASON_HELP;
7720
8025
  var init_Panel = __esm({
7721
8026
  "src/client/components/Panel.tsx"() {
7722
8027
  "use strict";
7723
- import_react13 = require("react");
8028
+ import_react14 = require("react");
7724
8029
  init_schema();
7725
8030
  init_env();
8031
+ init_sync();
7726
8032
  init_emblema();
7727
8033
  init_exportSession();
7728
8034
  init_shortcuts();
@@ -7730,11 +8036,23 @@ var init_Panel = __esm({
7730
8036
  init_target();
7731
8037
  init_store();
7732
8038
  init_icons();
7733
- import_jsx_runtime11 = require("react/jsx-runtime");
8039
+ import_jsx_runtime12 = require("react/jsx-runtime");
7734
8040
  TYPE_FILTERS = ["copy", "image", "comment", "delete", "move", "style"];
7735
8041
  PRIORITY_FILTERS = ["must", "nice"];
7736
8042
  STATUSES = ["open", "accepted", "rejected", "applied"];
7737
8043
  PRIORITY_LABELS = { must: "Must", nice: "Nice to have" };
8044
+ SYNC_REASON_LABEL = {
8045
+ "token-short": "token too short",
8046
+ "bad-token": "token rejected",
8047
+ "room-full": "room full",
8048
+ unreachable: "server unreachable"
8049
+ };
8050
+ SYNC_REASON_HELP = {
8051
+ "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.",
8052
+ "bad-token": "The sync server rejected the token. Check `syncToken` / `token` in <ReviewKit />.",
8053
+ "room-full": "This page already has the maximum number of reviewers online (16). Try again later.",
8054
+ 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."
8055
+ };
7738
8056
  }
7739
8057
  });
7740
8058
 
@@ -7748,8 +8066,8 @@ function initials(name) {
7748
8066
  function PresenceStrip() {
7749
8067
  const { peers, syncStatus } = useStore();
7750
8068
  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)(
8069
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rk-presence", "aria-label": `${peers.length} reviewer${peers.length === 1 ? "" : "s"} online`, children: [
8070
+ peers.slice(0, 5).map((peer) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7753
8071
  "span",
7754
8072
  {
7755
8073
  className: "rk-avatar",
@@ -7759,7 +8077,7 @@ function PresenceStrip() {
7759
8077
  },
7760
8078
  peer.id
7761
8079
  )),
7762
- peers.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-avatar rk-avatar-more", children: [
8080
+ peers.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "rk-avatar rk-avatar-more", children: [
7763
8081
  "+",
7764
8082
  peers.length - 5
7765
8083
  ] })
@@ -7767,13 +8085,13 @@ function PresenceStrip() {
7767
8085
  }
7768
8086
  function PeerCursors() {
7769
8087
  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)(
8088
+ const ringRefs = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
8089
+ const cursorRefs = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
8090
+ const motion = (0, import_react15.useRef)(
7773
8091
  /* @__PURE__ */ new Map()
7774
8092
  );
7775
- const peersRef = (0, import_react14.useRef)(peers);
7776
- const seen = (0, import_react14.useRef)(/* @__PURE__ */ new Map());
8093
+ const peersRef = (0, import_react15.useRef)(peers);
8094
+ const seen = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
7777
8095
  for (const peer of peers) {
7778
8096
  const sig = peer.cursor ? `${peer.cursor.x},${peer.cursor.y},${peer.cursor.ox},${peer.cursor.oy}` : "";
7779
8097
  if (seen.current.get(peer.id) !== sig) {
@@ -7783,7 +8101,7 @@ function PeerCursors() {
7783
8101
  }
7784
8102
  }
7785
8103
  peersRef.current = peers;
7786
- (0, import_react14.useEffect)(() => {
8104
+ (0, import_react15.useEffect)(() => {
7787
8105
  const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
7788
8106
  let raf = 0;
7789
8107
  let last = performance.now();
@@ -7888,8 +8206,8 @@ function PeerCursors() {
7888
8206
  return () => cancelAnimationFrame(raf);
7889
8207
  }, []);
7890
8208
  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)(
8209
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
8210
+ peers.map((peer) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7893
8211
  "div",
7894
8212
  {
7895
8213
  ref: (el) => {
@@ -7901,7 +8219,7 @@ function PeerCursors() {
7901
8219
  },
7902
8220
  `ring-${peer.id}`
7903
8221
  )),
7904
- peers.map((peer, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
8222
+ peers.map((peer, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7905
8223
  "div",
7906
8224
  {
7907
8225
  ref: (el) => {
@@ -7911,8 +8229,8 @@ function PeerCursors() {
7911
8229
  className: "rk-peer-cursor",
7912
8230
  style: { opacity: 0 },
7913
8231
  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)(
8232
+ /* @__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" }) }),
8233
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7916
8234
  "span",
7917
8235
  {
7918
8236
  className: "rk-peer-name",
@@ -7929,14 +8247,14 @@ function PeerCursors() {
7929
8247
  ))
7930
8248
  ] });
7931
8249
  }
7932
- var import_react14, import_jsx_runtime12;
8250
+ var import_react15, import_jsx_runtime13;
7933
8251
  var init_Presence = __esm({
7934
8252
  "src/client/components/Presence.tsx"() {
7935
8253
  "use strict";
7936
- import_react14 = require("react");
8254
+ import_react15 = require("react");
7937
8255
  init_store();
7938
8256
  init_target();
7939
- import_jsx_runtime12 = require("react/jsx-runtime");
8257
+ import_jsx_runtime13 = require("react/jsx-runtime");
7940
8258
  }
7941
8259
  });
7942
8260
 
@@ -7944,14 +8262,14 @@ var init_Presence = __esm({
7944
8262
  function QuickComment() {
7945
8263
  const { quick } = useStore();
7946
8264
  if (!quick) return null;
7947
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(QuickComposerCard, { quick }, quick.id);
8265
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(QuickComposerCard, { quick }, quick.id);
7948
8266
  }
7949
8267
  function QuickComposerCard({ quick }) {
7950
8268
  const { route, session } = useStore();
7951
8269
  const dispatch = useDispatch();
7952
- const [text, setText] = (0, import_react15.useState)("");
7953
- const fieldRef = (0, import_react15.useRef)(null);
7954
- (0, import_react15.useEffect)(() => {
8270
+ const [text, setText] = (0, import_react16.useState)("");
8271
+ const fieldRef = (0, import_react16.useRef)(null);
8272
+ (0, import_react16.useEffect)(() => {
7955
8273
  const field = fieldRef.current;
7956
8274
  if (!field) return;
7957
8275
  field.focus();
@@ -8004,18 +8322,18 @@ function QuickComposerCard({ quick }) {
8004
8322
  };
8005
8323
  const x = Math.min(Math.max(quick.x, 8), window.innerWidth - 288);
8006
8324
  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" }),
8325
+ 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: [
8326
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rk-quick-head", children: [
8327
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(IconComment, { size: 12 }),
8328
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Comment here" }),
8329
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "rk-hint", children: [
8330
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
8013
8331
  " save \xB7 ",
8014
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "rk-kbd", children: "esc" }),
8332
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-kbd", children: "esc" }),
8015
8333
  " cancel"
8016
8334
  ] })
8017
8335
  ] }),
8018
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
8336
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
8019
8337
  "textarea",
8020
8338
  {
8021
8339
  ref: fieldRef,
@@ -8029,11 +8347,11 @@ function QuickComposerCard({ quick }) {
8029
8347
  )
8030
8348
  ] });
8031
8349
  }
8032
- var import_react15, import_jsx_runtime13;
8350
+ var import_react16, import_jsx_runtime14;
8033
8351
  var init_QuickComment = __esm({
8034
8352
  "src/client/components/QuickComment.tsx"() {
8035
8353
  "use strict";
8036
- import_react15 = require("react");
8354
+ import_react16 = require("react");
8037
8355
  init_effectCatalog();
8038
8356
  init_effectsLazy();
8039
8357
  init_id();
@@ -8042,7 +8360,7 @@ var init_QuickComment = __esm({
8042
8360
  init_sync();
8043
8361
  init_store();
8044
8362
  init_icons();
8045
- import_jsx_runtime13 = require("react/jsx-runtime");
8363
+ import_jsx_runtime14 = require("react/jsx-runtime");
8046
8364
  }
8047
8365
  });
8048
8366
 
@@ -8061,14 +8379,14 @@ function applyRect(el, rect, pad2 = 3) {
8061
8379
  function PickLayer() {
8062
8380
  const { mode, selection, tool } = useStore();
8063
8381
  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);
8382
+ const [hovered, setHovered] = (0, import_react17.useState)(null);
8383
+ const outlineRef = (0, import_react17.useRef)(null);
8384
+ const labelRef = (0, import_react17.useRef)(null);
8385
+ const selectRef = (0, import_react17.useRef)(null);
8386
+ const hoveredRef = (0, import_react17.useRef)(null);
8069
8387
  hoveredRef.current = hovered;
8070
8388
  const picking = mode === "pick";
8071
- (0, import_react16.useEffect)(() => {
8389
+ (0, import_react17.useEffect)(() => {
8072
8390
  if (!picking) {
8073
8391
  setHovered(null);
8074
8392
  return;
@@ -8112,7 +8430,7 @@ function PickLayer() {
8112
8430
  document.removeEventListener("mousedown", swallow, true);
8113
8431
  };
8114
8432
  }, [picking, tool, dispatch]);
8115
- (0, import_react16.useEffect)(() => {
8433
+ (0, import_react17.useEffect)(() => {
8116
8434
  if (!picking) return;
8117
8435
  const body = document.body;
8118
8436
  const prev = body.style.cursor;
@@ -8122,7 +8440,7 @@ function PickLayer() {
8122
8440
  if (body.getAttribute("style") === "") body.removeAttribute("style");
8123
8441
  };
8124
8442
  }, [picking, tool]);
8125
- (0, import_react16.useEffect)(() => {
8443
+ (0, import_react17.useEffect)(() => {
8126
8444
  let raf = 0;
8127
8445
  const tick = () => {
8128
8446
  const hoverEl = hoveredRef.current;
@@ -8148,26 +8466,26 @@ function PickLayer() {
8148
8466
  raf = requestAnimationFrame(tick);
8149
8467
  return () => cancelAnimationFrame(raf);
8150
8468
  }, [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" }) })
8469
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
8470
+ picking && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
8471
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: outlineRef, className: "rk-outline", style: { opacity: 0 } }),
8472
+ /* @__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: [
8473
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rk-tag", children: hovered.tagName.toLowerCase() }),
8474
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: describeElement(hovered).replace(/^[a-z0-9]+ · /, "") })
8475
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Pick an element" }) })
8158
8476
  ] }),
8159
- selection && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { ref: selectRef, className: "rk-select-ring", style: { opacity: 0 } })
8477
+ selection && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: selectRef, className: "rk-select-ring", style: { opacity: 0 } })
8160
8478
  ] });
8161
8479
  }
8162
- var import_react16, import_jsx_runtime14;
8480
+ var import_react17, import_jsx_runtime15;
8163
8481
  var init_PickLayer = __esm({
8164
8482
  "src/client/components/PickLayer.tsx"() {
8165
8483
  "use strict";
8166
- import_react16 = require("react");
8484
+ import_react17 = require("react");
8167
8485
  init_shortcuts();
8168
8486
  init_target();
8169
8487
  init_store();
8170
- import_jsx_runtime14 = require("react/jsx-runtime");
8488
+ import_jsx_runtime15 = require("react/jsx-runtime");
8171
8489
  }
8172
8490
  });
8173
8491
 
@@ -8175,22 +8493,22 @@ var init_PickLayer = __esm({
8175
8493
  function Pins() {
8176
8494
  const { session, route, activeItemId, editor, mode, filter } = useStore();
8177
8495
  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)(() => {
8496
+ const [clusters, setClusters] = (0, import_react18.useState)([]);
8497
+ const [orphanCount, setOrphanCount] = (0, import_react18.useState)(0);
8498
+ const wrapRefs = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
8499
+ const visibleCache = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
8500
+ const highlightRef = (0, import_react18.useRef)(null);
8501
+ const hoveredItems = (0, import_react18.useRef)(null);
8502
+ const elementCache = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
8503
+ const lastResolve = (0, import_react18.useRef)(0);
8504
+ const [newestId, setNewestId] = (0, import_react18.useState)(null);
8505
+ const prevCount = (0, import_react18.useRef)(0);
8506
+ const items = (0, import_react18.useMemo)(() => {
8189
8507
  const all = session?.items ?? [];
8190
8508
  return all.map((item, index) => ({ item, number: index + 1 })).filter(({ item }) => item.route === route);
8191
8509
  }, [session, route]);
8192
8510
  const byId = new Map(items.map(({ item }) => [item.id, item]));
8193
- (0, import_react17.useEffect)(() => {
8511
+ (0, import_react18.useEffect)(() => {
8194
8512
  const count = session?.items.length ?? 0;
8195
8513
  if (count > prevCount.current && session && count > 0) {
8196
8514
  const id = session.items[count - 1].id;
@@ -8201,7 +8519,7 @@ function Pins() {
8201
8519
  }
8202
8520
  prevCount.current = count;
8203
8521
  }, [session]);
8204
- (0, import_react17.useEffect)(() => {
8522
+ (0, import_react18.useEffect)(() => {
8205
8523
  let raf = 0;
8206
8524
  let lastSignature = "";
8207
8525
  const tick = (time) => {
@@ -8285,8 +8603,8 @@ function Pins() {
8285
8603
  dispatch({ type: "SET_ACTIVE_ITEM", id });
8286
8604
  dispatch({ type: "SET_PANEL", open: true });
8287
8605
  };
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 } }),
8606
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
8607
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref: highlightRef, className: "rk-hl-ring", style: { opacity: 0 } }),
8290
8608
  clusters.map((cluster) => {
8291
8609
  const isCluster = cluster.ids.length > 1;
8292
8610
  const isActive = activeItemId !== null && cluster.ids.includes(activeItemId);
@@ -8296,7 +8614,7 @@ function Pins() {
8296
8614
  const status = statuses.size === 1 ? members[0]?.status : void 0;
8297
8615
  const dimmed = filter !== null && members.length > 0 && !members.some((item) => itemMatchesFilter(item, filter));
8298
8616
  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)(
8617
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8300
8618
  "div",
8301
8619
  {
8302
8620
  ref: (el) => {
@@ -8304,7 +8622,7 @@ function Pins() {
8304
8622
  else wrapRefs.current.delete(cluster.key);
8305
8623
  },
8306
8624
  className: `rk-pin-wrap${picking ? " rk-pin-ghost" : ""}`,
8307
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8625
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8308
8626
  "button",
8309
8627
  {
8310
8628
  type: "button",
@@ -8326,7 +8644,7 @@ function Pins() {
8326
8644
  cluster.key
8327
8645
  );
8328
8646
  }),
8329
- orphanCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
8647
+ orphanCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8330
8648
  "button",
8331
8649
  {
8332
8650
  type: "button",
@@ -8334,7 +8652,7 @@ function Pins() {
8334
8652
  style: { bottom: 16, left: "50%", transform: "translateX(-50%)" },
8335
8653
  onClick: () => dispatch({ type: "SET_PANEL", open: true }),
8336
8654
  children: [
8337
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IconUnlink, { size: 13 }),
8655
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconUnlink, { size: 13 }),
8338
8656
  orphanCount,
8339
8657
  " unanchored item",
8340
8658
  orphanCount === 1 ? "" : "s"
@@ -8343,15 +8661,15 @@ function Pins() {
8343
8661
  )
8344
8662
  ] });
8345
8663
  }
8346
- var import_react17, import_jsx_runtime15, STATUS_LABELS, CLUSTER_RADIUS, RERESOLVE_MS;
8664
+ var import_react18, import_jsx_runtime16, STATUS_LABELS, CLUSTER_RADIUS, RERESOLVE_MS;
8347
8665
  var init_Pins = __esm({
8348
8666
  "src/client/components/Pins.tsx"() {
8349
8667
  "use strict";
8350
- import_react17 = require("react");
8668
+ import_react18 = require("react");
8351
8669
  init_target();
8352
8670
  init_store();
8353
8671
  init_icons();
8354
- import_jsx_runtime15 = require("react/jsx-runtime");
8672
+ import_jsx_runtime16 = require("react/jsx-runtime");
8355
8673
  STATUS_LABELS = {
8356
8674
  open: "open",
8357
8675
  accepted: "accepted",
@@ -8368,24 +8686,24 @@ function Toolbar() {
8368
8686
  const { selection, editor, peers, syncStatus, mode, tool } = useStore();
8369
8687
  const hasPeers = syncStatus !== "disabled" && peers.length > 0;
8370
8688
  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);
8689
+ const ref = (0, import_react19.useRef)(null);
8690
+ const [pos, setPos] = (0, import_react19.useState)(() => readStoredPos(POS_KEY2));
8691
+ const drag = (0, import_react19.useRef)(null);
8692
+ const [dragging, setDragging] = (0, import_react19.useState)(false);
8693
+ const justDragged = (0, import_react19.useRef)(false);
8376
8694
  const visible = editor === null || selection !== null;
8377
8695
  const applyPos = (next, persist) => {
8378
8696
  if (next === null && ref.current) ref.current.style.bottom = "";
8379
8697
  setPos(next);
8380
8698
  if (persist) storePos(POS_KEY2, next);
8381
8699
  };
8382
- (0, import_react18.useLayoutEffect)(() => {
8700
+ (0, import_react19.useLayoutEffect)(() => {
8383
8701
  const el = ref.current;
8384
8702
  if (!el || pos === null) return;
8385
8703
  const clamped = clampPos(pos.x, pos.y, el.offsetWidth, el.offsetHeight);
8386
8704
  if (clamped.x !== pos.x || clamped.y !== pos.y) applyPos(clamped, true);
8387
8705
  }, [pos, selection, hasPeers, visible]);
8388
- (0, import_react18.useEffect)(() => {
8706
+ (0, import_react19.useEffect)(() => {
8389
8707
  const onResize = () => {
8390
8708
  const el = ref.current;
8391
8709
  const current = readStoredPos(POS_KEY2);
@@ -8498,7 +8816,7 @@ function Toolbar() {
8498
8816
  mode === "pick" && selection === null ? "rk-ghost" : ""
8499
8817
  ].filter(Boolean).join(" ");
8500
8818
  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)(
8819
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8502
8820
  "div",
8503
8821
  {
8504
8822
  ref,
@@ -8509,7 +8827,7 @@ function Toolbar() {
8509
8827
  onPointerDown,
8510
8828
  onClickCapture,
8511
8829
  children: [
8512
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8830
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8513
8831
  "button",
8514
8832
  {
8515
8833
  type: "button",
@@ -8517,19 +8835,19 @@ function Toolbar() {
8517
8835
  "aria-label": "Move the toolbar \u2014 drag, or use arrow keys; double-click to reset its position",
8518
8836
  onKeyDown: onGripKeyDown,
8519
8837
  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" })
8838
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("svg", { width: "8", height: "14", viewBox: "0 0 8 14", "aria-hidden": "true", fill: "currentColor", children: [
8839
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "2", r: "1.1" }),
8840
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "2", r: "1.1" }),
8841
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "7", r: "1.1" }),
8842
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "7", r: "1.1" }),
8843
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "12", r: "1.1" }),
8844
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "12", r: "1.1" })
8527
8845
  ] })
8528
8846
  }
8529
8847
  ),
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)(
8848
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PresenceStrip, {}),
8849
+ hasPeers && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
8850
+ /* @__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
8851
  "button",
8534
8852
  {
8535
8853
  type: "button",
@@ -8541,9 +8859,9 @@ function Toolbar() {
8541
8859
  },
8542
8860
  entry.tool
8543
8861
  )) }),
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)(
8862
+ selection && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
8863
+ selection && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
8864
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8547
8865
  "button",
8548
8866
  {
8549
8867
  type: "button",
@@ -8552,12 +8870,12 @@ function Toolbar() {
8552
8870
  title: `Rewrite text${keyHint("tool-copy")}`,
8553
8871
  onClick: () => open("copy"),
8554
8872
  children: [
8555
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconText, { size: 14 }),
8873
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconText, { size: 14 }),
8556
8874
  " Rewrite"
8557
8875
  ]
8558
8876
  }
8559
8877
  ),
8560
- hasImage && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8878
+ hasImage && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8561
8879
  "button",
8562
8880
  {
8563
8881
  type: "button",
@@ -8566,12 +8884,12 @@ function Toolbar() {
8566
8884
  title: `Replace image${keyHint("tool-image")}`,
8567
8885
  onClick: () => open("image"),
8568
8886
  children: [
8569
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconImage, { size: 14 }),
8887
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconImage, { size: 14 }),
8570
8888
  " Image"
8571
8889
  ]
8572
8890
  }
8573
8891
  ),
8574
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8892
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8575
8893
  "button",
8576
8894
  {
8577
8895
  type: "button",
@@ -8580,32 +8898,32 @@ function Toolbar() {
8580
8898
  title: `Comment${keyHint("tool-comment")}`,
8581
8899
  onClick: () => open("comment"),
8582
8900
  children: [
8583
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconComment, { size: 14 }),
8901
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: 14 }),
8584
8902
  " Comment"
8585
8903
  ]
8586
8904
  }
8587
8905
  ),
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 }),
8906
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("style"), children: [
8907
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconStyle, { size: 14 }),
8590
8908
  " Style"
8591
8909
  ] }),
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 }),
8910
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("move"), children: [
8911
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconMove, { size: 14 }),
8594
8912
  " Move"
8595
8913
  ] }),
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 }),
8914
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn rk-danger", onClick: () => open("delete"), children: [
8915
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconTrash, { size: 14 }),
8598
8916
  " Delete"
8599
8917
  ] }),
8600
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "rk-toolbar-sep" }),
8601
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8918
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
8919
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8602
8920
  "button",
8603
8921
  {
8604
8922
  type: "button",
8605
8923
  className: "rk-icon-btn",
8606
8924
  "aria-label": "Deselect",
8607
8925
  onClick: () => dispatch({ type: "SELECT", selection: null }),
8608
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconClose, { size: 13 })
8926
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconClose, { size: 13 })
8609
8927
  }
8610
8928
  )
8611
8929
  ] })
@@ -8613,11 +8931,11 @@ function Toolbar() {
8613
8931
  }
8614
8932
  );
8615
8933
  }
8616
- var import_react18, import_jsx_runtime16, TOOLS, POS_KEY2, DRAG_THRESHOLD2;
8934
+ var import_react19, import_jsx_runtime17, TOOLS, POS_KEY2, DRAG_THRESHOLD2;
8617
8935
  var init_Toolbar = __esm({
8618
8936
  "src/client/components/Toolbar.tsx"() {
8619
8937
  "use strict";
8620
- import_react18 = require("react");
8938
+ import_react19 = require("react");
8621
8939
  init_dragPosition();
8622
8940
  init_store();
8623
8941
  init_preview();
@@ -8625,12 +8943,12 @@ var init_Toolbar = __esm({
8625
8943
  init_target();
8626
8944
  init_Presence();
8627
8945
  init_icons();
8628
- import_jsx_runtime16 = require("react/jsx-runtime");
8946
+ import_jsx_runtime17 = require("react/jsx-runtime");
8629
8947
  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 }) }
8948
+ { tool: "select", hintId: "tool-select", label: "Select", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconTarget, { size: n }) },
8949
+ { tool: "copy", hintId: "tool-copy", label: "Rewrite text", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconText, { size: n }) },
8950
+ { tool: "comment", hintId: "tool-comment", label: "Comment", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: n }) },
8951
+ { tool: "image", hintId: "tool-image", label: "Replace image", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconImage, { size: n }) }
8634
8952
  ];
8635
8953
  POS_KEY2 = "review-kit:toolbar-pos";
8636
8954
  DRAG_THRESHOLD2 = 6;
@@ -8640,28 +8958,28 @@ var init_Toolbar = __esm({
8640
8958
  // src/client/components/Toast.tsx
8641
8959
  function ToastRow({ toast: toast2 }) {
8642
8960
  const dispatch = useDispatch();
8643
- (0, import_react19.useEffect)(() => {
8961
+ (0, import_react20.useEffect)(() => {
8644
8962
  const timer = window.setTimeout(() => dispatch({ type: "DISMISS_TOAST", id: toast2.id }), 3500);
8645
8963
  return () => window.clearTimeout(timer);
8646
8964
  }, [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 }),
8965
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `rk-toast rk-${toast2.tone}`, role: "status", children: [
8966
+ 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
8967
  toast2.message
8650
8968
  ] });
8651
8969
  }
8652
8970
  function ToastHost() {
8653
8971
  const { toasts } = useStore();
8654
8972
  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)) });
8973
+ 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
8974
  }
8657
- var import_react19, import_jsx_runtime17;
8975
+ var import_react20, import_jsx_runtime18;
8658
8976
  var init_Toast = __esm({
8659
8977
  "src/client/components/Toast.tsx"() {
8660
8978
  "use strict";
8661
- import_react19 = require("react");
8979
+ import_react20 = require("react");
8662
8980
  init_store();
8663
8981
  init_icons();
8664
- import_jsx_runtime17 = require("react/jsx-runtime");
8982
+ import_jsx_runtime18 = require("react/jsx-runtime");
8665
8983
  }
8666
8984
  });
8667
8985
 
@@ -8671,14 +8989,14 @@ function App() {
8671
8989
  const rawDispatch = useDispatch();
8672
8990
  const config = useConfig();
8673
8991
  const dispatch = useRealtimeSync(state, rawDispatch, config, reducer);
8674
- const saveTimer = (0, import_react20.useRef)(null);
8992
+ const saveTimer = (0, import_react21.useRef)(null);
8675
8993
  const storageKey = config.storageKey ?? defaultStorageKey();
8676
8994
  useAppliedPreview(state, dispatch);
8677
8995
  useEmblemaAutoPush(state, dispatch, config);
8678
- (0, import_react20.useEffect)(() => {
8996
+ (0, import_react21.useEffect)(() => {
8679
8997
  setEffectAssetsUrl(config.fxAssetsUrl);
8680
8998
  }, [config.fxAssetsUrl]);
8681
- (0, import_react20.useEffect)(() => {
8999
+ (0, import_react21.useEffect)(() => {
8682
9000
  let cancelled = false;
8683
9001
  void loadSession(storageKey).then((stored) => {
8684
9002
  if (cancelled) return;
@@ -8696,7 +9014,7 @@ function App() {
8696
9014
  };
8697
9015
  }, [storageKey, config.defaultAuthor, dispatch]);
8698
9016
  const { session } = state;
8699
- (0, import_react20.useEffect)(() => {
9017
+ (0, import_react21.useEffect)(() => {
8700
9018
  if (!session) return;
8701
9019
  if (saveTimer.current !== null) window.clearTimeout(saveTimer.current);
8702
9020
  saveTimer.current = window.setTimeout(() => {
@@ -8707,9 +9025,9 @@ function App() {
8707
9025
  if (saveTimer.current !== null) window.clearTimeout(saveTimer.current);
8708
9026
  };
8709
9027
  }, [session, storageKey, config]);
8710
- (0, import_react20.useEffect)(() => trackPointer(), []);
8711
- const focusHandled = (0, import_react20.useRef)(false);
8712
- (0, import_react20.useEffect)(() => {
9028
+ (0, import_react21.useEffect)(() => trackPointer(), []);
9029
+ const focusHandled = (0, import_react21.useRef)(false);
9030
+ (0, import_react21.useEffect)(() => {
8713
9031
  if (!session || focusHandled.current) return;
8714
9032
  focusHandled.current = true;
8715
9033
  const id = takeFocusItem();
@@ -8734,7 +9052,7 @@ function App() {
8734
9052
  cancelled = true;
8735
9053
  };
8736
9054
  }, [session, dispatch]);
8737
- (0, import_react20.useEffect)(() => {
9055
+ (0, import_react21.useEffect)(() => {
8738
9056
  let last = window.location.pathname;
8739
9057
  const check = () => {
8740
9058
  if (window.location.pathname !== last) {
@@ -8749,9 +9067,9 @@ function App() {
8749
9067
  window.removeEventListener("popstate", check);
8750
9068
  };
8751
9069
  }, [dispatch]);
8752
- const stateRef = (0, import_react20.useRef)(state);
9070
+ const stateRef = (0, import_react21.useRef)(state);
8753
9071
  stateRef.current = state;
8754
- (0, import_react20.useEffect)(() => {
9072
+ (0, import_react21.useEffect)(() => {
8755
9073
  const onKeyDown = (event) => {
8756
9074
  const current = stateRef.current;
8757
9075
  for (const def of SHORTCUTS) {
@@ -8766,7 +9084,7 @@ function App() {
8766
9084
  document.addEventListener("keydown", onKeyDown);
8767
9085
  return () => document.removeEventListener("keydown", onKeyDown);
8768
9086
  }, [dispatch]);
8769
- (0, import_react20.useEffect)(() => {
9087
+ (0, import_react21.useEffect)(() => {
8770
9088
  if (!state.editor) return;
8771
9089
  const editorEl = state.editor.element;
8772
9090
  const onPointerDown = (event) => {
@@ -8779,31 +9097,32 @@ function App() {
8779
9097
  }, [state.editor, dispatch]);
8780
9098
  if (!session) return null;
8781
9099
  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, {})
9100
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DispatchContext.Provider, { value: dispatch, children: null });
9101
+ }
9102
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DispatchContext.Provider, { value: dispatch, children: [
9103
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PickLayer, {}),
9104
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PeerCursors, {}),
9105
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Toolbar, {}),
9106
+ state.editor?.kind === "copy" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InlineEditor, { editor: state.editor }),
9107
+ state.editor?.kind === "image" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ImageEditor, { editor: state.editor }),
9108
+ state.editor && state.editor.kind !== "copy" && state.editor.kind !== "image" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NoteComposer, { editor: state.editor }),
9109
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pins, {}),
9110
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(QuickComment, {}),
9111
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Panel, {}),
9112
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Badge, {}),
9113
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CoachMark, {}),
9114
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CheatSheet, {}),
9115
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmblemaConnect, {}),
9116
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TerminalConnect, {}),
9117
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ConfirmHost, {}),
9118
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ToastHost, {})
8800
9119
  ] });
8801
9120
  }
8802
- var import_react20, import_jsx_runtime18;
9121
+ var import_react21, import_jsx_runtime19;
8803
9122
  var init_App = __esm({
8804
9123
  "src/client/App.tsx"() {
8805
9124
  "use strict";
8806
- import_react20 = require("react");
9125
+ import_react21 = require("react");
8807
9126
  init_env();
8808
9127
  init_persist();
8809
9128
  init_reveal();
@@ -8819,6 +9138,7 @@ var init_App = __esm({
8819
9138
  init_Badge();
8820
9139
  init_CheatSheet();
8821
9140
  init_EmblemaConnect();
9141
+ init_TerminalConnect();
8822
9142
  init_CoachMark();
8823
9143
  init_Confirm();
8824
9144
  init_ImageEditor();
@@ -8831,14 +9151,14 @@ var init_App = __esm({
8831
9151
  init_Pins();
8832
9152
  init_Toolbar();
8833
9153
  init_Toast();
8834
- import_jsx_runtime18 = require("react/jsx-runtime");
9154
+ import_jsx_runtime19 = require("react/jsx-runtime");
8835
9155
  }
8836
9156
  });
8837
9157
 
8838
9158
  // src/client/ReviewKit.tsx
8839
9159
  function ShadowHost({ config }) {
8840
- const [mount, setMount] = (0, import_react21.useState)(null);
8841
- (0, import_react21.useEffect)(() => {
9160
+ const [mount, setMount] = (0, import_react22.useState)(null);
9161
+ (0, import_react22.useEffect)(() => {
8842
9162
  const host = document.createElement("div");
8843
9163
  host.setAttribute(HOST_ATTR, "");
8844
9164
  host.style.position = "fixed";
@@ -8874,15 +9194,15 @@ function ShadowHost({ config }) {
8874
9194
  }, []);
8875
9195
  if (!mount) return null;
8876
9196
  return (0, import_react_dom.createPortal)(
8877
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StoreProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(App, {}) }),
9197
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StoreProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(App, {}) }),
8878
9198
  mount
8879
9199
  );
8880
9200
  }
8881
9201
  function ReviewKit(props) {
8882
- const [active2, setActive] = (0, import_react21.useState)(false);
9202
+ const [active2, setActive] = (0, import_react22.useState)(false);
8883
9203
  const { enabled, token, allowedHosts, devAutoOn } = props;
8884
9204
  const hostsKey = allowedHosts?.join("\0") ?? "";
8885
- (0, import_react21.useEffect)(() => {
9205
+ (0, import_react22.useEffect)(() => {
8886
9206
  if (enabled === false) {
8887
9207
  setActive(false);
8888
9208
  return;
@@ -8893,13 +9213,13 @@ function ReviewKit(props) {
8893
9213
  return () => window.removeEventListener(DEACTIVATE_EVENT, onDeactivate);
8894
9214
  }, [enabled, token, devAutoOn, hostsKey]);
8895
9215
  if (enabled === false || !active2) return null;
8896
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ShadowHost, { config: props });
9216
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ShadowHost, { config: props });
8897
9217
  }
8898
- var import_react21, import_react_dom, import_jsx_runtime19;
9218
+ var import_react22, import_react_dom, import_jsx_runtime20;
8899
9219
  var init_ReviewKit = __esm({
8900
9220
  "src/client/ReviewKit.tsx"() {
8901
9221
  "use strict";
8902
- import_react21 = require("react");
9222
+ import_react22 = require("react");
8903
9223
  import_react_dom = require("react-dom");
8904
9224
  init_env();
8905
9225
  init_pointer();
@@ -8907,7 +9227,7 @@ var init_ReviewKit = __esm({
8907
9227
  init_target();
8908
9228
  init_store();
8909
9229
  init_App();
8910
- import_jsx_runtime19 = require("react/jsx-runtime");
9230
+ import_jsx_runtime20 = require("react/jsx-runtime");
8911
9231
  }
8912
9232
  });
8913
9233
 
@@ -8954,19 +9274,19 @@ __export(lazy_exports, {
8954
9274
  module.exports = __toCommonJS(lazy_exports);
8955
9275
 
8956
9276
  // src/LazyReviewKit.tsx
8957
- var import_react22 = require("react");
9277
+ var import_react23 = require("react");
8958
9278
  init_activate();
8959
- var import_jsx_runtime20 = require("react/jsx-runtime");
9279
+ var import_jsx_runtime21 = require("react/jsx-runtime");
8960
9280
  var coreModule = null;
8961
9281
  function loadCore() {
8962
9282
  if (!coreModule) coreModule = Promise.resolve().then(() => (init_client(), client_exports)).then((mod) => mod.ReviewKit);
8963
9283
  return coreModule;
8964
9284
  }
8965
9285
  function LazyReviewKit(props) {
8966
- const [Core, setCore] = (0, import_react22.useState)(null);
9286
+ const [Core, setCore] = (0, import_react23.useState)(null);
8967
9287
  const { enabled, token, allowedHosts, devAutoOn } = props;
8968
9288
  const hostsKey = allowedHosts?.join(" ") ?? "";
8969
- (0, import_react22.useEffect)(() => {
9289
+ (0, import_react23.useEffect)(() => {
8970
9290
  if (!shouldActivate({ enabled, token, allowedHosts, devAutoOn })) return;
8971
9291
  let cancelled = false;
8972
9292
  loadCore().then((component) => {
@@ -8979,7 +9299,7 @@ function LazyReviewKit(props) {
8979
9299
  };
8980
9300
  }, [enabled, token, devAutoOn, hostsKey]);
8981
9301
  if (!Core || enabled === false) return null;
8982
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Core, { ...props });
9302
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Core, { ...props });
8983
9303
  }
8984
9304
  // Annotate the CommonJS export names for ESM import in node:
8985
9305
  0 && (module.exports = {