@satanwagen/reviewkit 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +181 -1
- package/README.md +43 -18
- package/dist/{chunk-Q7U43PXE.js → chunk-L7JLBD7Q.js} +1 -1
- package/dist/{chunk-NSXRFM75.js → chunk-VNRVRNZX.js} +755 -450
- package/dist/chunk-VNRVRNZX.js.map +1 -0
- package/dist/client/index.cjs +803 -498
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/{index-Dl2Fl0qr.d.cts → index-CWGkg1-E.d.cts} +17 -8
- package/dist/{index-BUSmAweg.d.ts → index-DPsjkvaY.d.ts} +17 -8
- package/dist/index.cjs +803 -498
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lazy.cjs +849 -521
- package/dist/lazy.cjs.map +1 -1
- package/dist/lazy.d.cts +1 -1
- package/dist/lazy.d.ts +1 -1
- package/dist/lazy.js +1 -1
- package/dist/next.cjs +849 -521
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +1 -1
- package/dist/next.d.ts +1 -1
- package/dist/next.js +1 -1
- package/package.json +4 -2
- package/dist/chunk-NSXRFM75.js.map +0 -1
- /package/dist/{chunk-Q7U43PXE.js.map → chunk-L7JLBD7Q.js.map} +0 -0
package/dist/client/index.cjs
CHANGED
|
@@ -906,7 +906,7 @@ __export(client_exports, {
|
|
|
906
906
|
module.exports = __toCommonJS(client_exports);
|
|
907
907
|
|
|
908
908
|
// src/client/ReviewKit.tsx
|
|
909
|
-
var
|
|
909
|
+
var import_react22 = require("react");
|
|
910
910
|
var import_react_dom = require("react-dom");
|
|
911
911
|
|
|
912
912
|
// src/activate.ts
|
|
@@ -1908,6 +1908,8 @@ input, textarea, select {
|
|
|
1908
1908
|
.rk-sync-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--rk-fg-faint); }
|
|
1909
1909
|
.rk-sync-online .rk-sync-dot { background: var(--rk-success); }
|
|
1910
1910
|
.rk-sync-connecting .rk-sync-dot { background: var(--rk-warn); }
|
|
1911
|
+
.rk-sync-reason-token-short .rk-sync-dot, .rk-sync-reason-bad-token .rk-sync-dot { background: var(--rk-danger); }
|
|
1912
|
+
.rk-sync[title] { cursor: help; }
|
|
1911
1913
|
/* Automatic Emblema push hint (same quiet language) */
|
|
1912
1914
|
.rk-epush-ok .rk-sync-dot { background: var(--rk-success); }
|
|
1913
1915
|
.rk-epush-sending .rk-sync-dot { background: var(--rk-warn); }
|
|
@@ -3483,7 +3485,8 @@ function reducer(state, action) {
|
|
|
3483
3485
|
panelOpen: false,
|
|
3484
3486
|
confirm: null,
|
|
3485
3487
|
cheatsheetOpen: false,
|
|
3486
|
-
emblemaConnectOpen: false
|
|
3488
|
+
emblemaConnectOpen: false,
|
|
3489
|
+
terminalConnectOpen: false
|
|
3487
3490
|
} : { ...state, hidden: false };
|
|
3488
3491
|
case "SELECT":
|
|
3489
3492
|
return { ...state, selection: action.selection };
|
|
@@ -3593,12 +3596,16 @@ function reducer(state, action) {
|
|
|
3593
3596
|
return { ...state, cheatsheetOpen: action.open };
|
|
3594
3597
|
case "SET_EMBLEMA_CONNECT":
|
|
3595
3598
|
return { ...state, emblemaConnectOpen: action.open };
|
|
3599
|
+
case "SET_TERMINAL_CONNECT":
|
|
3600
|
+
return { ...state, terminalConnectOpen: action.open };
|
|
3596
3601
|
case "SET_COACH":
|
|
3597
3602
|
return { ...state, coachOpen: action.open };
|
|
3598
3603
|
case "SET_CORNER":
|
|
3599
3604
|
return { ...state, badgeCorner: action.corner };
|
|
3600
|
-
case "SYNC_STATUS":
|
|
3601
|
-
|
|
3605
|
+
case "SYNC_STATUS": {
|
|
3606
|
+
const reason = action.reason === void 0 ? action.status === "online" ? null : state.syncReason : action.reason;
|
|
3607
|
+
return state.syncStatus === action.status && state.syncReason === reason ? state : { ...state, syncStatus: action.status, syncReason: reason };
|
|
3608
|
+
}
|
|
3602
3609
|
case "EMBLEMA_PUSH_STATUS":
|
|
3603
3610
|
return state.emblemaPush === action.status ? state : { ...state, emblemaPush: action.status };
|
|
3604
3611
|
/*
|
|
@@ -3727,9 +3734,11 @@ function initialState() {
|
|
|
3727
3734
|
confirm: null,
|
|
3728
3735
|
cheatsheetOpen: false,
|
|
3729
3736
|
emblemaConnectOpen: false,
|
|
3737
|
+
terminalConnectOpen: false,
|
|
3730
3738
|
coachOpen: false,
|
|
3731
3739
|
undoStack: [],
|
|
3732
3740
|
syncStatus: "disabled",
|
|
3741
|
+
syncReason: null,
|
|
3733
3742
|
emblemaPush: "idle",
|
|
3734
3743
|
peers: [],
|
|
3735
3744
|
quick: null,
|
|
@@ -3744,7 +3753,7 @@ function StoreProvider({ config, children }) {
|
|
|
3744
3753
|
const configValue = (0, import_react.useMemo)(
|
|
3745
3754
|
() => config,
|
|
3746
3755
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- config object identity is per-render; depend on its fields
|
|
3747
|
-
[config.enabled, config.token, config.devAutoOn, config.syncToken, config.syncUrl, config.defaultAuthor, config.fxAssetsUrl, config.position, config.storageKey, config.onSessionChange, config.emblema]
|
|
3756
|
+
[config.enabled, config.token, config.devAutoOn, config.sync, config.syncToken, config.syncUrl, config.defaultAuthor, config.fxAssetsUrl, config.position, config.storageKey, config.onSessionChange, config.emblema]
|
|
3748
3757
|
);
|
|
3749
3758
|
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 }) }) });
|
|
3750
3759
|
}
|
|
@@ -3773,7 +3782,7 @@ function toast(dispatch, message, tone = "info") {
|
|
|
3773
3782
|
}
|
|
3774
3783
|
|
|
3775
3784
|
// src/client/App.tsx
|
|
3776
|
-
var
|
|
3785
|
+
var import_react21 = require("react");
|
|
3777
3786
|
|
|
3778
3787
|
// src/client/persist.ts
|
|
3779
3788
|
var DB_NAME = "review-kit";
|
|
@@ -4757,9 +4766,13 @@ function createRkSync(options) {
|
|
|
4757
4766
|
pongTimer = null;
|
|
4758
4767
|
}
|
|
4759
4768
|
break;
|
|
4760
|
-
case "error":
|
|
4769
|
+
case "error": {
|
|
4761
4770
|
log("server error:", msg.code, msg.message);
|
|
4771
|
+
const code = typeof msg.code === "string" ? msg.code : "error";
|
|
4772
|
+
const message = typeof msg.message === "string" ? msg.message : "";
|
|
4773
|
+
safely(() => handlers.onError?.(code, message));
|
|
4762
4774
|
break;
|
|
4775
|
+
}
|
|
4763
4776
|
case "presence:join": {
|
|
4764
4777
|
const peer = msg.peer;
|
|
4765
4778
|
if (peer && typeof peer.id === "string") safely(() => handlers.onPeerJoin?.(peer));
|
|
@@ -4961,6 +4974,23 @@ function currentAuthor(name) {
|
|
|
4961
4974
|
}
|
|
4962
4975
|
|
|
4963
4976
|
// src/client/sync.ts
|
|
4977
|
+
var DEFAULT_SYNC_URL = "wss://2-59-219-26.sslip.io/rk-sync";
|
|
4978
|
+
function normalizeRoute(route) {
|
|
4979
|
+
let r = String(route ?? "/");
|
|
4980
|
+
if (!r.startsWith("/")) r = "/" + r;
|
|
4981
|
+
return r.length > 1 ? r.replace(/\/+$/, "") : r;
|
|
4982
|
+
}
|
|
4983
|
+
function resolveSyncUrl(config) {
|
|
4984
|
+
return typeof config.syncUrl === "string" && config.syncUrl !== "" ? config.syncUrl : DEFAULT_SYNC_URL;
|
|
4985
|
+
}
|
|
4986
|
+
var MIN_SYNC_TOKEN_LENGTH = 8;
|
|
4987
|
+
var warnedShortToken = false;
|
|
4988
|
+
function resolveSyncToken(config) {
|
|
4989
|
+
if (config.sync === false) return null;
|
|
4990
|
+
const explicit = typeof config.syncToken === "string" && config.syncToken !== "" ? config.syncToken : null;
|
|
4991
|
+
const fallback = typeof config.token === "string" && config.token !== "" ? config.token : null;
|
|
4992
|
+
return explicit ?? fallback;
|
|
4993
|
+
}
|
|
4964
4994
|
function toPeerState(peer) {
|
|
4965
4995
|
return {
|
|
4966
4996
|
id: peer.id,
|
|
@@ -4988,20 +5018,43 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
|
|
|
4988
5018
|
const stateRef = (0, import_react4.useRef)(state);
|
|
4989
5019
|
stateRef.current = state;
|
|
4990
5020
|
const myIdRef = (0, import_react4.useRef)("");
|
|
4991
|
-
const
|
|
5021
|
+
const syncToken = resolveSyncToken(config);
|
|
5022
|
+
const syncUrl = resolveSyncUrl(config);
|
|
5023
|
+
const enabled = syncToken !== null;
|
|
4992
5024
|
const author = state.session?.author ?? "";
|
|
4993
5025
|
const hasSession = state.session !== null;
|
|
4994
5026
|
(0, import_react4.useEffect)(() => {
|
|
4995
5027
|
if (!enabled || !hasSession) return;
|
|
5028
|
+
const dispatchGuard = rawDispatch;
|
|
5029
|
+
if (syncToken.length < MIN_SYNC_TOKEN_LENGTH) {
|
|
5030
|
+
dispatchGuard({ type: "SYNC_STATUS", status: "offline", reason: "token-short" });
|
|
5031
|
+
if (!warnedShortToken) {
|
|
5032
|
+
warnedShortToken = true;
|
|
5033
|
+
console.warn(
|
|
5034
|
+
`[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.`
|
|
5035
|
+
);
|
|
5036
|
+
}
|
|
5037
|
+
return () => dispatchGuard({ type: "SYNC_STATUS", status: "disabled", reason: null });
|
|
5038
|
+
}
|
|
4996
5039
|
const id = reviewerId();
|
|
4997
5040
|
myIdRef.current = id;
|
|
4998
5041
|
const dispatch = rawDispatch;
|
|
4999
5042
|
const sync = createRkSync({
|
|
5000
|
-
token:
|
|
5001
|
-
url:
|
|
5043
|
+
token: syncToken,
|
|
5044
|
+
url: syncUrl,
|
|
5002
5045
|
user: { id, name: author || "Reviewer", color: colorForReviewer(id) },
|
|
5003
5046
|
handlers: {
|
|
5004
|
-
onStatus: (status) => dispatch({
|
|
5047
|
+
onStatus: (status) => dispatch({
|
|
5048
|
+
type: "SYNC_STATUS",
|
|
5049
|
+
status,
|
|
5050
|
+
// Offline with no server verdict = the socket never got through
|
|
5051
|
+
// (server down, CSP connect-src, network); a verdict keeps its reason.
|
|
5052
|
+
...status === "offline" ? { reason: stateRef.current.syncReason ?? "unreachable" } : {}
|
|
5053
|
+
}),
|
|
5054
|
+
onError: (code) => {
|
|
5055
|
+
if (code === "bad-token") dispatch({ type: "SYNC_STATUS", status: "offline", reason: "bad-token" });
|
|
5056
|
+
else if (code === "room-full") dispatch({ type: "SYNC_STATUS", status: "offline", reason: "room-full" });
|
|
5057
|
+
},
|
|
5005
5058
|
onSnapshot: (items, peers, deletedIds = []) => {
|
|
5006
5059
|
const safeItems = items.map(sanitizeRemoteItem).filter((item) => item !== null);
|
|
5007
5060
|
dispatch({ type: "SYNC_SNAPSHOT", items: safeItems });
|
|
@@ -5009,8 +5062,11 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
|
|
|
5009
5062
|
for (const id2 of deletedIds) dispatch({ type: "REMOTE_DELETE", id: id2 });
|
|
5010
5063
|
dispatch({ type: "PEERS_SET", peers: peers.filter((peer) => peer.id !== id).map(toPeerState) });
|
|
5011
5064
|
const serverIds = new Set(items.map((item) => item.id));
|
|
5065
|
+
const here = normalizeRoute(window.location.pathname);
|
|
5012
5066
|
for (const item of stateRef.current.session?.items ?? []) {
|
|
5013
|
-
if (
|
|
5067
|
+
if (serverIds.has(item.id) || deleted.has(item.id)) continue;
|
|
5068
|
+
if (normalizeRoute(item.route) !== here) continue;
|
|
5069
|
+
sync.addItem(item);
|
|
5014
5070
|
}
|
|
5015
5071
|
},
|
|
5016
5072
|
onPeerJoin: (peer) => dispatch({
|
|
@@ -5058,10 +5114,10 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
|
|
|
5058
5114
|
if (activeSyncRef === sync) activeSyncRef = null;
|
|
5059
5115
|
setEffectBroadcaster2(null);
|
|
5060
5116
|
sync.stop();
|
|
5061
|
-
dispatch({ type: "SYNC_STATUS", status: "disabled" });
|
|
5117
|
+
dispatch({ type: "SYNC_STATUS", status: "disabled", reason: null });
|
|
5062
5118
|
dispatch({ type: "PEERS_SET", peers: [] });
|
|
5063
5119
|
};
|
|
5064
|
-
}, [enabled, hasSession,
|
|
5120
|
+
}, [enabled, hasSession, syncToken, syncUrl, author, rawDispatch]);
|
|
5065
5121
|
const wrapped = (0, import_react4.useMemo)(() => {
|
|
5066
5122
|
return (action) => {
|
|
5067
5123
|
const prev = stateRef.current;
|
|
@@ -5577,10 +5633,10 @@ function EmblemaConnect() {
|
|
|
5577
5633
|
state === null && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5578
5634
|
"The local sync agent isn't running. In the project repo run:",
|
|
5579
5635
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("code", { className: "rk-connect-cmd", children: [
|
|
5580
|
-
"npx @satanwagen/reviewkit-cli init --origin ",
|
|
5636
|
+
"npx -p @satanwagen/reviewkit-cli reviewkit-emblema init --origin ",
|
|
5581
5637
|
window.location.origin
|
|
5582
5638
|
] }),
|
|
5583
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "rk-connect-cmd", children: "npx @satanwagen/reviewkit-cli serve" }),
|
|
5639
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "rk-connect-cmd", children: "npx -p @satanwagen/reviewkit-cli reviewkit-emblema serve" }),
|
|
5584
5640
|
"then reopen this dialog."
|
|
5585
5641
|
] }),
|
|
5586
5642
|
state !== null && state !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
@@ -5667,15 +5723,229 @@ function EmblemaConnect() {
|
|
|
5667
5723
|
] });
|
|
5668
5724
|
}
|
|
5669
5725
|
|
|
5670
|
-
// src/client/components/
|
|
5726
|
+
// src/client/components/TerminalConnect.tsx
|
|
5671
5727
|
var import_react7 = require("react");
|
|
5728
|
+
|
|
5729
|
+
// src/integrations/terminal.ts
|
|
5730
|
+
var TERMINAL_PAIR_PORTS = [48780, 48781, 48782, 48783];
|
|
5731
|
+
async function fetchJson2(url, init, timeoutMs) {
|
|
5732
|
+
const abort = new AbortController();
|
|
5733
|
+
const timer = window.setTimeout(() => abort.abort(), timeoutMs);
|
|
5734
|
+
try {
|
|
5735
|
+
return await fetch(url, { ...init, signal: abort.signal });
|
|
5736
|
+
} finally {
|
|
5737
|
+
window.clearTimeout(timer);
|
|
5738
|
+
}
|
|
5739
|
+
}
|
|
5740
|
+
async function probeTerminal() {
|
|
5741
|
+
for (const port of TERMINAL_PAIR_PORTS) {
|
|
5742
|
+
try {
|
|
5743
|
+
const res = await fetchJson2(`http://127.0.0.1:${port}/pair`, { method: "GET" }, 900);
|
|
5744
|
+
if (!res.ok) continue;
|
|
5745
|
+
const body = await res.json();
|
|
5746
|
+
if (typeof body === "object" && body !== null && body.app === "reviewkit-cli") {
|
|
5747
|
+
const b = body;
|
|
5748
|
+
return {
|
|
5749
|
+
port,
|
|
5750
|
+
cwd: typeof b.cwd === "string" ? b.cwd : void 0,
|
|
5751
|
+
projects: Array.isArray(b.projects) ? b.projects.filter((p) => typeof p === "string") : []
|
|
5752
|
+
};
|
|
5753
|
+
}
|
|
5754
|
+
} catch {
|
|
5755
|
+
}
|
|
5756
|
+
}
|
|
5757
|
+
return null;
|
|
5758
|
+
}
|
|
5759
|
+
async function pairTerminal(port, key) {
|
|
5760
|
+
try {
|
|
5761
|
+
const res = await fetchJson2(
|
|
5762
|
+
`http://127.0.0.1:${port}/pair`,
|
|
5763
|
+
{ method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ key }) },
|
|
5764
|
+
5e3
|
|
5765
|
+
);
|
|
5766
|
+
const body = await res.json().catch(() => null);
|
|
5767
|
+
if (res.ok && body?.ok) return { ok: true, name: body.name ?? "", repo: body.repo ?? null };
|
|
5768
|
+
return { ok: false, error: body?.error ?? `HTTP ${res.status}` };
|
|
5769
|
+
} catch {
|
|
5770
|
+
return { ok: false, error: "the terminal stopped answering" };
|
|
5771
|
+
}
|
|
5772
|
+
}
|
|
5773
|
+
|
|
5774
|
+
// src/client/terminalKey.ts
|
|
5775
|
+
var TERMINAL_KEY_PREFIX = "rkc_";
|
|
5776
|
+
var TERMINAL_KEY_VERSION = 1;
|
|
5777
|
+
function base64url(text) {
|
|
5778
|
+
const bytes = new TextEncoder().encode(text);
|
|
5779
|
+
let binary = "";
|
|
5780
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
5781
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
5782
|
+
}
|
|
5783
|
+
function encodeTerminalKey(fields) {
|
|
5784
|
+
const payload = { v: TERMINAL_KEY_VERSION, ...fields };
|
|
5785
|
+
return TERMINAL_KEY_PREFIX + base64url(JSON.stringify(payload));
|
|
5786
|
+
}
|
|
5787
|
+
function currentTerminalKey(syncUrl, syncToken) {
|
|
5788
|
+
const origin = window.location.origin;
|
|
5789
|
+
let route = "/";
|
|
5790
|
+
try {
|
|
5791
|
+
route = window.location.pathname || "/";
|
|
5792
|
+
} catch {
|
|
5793
|
+
}
|
|
5794
|
+
return encodeTerminalKey({ name: window.location.hostname, origin, syncUrl, syncToken, route });
|
|
5795
|
+
}
|
|
5796
|
+
|
|
5797
|
+
// src/client/components/TerminalConnect.tsx
|
|
5672
5798
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
5799
|
+
function shortKey2(key) {
|
|
5800
|
+
return `${key.slice(0, 8)}\u2026${key.slice(-6)}`;
|
|
5801
|
+
}
|
|
5802
|
+
function shortPath(path) {
|
|
5803
|
+
if (!path) return "";
|
|
5804
|
+
const parts = path.split("/").filter(Boolean);
|
|
5805
|
+
return parts.length > 2 ? `\u2026/${parts.slice(-2).join("/")}` : path;
|
|
5806
|
+
}
|
|
5807
|
+
function TerminalConnect() {
|
|
5808
|
+
const { terminalConnectOpen } = useStore();
|
|
5809
|
+
const config = useConfig();
|
|
5810
|
+
const dispatch = useDispatch();
|
|
5811
|
+
const [phase, setPhase] = (0, import_react7.useState)("probing");
|
|
5812
|
+
const [probe, setProbe] = (0, import_react7.useState)(null);
|
|
5813
|
+
const [paired, setPaired] = (0, import_react7.useState)(null);
|
|
5814
|
+
const [showManual, setShowManual] = (0, import_react7.useState)(false);
|
|
5815
|
+
const syncToken = resolveSyncToken(config);
|
|
5816
|
+
const key = terminalConnectOpen && syncToken ? currentTerminalKey(resolveSyncUrl(config), syncToken) : null;
|
|
5817
|
+
(0, import_react7.useEffect)(() => {
|
|
5818
|
+
if (!terminalConnectOpen) return;
|
|
5819
|
+
let cancelled = false;
|
|
5820
|
+
setPhase("probing");
|
|
5821
|
+
setProbe(null);
|
|
5822
|
+
setPaired(null);
|
|
5823
|
+
setShowManual(false);
|
|
5824
|
+
const look = () => void probeTerminal().then((found) => {
|
|
5825
|
+
if (cancelled) return;
|
|
5826
|
+
setProbe(found);
|
|
5827
|
+
setPhase((current) => current === "pairing" || current === "paired" ? current : found ? "found" : "missing");
|
|
5828
|
+
});
|
|
5829
|
+
look();
|
|
5830
|
+
const timer = window.setInterval(look, 2e3);
|
|
5831
|
+
return () => {
|
|
5832
|
+
cancelled = true;
|
|
5833
|
+
window.clearInterval(timer);
|
|
5834
|
+
};
|
|
5835
|
+
}, [terminalConnectOpen]);
|
|
5836
|
+
if (!terminalConnectOpen) return null;
|
|
5837
|
+
const close = () => dispatch({ type: "SET_TERMINAL_CONNECT", open: false });
|
|
5838
|
+
const copy = async (value, what) => {
|
|
5839
|
+
try {
|
|
5840
|
+
await navigator.clipboard.writeText(value);
|
|
5841
|
+
toast(dispatch, `${what} copied`, "success");
|
|
5842
|
+
} catch {
|
|
5843
|
+
toast(dispatch, "Copy failed \u2014 select the text manually", "error");
|
|
5844
|
+
}
|
|
5845
|
+
};
|
|
5846
|
+
const connect = () => {
|
|
5847
|
+
if (!probe || !key) return;
|
|
5848
|
+
setPhase("pairing");
|
|
5849
|
+
void pairTerminal(probe.port, key).then((result) => {
|
|
5850
|
+
if (result.ok) {
|
|
5851
|
+
setPaired({ name: result.name, repo: result.repo });
|
|
5852
|
+
setPhase("paired");
|
|
5853
|
+
toast(dispatch, `Terminal paired as \u201C${result.name}\u201D`, "success");
|
|
5854
|
+
} else {
|
|
5855
|
+
setPhase("found");
|
|
5856
|
+
toast(dispatch, `Pairing failed: ${result.error}`, "error");
|
|
5857
|
+
}
|
|
5858
|
+
});
|
|
5859
|
+
};
|
|
5860
|
+
const connectCmd = key ? `npx -y @satanwagen/reviewkit-cli connect ${key}` : "";
|
|
5861
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5862
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "rk-backdrop", onClick: close }),
|
|
5863
|
+
/* @__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: [
|
|
5864
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
5865
|
+
"Connect terminal / agent",
|
|
5866
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { flex: 1 } }),
|
|
5867
|
+
/* @__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 }) })
|
|
5868
|
+
] }),
|
|
5869
|
+
!key && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5870
|
+
"Live sync is off on this page (",
|
|
5871
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "sync=false" }),
|
|
5872
|
+
" or no token), so there is no shared room a terminal could read."
|
|
5873
|
+
] }),
|
|
5874
|
+
key && phase === "paired" && paired && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5875
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-emblema-dot", "data-state": "live" }),
|
|
5876
|
+
" Paired as ",
|
|
5877
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: paired.name }),
|
|
5878
|
+
paired.repo ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5879
|
+
" in ",
|
|
5880
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: shortPath(paired.repo) })
|
|
5881
|
+
] }) : null,
|
|
5882
|
+
". The terminal shows this page's comments live, and Claude Code / Cursor can read and resolve them through the ",
|
|
5883
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "reviewkit" }),
|
|
5884
|
+
" MCP tools."
|
|
5885
|
+
] }),
|
|
5886
|
+
key && phase !== "paired" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5887
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5888
|
+
phase === "probing" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5889
|
+
"Looking for a ",
|
|
5890
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "reviewkit" }),
|
|
5891
|
+
" terminal on this machine\u2026"
|
|
5892
|
+
] }),
|
|
5893
|
+
phase === "missing" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5894
|
+
"No terminal is listening yet. In the site's repo run",
|
|
5895
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: "rk-connect-cmd", children: "npx -y @satanwagen/reviewkit-cli setup" }),
|
|
5896
|
+
"and this dialog will pick it up by itself."
|
|
5897
|
+
] }),
|
|
5898
|
+
(phase === "found" || phase === "pairing") && probe && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5899
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-emblema-dot", "data-state": "live" }),
|
|
5900
|
+
" Terminal found",
|
|
5901
|
+
probe.cwd ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5902
|
+
" in ",
|
|
5903
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: shortPath(probe.cwd) })
|
|
5904
|
+
] }) : null,
|
|
5905
|
+
".",
|
|
5906
|
+
probe.projects.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5907
|
+
" Already paired: ",
|
|
5908
|
+
probe.projects.join(", "),
|
|
5909
|
+
"."
|
|
5910
|
+
] }) : null
|
|
5911
|
+
] })
|
|
5912
|
+
] }),
|
|
5913
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-connect-actions", children: [
|
|
5914
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
5915
|
+
"button",
|
|
5916
|
+
{
|
|
5917
|
+
type: "button",
|
|
5918
|
+
className: "rk-btn rk-btn-primary",
|
|
5919
|
+
disabled: phase !== "found",
|
|
5920
|
+
onClick: connect,
|
|
5921
|
+
title: "Send this site's connection to the terminal \u2014 nothing to copy",
|
|
5922
|
+
children: phase === "pairing" ? "Connecting\u2026" : "Connect this terminal"
|
|
5923
|
+
}
|
|
5924
|
+
),
|
|
5925
|
+
/* @__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" })
|
|
5926
|
+
] }),
|
|
5927
|
+
showManual && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5928
|
+
/* @__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):" }),
|
|
5929
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("code", { className: "rk-connect-cmd", title: connectCmd, children: [
|
|
5930
|
+
"npx -y @satanwagen/reviewkit-cli connect ",
|
|
5931
|
+
shortKey2(key)
|
|
5932
|
+
] }),
|
|
5933
|
+
/* @__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" }) })
|
|
5934
|
+
] })
|
|
5935
|
+
] })
|
|
5936
|
+
] }) })
|
|
5937
|
+
] });
|
|
5938
|
+
}
|
|
5939
|
+
|
|
5940
|
+
// src/client/components/CoachMark.tsx
|
|
5941
|
+
var import_react8 = require("react");
|
|
5942
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
5673
5943
|
var COACH_KEY = "review-kit:coach-dismissed";
|
|
5674
5944
|
function CoachMark() {
|
|
5675
5945
|
const { coachOpen, session } = useStore();
|
|
5676
5946
|
const dispatch = useDispatch();
|
|
5677
5947
|
const config = useConfig();
|
|
5678
|
-
const [name, setName] = (0,
|
|
5948
|
+
const [name, setName] = (0, import_react8.useState)(session?.author ?? config.defaultAuthor ?? "");
|
|
5679
5949
|
if (!coachOpen) return null;
|
|
5680
5950
|
const done = (startPicking) => {
|
|
5681
5951
|
if (name.trim() !== "") dispatch({ type: "SET_AUTHOR", author: name.trim() });
|
|
@@ -5686,39 +5956,39 @@ function CoachMark() {
|
|
|
5686
5956
|
}
|
|
5687
5957
|
if (startPicking) dispatch({ type: "SET_MODE", mode: "pick" });
|
|
5688
5958
|
};
|
|
5689
|
-
return /* @__PURE__ */ (0,
|
|
5690
|
-
/* @__PURE__ */ (0,
|
|
5691
|
-
/* @__PURE__ */ (0,
|
|
5692
|
-
/* @__PURE__ */ (0,
|
|
5693
|
-
/* @__PURE__ */ (0,
|
|
5959
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach", role: "dialog", "aria-label": "Welcome to review mode", children: [
|
|
5960
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rk-coach-accent" }),
|
|
5961
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach-body", children: [
|
|
5962
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
5963
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconTarget, { size: 16 }),
|
|
5694
5964
|
" Review mode"
|
|
5695
5965
|
] }),
|
|
5696
|
-
/* @__PURE__ */ (0,
|
|
5697
|
-
/* @__PURE__ */ (0,
|
|
5698
|
-
/* @__PURE__ */ (0,
|
|
5699
|
-
/* @__PURE__ */ (0,
|
|
5966
|
+
/* @__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." }),
|
|
5967
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach-keys", "aria-label": "Key shortcuts", children: [
|
|
5968
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5969
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "T" }),
|
|
5700
5970
|
" rewrite"
|
|
5701
5971
|
] }),
|
|
5702
|
-
/* @__PURE__ */ (0,
|
|
5703
|
-
/* @__PURE__ */ (0,
|
|
5972
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5973
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "C" }),
|
|
5704
5974
|
" comment"
|
|
5705
5975
|
] }),
|
|
5706
|
-
/* @__PURE__ */ (0,
|
|
5707
|
-
/* @__PURE__ */ (0,
|
|
5976
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5977
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "I" }),
|
|
5708
5978
|
" image"
|
|
5709
5979
|
] }),
|
|
5710
|
-
/* @__PURE__ */ (0,
|
|
5711
|
-
/* @__PURE__ */ (0,
|
|
5980
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5981
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "V" }),
|
|
5712
5982
|
" select"
|
|
5713
5983
|
] }),
|
|
5714
|
-
/* @__PURE__ */ (0,
|
|
5715
|
-
/* @__PURE__ */ (0,
|
|
5984
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5985
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "?" }),
|
|
5716
5986
|
" all shortcuts"
|
|
5717
5987
|
] })
|
|
5718
5988
|
] }),
|
|
5719
|
-
/* @__PURE__ */ (0,
|
|
5720
|
-
/* @__PURE__ */ (0,
|
|
5721
|
-
/* @__PURE__ */ (0,
|
|
5989
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
|
|
5990
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "rk-label", htmlFor: "rk-author", children: "Your name" }),
|
|
5991
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
5722
5992
|
"input",
|
|
5723
5993
|
{
|
|
5724
5994
|
id: "rk-author",
|
|
@@ -5732,36 +6002,36 @@ function CoachMark() {
|
|
|
5732
6002
|
}
|
|
5733
6003
|
)
|
|
5734
6004
|
] }),
|
|
5735
|
-
/* @__PURE__ */ (0,
|
|
5736
|
-
/* @__PURE__ */ (0,
|
|
5737
|
-
/* @__PURE__ */ (0,
|
|
6005
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 4 }, children: [
|
|
6006
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => done(false), children: "Not now" }),
|
|
6007
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: () => done(true), children: "Start reviewing" })
|
|
5738
6008
|
] })
|
|
5739
6009
|
] })
|
|
5740
6010
|
] });
|
|
5741
6011
|
}
|
|
5742
6012
|
|
|
5743
6013
|
// src/client/components/Confirm.tsx
|
|
5744
|
-
var
|
|
5745
|
-
var
|
|
6014
|
+
var import_react9 = require("react");
|
|
6015
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
5746
6016
|
function ConfirmHost() {
|
|
5747
6017
|
const { confirm } = useStore();
|
|
5748
6018
|
const dispatch = useDispatch();
|
|
5749
|
-
const cancelRef = (0,
|
|
5750
|
-
(0,
|
|
6019
|
+
const cancelRef = (0, import_react9.useRef)(null);
|
|
6020
|
+
(0, import_react9.useEffect)(() => {
|
|
5751
6021
|
if (confirm) cancelRef.current?.focus();
|
|
5752
6022
|
}, [confirm]);
|
|
5753
6023
|
if (!confirm) return null;
|
|
5754
6024
|
const close = () => dispatch({ type: "SET_CONFIRM", confirm: null });
|
|
5755
|
-
return /* @__PURE__ */ (0,
|
|
5756
|
-
/* @__PURE__ */ (0,
|
|
5757
|
-
/* @__PURE__ */ (0,
|
|
5758
|
-
/* @__PURE__ */ (0,
|
|
5759
|
-
/* @__PURE__ */ (0,
|
|
5760
|
-
/* @__PURE__ */ (0,
|
|
6025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
6026
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-backdrop", onClick: close }),
|
|
6027
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal", role: "alertdialog", "aria-modal": "true", "aria-label": confirm.title, children: [
|
|
6028
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal-body", children: [
|
|
6029
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-modal-title", children: confirm.title }),
|
|
6030
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-modal-text", children: confirm.message })
|
|
5761
6031
|
] }),
|
|
5762
|
-
/* @__PURE__ */ (0,
|
|
5763
|
-
/* @__PURE__ */ (0,
|
|
5764
|
-
/* @__PURE__ */ (0,
|
|
6032
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal-actions", children: [
|
|
6033
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { ref: cancelRef, type: "button", className: "rk-btn rk-btn-ghost", onClick: close, children: "Cancel" }),
|
|
6034
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5765
6035
|
"button",
|
|
5766
6036
|
{
|
|
5767
6037
|
type: "button",
|
|
@@ -5780,10 +6050,10 @@ function ConfirmHost() {
|
|
|
5780
6050
|
}
|
|
5781
6051
|
|
|
5782
6052
|
// src/client/components/ImageEditor.tsx
|
|
5783
|
-
var
|
|
6053
|
+
var import_react11 = require("react");
|
|
5784
6054
|
|
|
5785
6055
|
// src/client/useAnchored.ts
|
|
5786
|
-
var
|
|
6056
|
+
var import_react10 = require("react");
|
|
5787
6057
|
|
|
5788
6058
|
// src/client/position.ts
|
|
5789
6059
|
function place(anchor, size, side, offset) {
|
|
@@ -5828,9 +6098,9 @@ function computePosition(anchor, size, options = {}) {
|
|
|
5828
6098
|
|
|
5829
6099
|
// src/client/useAnchored.ts
|
|
5830
6100
|
function useAnchored(anchorEl, side = "bottom", offset = 8) {
|
|
5831
|
-
const ref = (0,
|
|
5832
|
-
const [pos, setPos] = (0,
|
|
5833
|
-
(0,
|
|
6101
|
+
const ref = (0, import_react10.useRef)(null);
|
|
6102
|
+
const [pos, setPos] = (0, import_react10.useState)(null);
|
|
6103
|
+
(0, import_react10.useLayoutEffect)(() => {
|
|
5834
6104
|
if (!anchorEl) {
|
|
5835
6105
|
setPos(null);
|
|
5836
6106
|
return;
|
|
@@ -5861,7 +6131,7 @@ function anchoredStyle(pos) {
|
|
|
5861
6131
|
}
|
|
5862
6132
|
|
|
5863
6133
|
// src/client/components/ImageEditor.tsx
|
|
5864
|
-
var
|
|
6134
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
5865
6135
|
var MAX_BYTES = 2 * 1024 * 1024;
|
|
5866
6136
|
var FETCH_TIMEOUT_MS = 12e3;
|
|
5867
6137
|
var PROBE_TIMEOUT_MS = 8e3;
|
|
@@ -5919,15 +6189,15 @@ function urlFromDataTransfer(dt) {
|
|
|
5919
6189
|
function ImageEditor({ editor }) {
|
|
5920
6190
|
const dispatch = useDispatch();
|
|
5921
6191
|
const { route, session } = useStore();
|
|
5922
|
-
const [replacement, setReplacement] = (0,
|
|
5923
|
-
const [urlValue, setUrlValue] = (0,
|
|
5924
|
-
const [loading2, setLoading] = (0,
|
|
5925
|
-
const [description, setDescription] = (0,
|
|
5926
|
-
const [priority, setPriority] = (0,
|
|
5927
|
-
const [over, setOver] = (0,
|
|
5928
|
-
const fileInput = (0,
|
|
5929
|
-
const abortRef = (0,
|
|
5930
|
-
const debounceRef = (0,
|
|
6192
|
+
const [replacement, setReplacement] = (0, import_react11.useState)(null);
|
|
6193
|
+
const [urlValue, setUrlValue] = (0, import_react11.useState)("");
|
|
6194
|
+
const [loading2, setLoading] = (0, import_react11.useState)(false);
|
|
6195
|
+
const [description, setDescription] = (0, import_react11.useState)("");
|
|
6196
|
+
const [priority, setPriority] = (0, import_react11.useState)("nice");
|
|
6197
|
+
const [over, setOver] = (0, import_react11.useState)(false);
|
|
6198
|
+
const fileInput = (0, import_react11.useRef)(null);
|
|
6199
|
+
const abortRef = (0, import_react11.useRef)(null);
|
|
6200
|
+
const debounceRef = (0, import_react11.useRef)(null);
|
|
5931
6201
|
const { ref, pos } = useAnchored(editor.element, "bottom", 12);
|
|
5932
6202
|
const image = findImage(editor.element);
|
|
5933
6203
|
const beforeSrc = image?.currentSrc || image?.src || "";
|
|
@@ -5991,7 +6261,7 @@ function ImageEditor({ editor }) {
|
|
|
5991
6261
|
}
|
|
5992
6262
|
}
|
|
5993
6263
|
};
|
|
5994
|
-
(0,
|
|
6264
|
+
(0, import_react11.useEffect)(() => {
|
|
5995
6265
|
if (debounceRef.current !== null) window.clearTimeout(debounceRef.current);
|
|
5996
6266
|
if (urlValue.trim() === "" || replacement !== null) return;
|
|
5997
6267
|
debounceRef.current = window.setTimeout(() => {
|
|
@@ -6001,8 +6271,8 @@ function ImageEditor({ editor }) {
|
|
|
6001
6271
|
if (debounceRef.current !== null) window.clearTimeout(debounceRef.current);
|
|
6002
6272
|
};
|
|
6003
6273
|
}, [urlValue, replacement]);
|
|
6004
|
-
(0,
|
|
6005
|
-
(0,
|
|
6274
|
+
(0, import_react11.useEffect)(() => () => abortRef.current?.abort(), []);
|
|
6275
|
+
(0, import_react11.useEffect)(() => {
|
|
6006
6276
|
const onPaste = (event) => {
|
|
6007
6277
|
const data = event.clipboardData;
|
|
6008
6278
|
if (!data) return;
|
|
@@ -6080,23 +6350,23 @@ function ImageEditor({ editor }) {
|
|
|
6080
6350
|
toast(dispatch, "Image proposal saved", "success");
|
|
6081
6351
|
};
|
|
6082
6352
|
const previewSrc = replacement?.kind === "data" ? replacement.dataUrl : replacement?.url;
|
|
6083
|
-
return /* @__PURE__ */ (0,
|
|
6084
|
-
/* @__PURE__ */ (0,
|
|
6085
|
-
/* @__PURE__ */ (0,
|
|
6353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Replace image", children: [
|
|
6354
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-head", children: [
|
|
6355
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconImage, { size: 14 }),
|
|
6086
6356
|
"Replace image"
|
|
6087
6357
|
] }),
|
|
6088
|
-
/* @__PURE__ */ (0,
|
|
6089
|
-
replacement && previewSrc ? /* @__PURE__ */ (0,
|
|
6090
|
-
/* @__PURE__ */ (0,
|
|
6091
|
-
/* @__PURE__ */ (0,
|
|
6092
|
-
/* @__PURE__ */ (0,
|
|
6358
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-body", children: [
|
|
6359
|
+
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: [
|
|
6360
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6361
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: beforeSrc, alt: "Current" }),
|
|
6362
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { children: "Before" })
|
|
6093
6363
|
] }),
|
|
6094
|
-
/* @__PURE__ */ (0,
|
|
6095
|
-
/* @__PURE__ */ (0,
|
|
6096
|
-
/* @__PURE__ */ (0,
|
|
6364
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6365
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: previewSrc, alt: "Proposed replacement" }),
|
|
6366
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { children: replacement.kind === "url" ? "After \xB7 linked" : "After" })
|
|
6097
6367
|
] })
|
|
6098
|
-
] }) }) : /* @__PURE__ */ (0,
|
|
6099
|
-
/* @__PURE__ */ (0,
|
|
6368
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
6369
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
6100
6370
|
"button",
|
|
6101
6371
|
{
|
|
6102
6372
|
type: "button",
|
|
@@ -6109,18 +6379,18 @@ function ImageEditor({ editor }) {
|
|
|
6109
6379
|
onDragLeave: () => setOver(false),
|
|
6110
6380
|
onDrop,
|
|
6111
6381
|
children: [
|
|
6112
|
-
/* @__PURE__ */ (0,
|
|
6113
|
-
/* @__PURE__ */ (0,
|
|
6382
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconUpload, { size: 18 }),
|
|
6383
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
|
|
6114
6384
|
"Drop an image \u2014 from your disk or another tab \u2014",
|
|
6115
|
-
/* @__PURE__ */ (0,
|
|
6385
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("br", {}),
|
|
6116
6386
|
"or click to browse (max 2 MB)"
|
|
6117
6387
|
] })
|
|
6118
6388
|
]
|
|
6119
6389
|
}
|
|
6120
6390
|
),
|
|
6121
|
-
/* @__PURE__ */ (0,
|
|
6122
|
-
loading2 ? /* @__PURE__ */ (0,
|
|
6123
|
-
/* @__PURE__ */ (0,
|
|
6391
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-url", children: [
|
|
6392
|
+
loading2 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-spinner", "aria-label": "Loading image" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconLink, { size: 13 }),
|
|
6393
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6124
6394
|
"input",
|
|
6125
6395
|
{
|
|
6126
6396
|
className: "rk-input",
|
|
@@ -6135,9 +6405,9 @@ function ImageEditor({ editor }) {
|
|
|
6135
6405
|
)
|
|
6136
6406
|
] })
|
|
6137
6407
|
] }),
|
|
6138
|
-
replacement && /* @__PURE__ */ (0,
|
|
6139
|
-
/* @__PURE__ */ (0,
|
|
6140
|
-
/* @__PURE__ */ (0,
|
|
6408
|
+
replacement && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: clearReplacement, children: "Remove replacement" }),
|
|
6409
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { ref: fileInput, type: "file", accept: "image/*", hidden: true, onChange: onPick }),
|
|
6410
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6141
6411
|
"textarea",
|
|
6142
6412
|
{
|
|
6143
6413
|
className: "rk-textarea",
|
|
@@ -6147,43 +6417,43 @@ function ImageEditor({ editor }) {
|
|
|
6147
6417
|
rows: 2
|
|
6148
6418
|
}
|
|
6149
6419
|
),
|
|
6150
|
-
/* @__PURE__ */ (0,
|
|
6151
|
-
/* @__PURE__ */ (0,
|
|
6152
|
-
/* @__PURE__ */ (0,
|
|
6420
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
6421
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
|
|
6422
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
|
|
6153
6423
|
] })
|
|
6154
6424
|
] }),
|
|
6155
|
-
/* @__PURE__ */ (0,
|
|
6156
|
-
/* @__PURE__ */ (0,
|
|
6157
|
-
/* @__PURE__ */ (0,
|
|
6425
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-foot", children: [
|
|
6426
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "rk-hint", children: [
|
|
6427
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
6158
6428
|
" cancel"
|
|
6159
6429
|
] }),
|
|
6160
|
-
/* @__PURE__ */ (0,
|
|
6161
|
-
/* @__PURE__ */ (0,
|
|
6162
|
-
/* @__PURE__ */ (0,
|
|
6430
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-actions", children: [
|
|
6431
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
|
|
6432
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
|
|
6163
6433
|
] })
|
|
6164
6434
|
] })
|
|
6165
6435
|
] });
|
|
6166
6436
|
}
|
|
6167
6437
|
|
|
6168
6438
|
// src/client/components/InlineEditor.tsx
|
|
6169
|
-
var
|
|
6170
|
-
var
|
|
6439
|
+
var import_react12 = require("react");
|
|
6440
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
6171
6441
|
function InlineEditor({ editor }) {
|
|
6172
6442
|
const dispatch = useDispatch();
|
|
6173
6443
|
const { route, session } = useStore();
|
|
6174
|
-
const [after, setAfter] = (0,
|
|
6175
|
-
const [priority, setPriority] = (0,
|
|
6176
|
-
const [note, setNote] = (0,
|
|
6177
|
-
const original = (0,
|
|
6178
|
-
const baseline = (0,
|
|
6179
|
-
const [sizeDelta, setSizeDelta] = (0,
|
|
6180
|
-
const [widthDelta, setWidthDelta] = (0,
|
|
6181
|
-
const [clipped, setClipped] = (0,
|
|
6182
|
-
const ringRef = (0,
|
|
6183
|
-
const afterRef = (0,
|
|
6444
|
+
const [after, setAfter] = (0, import_react12.useState)(() => editor.element.innerText);
|
|
6445
|
+
const [priority, setPriority] = (0, import_react12.useState)("nice");
|
|
6446
|
+
const [note, setNote] = (0, import_react12.useState)("");
|
|
6447
|
+
const original = (0, import_react12.useRef)(null);
|
|
6448
|
+
const baseline = (0, import_react12.useRef)(null);
|
|
6449
|
+
const [sizeDelta, setSizeDelta] = (0, import_react12.useState)(0);
|
|
6450
|
+
const [widthDelta, setWidthDelta] = (0, import_react12.useState)(0);
|
|
6451
|
+
const [clipped, setClipped] = (0, import_react12.useState)(false);
|
|
6452
|
+
const ringRef = (0, import_react12.useRef)(null);
|
|
6453
|
+
const afterRef = (0, import_react12.useRef)(null);
|
|
6184
6454
|
const { ref, pos } = useAnchored(editor.element, "bottom", 12);
|
|
6185
6455
|
const element = editor.element;
|
|
6186
|
-
(0,
|
|
6456
|
+
(0, import_react12.useEffect)(() => {
|
|
6187
6457
|
const el = element;
|
|
6188
6458
|
original.current = { html: el.innerHTML, text: el.innerText, styleAttr: el.getAttribute("style") };
|
|
6189
6459
|
const rect = el.getBoundingClientRect();
|
|
@@ -6213,8 +6483,8 @@ function InlineEditor({ editor }) {
|
|
|
6213
6483
|
}
|
|
6214
6484
|
};
|
|
6215
6485
|
}, [element]);
|
|
6216
|
-
const focusedOnce = (0,
|
|
6217
|
-
(0,
|
|
6486
|
+
const focusedOnce = (0, import_react12.useRef)(false);
|
|
6487
|
+
(0, import_react12.useEffect)(() => {
|
|
6218
6488
|
const field = afterRef.current;
|
|
6219
6489
|
if (pos === null || focusedOnce.current || !field) return;
|
|
6220
6490
|
focusedOnce.current = true;
|
|
@@ -6222,7 +6492,7 @@ function InlineEditor({ editor }) {
|
|
|
6222
6492
|
const end = field.value.length;
|
|
6223
6493
|
field.setSelectionRange(end, end);
|
|
6224
6494
|
}, [pos]);
|
|
6225
|
-
(0,
|
|
6495
|
+
(0, import_react12.useEffect)(() => {
|
|
6226
6496
|
const field = afterRef.current;
|
|
6227
6497
|
if (!field) return;
|
|
6228
6498
|
field.style.height = "auto";
|
|
@@ -6232,7 +6502,7 @@ function InlineEditor({ editor }) {
|
|
|
6232
6502
|
setAfter(value);
|
|
6233
6503
|
if (element.innerText !== value) setElementText(element, value);
|
|
6234
6504
|
};
|
|
6235
|
-
(0,
|
|
6505
|
+
(0, import_react12.useEffect)(() => {
|
|
6236
6506
|
let raf = 0;
|
|
6237
6507
|
let lastDelta = 0;
|
|
6238
6508
|
let lastWidth = 0;
|
|
@@ -6302,7 +6572,7 @@ function InlineEditor({ editor }) {
|
|
|
6302
6572
|
cancel();
|
|
6303
6573
|
}
|
|
6304
6574
|
};
|
|
6305
|
-
(0,
|
|
6575
|
+
(0, import_react12.useEffect)(() => {
|
|
6306
6576
|
const el = element;
|
|
6307
6577
|
const onKeyDown = (event) => {
|
|
6308
6578
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
@@ -6320,19 +6590,19 @@ function InlineEditor({ editor }) {
|
|
|
6320
6590
|
});
|
|
6321
6591
|
const before = original.current?.text ?? "";
|
|
6322
6592
|
const delta = after.length - before.length;
|
|
6323
|
-
return /* @__PURE__ */ (0,
|
|
6324
|
-
/* @__PURE__ */ (0,
|
|
6325
|
-
/* @__PURE__ */ (0,
|
|
6326
|
-
/* @__PURE__ */ (0,
|
|
6327
|
-
/* @__PURE__ */ (0,
|
|
6593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
6594
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: ringRef, className: "rk-edit-ring" }),
|
|
6595
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Rewrite text", children: [
|
|
6596
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-head", children: [
|
|
6597
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconText, { size: 14 }),
|
|
6328
6598
|
"Rewrite text",
|
|
6329
|
-
/* @__PURE__ */ (0,
|
|
6330
|
-
/* @__PURE__ */ (0,
|
|
6599
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-spacer" }),
|
|
6600
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-delta", "aria-live": "polite", children: [
|
|
6331
6601
|
before.length,
|
|
6332
6602
|
" \u2192 ",
|
|
6333
6603
|
after.length,
|
|
6334
6604
|
" ",
|
|
6335
|
-
delta !== 0 && /* @__PURE__ */ (0,
|
|
6605
|
+
delta !== 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: delta > 0 ? "rk-plus" : "rk-minus", children: [
|
|
6336
6606
|
"(",
|
|
6337
6607
|
delta > 0 ? "+" : "",
|
|
6338
6608
|
delta,
|
|
@@ -6340,15 +6610,15 @@ function InlineEditor({ editor }) {
|
|
|
6340
6610
|
] })
|
|
6341
6611
|
] })
|
|
6342
6612
|
] }),
|
|
6343
|
-
/* @__PURE__ */ (0,
|
|
6344
|
-
/* @__PURE__ */ (0,
|
|
6345
|
-
/* @__PURE__ */ (0,
|
|
6346
|
-
/* @__PURE__ */ (0,
|
|
6347
|
-
/* @__PURE__ */ (0,
|
|
6613
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-body", children: [
|
|
6614
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff", "aria-label": "Before and after", children: [
|
|
6615
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
|
|
6616
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
|
|
6617
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-text", children: before })
|
|
6348
6618
|
] }),
|
|
6349
|
-
/* @__PURE__ */ (0,
|
|
6350
|
-
/* @__PURE__ */ (0,
|
|
6351
|
-
/* @__PURE__ */ (0,
|
|
6619
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
|
|
6620
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-tag", children: "After" }),
|
|
6621
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6352
6622
|
"textarea",
|
|
6353
6623
|
{
|
|
6354
6624
|
ref: afterRef,
|
|
@@ -6362,11 +6632,11 @@ function InlineEditor({ editor }) {
|
|
|
6362
6632
|
)
|
|
6363
6633
|
] })
|
|
6364
6634
|
] }),
|
|
6365
|
-
(Math.abs(sizeDelta) > 2 || Math.abs(widthDelta) > 4 || clipped) && /* @__PURE__ */ (0,
|
|
6635
|
+
(Math.abs(sizeDelta) > 2 || Math.abs(widthDelta) > 4 || clipped) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-size-note", role: "status", children: [
|
|
6366
6636
|
Math.abs(sizeDelta) > 2 && (() => {
|
|
6367
6637
|
const lines = baseline.current ? Math.round(Math.abs(sizeDelta) / baseline.current.lineHeight) : 0;
|
|
6368
6638
|
const lineNote = lines >= 1 ? ` (~${lines} line${lines === 1 ? "" : "s"})` : "";
|
|
6369
|
-
return /* @__PURE__ */ (0,
|
|
6639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
6370
6640
|
"Block ",
|
|
6371
6641
|
sizeDelta > 0 ? "grew" : "shrank",
|
|
6372
6642
|
" by ",
|
|
@@ -6376,16 +6646,16 @@ function InlineEditor({ editor }) {
|
|
|
6376
6646
|
" \u2014 as it would with this text live."
|
|
6377
6647
|
] });
|
|
6378
6648
|
})(),
|
|
6379
|
-
Math.abs(sizeDelta) <= 2 && Math.abs(widthDelta) > 4 && /* @__PURE__ */ (0,
|
|
6649
|
+
Math.abs(sizeDelta) <= 2 && Math.abs(widthDelta) > 4 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
6380
6650
|
"Block got ",
|
|
6381
6651
|
widthDelta > 0 ? "wider" : "narrower",
|
|
6382
6652
|
" by ",
|
|
6383
6653
|
Math.abs(widthDelta),
|
|
6384
6654
|
" px \u2014 as it would with this text live."
|
|
6385
6655
|
] }),
|
|
6386
|
-
clipped && /* @__PURE__ */ (0,
|
|
6656
|
+
clipped && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-clip-note", children: "Text exceeds the visible crop here and will be cut off." })
|
|
6387
6657
|
] }),
|
|
6388
|
-
/* @__PURE__ */ (0,
|
|
6658
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6389
6659
|
"input",
|
|
6390
6660
|
{
|
|
6391
6661
|
className: "rk-input",
|
|
@@ -6394,24 +6664,24 @@ function InlineEditor({ editor }) {
|
|
|
6394
6664
|
onChange: (event) => setNote(event.target.value)
|
|
6395
6665
|
}
|
|
6396
6666
|
),
|
|
6397
|
-
/* @__PURE__ */ (0,
|
|
6398
|
-
/* @__PURE__ */ (0,
|
|
6399
|
-
/* @__PURE__ */ (0,
|
|
6667
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
6668
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
|
|
6669
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
|
|
6400
6670
|
] })
|
|
6401
6671
|
] }),
|
|
6402
|
-
/* @__PURE__ */ (0,
|
|
6403
|
-
/* @__PURE__ */ (0,
|
|
6404
|
-
/* @__PURE__ */ (0,
|
|
6672
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-foot", children: [
|
|
6673
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-hint", children: [
|
|
6674
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
|
|
6405
6675
|
" save \xB7 ",
|
|
6406
|
-
/* @__PURE__ */ (0,
|
|
6676
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u21E7\u21B5" }),
|
|
6407
6677
|
" newline \xB7",
|
|
6408
6678
|
" ",
|
|
6409
|
-
/* @__PURE__ */ (0,
|
|
6679
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
6410
6680
|
" cancel"
|
|
6411
6681
|
] }),
|
|
6412
|
-
/* @__PURE__ */ (0,
|
|
6413
|
-
/* @__PURE__ */ (0,
|
|
6414
|
-
/* @__PURE__ */ (0,
|
|
6682
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-actions", children: [
|
|
6683
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: cancel, children: "Cancel" }),
|
|
6684
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: commit, children: "Save" })
|
|
6415
6685
|
] })
|
|
6416
6686
|
] })
|
|
6417
6687
|
] })
|
|
@@ -6419,8 +6689,8 @@ function InlineEditor({ editor }) {
|
|
|
6419
6689
|
}
|
|
6420
6690
|
|
|
6421
6691
|
// src/client/components/NoteComposer.tsx
|
|
6422
|
-
var
|
|
6423
|
-
var
|
|
6692
|
+
var import_react13 = require("react");
|
|
6693
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
6424
6694
|
var TITLES = {
|
|
6425
6695
|
comment: "Comment",
|
|
6426
6696
|
delete: "Mark for deletion",
|
|
@@ -6436,14 +6706,14 @@ var PLACEHOLDERS = {
|
|
|
6436
6706
|
function NoteComposer({ editor }) {
|
|
6437
6707
|
const dispatch = useDispatch();
|
|
6438
6708
|
const { route, session } = useStore();
|
|
6439
|
-
const [text, setText] = (0,
|
|
6440
|
-
const [direction, setDirection] = (0,
|
|
6441
|
-
const [priority, setPriority] = (0,
|
|
6442
|
-
const textareaRef = (0,
|
|
6709
|
+
const [text, setText] = (0, import_react13.useState)("");
|
|
6710
|
+
const [direction, setDirection] = (0, import_react13.useState)(void 0);
|
|
6711
|
+
const [priority, setPriority] = (0, import_react13.useState)("nice");
|
|
6712
|
+
const textareaRef = (0, import_react13.useRef)(null);
|
|
6443
6713
|
const { ref, pos } = useAnchored(editor.element, "bottom", 12);
|
|
6444
6714
|
const { kind } = editor;
|
|
6445
|
-
const focusedOnce = (0,
|
|
6446
|
-
(0,
|
|
6715
|
+
const focusedOnce = (0, import_react13.useRef)(false);
|
|
6716
|
+
(0, import_react13.useEffect)(() => {
|
|
6447
6717
|
const field = textareaRef.current;
|
|
6448
6718
|
if (pos === null || focusedOnce.current || !field) return;
|
|
6449
6719
|
focusedOnce.current = true;
|
|
@@ -6502,13 +6772,13 @@ function NoteComposer({ editor }) {
|
|
|
6502
6772
|
save();
|
|
6503
6773
|
}
|
|
6504
6774
|
};
|
|
6505
|
-
return /* @__PURE__ */ (0,
|
|
6506
|
-
/* @__PURE__ */ (0,
|
|
6775
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": TITLES[kind], children: [
|
|
6776
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-head", children: [
|
|
6507
6777
|
iconForType(kind),
|
|
6508
6778
|
TITLES[kind]
|
|
6509
6779
|
] }),
|
|
6510
|
-
/* @__PURE__ */ (0,
|
|
6511
|
-
kind === "move" && /* @__PURE__ */ (0,
|
|
6780
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-body", children: [
|
|
6781
|
+
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)(
|
|
6512
6782
|
"button",
|
|
6513
6783
|
{
|
|
6514
6784
|
type: "button",
|
|
@@ -6518,7 +6788,7 @@ function NoteComposer({ editor }) {
|
|
|
6518
6788
|
},
|
|
6519
6789
|
option
|
|
6520
6790
|
)) }),
|
|
6521
|
-
/* @__PURE__ */ (0,
|
|
6791
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
6522
6792
|
"textarea",
|
|
6523
6793
|
{
|
|
6524
6794
|
ref: textareaRef,
|
|
@@ -6530,29 +6800,29 @@ function NoteComposer({ editor }) {
|
|
|
6530
6800
|
rows: 3
|
|
6531
6801
|
}
|
|
6532
6802
|
),
|
|
6533
|
-
/* @__PURE__ */ (0,
|
|
6534
|
-
/* @__PURE__ */ (0,
|
|
6535
|
-
/* @__PURE__ */ (0,
|
|
6803
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
6804
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
|
|
6805
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
|
|
6536
6806
|
] })
|
|
6537
6807
|
] }),
|
|
6538
|
-
/* @__PURE__ */ (0,
|
|
6539
|
-
/* @__PURE__ */ (0,
|
|
6540
|
-
/* @__PURE__ */ (0,
|
|
6808
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-foot", children: [
|
|
6809
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-hint", children: [
|
|
6810
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-kbd", children: "\u2318\u21B5" }),
|
|
6541
6811
|
" save \xB7 ",
|
|
6542
|
-
/* @__PURE__ */ (0,
|
|
6812
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
6543
6813
|
" cancel"
|
|
6544
6814
|
] }),
|
|
6545
|
-
/* @__PURE__ */ (0,
|
|
6546
|
-
/* @__PURE__ */ (0,
|
|
6547
|
-
/* @__PURE__ */ (0,
|
|
6815
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-actions", children: [
|
|
6816
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
|
|
6817
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
|
|
6548
6818
|
] })
|
|
6549
6819
|
] })
|
|
6550
6820
|
] });
|
|
6551
6821
|
}
|
|
6552
6822
|
|
|
6553
6823
|
// src/client/components/Panel.tsx
|
|
6554
|
-
var
|
|
6555
|
-
var
|
|
6824
|
+
var import_react14 = require("react");
|
|
6825
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
6556
6826
|
function changeSummary(item) {
|
|
6557
6827
|
if (isCopyItem(item)) return `\u201C${item.payload.after}\u201D`;
|
|
6558
6828
|
if (isImageItem(item)) {
|
|
@@ -6634,24 +6904,24 @@ function formatBytes(bytes) {
|
|
|
6634
6904
|
function CopyDiff({ before, after }) {
|
|
6635
6905
|
const parts = diffParts(before, after);
|
|
6636
6906
|
const delta = after.length - before.length;
|
|
6637
|
-
return /* @__PURE__ */ (0,
|
|
6638
|
-
/* @__PURE__ */ (0,
|
|
6639
|
-
/* @__PURE__ */ (0,
|
|
6640
|
-
/* @__PURE__ */ (0,
|
|
6907
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diffview", children: [
|
|
6908
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
|
|
6909
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
|
|
6910
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-diff-text", children: [
|
|
6641
6911
|
parts.prefix,
|
|
6642
|
-
parts.delMid && /* @__PURE__ */ (0,
|
|
6912
|
+
parts.delMid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("mark", { className: "rk-del", children: parts.delMid }),
|
|
6643
6913
|
parts.suffix
|
|
6644
6914
|
] })
|
|
6645
6915
|
] }),
|
|
6646
|
-
/* @__PURE__ */ (0,
|
|
6647
|
-
/* @__PURE__ */ (0,
|
|
6648
|
-
/* @__PURE__ */ (0,
|
|
6916
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
|
|
6917
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-diff-tag", children: "After" }),
|
|
6918
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-diff-text", children: [
|
|
6649
6919
|
parts.prefix,
|
|
6650
|
-
parts.insMid && /* @__PURE__ */ (0,
|
|
6920
|
+
parts.insMid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("mark", { className: "rk-ins", children: parts.insMid }),
|
|
6651
6921
|
parts.suffix
|
|
6652
6922
|
] })
|
|
6653
6923
|
] }),
|
|
6654
|
-
/* @__PURE__ */ (0,
|
|
6924
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-len", children: [
|
|
6655
6925
|
before.length,
|
|
6656
6926
|
" \u2192 ",
|
|
6657
6927
|
after.length,
|
|
@@ -6662,8 +6932,8 @@ function CopyDiff({ before, after }) {
|
|
|
6662
6932
|
}
|
|
6663
6933
|
function ImageDetail({ beforeSrc, afterSrc, afterDataUrl }) {
|
|
6664
6934
|
const replacement = afterDataUrl ?? afterSrc;
|
|
6665
|
-
const [dims, setDims] = (0,
|
|
6666
|
-
(0,
|
|
6935
|
+
const [dims, setDims] = (0, import_react14.useState)("");
|
|
6936
|
+
(0, import_react14.useEffect)(() => {
|
|
6667
6937
|
if (!replacement) return;
|
|
6668
6938
|
const img = new Image();
|
|
6669
6939
|
img.onload = () => setDims(`${img.naturalWidth}\xD7${img.naturalHeight}px`);
|
|
@@ -6688,55 +6958,67 @@ function ImageDetail({ beforeSrc, afterSrc, afterDataUrl }) {
|
|
|
6688
6958
|
window.open(replacement, "_blank", "noopener");
|
|
6689
6959
|
}
|
|
6690
6960
|
};
|
|
6691
|
-
return /* @__PURE__ */ (0,
|
|
6692
|
-
/* @__PURE__ */ (0,
|
|
6693
|
-
/* @__PURE__ */ (0,
|
|
6694
|
-
beforeSrc ? /* @__PURE__ */ (0,
|
|
6695
|
-
/* @__PURE__ */ (0,
|
|
6961
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail", children: [
|
|
6962
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-thumbs", children: [
|
|
6963
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6964
|
+
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" }),
|
|
6965
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { children: "Before" })
|
|
6696
6966
|
] }),
|
|
6697
|
-
/* @__PURE__ */ (0,
|
|
6698
|
-
/* @__PURE__ */ (0,
|
|
6699
|
-
/* @__PURE__ */ (0,
|
|
6967
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6968
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("img", { src: replacement, alt: "Proposed replacement" }),
|
|
6969
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figcaption", { children: [
|
|
6700
6970
|
"After",
|
|
6701
6971
|
embedded ? "" : " \xB7 linked"
|
|
6702
6972
|
] })
|
|
6703
6973
|
] })
|
|
6704
6974
|
] }),
|
|
6705
|
-
/* @__PURE__ */ (0,
|
|
6975
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail-meta", children: [
|
|
6706
6976
|
embedded ? "Embedded image" : "Linked image",
|
|
6707
6977
|
dims ? ` \xB7 ${dims}` : "",
|
|
6708
6978
|
bytes !== null ? ` \xB7 ${formatBytes(bytes)}` : ""
|
|
6709
6979
|
] }),
|
|
6710
|
-
!embedded && afterSrc && /* @__PURE__ */ (0,
|
|
6711
|
-
/* @__PURE__ */ (0,
|
|
6712
|
-
/* @__PURE__ */ (0,
|
|
6713
|
-
/* @__PURE__ */ (0,
|
|
6980
|
+
!embedded && afterSrc && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { className: "rk-imgdetail-url", href: afterSrc, target: "_blank", rel: "noopener noreferrer", title: afterSrc, children: afterSrc }),
|
|
6981
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail-actions", children: [
|
|
6982
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void download(), children: [
|
|
6983
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconDownload, { size: 12 }),
|
|
6714
6984
|
" Download"
|
|
6715
6985
|
] }),
|
|
6716
|
-
/* @__PURE__ */ (0,
|
|
6986
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => window.open(replacement, "_blank", "noopener"), children: "Open" })
|
|
6717
6987
|
] })
|
|
6718
6988
|
] });
|
|
6719
6989
|
}
|
|
6990
|
+
var SYNC_REASON_LABEL = {
|
|
6991
|
+
"token-short": "token too short",
|
|
6992
|
+
"bad-token": "token rejected",
|
|
6993
|
+
"room-full": "room full",
|
|
6994
|
+
unreachable: "server unreachable"
|
|
6995
|
+
};
|
|
6996
|
+
var SYNC_REASON_HELP = {
|
|
6997
|
+
"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.",
|
|
6998
|
+
"bad-token": "The sync server rejected the token. Check `syncToken` / `token` in <ReviewKit />.",
|
|
6999
|
+
"room-full": "This page already has the maximum number of reviewers online (16). Try again later.",
|
|
7000
|
+
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."
|
|
7001
|
+
};
|
|
6720
7002
|
function Panel() {
|
|
6721
|
-
const { session, panelOpen, activeItemId, badgeCorner, undoStack, preview, unapplied, syncStatus, emblemaPush, peers } = useStore();
|
|
7003
|
+
const { session, panelOpen, activeItemId, badgeCorner, undoStack, preview, unapplied, syncStatus, syncReason, emblemaPush, peers } = useStore();
|
|
6722
7004
|
const dispatch = useDispatch();
|
|
6723
7005
|
const config = useConfig();
|
|
6724
|
-
const [sticky, setStickyState] = (0,
|
|
6725
|
-
const [query, setQuery] = (0,
|
|
6726
|
-
const [typeFilter, setTypeFilter] = (0,
|
|
6727
|
-
const [prioFilter, setPrioFilter] = (0,
|
|
6728
|
-
const [statusFilter, setStatusFilter] = (0,
|
|
6729
|
-
const [filterOpen, setFilterOpen] = (0,
|
|
6730
|
-
const [settingsOpen, setSettingsOpen] = (0,
|
|
6731
|
-
const [emblemaAlive, setEmblemaAlive] = (0,
|
|
6732
|
-
const [emblemaSending, setEmblemaSending] = (0,
|
|
6733
|
-
const [emblemaSync, setEmblemaSync] = (0,
|
|
6734
|
-
const panelRef = (0,
|
|
6735
|
-
const searchRef = (0,
|
|
6736
|
-
const importRef = (0,
|
|
6737
|
-
const sheetDrag = (0,
|
|
6738
|
-
const items = (0,
|
|
6739
|
-
const { orphanIds, hiddenIds } = (0,
|
|
7006
|
+
const [sticky, setStickyState] = (0, import_react14.useState)(() => isStickyEnabled(config.token));
|
|
7007
|
+
const [query, setQuery] = (0, import_react14.useState)("");
|
|
7008
|
+
const [typeFilter, setTypeFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
7009
|
+
const [prioFilter, setPrioFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
7010
|
+
const [statusFilter, setStatusFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
7011
|
+
const [filterOpen, setFilterOpen] = (0, import_react14.useState)(false);
|
|
7012
|
+
const [settingsOpen, setSettingsOpen] = (0, import_react14.useState)(false);
|
|
7013
|
+
const [emblemaAlive, setEmblemaAlive] = (0, import_react14.useState)(null);
|
|
7014
|
+
const [emblemaSending, setEmblemaSending] = (0, import_react14.useState)(false);
|
|
7015
|
+
const [emblemaSync, setEmblemaSync] = (0, import_react14.useState)("unknown");
|
|
7016
|
+
const panelRef = (0, import_react14.useRef)(null);
|
|
7017
|
+
const searchRef = (0, import_react14.useRef)(null);
|
|
7018
|
+
const importRef = (0, import_react14.useRef)(null);
|
|
7019
|
+
const sheetDrag = (0, import_react14.useRef)(null);
|
|
7020
|
+
const items = (0, import_react14.useMemo)(() => session?.items ?? [], [session]);
|
|
7021
|
+
const { orphanIds, hiddenIds } = (0, import_react14.useMemo)(() => {
|
|
6740
7022
|
const orphans = /* @__PURE__ */ new Set();
|
|
6741
7023
|
const hiddens = /* @__PURE__ */ new Set();
|
|
6742
7024
|
for (const item of items) {
|
|
@@ -6747,15 +7029,15 @@ function Panel() {
|
|
|
6747
7029
|
}
|
|
6748
7030
|
return { orphanIds: orphans, hiddenIds: hiddens };
|
|
6749
7031
|
}, [items, panelOpen]);
|
|
6750
|
-
const activeFilter = (0,
|
|
7032
|
+
const activeFilter = (0, import_react14.useMemo)(
|
|
6751
7033
|
() => typeFilter.size + prioFilter.size + statusFilter.size > 0 ? { types: [...typeFilter], priorities: [...prioFilter], statuses: [...statusFilter] } : null,
|
|
6752
7034
|
[typeFilter, prioFilter, statusFilter]
|
|
6753
7035
|
);
|
|
6754
|
-
(0,
|
|
7036
|
+
(0, import_react14.useEffect)(() => {
|
|
6755
7037
|
dispatch({ type: "SET_FILTER", filter: activeFilter });
|
|
6756
7038
|
return () => dispatch({ type: "SET_FILTER", filter: null });
|
|
6757
7039
|
}, [activeFilter, dispatch]);
|
|
6758
|
-
const filtered = (0,
|
|
7040
|
+
const filtered = (0, import_react14.useMemo)(() => {
|
|
6759
7041
|
const q = query.trim().toLowerCase();
|
|
6760
7042
|
return items.map((item, index) => ({ item, number: index + 1 })).filter(({ item }) => {
|
|
6761
7043
|
if (!itemMatchesFilter(item, activeFilter)) return false;
|
|
@@ -6764,22 +7046,22 @@ function Panel() {
|
|
|
6764
7046
|
return haystack.includes(q);
|
|
6765
7047
|
});
|
|
6766
7048
|
}, [items, query, activeFilter]);
|
|
6767
|
-
const typeCounts = (0,
|
|
7049
|
+
const typeCounts = (0, import_react14.useMemo)(() => {
|
|
6768
7050
|
const counts = /* @__PURE__ */ new Map();
|
|
6769
7051
|
for (const item of items) counts.set(item.type, (counts.get(item.type) ?? 0) + 1);
|
|
6770
7052
|
return counts;
|
|
6771
7053
|
}, [items]);
|
|
6772
|
-
const prioCounts = (0,
|
|
7054
|
+
const prioCounts = (0, import_react14.useMemo)(() => {
|
|
6773
7055
|
const counts = /* @__PURE__ */ new Map();
|
|
6774
7056
|
for (const item of items) counts.set(item.priority, (counts.get(item.priority) ?? 0) + 1);
|
|
6775
7057
|
return counts;
|
|
6776
7058
|
}, [items]);
|
|
6777
|
-
const statusCounts = (0,
|
|
7059
|
+
const statusCounts = (0, import_react14.useMemo)(() => {
|
|
6778
7060
|
const counts = /* @__PURE__ */ new Map();
|
|
6779
7061
|
for (const item of items) counts.set(item.status, (counts.get(item.status) ?? 0) + 1);
|
|
6780
7062
|
return counts;
|
|
6781
7063
|
}, [items]);
|
|
6782
|
-
const groups = (0,
|
|
7064
|
+
const groups = (0, import_react14.useMemo)(() => {
|
|
6783
7065
|
const map = /* @__PURE__ */ new Map();
|
|
6784
7066
|
for (const entry of filtered) {
|
|
6785
7067
|
const list = map.get(entry.item.route) ?? [];
|
|
@@ -6788,7 +7070,7 @@ function Panel() {
|
|
|
6788
7070
|
}
|
|
6789
7071
|
return Array.from(map.entries());
|
|
6790
7072
|
}, [filtered]);
|
|
6791
|
-
(0,
|
|
7073
|
+
(0, import_react14.useEffect)(() => {
|
|
6792
7074
|
if (!filterOpen && !settingsOpen) return;
|
|
6793
7075
|
const onDown = (event) => {
|
|
6794
7076
|
const path = event.composedPath();
|
|
@@ -6799,7 +7081,7 @@ function Panel() {
|
|
|
6799
7081
|
document.addEventListener("pointerdown", onDown, true);
|
|
6800
7082
|
return () => document.removeEventListener("pointerdown", onDown, true);
|
|
6801
7083
|
}, [filterOpen, settingsOpen]);
|
|
6802
|
-
(0,
|
|
7084
|
+
(0, import_react14.useEffect)(() => {
|
|
6803
7085
|
if (!settingsOpen) return;
|
|
6804
7086
|
let alive = true;
|
|
6805
7087
|
const probe = () => {
|
|
@@ -6823,7 +7105,7 @@ function Panel() {
|
|
|
6823
7105
|
live: "paired",
|
|
6824
7106
|
off: "not paired"
|
|
6825
7107
|
}[emblemaPairState];
|
|
6826
|
-
(0,
|
|
7108
|
+
(0, import_react14.useEffect)(() => {
|
|
6827
7109
|
if (!panelOpen || activeItemId === null) return;
|
|
6828
7110
|
const row = panelRef.current?.querySelector(`[data-item-id="${activeItemId}"]`);
|
|
6829
7111
|
row?.scrollIntoView({ block: "nearest" });
|
|
@@ -6939,7 +7221,7 @@ function Panel() {
|
|
|
6939
7221
|
panel.style.transform = "";
|
|
6940
7222
|
if (dy > 110) dispatch({ type: "SET_PANEL", open: false });
|
|
6941
7223
|
};
|
|
6942
|
-
return /* @__PURE__ */ (0,
|
|
7224
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
6943
7225
|
"div",
|
|
6944
7226
|
{
|
|
6945
7227
|
ref: panelRef,
|
|
@@ -6949,7 +7231,7 @@ function Panel() {
|
|
|
6949
7231
|
"aria-label": "Review feedback panel",
|
|
6950
7232
|
onKeyDown,
|
|
6951
7233
|
children: [
|
|
6952
|
-
/* @__PURE__ */ (0,
|
|
7234
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6953
7235
|
"div",
|
|
6954
7236
|
{
|
|
6955
7237
|
className: "rk-sheet-handle",
|
|
@@ -6960,34 +7242,41 @@ function Panel() {
|
|
|
6960
7242
|
onPointerCancel: onSheetHandleUp
|
|
6961
7243
|
}
|
|
6962
7244
|
),
|
|
6963
|
-
/* @__PURE__ */ (0,
|
|
6964
|
-
/* @__PURE__ */ (0,
|
|
6965
|
-
/* @__PURE__ */ (0,
|
|
6966
|
-
/* @__PURE__ */ (0,
|
|
7245
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-head", children: [
|
|
7246
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
7247
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-panel-title", children: "Feedback" }),
|
|
7248
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-sub", children: [
|
|
6967
7249
|
items.length,
|
|
6968
7250
|
" item",
|
|
6969
7251
|
items.length === 1 ? "" : "s",
|
|
6970
7252
|
session.author ? ` \xB7 ${session.author}` : "",
|
|
6971
|
-
syncStatus !== "disabled" && /* @__PURE__ */ (0,
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
7253
|
+
syncStatus !== "disabled" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7254
|
+
"span",
|
|
7255
|
+
{
|
|
7256
|
+
className: `rk-sync rk-sync-${syncStatus}${syncReason ? ` rk-sync-reason-${syncReason}` : ""}`,
|
|
7257
|
+
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"],
|
|
7258
|
+
children: [
|
|
7259
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-sync-dot" }),
|
|
7260
|
+
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"]}`
|
|
7261
|
+
]
|
|
7262
|
+
}
|
|
7263
|
+
),
|
|
7264
|
+
config.emblema && emblemaPush !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
6976
7265
|
"span",
|
|
6977
7266
|
{
|
|
6978
7267
|
className: `rk-sync rk-epush-${emblemaPush}`,
|
|
6979
7268
|
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",
|
|
6980
7269
|
children: [
|
|
6981
|
-
/* @__PURE__ */ (0,
|
|
7270
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-sync-dot" }),
|
|
6982
7271
|
emblemaPush === "ok" ? "emblema" : emblemaPush === "sending" ? "emblema\u2026" : emblemaPush === "rejected" ? "emblema rejected" : "emblema offline"
|
|
6983
7272
|
]
|
|
6984
7273
|
}
|
|
6985
7274
|
)
|
|
6986
7275
|
] })
|
|
6987
7276
|
] }),
|
|
6988
|
-
/* @__PURE__ */ (0,
|
|
6989
|
-
/* @__PURE__ */ (0,
|
|
6990
|
-
/* @__PURE__ */ (0,
|
|
7277
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-spacer" }),
|
|
7278
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
|
|
7279
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6991
7280
|
"button",
|
|
6992
7281
|
{
|
|
6993
7282
|
type: "button",
|
|
@@ -7003,11 +7292,11 @@ function Panel() {
|
|
|
7003
7292
|
void pingEmblema(config.emblema).then((port) => setEmblemaAlive(port !== null));
|
|
7004
7293
|
}
|
|
7005
7294
|
},
|
|
7006
|
-
children: /* @__PURE__ */ (0,
|
|
7295
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconGear, { size: 15 })
|
|
7007
7296
|
}
|
|
7008
7297
|
),
|
|
7009
|
-
settingsOpen && /* @__PURE__ */ (0,
|
|
7010
|
-
config.token && /* @__PURE__ */ (0,
|
|
7298
|
+
settingsOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Session settings", children: [
|
|
7299
|
+
config.token && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7011
7300
|
"button",
|
|
7012
7301
|
{
|
|
7013
7302
|
type: "button",
|
|
@@ -7022,12 +7311,12 @@ function Panel() {
|
|
|
7022
7311
|
toast(dispatch, next ? "Review stays on in this tab" : "Review active only via the link", "info");
|
|
7023
7312
|
},
|
|
7024
7313
|
children: [
|
|
7025
|
-
/* @__PURE__ */ (0,
|
|
7314
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${sticky ? " rk-on" : ""}` }),
|
|
7026
7315
|
"Keep review on in this tab"
|
|
7027
7316
|
]
|
|
7028
7317
|
}
|
|
7029
7318
|
),
|
|
7030
|
-
config.emblema && /* @__PURE__ */ (0,
|
|
7319
|
+
config.emblema && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7031
7320
|
"button",
|
|
7032
7321
|
{
|
|
7033
7322
|
type: "button",
|
|
@@ -7057,7 +7346,7 @@ function Panel() {
|
|
|
7057
7346
|
}).finally(() => setEmblemaSending(false));
|
|
7058
7347
|
},
|
|
7059
7348
|
children: [
|
|
7060
|
-
/* @__PURE__ */ (0,
|
|
7349
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7061
7350
|
"span",
|
|
7062
7351
|
{
|
|
7063
7352
|
className: "rk-emblema-dot",
|
|
@@ -7068,25 +7357,40 @@ function Panel() {
|
|
|
7068
7357
|
]
|
|
7069
7358
|
}
|
|
7070
7359
|
),
|
|
7071
|
-
/* @__PURE__ */ (0,
|
|
7360
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7072
7361
|
"button",
|
|
7073
7362
|
{
|
|
7074
7363
|
type: "button",
|
|
7075
7364
|
role: "menuitem",
|
|
7076
7365
|
className: "rk-menu-item",
|
|
7077
|
-
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",
|
|
7366
|
+
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",
|
|
7078
7367
|
onClick: () => {
|
|
7079
7368
|
setSettingsOpen(false);
|
|
7080
7369
|
dispatch({ type: "SET_EMBLEMA_CONNECT", open: true });
|
|
7081
7370
|
},
|
|
7082
7371
|
children: [
|
|
7083
|
-
/* @__PURE__ */ (0,
|
|
7372
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-emblema-dot", "data-state": emblemaPairState }),
|
|
7084
7373
|
"Connect to Emblema\u2026",
|
|
7085
|
-
/* @__PURE__ */ (0,
|
|
7374
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: emblemaPairLabel })
|
|
7086
7375
|
]
|
|
7087
7376
|
}
|
|
7088
7377
|
),
|
|
7089
|
-
/* @__PURE__ */ (0,
|
|
7378
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7379
|
+
"button",
|
|
7380
|
+
{
|
|
7381
|
+
type: "button",
|
|
7382
|
+
role: "menuitem",
|
|
7383
|
+
className: "rk-menu-item",
|
|
7384
|
+
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",
|
|
7385
|
+
disabled: !resolveSyncToken(config),
|
|
7386
|
+
onClick: () => {
|
|
7387
|
+
setSettingsOpen(false);
|
|
7388
|
+
dispatch({ type: "SET_TERMINAL_CONNECT", open: true });
|
|
7389
|
+
},
|
|
7390
|
+
children: "Connect terminal / agent\u2026"
|
|
7391
|
+
}
|
|
7392
|
+
),
|
|
7393
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7090
7394
|
"button",
|
|
7091
7395
|
{
|
|
7092
7396
|
type: "button",
|
|
@@ -7099,31 +7403,31 @@ function Panel() {
|
|
|
7099
7403
|
)
|
|
7100
7404
|
] })
|
|
7101
7405
|
] }),
|
|
7102
|
-
/* @__PURE__ */ (0,
|
|
7406
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7103
7407
|
"button",
|
|
7104
7408
|
{
|
|
7105
7409
|
type: "button",
|
|
7106
7410
|
className: "rk-icon-btn",
|
|
7107
7411
|
"aria-label": "Keyboard shortcuts",
|
|
7108
7412
|
onClick: () => dispatch({ type: "SET_CHEATSHEET", open: true }),
|
|
7109
|
-
children: /* @__PURE__ */ (0,
|
|
7413
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconKeyboard, { size: 15 })
|
|
7110
7414
|
}
|
|
7111
7415
|
),
|
|
7112
|
-
/* @__PURE__ */ (0,
|
|
7416
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7113
7417
|
"button",
|
|
7114
7418
|
{
|
|
7115
7419
|
type: "button",
|
|
7116
7420
|
className: "rk-icon-btn",
|
|
7117
7421
|
"aria-label": "Close panel",
|
|
7118
7422
|
onClick: () => dispatch({ type: "SET_PANEL", open: false }),
|
|
7119
|
-
children: /* @__PURE__ */ (0,
|
|
7423
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconClose, { size: 14 })
|
|
7120
7424
|
}
|
|
7121
7425
|
)
|
|
7122
7426
|
] }),
|
|
7123
|
-
/* @__PURE__ */ (0,
|
|
7124
|
-
/* @__PURE__ */ (0,
|
|
7125
|
-
/* @__PURE__ */ (0,
|
|
7126
|
-
/* @__PURE__ */ (0,
|
|
7427
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-view-row", children: [
|
|
7428
|
+
/* @__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" }) }),
|
|
7429
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-seg rk-view-toggle", role: "group", "aria-label": "Page view (P to toggle)", children: [
|
|
7430
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7127
7431
|
"button",
|
|
7128
7432
|
{
|
|
7129
7433
|
type: "button",
|
|
@@ -7133,7 +7437,7 @@ function Panel() {
|
|
|
7133
7437
|
children: "Original"
|
|
7134
7438
|
}
|
|
7135
7439
|
),
|
|
7136
|
-
/* @__PURE__ */ (0,
|
|
7440
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7137
7441
|
"button",
|
|
7138
7442
|
{
|
|
7139
7443
|
type: "button",
|
|
@@ -7145,8 +7449,8 @@ function Panel() {
|
|
|
7145
7449
|
)
|
|
7146
7450
|
] })
|
|
7147
7451
|
] }),
|
|
7148
|
-
/* @__PURE__ */ (0,
|
|
7149
|
-
/* @__PURE__ */ (0,
|
|
7452
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-tools", children: [
|
|
7453
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7150
7454
|
"button",
|
|
7151
7455
|
{
|
|
7152
7456
|
type: "button",
|
|
@@ -7157,15 +7461,15 @@ function Panel() {
|
|
|
7157
7461
|
dispatch({ type: "SET_MODE", mode: "pick" });
|
|
7158
7462
|
},
|
|
7159
7463
|
children: [
|
|
7160
|
-
/* @__PURE__ */ (0,
|
|
7464
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTarget, { size: 14 }),
|
|
7161
7465
|
" Pick an element"
|
|
7162
7466
|
]
|
|
7163
7467
|
}
|
|
7164
7468
|
),
|
|
7165
|
-
/* @__PURE__ */ (0,
|
|
7166
|
-
/* @__PURE__ */ (0,
|
|
7167
|
-
/* @__PURE__ */ (0,
|
|
7168
|
-
/* @__PURE__ */ (0,
|
|
7469
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-search-row", children: [
|
|
7470
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-search", children: [
|
|
7471
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconSearch, { size: 13 }),
|
|
7472
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7169
7473
|
"input",
|
|
7170
7474
|
{
|
|
7171
7475
|
ref: searchRef,
|
|
@@ -7177,8 +7481,8 @@ function Panel() {
|
|
|
7177
7481
|
}
|
|
7178
7482
|
)
|
|
7179
7483
|
] }),
|
|
7180
|
-
/* @__PURE__ */ (0,
|
|
7181
|
-
/* @__PURE__ */ (0,
|
|
7484
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
|
|
7485
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7182
7486
|
"button",
|
|
7183
7487
|
{
|
|
7184
7488
|
type: "button",
|
|
@@ -7190,15 +7494,15 @@ function Panel() {
|
|
|
7190
7494
|
setSettingsOpen(false);
|
|
7191
7495
|
},
|
|
7192
7496
|
children: [
|
|
7193
|
-
/* @__PURE__ */ (0,
|
|
7497
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFilter, { size: 13 }),
|
|
7194
7498
|
"Filter",
|
|
7195
|
-
typeFilter.size + prioFilter.size + statusFilter.size > 0 && /* @__PURE__ */ (0,
|
|
7499
|
+
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 })
|
|
7196
7500
|
]
|
|
7197
7501
|
}
|
|
7198
7502
|
),
|
|
7199
|
-
filterOpen && /* @__PURE__ */ (0,
|
|
7200
|
-
/* @__PURE__ */ (0,
|
|
7201
|
-
TYPE_FILTERS.map((type) => /* @__PURE__ */ (0,
|
|
7503
|
+
filterOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Filter items", children: [
|
|
7504
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Type" }),
|
|
7505
|
+
TYPE_FILTERS.map((type) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7202
7506
|
"button",
|
|
7203
7507
|
{
|
|
7204
7508
|
type: "button",
|
|
@@ -7212,16 +7516,16 @@ function Panel() {
|
|
|
7212
7516
|
setTypeFilter(next);
|
|
7213
7517
|
},
|
|
7214
7518
|
children: [
|
|
7215
|
-
/* @__PURE__ */ (0,
|
|
7519
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${typeFilter.has(type) ? " rk-on" : ""}` }),
|
|
7216
7520
|
iconForType(type, 12),
|
|
7217
|
-
/* @__PURE__ */ (0,
|
|
7218
|
-
/* @__PURE__ */ (0,
|
|
7521
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: type }),
|
|
7522
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: typeCounts.get(type) ?? 0 })
|
|
7219
7523
|
]
|
|
7220
7524
|
},
|
|
7221
7525
|
type
|
|
7222
7526
|
)),
|
|
7223
|
-
/* @__PURE__ */ (0,
|
|
7224
|
-
PRIORITY_FILTERS.map((priority) => /* @__PURE__ */ (0,
|
|
7527
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Priority" }),
|
|
7528
|
+
PRIORITY_FILTERS.map((priority) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7225
7529
|
"button",
|
|
7226
7530
|
{
|
|
7227
7531
|
type: "button",
|
|
@@ -7235,15 +7539,15 @@ function Panel() {
|
|
|
7235
7539
|
setPrioFilter(next);
|
|
7236
7540
|
},
|
|
7237
7541
|
children: [
|
|
7238
|
-
/* @__PURE__ */ (0,
|
|
7239
|
-
/* @__PURE__ */ (0,
|
|
7240
|
-
/* @__PURE__ */ (0,
|
|
7542
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${prioFilter.has(priority) ? " rk-on" : ""}` }),
|
|
7543
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: PRIORITY_LABELS[priority] }),
|
|
7544
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: prioCounts.get(priority) ?? 0 })
|
|
7241
7545
|
]
|
|
7242
7546
|
},
|
|
7243
7547
|
priority
|
|
7244
7548
|
)),
|
|
7245
|
-
/* @__PURE__ */ (0,
|
|
7246
|
-
STATUSES.map((status) => /* @__PURE__ */ (0,
|
|
7549
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Status" }),
|
|
7550
|
+
STATUSES.map((status) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7247
7551
|
"button",
|
|
7248
7552
|
{
|
|
7249
7553
|
type: "button",
|
|
@@ -7257,15 +7561,15 @@ function Panel() {
|
|
|
7257
7561
|
setStatusFilter(next);
|
|
7258
7562
|
},
|
|
7259
7563
|
children: [
|
|
7260
|
-
/* @__PURE__ */ (0,
|
|
7261
|
-
/* @__PURE__ */ (0,
|
|
7262
|
-
/* @__PURE__ */ (0,
|
|
7263
|
-
/* @__PURE__ */ (0,
|
|
7564
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${statusFilter.has(status) ? " rk-on" : ""}` }),
|
|
7565
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-status-dot rk-st-${status}` }),
|
|
7566
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: status }),
|
|
7567
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: statusCounts.get(status) ?? 0 })
|
|
7264
7568
|
]
|
|
7265
7569
|
},
|
|
7266
7570
|
status
|
|
7267
7571
|
)),
|
|
7268
|
-
/* @__PURE__ */ (0,
|
|
7572
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7269
7573
|
"button",
|
|
7270
7574
|
{
|
|
7271
7575
|
type: "button",
|
|
@@ -7285,24 +7589,24 @@ function Panel() {
|
|
|
7285
7589
|
] })
|
|
7286
7590
|
] })
|
|
7287
7591
|
] }),
|
|
7288
|
-
preview && unapplied > 0 && /* @__PURE__ */ (0,
|
|
7592
|
+
preview && unapplied > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-unplaced", role: "status", children: [
|
|
7289
7593
|
unapplied,
|
|
7290
7594
|
" saved change",
|
|
7291
7595
|
unapplied === 1 ? "" : "s",
|
|
7292
7596
|
" couldn\u2019t be placed on the current page \u2014 the page has changed since they were captured."
|
|
7293
7597
|
] }),
|
|
7294
|
-
/* @__PURE__ */ (0,
|
|
7295
|
-
/* @__PURE__ */ (0,
|
|
7296
|
-
/* @__PURE__ */ (0,
|
|
7297
|
-
/* @__PURE__ */ (0,
|
|
7298
|
-
] }) : groups.map(([route, entries]) => /* @__PURE__ */ (0,
|
|
7299
|
-
/* @__PURE__ */ (0,
|
|
7598
|
+
/* @__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: [
|
|
7599
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-art", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTarget, { size: 22 }) }),
|
|
7600
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-title", children: items.length === 0 ? "Nothing here yet" : "No matches" }),
|
|
7601
|
+
/* @__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." })
|
|
7602
|
+
] }) : groups.map(([route, entries]) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
7603
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-group-title", children: route }),
|
|
7300
7604
|
entries.map(({ item, number }) => {
|
|
7301
7605
|
const active2 = item.id === activeItemId;
|
|
7302
7606
|
const orphan = orphanIds.has(item.id);
|
|
7303
7607
|
const hiddenEl = hiddenIds.has(item.id);
|
|
7304
|
-
return /* @__PURE__ */ (0,
|
|
7305
|
-
/* @__PURE__ */ (0,
|
|
7608
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
7609
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7306
7610
|
"div",
|
|
7307
7611
|
{
|
|
7308
7612
|
"data-item-id": item.id,
|
|
@@ -7317,18 +7621,18 @@ function Panel() {
|
|
|
7317
7621
|
}
|
|
7318
7622
|
},
|
|
7319
7623
|
children: [
|
|
7320
|
-
/* @__PURE__ */ (0,
|
|
7321
|
-
/* @__PURE__ */ (0,
|
|
7322
|
-
/* @__PURE__ */ (0,
|
|
7323
|
-
/* @__PURE__ */ (0,
|
|
7624
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-num", children: number }),
|
|
7625
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-icon", children: iconForType(item.type) }),
|
|
7626
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-body", children: [
|
|
7627
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-snippet", children: [
|
|
7324
7628
|
item.target.tagName,
|
|
7325
7629
|
" \xB7 ",
|
|
7326
7630
|
item.target.textSnippet || item.target.selector
|
|
7327
7631
|
] }),
|
|
7328
|
-
/* @__PURE__ */ (0,
|
|
7329
|
-
/* @__PURE__ */ (0,
|
|
7330
|
-
/* @__PURE__ */ (0,
|
|
7331
|
-
/* @__PURE__ */ (0,
|
|
7632
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-change", children: changeSummary(item) }),
|
|
7633
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-meta", children: [
|
|
7634
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-author", title: new Date(item.createdAt).toLocaleString(), children: [
|
|
7635
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7332
7636
|
"span",
|
|
7333
7637
|
{
|
|
7334
7638
|
className: "rk-author-dot",
|
|
@@ -7336,15 +7640,15 @@ function Panel() {
|
|
|
7336
7640
|
}
|
|
7337
7641
|
),
|
|
7338
7642
|
item.author?.name ?? "Unknown",
|
|
7339
|
-
/* @__PURE__ */ (0,
|
|
7643
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-time", children: [
|
|
7340
7644
|
" \xB7 ",
|
|
7341
7645
|
timeAgo(item.createdAt)
|
|
7342
7646
|
] })
|
|
7343
7647
|
] }),
|
|
7344
|
-
item.priority === "must" && /* @__PURE__ */ (0,
|
|
7345
|
-
item.status !== "open" && /* @__PURE__ */ (0,
|
|
7346
|
-
orphan && /* @__PURE__ */ (0,
|
|
7347
|
-
hiddenEl && /* @__PURE__ */ (0,
|
|
7648
|
+
item.priority === "must" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini rk-must", children: "must" }),
|
|
7649
|
+
item.status !== "open" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-badge-mini rk-${item.status}`, children: item.status }),
|
|
7650
|
+
orphan && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini rk-orphaned", children: "unanchored" }),
|
|
7651
|
+
hiddenEl && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7348
7652
|
"span",
|
|
7349
7653
|
{
|
|
7350
7654
|
className: "rk-badge-mini rk-hidden-el",
|
|
@@ -7352,14 +7656,14 @@ function Panel() {
|
|
|
7352
7656
|
children: "hidden"
|
|
7353
7657
|
}
|
|
7354
7658
|
),
|
|
7355
|
-
item.note && /* @__PURE__ */ (0,
|
|
7356
|
-
peers.filter((peer) => peer.typingActive && peer.typingItemId === item.id).map((peer) => /* @__PURE__ */ (0,
|
|
7659
|
+
item.note && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini", children: "note" }),
|
|
7660
|
+
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: [
|
|
7357
7661
|
peer.name || "peer",
|
|
7358
7662
|
" is writing\u2026"
|
|
7359
7663
|
] }, peer.id))
|
|
7360
7664
|
] })
|
|
7361
7665
|
] }),
|
|
7362
|
-
/* @__PURE__ */ (0,
|
|
7666
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-actions", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7363
7667
|
"button",
|
|
7364
7668
|
{
|
|
7365
7669
|
type: "button",
|
|
@@ -7374,15 +7678,15 @@ function Panel() {
|
|
|
7374
7678
|
"info"
|
|
7375
7679
|
);
|
|
7376
7680
|
},
|
|
7377
|
-
children: /* @__PURE__ */ (0,
|
|
7681
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTrash, { size: 13 })
|
|
7378
7682
|
}
|
|
7379
7683
|
) })
|
|
7380
7684
|
]
|
|
7381
7685
|
}
|
|
7382
7686
|
),
|
|
7383
|
-
active2 && /* @__PURE__ */ (0,
|
|
7384
|
-
/* @__PURE__ */ (0,
|
|
7385
|
-
/* @__PURE__ */ (0,
|
|
7687
|
+
active2 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-item-edit", children: [
|
|
7688
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-detail-byline", title: new Date(item.createdAt).toLocaleString(), children: [
|
|
7689
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7386
7690
|
"span",
|
|
7387
7691
|
{
|
|
7388
7692
|
className: "rk-author-dot",
|
|
@@ -7393,8 +7697,8 @@ function Panel() {
|
|
|
7393
7697
|
" \xB7 ",
|
|
7394
7698
|
timeAgo(item.createdAt)
|
|
7395
7699
|
] }),
|
|
7396
|
-
isCopyItem(item) && /* @__PURE__ */ (0,
|
|
7397
|
-
isImageItem(item) && /* @__PURE__ */ (0,
|
|
7700
|
+
isCopyItem(item) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CopyDiff, { before: item.payload.before, after: item.payload.after }),
|
|
7701
|
+
isImageItem(item) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7398
7702
|
ImageDetail,
|
|
7399
7703
|
{
|
|
7400
7704
|
beforeSrc: item.payload.beforeSrc,
|
|
@@ -7402,7 +7706,7 @@ function Panel() {
|
|
|
7402
7706
|
afterDataUrl: item.payload.afterDataUrl
|
|
7403
7707
|
}
|
|
7404
7708
|
),
|
|
7405
|
-
isKnownItemType(item.type) && item.type !== "move" && /* @__PURE__ */ (0,
|
|
7709
|
+
isKnownItemType(item.type) && item.type !== "move" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7406
7710
|
"textarea",
|
|
7407
7711
|
{
|
|
7408
7712
|
className: "rk-textarea",
|
|
@@ -7412,7 +7716,7 @@ function Panel() {
|
|
|
7412
7716
|
onChange: (event) => dispatch({ type: "UPDATE_ITEM", id: item.id, patch: withPayloadText(item, event.target.value) })
|
|
7413
7717
|
}
|
|
7414
7718
|
),
|
|
7415
|
-
/* @__PURE__ */ (0,
|
|
7719
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7416
7720
|
"input",
|
|
7417
7721
|
{
|
|
7418
7722
|
className: "rk-input",
|
|
@@ -7422,9 +7726,9 @@ function Panel() {
|
|
|
7422
7726
|
onChange: (event) => dispatch({ type: "UPDATE_ITEM", id: item.id, patch: { note: event.target.value } })
|
|
7423
7727
|
}
|
|
7424
7728
|
),
|
|
7425
|
-
/* @__PURE__ */ (0,
|
|
7426
|
-
/* @__PURE__ */ (0,
|
|
7427
|
-
/* @__PURE__ */ (0,
|
|
7729
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
|
|
7730
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
7731
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7428
7732
|
"button",
|
|
7429
7733
|
{
|
|
7430
7734
|
type: "button",
|
|
@@ -7433,7 +7737,7 @@ function Panel() {
|
|
|
7433
7737
|
children: "Must"
|
|
7434
7738
|
}
|
|
7435
7739
|
),
|
|
7436
|
-
/* @__PURE__ */ (0,
|
|
7740
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7437
7741
|
"button",
|
|
7438
7742
|
{
|
|
7439
7743
|
type: "button",
|
|
@@ -7443,7 +7747,7 @@ function Panel() {
|
|
|
7443
7747
|
}
|
|
7444
7748
|
)
|
|
7445
7749
|
] }),
|
|
7446
|
-
/* @__PURE__ */ (0,
|
|
7750
|
+
/* @__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)(
|
|
7447
7751
|
"button",
|
|
7448
7752
|
{
|
|
7449
7753
|
type: "button",
|
|
@@ -7458,22 +7762,22 @@ function Panel() {
|
|
|
7458
7762
|
] }, item.id);
|
|
7459
7763
|
})
|
|
7460
7764
|
] }, route)) }),
|
|
7461
|
-
/* @__PURE__ */ (0,
|
|
7462
|
-
/* @__PURE__ */ (0,
|
|
7463
|
-
/* @__PURE__ */ (0,
|
|
7765
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-foot", children: [
|
|
7766
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: onExport, disabled: items.length === 0, children: [
|
|
7767
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconDownload, { size: 13 }),
|
|
7464
7768
|
" Export"
|
|
7465
7769
|
] }),
|
|
7466
|
-
/* @__PURE__ */ (0,
|
|
7467
|
-
/* @__PURE__ */ (0,
|
|
7770
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void onCopy(), disabled: items.length === 0, children: [
|
|
7771
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconCopyClipboard, { size: 13 }),
|
|
7468
7772
|
" Copy"
|
|
7469
7773
|
] }),
|
|
7470
|
-
/* @__PURE__ */ (0,
|
|
7471
|
-
/* @__PURE__ */ (0,
|
|
7774
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => importRef.current?.click(), children: [
|
|
7775
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconUpload, { size: 13 }),
|
|
7472
7776
|
" Import"
|
|
7473
7777
|
] }),
|
|
7474
|
-
/* @__PURE__ */ (0,
|
|
7475
|
-
undoStack.length > 0 && /* @__PURE__ */ (0,
|
|
7476
|
-
/* @__PURE__ */ (0,
|
|
7778
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-spacer" }),
|
|
7779
|
+
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 }) }),
|
|
7780
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7477
7781
|
"button",
|
|
7478
7782
|
{
|
|
7479
7783
|
type: "button",
|
|
@@ -7484,7 +7788,7 @@ function Panel() {
|
|
|
7484
7788
|
children: "Clear"
|
|
7485
7789
|
}
|
|
7486
7790
|
),
|
|
7487
|
-
/* @__PURE__ */ (0,
|
|
7791
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7488
7792
|
"button",
|
|
7489
7793
|
{
|
|
7490
7794
|
type: "button",
|
|
@@ -7494,7 +7798,7 @@ function Panel() {
|
|
|
7494
7798
|
children: "Exit review"
|
|
7495
7799
|
}
|
|
7496
7800
|
),
|
|
7497
|
-
/* @__PURE__ */ (0,
|
|
7801
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7498
7802
|
"input",
|
|
7499
7803
|
{
|
|
7500
7804
|
ref: importRef,
|
|
@@ -7515,8 +7819,8 @@ function Panel() {
|
|
|
7515
7819
|
}
|
|
7516
7820
|
|
|
7517
7821
|
// src/client/components/Presence.tsx
|
|
7518
|
-
var
|
|
7519
|
-
var
|
|
7822
|
+
var import_react15 = require("react");
|
|
7823
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
7520
7824
|
function initials(name) {
|
|
7521
7825
|
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
7522
7826
|
if (parts.length === 0) return "\xB7";
|
|
@@ -7526,8 +7830,8 @@ function initials(name) {
|
|
|
7526
7830
|
function PresenceStrip() {
|
|
7527
7831
|
const { peers, syncStatus } = useStore();
|
|
7528
7832
|
if (syncStatus === "disabled" || peers.length === 0) return null;
|
|
7529
|
-
return /* @__PURE__ */ (0,
|
|
7530
|
-
peers.slice(0, 5).map((peer) => /* @__PURE__ */ (0,
|
|
7833
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rk-presence", "aria-label": `${peers.length} reviewer${peers.length === 1 ? "" : "s"} online`, children: [
|
|
7834
|
+
peers.slice(0, 5).map((peer) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7531
7835
|
"span",
|
|
7532
7836
|
{
|
|
7533
7837
|
className: "rk-avatar",
|
|
@@ -7537,7 +7841,7 @@ function PresenceStrip() {
|
|
|
7537
7841
|
},
|
|
7538
7842
|
peer.id
|
|
7539
7843
|
)),
|
|
7540
|
-
peers.length > 5 && /* @__PURE__ */ (0,
|
|
7844
|
+
peers.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "rk-avatar rk-avatar-more", children: [
|
|
7541
7845
|
"+",
|
|
7542
7846
|
peers.length - 5
|
|
7543
7847
|
] })
|
|
@@ -7545,13 +7849,13 @@ function PresenceStrip() {
|
|
|
7545
7849
|
}
|
|
7546
7850
|
function PeerCursors() {
|
|
7547
7851
|
const { peers } = useStore();
|
|
7548
|
-
const ringRefs = (0,
|
|
7549
|
-
const cursorRefs = (0,
|
|
7550
|
-
const motion = (0,
|
|
7852
|
+
const ringRefs = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
|
|
7853
|
+
const cursorRefs = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
|
|
7854
|
+
const motion = (0, import_react15.useRef)(
|
|
7551
7855
|
/* @__PURE__ */ new Map()
|
|
7552
7856
|
);
|
|
7553
|
-
const peersRef = (0,
|
|
7554
|
-
const seen = (0,
|
|
7857
|
+
const peersRef = (0, import_react15.useRef)(peers);
|
|
7858
|
+
const seen = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
|
|
7555
7859
|
for (const peer of peers) {
|
|
7556
7860
|
const sig = peer.cursor ? `${peer.cursor.x},${peer.cursor.y},${peer.cursor.ox},${peer.cursor.oy}` : "";
|
|
7557
7861
|
if (seen.current.get(peer.id) !== sig) {
|
|
@@ -7561,7 +7865,7 @@ function PeerCursors() {
|
|
|
7561
7865
|
}
|
|
7562
7866
|
}
|
|
7563
7867
|
peersRef.current = peers;
|
|
7564
|
-
(0,
|
|
7868
|
+
(0, import_react15.useEffect)(() => {
|
|
7565
7869
|
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
7566
7870
|
let raf = 0;
|
|
7567
7871
|
let last = performance.now();
|
|
@@ -7666,8 +7970,8 @@ function PeerCursors() {
|
|
|
7666
7970
|
return () => cancelAnimationFrame(raf);
|
|
7667
7971
|
}, []);
|
|
7668
7972
|
if (peers.length === 0) return null;
|
|
7669
|
-
return /* @__PURE__ */ (0,
|
|
7670
|
-
peers.map((peer) => /* @__PURE__ */ (0,
|
|
7973
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
7974
|
+
peers.map((peer) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7671
7975
|
"div",
|
|
7672
7976
|
{
|
|
7673
7977
|
ref: (el) => {
|
|
@@ -7679,7 +7983,7 @@ function PeerCursors() {
|
|
|
7679
7983
|
},
|
|
7680
7984
|
`ring-${peer.id}`
|
|
7681
7985
|
)),
|
|
7682
|
-
peers.map((peer, index) => /* @__PURE__ */ (0,
|
|
7986
|
+
peers.map((peer, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7683
7987
|
"div",
|
|
7684
7988
|
{
|
|
7685
7989
|
ref: (el) => {
|
|
@@ -7689,8 +7993,8 @@ function PeerCursors() {
|
|
|
7689
7993
|
className: "rk-peer-cursor",
|
|
7690
7994
|
style: { opacity: 0 },
|
|
7691
7995
|
children: [
|
|
7692
|
-
/* @__PURE__ */ (0,
|
|
7693
|
-
/* @__PURE__ */ (0,
|
|
7996
|
+
/* @__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" }) }),
|
|
7997
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7694
7998
|
"span",
|
|
7695
7999
|
{
|
|
7696
8000
|
className: "rk-peer-name",
|
|
@@ -7709,19 +8013,19 @@ function PeerCursors() {
|
|
|
7709
8013
|
}
|
|
7710
8014
|
|
|
7711
8015
|
// src/client/components/QuickComment.tsx
|
|
7712
|
-
var
|
|
7713
|
-
var
|
|
8016
|
+
var import_react16 = require("react");
|
|
8017
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
7714
8018
|
function QuickComment() {
|
|
7715
8019
|
const { quick } = useStore();
|
|
7716
8020
|
if (!quick) return null;
|
|
7717
|
-
return /* @__PURE__ */ (0,
|
|
8021
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(QuickComposerCard, { quick }, quick.id);
|
|
7718
8022
|
}
|
|
7719
8023
|
function QuickComposerCard({ quick }) {
|
|
7720
8024
|
const { route, session } = useStore();
|
|
7721
8025
|
const dispatch = useDispatch();
|
|
7722
|
-
const [text, setText] = (0,
|
|
7723
|
-
const fieldRef = (0,
|
|
7724
|
-
(0,
|
|
8026
|
+
const [text, setText] = (0, import_react16.useState)("");
|
|
8027
|
+
const fieldRef = (0, import_react16.useRef)(null);
|
|
8028
|
+
(0, import_react16.useEffect)(() => {
|
|
7725
8029
|
const field = fieldRef.current;
|
|
7726
8030
|
if (!field) return;
|
|
7727
8031
|
field.focus();
|
|
@@ -7774,18 +8078,18 @@ function QuickComposerCard({ quick }) {
|
|
|
7774
8078
|
};
|
|
7775
8079
|
const x = Math.min(Math.max(quick.x, 8), window.innerWidth - 288);
|
|
7776
8080
|
const y = Math.min(Math.max(quick.y + 12, 8), window.innerHeight - 108);
|
|
7777
|
-
return /* @__PURE__ */ (0,
|
|
7778
|
-
/* @__PURE__ */ (0,
|
|
7779
|
-
/* @__PURE__ */ (0,
|
|
7780
|
-
/* @__PURE__ */ (0,
|
|
7781
|
-
/* @__PURE__ */ (0,
|
|
7782
|
-
/* @__PURE__ */ (0,
|
|
8081
|
+
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: [
|
|
8082
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rk-quick-head", children: [
|
|
8083
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(IconComment, { size: 12 }),
|
|
8084
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Comment here" }),
|
|
8085
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "rk-hint", children: [
|
|
8086
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
|
|
7783
8087
|
" save \xB7 ",
|
|
7784
|
-
/* @__PURE__ */ (0,
|
|
8088
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
7785
8089
|
" cancel"
|
|
7786
8090
|
] })
|
|
7787
8091
|
] }),
|
|
7788
|
-
/* @__PURE__ */ (0,
|
|
8092
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7789
8093
|
"textarea",
|
|
7790
8094
|
{
|
|
7791
8095
|
ref: fieldRef,
|
|
@@ -7801,8 +8105,8 @@ function QuickComposerCard({ quick }) {
|
|
|
7801
8105
|
}
|
|
7802
8106
|
|
|
7803
8107
|
// src/client/components/PickLayer.tsx
|
|
7804
|
-
var
|
|
7805
|
-
var
|
|
8108
|
+
var import_react17 = require("react");
|
|
8109
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
7806
8110
|
function applyRect(el, rect, pad2 = 3) {
|
|
7807
8111
|
if (!el) return;
|
|
7808
8112
|
if (!rect) {
|
|
@@ -7817,14 +8121,14 @@ function applyRect(el, rect, pad2 = 3) {
|
|
|
7817
8121
|
function PickLayer() {
|
|
7818
8122
|
const { mode, selection, tool } = useStore();
|
|
7819
8123
|
const dispatch = useDispatch();
|
|
7820
|
-
const [hovered, setHovered] = (0,
|
|
7821
|
-
const outlineRef = (0,
|
|
7822
|
-
const labelRef = (0,
|
|
7823
|
-
const selectRef = (0,
|
|
7824
|
-
const hoveredRef = (0,
|
|
8124
|
+
const [hovered, setHovered] = (0, import_react17.useState)(null);
|
|
8125
|
+
const outlineRef = (0, import_react17.useRef)(null);
|
|
8126
|
+
const labelRef = (0, import_react17.useRef)(null);
|
|
8127
|
+
const selectRef = (0, import_react17.useRef)(null);
|
|
8128
|
+
const hoveredRef = (0, import_react17.useRef)(null);
|
|
7825
8129
|
hoveredRef.current = hovered;
|
|
7826
8130
|
const picking = mode === "pick";
|
|
7827
|
-
(0,
|
|
8131
|
+
(0, import_react17.useEffect)(() => {
|
|
7828
8132
|
if (!picking) {
|
|
7829
8133
|
setHovered(null);
|
|
7830
8134
|
return;
|
|
@@ -7868,7 +8172,7 @@ function PickLayer() {
|
|
|
7868
8172
|
document.removeEventListener("mousedown", swallow, true);
|
|
7869
8173
|
};
|
|
7870
8174
|
}, [picking, tool, dispatch]);
|
|
7871
|
-
(0,
|
|
8175
|
+
(0, import_react17.useEffect)(() => {
|
|
7872
8176
|
if (!picking) return;
|
|
7873
8177
|
const body = document.body;
|
|
7874
8178
|
const prev = body.style.cursor;
|
|
@@ -7878,7 +8182,7 @@ function PickLayer() {
|
|
|
7878
8182
|
if (body.getAttribute("style") === "") body.removeAttribute("style");
|
|
7879
8183
|
};
|
|
7880
8184
|
}, [picking, tool]);
|
|
7881
|
-
(0,
|
|
8185
|
+
(0, import_react17.useEffect)(() => {
|
|
7882
8186
|
let raf = 0;
|
|
7883
8187
|
const tick = () => {
|
|
7884
8188
|
const hoverEl = hoveredRef.current;
|
|
@@ -7904,21 +8208,21 @@ function PickLayer() {
|
|
|
7904
8208
|
raf = requestAnimationFrame(tick);
|
|
7905
8209
|
return () => cancelAnimationFrame(raf);
|
|
7906
8210
|
}, [picking, selection]);
|
|
7907
|
-
return /* @__PURE__ */ (0,
|
|
7908
|
-
picking && /* @__PURE__ */ (0,
|
|
7909
|
-
/* @__PURE__ */ (0,
|
|
7910
|
-
/* @__PURE__ */ (0,
|
|
7911
|
-
/* @__PURE__ */ (0,
|
|
7912
|
-
/* @__PURE__ */ (0,
|
|
7913
|
-
] }) : /* @__PURE__ */ (0,
|
|
8211
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
8212
|
+
picking && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
8213
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: outlineRef, className: "rk-outline", style: { opacity: 0 } }),
|
|
8214
|
+
/* @__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: [
|
|
8215
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rk-tag", children: hovered.tagName.toLowerCase() }),
|
|
8216
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: describeElement(hovered).replace(/^[a-z0-9]+ · /, "") })
|
|
8217
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Pick an element" }) })
|
|
7914
8218
|
] }),
|
|
7915
|
-
selection && /* @__PURE__ */ (0,
|
|
8219
|
+
selection && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: selectRef, className: "rk-select-ring", style: { opacity: 0 } })
|
|
7916
8220
|
] });
|
|
7917
8221
|
}
|
|
7918
8222
|
|
|
7919
8223
|
// src/client/components/Pins.tsx
|
|
7920
|
-
var
|
|
7921
|
-
var
|
|
8224
|
+
var import_react18 = require("react");
|
|
8225
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
7922
8226
|
var STATUS_LABELS = {
|
|
7923
8227
|
open: "open",
|
|
7924
8228
|
accepted: "accepted",
|
|
@@ -7930,22 +8234,22 @@ var RERESOLVE_MS = 800;
|
|
|
7930
8234
|
function Pins() {
|
|
7931
8235
|
const { session, route, activeItemId, editor, mode, filter } = useStore();
|
|
7932
8236
|
const dispatch = useDispatch();
|
|
7933
|
-
const [clusters, setClusters] = (0,
|
|
7934
|
-
const [orphanCount, setOrphanCount] = (0,
|
|
7935
|
-
const wrapRefs = (0,
|
|
7936
|
-
const visibleCache = (0,
|
|
7937
|
-
const highlightRef = (0,
|
|
7938
|
-
const hoveredItems = (0,
|
|
7939
|
-
const elementCache = (0,
|
|
7940
|
-
const lastResolve = (0,
|
|
7941
|
-
const [newestId, setNewestId] = (0,
|
|
7942
|
-
const prevCount = (0,
|
|
7943
|
-
const items = (0,
|
|
8237
|
+
const [clusters, setClusters] = (0, import_react18.useState)([]);
|
|
8238
|
+
const [orphanCount, setOrphanCount] = (0, import_react18.useState)(0);
|
|
8239
|
+
const wrapRefs = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
8240
|
+
const visibleCache = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
8241
|
+
const highlightRef = (0, import_react18.useRef)(null);
|
|
8242
|
+
const hoveredItems = (0, import_react18.useRef)(null);
|
|
8243
|
+
const elementCache = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
8244
|
+
const lastResolve = (0, import_react18.useRef)(0);
|
|
8245
|
+
const [newestId, setNewestId] = (0, import_react18.useState)(null);
|
|
8246
|
+
const prevCount = (0, import_react18.useRef)(0);
|
|
8247
|
+
const items = (0, import_react18.useMemo)(() => {
|
|
7944
8248
|
const all = session?.items ?? [];
|
|
7945
8249
|
return all.map((item, index) => ({ item, number: index + 1 })).filter(({ item }) => item.route === route);
|
|
7946
8250
|
}, [session, route]);
|
|
7947
8251
|
const byId = new Map(items.map(({ item }) => [item.id, item]));
|
|
7948
|
-
(0,
|
|
8252
|
+
(0, import_react18.useEffect)(() => {
|
|
7949
8253
|
const count = session?.items.length ?? 0;
|
|
7950
8254
|
if (count > prevCount.current && session && count > 0) {
|
|
7951
8255
|
const id = session.items[count - 1].id;
|
|
@@ -7956,7 +8260,7 @@ function Pins() {
|
|
|
7956
8260
|
}
|
|
7957
8261
|
prevCount.current = count;
|
|
7958
8262
|
}, [session]);
|
|
7959
|
-
(0,
|
|
8263
|
+
(0, import_react18.useEffect)(() => {
|
|
7960
8264
|
let raf = 0;
|
|
7961
8265
|
let lastSignature = "";
|
|
7962
8266
|
const tick = (time) => {
|
|
@@ -8040,8 +8344,8 @@ function Pins() {
|
|
|
8040
8344
|
dispatch({ type: "SET_ACTIVE_ITEM", id });
|
|
8041
8345
|
dispatch({ type: "SET_PANEL", open: true });
|
|
8042
8346
|
};
|
|
8043
|
-
return /* @__PURE__ */ (0,
|
|
8044
|
-
/* @__PURE__ */ (0,
|
|
8347
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
8348
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref: highlightRef, className: "rk-hl-ring", style: { opacity: 0 } }),
|
|
8045
8349
|
clusters.map((cluster) => {
|
|
8046
8350
|
const isCluster = cluster.ids.length > 1;
|
|
8047
8351
|
const isActive = activeItemId !== null && cluster.ids.includes(activeItemId);
|
|
@@ -8051,7 +8355,7 @@ function Pins() {
|
|
|
8051
8355
|
const status = statuses.size === 1 ? members[0]?.status : void 0;
|
|
8052
8356
|
const dimmed = filter !== null && members.length > 0 && !members.some((item) => itemMatchesFilter(item, filter));
|
|
8053
8357
|
const statusHint = isCluster ? status ? ` \xB7 all ${STATUS_LABELS[status] ?? status}` : "" : ` \xB7 ${STATUS_LABELS[members[0]?.status ?? "open"] ?? members[0]?.status}`;
|
|
8054
|
-
return /* @__PURE__ */ (0,
|
|
8358
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
8055
8359
|
"div",
|
|
8056
8360
|
{
|
|
8057
8361
|
ref: (el) => {
|
|
@@ -8059,7 +8363,7 @@ function Pins() {
|
|
|
8059
8363
|
else wrapRefs.current.delete(cluster.key);
|
|
8060
8364
|
},
|
|
8061
8365
|
className: `rk-pin-wrap${picking ? " rk-pin-ghost" : ""}`,
|
|
8062
|
-
children: /* @__PURE__ */ (0,
|
|
8366
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
8063
8367
|
"button",
|
|
8064
8368
|
{
|
|
8065
8369
|
type: "button",
|
|
@@ -8081,7 +8385,7 @@ function Pins() {
|
|
|
8081
8385
|
cluster.key
|
|
8082
8386
|
);
|
|
8083
8387
|
}),
|
|
8084
|
-
orphanCount > 0 && /* @__PURE__ */ (0,
|
|
8388
|
+
orphanCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
8085
8389
|
"button",
|
|
8086
8390
|
{
|
|
8087
8391
|
type: "button",
|
|
@@ -8089,7 +8393,7 @@ function Pins() {
|
|
|
8089
8393
|
style: { bottom: 16, left: "50%", transform: "translateX(-50%)" },
|
|
8090
8394
|
onClick: () => dispatch({ type: "SET_PANEL", open: true }),
|
|
8091
8395
|
children: [
|
|
8092
|
-
/* @__PURE__ */ (0,
|
|
8396
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconUnlink, { size: 13 }),
|
|
8093
8397
|
orphanCount,
|
|
8094
8398
|
" unanchored item",
|
|
8095
8399
|
orphanCount === 1 ? "" : "s"
|
|
@@ -8100,13 +8404,13 @@ function Pins() {
|
|
|
8100
8404
|
}
|
|
8101
8405
|
|
|
8102
8406
|
// src/client/components/Toolbar.tsx
|
|
8103
|
-
var
|
|
8104
|
-
var
|
|
8407
|
+
var import_react19 = require("react");
|
|
8408
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
8105
8409
|
var TOOLS = [
|
|
8106
|
-
{ tool: "select", hintId: "tool-select", label: "Select", icon: (n) => /* @__PURE__ */ (0,
|
|
8107
|
-
{ tool: "copy", hintId: "tool-copy", label: "Rewrite text", icon: (n) => /* @__PURE__ */ (0,
|
|
8108
|
-
{ tool: "comment", hintId: "tool-comment", label: "Comment", icon: (n) => /* @__PURE__ */ (0,
|
|
8109
|
-
{ tool: "image", hintId: "tool-image", label: "Replace image", icon: (n) => /* @__PURE__ */ (0,
|
|
8410
|
+
{ tool: "select", hintId: "tool-select", label: "Select", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconTarget, { size: n }) },
|
|
8411
|
+
{ tool: "copy", hintId: "tool-copy", label: "Rewrite text", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconText, { size: n }) },
|
|
8412
|
+
{ tool: "comment", hintId: "tool-comment", label: "Comment", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: n }) },
|
|
8413
|
+
{ tool: "image", hintId: "tool-image", label: "Replace image", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconImage, { size: n }) }
|
|
8110
8414
|
];
|
|
8111
8415
|
var POS_KEY2 = "review-kit:toolbar-pos";
|
|
8112
8416
|
var DRAG_THRESHOLD2 = 6;
|
|
@@ -8114,24 +8418,24 @@ function Toolbar() {
|
|
|
8114
8418
|
const { selection, editor, peers, syncStatus, mode, tool } = useStore();
|
|
8115
8419
|
const hasPeers = syncStatus !== "disabled" && peers.length > 0;
|
|
8116
8420
|
const dispatch = useDispatch();
|
|
8117
|
-
const ref = (0,
|
|
8118
|
-
const [pos, setPos] = (0,
|
|
8119
|
-
const drag = (0,
|
|
8120
|
-
const [dragging, setDragging] = (0,
|
|
8121
|
-
const justDragged = (0,
|
|
8421
|
+
const ref = (0, import_react19.useRef)(null);
|
|
8422
|
+
const [pos, setPos] = (0, import_react19.useState)(() => readStoredPos(POS_KEY2));
|
|
8423
|
+
const drag = (0, import_react19.useRef)(null);
|
|
8424
|
+
const [dragging, setDragging] = (0, import_react19.useState)(false);
|
|
8425
|
+
const justDragged = (0, import_react19.useRef)(false);
|
|
8122
8426
|
const visible = editor === null || selection !== null;
|
|
8123
8427
|
const applyPos = (next, persist) => {
|
|
8124
8428
|
if (next === null && ref.current) ref.current.style.bottom = "";
|
|
8125
8429
|
setPos(next);
|
|
8126
8430
|
if (persist) storePos(POS_KEY2, next);
|
|
8127
8431
|
};
|
|
8128
|
-
(0,
|
|
8432
|
+
(0, import_react19.useLayoutEffect)(() => {
|
|
8129
8433
|
const el = ref.current;
|
|
8130
8434
|
if (!el || pos === null) return;
|
|
8131
8435
|
const clamped = clampPos(pos.x, pos.y, el.offsetWidth, el.offsetHeight);
|
|
8132
8436
|
if (clamped.x !== pos.x || clamped.y !== pos.y) applyPos(clamped, true);
|
|
8133
8437
|
}, [pos, selection, hasPeers, visible]);
|
|
8134
|
-
(0,
|
|
8438
|
+
(0, import_react19.useEffect)(() => {
|
|
8135
8439
|
const onResize = () => {
|
|
8136
8440
|
const el = ref.current;
|
|
8137
8441
|
const current = readStoredPos(POS_KEY2);
|
|
@@ -8244,7 +8548,7 @@ function Toolbar() {
|
|
|
8244
8548
|
mode === "pick" && selection === null ? "rk-ghost" : ""
|
|
8245
8549
|
].filter(Boolean).join(" ");
|
|
8246
8550
|
const style = pos !== null ? { left: 0, top: 0, translate: `${pos.x}px ${pos.y}px` } : void 0;
|
|
8247
|
-
return /* @__PURE__ */ (0,
|
|
8551
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8248
8552
|
"div",
|
|
8249
8553
|
{
|
|
8250
8554
|
ref,
|
|
@@ -8255,7 +8559,7 @@ function Toolbar() {
|
|
|
8255
8559
|
onPointerDown,
|
|
8256
8560
|
onClickCapture,
|
|
8257
8561
|
children: [
|
|
8258
|
-
/* @__PURE__ */ (0,
|
|
8562
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
8259
8563
|
"button",
|
|
8260
8564
|
{
|
|
8261
8565
|
type: "button",
|
|
@@ -8263,19 +8567,19 @@ function Toolbar() {
|
|
|
8263
8567
|
"aria-label": "Move the toolbar \u2014 drag, or use arrow keys; double-click to reset its position",
|
|
8264
8568
|
onKeyDown: onGripKeyDown,
|
|
8265
8569
|
onDoubleClick: () => applyPos(null, true),
|
|
8266
|
-
children: /* @__PURE__ */ (0,
|
|
8267
|
-
/* @__PURE__ */ (0,
|
|
8268
|
-
/* @__PURE__ */ (0,
|
|
8269
|
-
/* @__PURE__ */ (0,
|
|
8270
|
-
/* @__PURE__ */ (0,
|
|
8271
|
-
/* @__PURE__ */ (0,
|
|
8272
|
-
/* @__PURE__ */ (0,
|
|
8570
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("svg", { width: "8", height: "14", viewBox: "0 0 8 14", "aria-hidden": "true", fill: "currentColor", children: [
|
|
8571
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "2", r: "1.1" }),
|
|
8572
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "2", r: "1.1" }),
|
|
8573
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "7", r: "1.1" }),
|
|
8574
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "7", r: "1.1" }),
|
|
8575
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "12", r: "1.1" }),
|
|
8576
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "12", r: "1.1" })
|
|
8273
8577
|
] })
|
|
8274
8578
|
}
|
|
8275
8579
|
),
|
|
8276
|
-
/* @__PURE__ */ (0,
|
|
8277
|
-
hasPeers && /* @__PURE__ */ (0,
|
|
8278
|
-
/* @__PURE__ */ (0,
|
|
8580
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PresenceStrip, {}),
|
|
8581
|
+
hasPeers && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
|
|
8582
|
+
/* @__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)(
|
|
8279
8583
|
"button",
|
|
8280
8584
|
{
|
|
8281
8585
|
type: "button",
|
|
@@ -8287,9 +8591,9 @@ function Toolbar() {
|
|
|
8287
8591
|
},
|
|
8288
8592
|
entry.tool
|
|
8289
8593
|
)) }),
|
|
8290
|
-
selection && /* @__PURE__ */ (0,
|
|
8291
|
-
selection && /* @__PURE__ */ (0,
|
|
8292
|
-
/* @__PURE__ */ (0,
|
|
8594
|
+
selection && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
|
|
8595
|
+
selection && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
8596
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8293
8597
|
"button",
|
|
8294
8598
|
{
|
|
8295
8599
|
type: "button",
|
|
@@ -8298,12 +8602,12 @@ function Toolbar() {
|
|
|
8298
8602
|
title: `Rewrite text${keyHint("tool-copy")}`,
|
|
8299
8603
|
onClick: () => open("copy"),
|
|
8300
8604
|
children: [
|
|
8301
|
-
/* @__PURE__ */ (0,
|
|
8605
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconText, { size: 14 }),
|
|
8302
8606
|
" Rewrite"
|
|
8303
8607
|
]
|
|
8304
8608
|
}
|
|
8305
8609
|
),
|
|
8306
|
-
hasImage && /* @__PURE__ */ (0,
|
|
8610
|
+
hasImage && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8307
8611
|
"button",
|
|
8308
8612
|
{
|
|
8309
8613
|
type: "button",
|
|
@@ -8312,12 +8616,12 @@ function Toolbar() {
|
|
|
8312
8616
|
title: `Replace image${keyHint("tool-image")}`,
|
|
8313
8617
|
onClick: () => open("image"),
|
|
8314
8618
|
children: [
|
|
8315
|
-
/* @__PURE__ */ (0,
|
|
8619
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconImage, { size: 14 }),
|
|
8316
8620
|
" Image"
|
|
8317
8621
|
]
|
|
8318
8622
|
}
|
|
8319
8623
|
),
|
|
8320
|
-
/* @__PURE__ */ (0,
|
|
8624
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8321
8625
|
"button",
|
|
8322
8626
|
{
|
|
8323
8627
|
type: "button",
|
|
@@ -8326,32 +8630,32 @@ function Toolbar() {
|
|
|
8326
8630
|
title: `Comment${keyHint("tool-comment")}`,
|
|
8327
8631
|
onClick: () => open("comment"),
|
|
8328
8632
|
children: [
|
|
8329
|
-
/* @__PURE__ */ (0,
|
|
8633
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: 14 }),
|
|
8330
8634
|
" Comment"
|
|
8331
8635
|
]
|
|
8332
8636
|
}
|
|
8333
8637
|
),
|
|
8334
|
-
/* @__PURE__ */ (0,
|
|
8335
|
-
/* @__PURE__ */ (0,
|
|
8638
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("style"), children: [
|
|
8639
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconStyle, { size: 14 }),
|
|
8336
8640
|
" Style"
|
|
8337
8641
|
] }),
|
|
8338
|
-
/* @__PURE__ */ (0,
|
|
8339
|
-
/* @__PURE__ */ (0,
|
|
8642
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("move"), children: [
|
|
8643
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconMove, { size: 14 }),
|
|
8340
8644
|
" Move"
|
|
8341
8645
|
] }),
|
|
8342
|
-
/* @__PURE__ */ (0,
|
|
8343
|
-
/* @__PURE__ */ (0,
|
|
8646
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn rk-danger", onClick: () => open("delete"), children: [
|
|
8647
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconTrash, { size: 14 }),
|
|
8344
8648
|
" Delete"
|
|
8345
8649
|
] }),
|
|
8346
|
-
/* @__PURE__ */ (0,
|
|
8347
|
-
/* @__PURE__ */ (0,
|
|
8650
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
|
|
8651
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
8348
8652
|
"button",
|
|
8349
8653
|
{
|
|
8350
8654
|
type: "button",
|
|
8351
8655
|
className: "rk-icon-btn",
|
|
8352
8656
|
"aria-label": "Deselect",
|
|
8353
8657
|
onClick: () => dispatch({ type: "SELECT", selection: null }),
|
|
8354
|
-
children: /* @__PURE__ */ (0,
|
|
8658
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconClose, { size: 13 })
|
|
8355
8659
|
}
|
|
8356
8660
|
)
|
|
8357
8661
|
] })
|
|
@@ -8361,40 +8665,40 @@ function Toolbar() {
|
|
|
8361
8665
|
}
|
|
8362
8666
|
|
|
8363
8667
|
// src/client/components/Toast.tsx
|
|
8364
|
-
var
|
|
8365
|
-
var
|
|
8668
|
+
var import_react20 = require("react");
|
|
8669
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
8366
8670
|
function ToastRow({ toast: toast2 }) {
|
|
8367
8671
|
const dispatch = useDispatch();
|
|
8368
|
-
(0,
|
|
8672
|
+
(0, import_react20.useEffect)(() => {
|
|
8369
8673
|
const timer = window.setTimeout(() => dispatch({ type: "DISMISS_TOAST", id: toast2.id }), 3500);
|
|
8370
8674
|
return () => window.clearTimeout(timer);
|
|
8371
8675
|
}, [toast2.id, dispatch]);
|
|
8372
|
-
return /* @__PURE__ */ (0,
|
|
8373
|
-
toast2.tone === "success" ? /* @__PURE__ */ (0,
|
|
8676
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `rk-toast rk-${toast2.tone}`, role: "status", children: [
|
|
8677
|
+
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 }),
|
|
8374
8678
|
toast2.message
|
|
8375
8679
|
] });
|
|
8376
8680
|
}
|
|
8377
8681
|
function ToastHost() {
|
|
8378
8682
|
const { toasts } = useStore();
|
|
8379
8683
|
if (toasts.length === 0) return null;
|
|
8380
|
-
return /* @__PURE__ */ (0,
|
|
8684
|
+
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)) });
|
|
8381
8685
|
}
|
|
8382
8686
|
|
|
8383
8687
|
// src/client/App.tsx
|
|
8384
|
-
var
|
|
8688
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
8385
8689
|
function App() {
|
|
8386
8690
|
const state = useStore();
|
|
8387
8691
|
const rawDispatch = useDispatch();
|
|
8388
8692
|
const config = useConfig();
|
|
8389
8693
|
const dispatch = useRealtimeSync(state, rawDispatch, config, reducer);
|
|
8390
|
-
const saveTimer = (0,
|
|
8694
|
+
const saveTimer = (0, import_react21.useRef)(null);
|
|
8391
8695
|
const storageKey = config.storageKey ?? defaultStorageKey();
|
|
8392
8696
|
useAppliedPreview(state, dispatch);
|
|
8393
8697
|
useEmblemaAutoPush(state, dispatch, config);
|
|
8394
|
-
(0,
|
|
8698
|
+
(0, import_react21.useEffect)(() => {
|
|
8395
8699
|
setEffectAssetsUrl(config.fxAssetsUrl);
|
|
8396
8700
|
}, [config.fxAssetsUrl]);
|
|
8397
|
-
(0,
|
|
8701
|
+
(0, import_react21.useEffect)(() => {
|
|
8398
8702
|
let cancelled = false;
|
|
8399
8703
|
void loadSession(storageKey).then((stored) => {
|
|
8400
8704
|
if (cancelled) return;
|
|
@@ -8412,7 +8716,7 @@ function App() {
|
|
|
8412
8716
|
};
|
|
8413
8717
|
}, [storageKey, config.defaultAuthor, dispatch]);
|
|
8414
8718
|
const { session } = state;
|
|
8415
|
-
(0,
|
|
8719
|
+
(0, import_react21.useEffect)(() => {
|
|
8416
8720
|
if (!session) return;
|
|
8417
8721
|
if (saveTimer.current !== null) window.clearTimeout(saveTimer.current);
|
|
8418
8722
|
saveTimer.current = window.setTimeout(() => {
|
|
@@ -8423,9 +8727,9 @@ function App() {
|
|
|
8423
8727
|
if (saveTimer.current !== null) window.clearTimeout(saveTimer.current);
|
|
8424
8728
|
};
|
|
8425
8729
|
}, [session, storageKey, config]);
|
|
8426
|
-
(0,
|
|
8427
|
-
const focusHandled = (0,
|
|
8428
|
-
(0,
|
|
8730
|
+
(0, import_react21.useEffect)(() => trackPointer(), []);
|
|
8731
|
+
const focusHandled = (0, import_react21.useRef)(false);
|
|
8732
|
+
(0, import_react21.useEffect)(() => {
|
|
8429
8733
|
if (!session || focusHandled.current) return;
|
|
8430
8734
|
focusHandled.current = true;
|
|
8431
8735
|
const id = takeFocusItem();
|
|
@@ -8450,7 +8754,7 @@ function App() {
|
|
|
8450
8754
|
cancelled = true;
|
|
8451
8755
|
};
|
|
8452
8756
|
}, [session, dispatch]);
|
|
8453
|
-
(0,
|
|
8757
|
+
(0, import_react21.useEffect)(() => {
|
|
8454
8758
|
let last = window.location.pathname;
|
|
8455
8759
|
const check = () => {
|
|
8456
8760
|
if (window.location.pathname !== last) {
|
|
@@ -8465,9 +8769,9 @@ function App() {
|
|
|
8465
8769
|
window.removeEventListener("popstate", check);
|
|
8466
8770
|
};
|
|
8467
8771
|
}, [dispatch]);
|
|
8468
|
-
const stateRef = (0,
|
|
8772
|
+
const stateRef = (0, import_react21.useRef)(state);
|
|
8469
8773
|
stateRef.current = state;
|
|
8470
|
-
(0,
|
|
8774
|
+
(0, import_react21.useEffect)(() => {
|
|
8471
8775
|
const onKeyDown = (event) => {
|
|
8472
8776
|
const current = stateRef.current;
|
|
8473
8777
|
for (const def of SHORTCUTS) {
|
|
@@ -8482,7 +8786,7 @@ function App() {
|
|
|
8482
8786
|
document.addEventListener("keydown", onKeyDown);
|
|
8483
8787
|
return () => document.removeEventListener("keydown", onKeyDown);
|
|
8484
8788
|
}, [dispatch]);
|
|
8485
|
-
(0,
|
|
8789
|
+
(0, import_react21.useEffect)(() => {
|
|
8486
8790
|
if (!state.editor) return;
|
|
8487
8791
|
const editorEl = state.editor.element;
|
|
8488
8792
|
const onPointerDown = (event) => {
|
|
@@ -8495,32 +8799,33 @@ function App() {
|
|
|
8495
8799
|
}, [state.editor, dispatch]);
|
|
8496
8800
|
if (!session) return null;
|
|
8497
8801
|
if (state.hidden) {
|
|
8498
|
-
return /* @__PURE__ */ (0,
|
|
8802
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DispatchContext.Provider, { value: dispatch, children: null });
|
|
8499
8803
|
}
|
|
8500
|
-
return /* @__PURE__ */ (0,
|
|
8501
|
-
/* @__PURE__ */ (0,
|
|
8502
|
-
/* @__PURE__ */ (0,
|
|
8503
|
-
/* @__PURE__ */ (0,
|
|
8504
|
-
state.editor?.kind === "copy" && /* @__PURE__ */ (0,
|
|
8505
|
-
state.editor?.kind === "image" && /* @__PURE__ */ (0,
|
|
8506
|
-
state.editor && state.editor.kind !== "copy" && state.editor.kind !== "image" && /* @__PURE__ */ (0,
|
|
8507
|
-
/* @__PURE__ */ (0,
|
|
8508
|
-
/* @__PURE__ */ (0,
|
|
8509
|
-
/* @__PURE__ */ (0,
|
|
8510
|
-
/* @__PURE__ */ (0,
|
|
8511
|
-
/* @__PURE__ */ (0,
|
|
8512
|
-
/* @__PURE__ */ (0,
|
|
8513
|
-
/* @__PURE__ */ (0,
|
|
8514
|
-
/* @__PURE__ */ (0,
|
|
8515
|
-
/* @__PURE__ */ (0,
|
|
8804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DispatchContext.Provider, { value: dispatch, children: [
|
|
8805
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PickLayer, {}),
|
|
8806
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PeerCursors, {}),
|
|
8807
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Toolbar, {}),
|
|
8808
|
+
state.editor?.kind === "copy" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InlineEditor, { editor: state.editor }),
|
|
8809
|
+
state.editor?.kind === "image" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ImageEditor, { editor: state.editor }),
|
|
8810
|
+
state.editor && state.editor.kind !== "copy" && state.editor.kind !== "image" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NoteComposer, { editor: state.editor }),
|
|
8811
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pins, {}),
|
|
8812
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(QuickComment, {}),
|
|
8813
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Panel, {}),
|
|
8814
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Badge, {}),
|
|
8815
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CoachMark, {}),
|
|
8816
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CheatSheet, {}),
|
|
8817
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmblemaConnect, {}),
|
|
8818
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TerminalConnect, {}),
|
|
8819
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ConfirmHost, {}),
|
|
8820
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ToastHost, {})
|
|
8516
8821
|
] });
|
|
8517
8822
|
}
|
|
8518
8823
|
|
|
8519
8824
|
// src/client/ReviewKit.tsx
|
|
8520
|
-
var
|
|
8825
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
8521
8826
|
function ShadowHost({ config }) {
|
|
8522
|
-
const [mount, setMount] = (0,
|
|
8523
|
-
(0,
|
|
8827
|
+
const [mount, setMount] = (0, import_react22.useState)(null);
|
|
8828
|
+
(0, import_react22.useEffect)(() => {
|
|
8524
8829
|
const host = document.createElement("div");
|
|
8525
8830
|
host.setAttribute(HOST_ATTR, "");
|
|
8526
8831
|
host.style.position = "fixed";
|
|
@@ -8556,15 +8861,15 @@ function ShadowHost({ config }) {
|
|
|
8556
8861
|
}, []);
|
|
8557
8862
|
if (!mount) return null;
|
|
8558
8863
|
return (0, import_react_dom.createPortal)(
|
|
8559
|
-
/* @__PURE__ */ (0,
|
|
8864
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StoreProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(App, {}) }),
|
|
8560
8865
|
mount
|
|
8561
8866
|
);
|
|
8562
8867
|
}
|
|
8563
8868
|
function ReviewKit(props) {
|
|
8564
|
-
const [active2, setActive] = (0,
|
|
8869
|
+
const [active2, setActive] = (0, import_react22.useState)(false);
|
|
8565
8870
|
const { enabled, token, allowedHosts, devAutoOn } = props;
|
|
8566
8871
|
const hostsKey = allowedHosts?.join("\0") ?? "";
|
|
8567
|
-
(0,
|
|
8872
|
+
(0, import_react22.useEffect)(() => {
|
|
8568
8873
|
if (enabled === false) {
|
|
8569
8874
|
setActive(false);
|
|
8570
8875
|
return;
|
|
@@ -8575,7 +8880,7 @@ function ReviewKit(props) {
|
|
|
8575
8880
|
return () => window.removeEventListener(DEACTIVATE_EVENT, onDeactivate);
|
|
8576
8881
|
}, [enabled, token, devAutoOn, hostsKey]);
|
|
8577
8882
|
if (enabled === false || !active2) return null;
|
|
8578
|
-
return /* @__PURE__ */ (0,
|
|
8883
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ShadowHost, { config: props });
|
|
8579
8884
|
}
|
|
8580
8885
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8581
8886
|
0 && (module.exports = {
|