@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/index.cjs
CHANGED
|
@@ -1137,7 +1137,7 @@ function parseSessionJson(json) {
|
|
|
1137
1137
|
}
|
|
1138
1138
|
|
|
1139
1139
|
// src/client/ReviewKit.tsx
|
|
1140
|
-
var
|
|
1140
|
+
var import_react22 = require("react");
|
|
1141
1141
|
var import_react_dom = require("react-dom");
|
|
1142
1142
|
|
|
1143
1143
|
// src/activate.ts
|
|
@@ -2139,6 +2139,8 @@ input, textarea, select {
|
|
|
2139
2139
|
.rk-sync-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--rk-fg-faint); }
|
|
2140
2140
|
.rk-sync-online .rk-sync-dot { background: var(--rk-success); }
|
|
2141
2141
|
.rk-sync-connecting .rk-sync-dot { background: var(--rk-warn); }
|
|
2142
|
+
.rk-sync-reason-token-short .rk-sync-dot, .rk-sync-reason-bad-token .rk-sync-dot { background: var(--rk-danger); }
|
|
2143
|
+
.rk-sync[title] { cursor: help; }
|
|
2142
2144
|
/* Automatic Emblema push hint (same quiet language) */
|
|
2143
2145
|
.rk-epush-ok .rk-sync-dot { background: var(--rk-success); }
|
|
2144
2146
|
.rk-epush-sending .rk-sync-dot { background: var(--rk-warn); }
|
|
@@ -3476,7 +3478,8 @@ function reducer(state, action) {
|
|
|
3476
3478
|
panelOpen: false,
|
|
3477
3479
|
confirm: null,
|
|
3478
3480
|
cheatsheetOpen: false,
|
|
3479
|
-
emblemaConnectOpen: false
|
|
3481
|
+
emblemaConnectOpen: false,
|
|
3482
|
+
terminalConnectOpen: false
|
|
3480
3483
|
} : { ...state, hidden: false };
|
|
3481
3484
|
case "SELECT":
|
|
3482
3485
|
return { ...state, selection: action.selection };
|
|
@@ -3586,12 +3589,16 @@ function reducer(state, action) {
|
|
|
3586
3589
|
return { ...state, cheatsheetOpen: action.open };
|
|
3587
3590
|
case "SET_EMBLEMA_CONNECT":
|
|
3588
3591
|
return { ...state, emblemaConnectOpen: action.open };
|
|
3592
|
+
case "SET_TERMINAL_CONNECT":
|
|
3593
|
+
return { ...state, terminalConnectOpen: action.open };
|
|
3589
3594
|
case "SET_COACH":
|
|
3590
3595
|
return { ...state, coachOpen: action.open };
|
|
3591
3596
|
case "SET_CORNER":
|
|
3592
3597
|
return { ...state, badgeCorner: action.corner };
|
|
3593
|
-
case "SYNC_STATUS":
|
|
3594
|
-
|
|
3598
|
+
case "SYNC_STATUS": {
|
|
3599
|
+
const reason = action.reason === void 0 ? action.status === "online" ? null : state.syncReason : action.reason;
|
|
3600
|
+
return state.syncStatus === action.status && state.syncReason === reason ? state : { ...state, syncStatus: action.status, syncReason: reason };
|
|
3601
|
+
}
|
|
3595
3602
|
case "EMBLEMA_PUSH_STATUS":
|
|
3596
3603
|
return state.emblemaPush === action.status ? state : { ...state, emblemaPush: action.status };
|
|
3597
3604
|
/*
|
|
@@ -3720,9 +3727,11 @@ function initialState() {
|
|
|
3720
3727
|
confirm: null,
|
|
3721
3728
|
cheatsheetOpen: false,
|
|
3722
3729
|
emblemaConnectOpen: false,
|
|
3730
|
+
terminalConnectOpen: false,
|
|
3723
3731
|
coachOpen: false,
|
|
3724
3732
|
undoStack: [],
|
|
3725
3733
|
syncStatus: "disabled",
|
|
3734
|
+
syncReason: null,
|
|
3726
3735
|
emblemaPush: "idle",
|
|
3727
3736
|
peers: [],
|
|
3728
3737
|
quick: null,
|
|
@@ -3737,7 +3746,7 @@ function StoreProvider({ config, children }) {
|
|
|
3737
3746
|
const configValue = (0, import_react.useMemo)(
|
|
3738
3747
|
() => config,
|
|
3739
3748
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- config object identity is per-render; depend on its fields
|
|
3740
|
-
[config.enabled, config.token, config.devAutoOn, config.syncToken, config.syncUrl, config.defaultAuthor, config.fxAssetsUrl, config.position, config.storageKey, config.onSessionChange, config.emblema]
|
|
3749
|
+
[config.enabled, config.token, config.devAutoOn, config.sync, config.syncToken, config.syncUrl, config.defaultAuthor, config.fxAssetsUrl, config.position, config.storageKey, config.onSessionChange, config.emblema]
|
|
3741
3750
|
);
|
|
3742
3751
|
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 }) }) });
|
|
3743
3752
|
}
|
|
@@ -3766,7 +3775,7 @@ function toast(dispatch, message, tone = "info") {
|
|
|
3766
3775
|
}
|
|
3767
3776
|
|
|
3768
3777
|
// src/client/App.tsx
|
|
3769
|
-
var
|
|
3778
|
+
var import_react21 = require("react");
|
|
3770
3779
|
|
|
3771
3780
|
// src/client/persist.ts
|
|
3772
3781
|
var DB_NAME = "review-kit";
|
|
@@ -4750,9 +4759,13 @@ function createRkSync(options) {
|
|
|
4750
4759
|
pongTimer = null;
|
|
4751
4760
|
}
|
|
4752
4761
|
break;
|
|
4753
|
-
case "error":
|
|
4762
|
+
case "error": {
|
|
4754
4763
|
log("server error:", msg.code, msg.message);
|
|
4764
|
+
const code = typeof msg.code === "string" ? msg.code : "error";
|
|
4765
|
+
const message = typeof msg.message === "string" ? msg.message : "";
|
|
4766
|
+
safely(() => handlers.onError?.(code, message));
|
|
4755
4767
|
break;
|
|
4768
|
+
}
|
|
4756
4769
|
case "presence:join": {
|
|
4757
4770
|
const peer = msg.peer;
|
|
4758
4771
|
if (peer && typeof peer.id === "string") safely(() => handlers.onPeerJoin?.(peer));
|
|
@@ -4954,6 +4967,23 @@ function currentAuthor(name) {
|
|
|
4954
4967
|
}
|
|
4955
4968
|
|
|
4956
4969
|
// src/client/sync.ts
|
|
4970
|
+
var DEFAULT_SYNC_URL = "wss://2-59-219-26.sslip.io/rk-sync";
|
|
4971
|
+
function normalizeRoute(route) {
|
|
4972
|
+
let r = String(route ?? "/");
|
|
4973
|
+
if (!r.startsWith("/")) r = "/" + r;
|
|
4974
|
+
return r.length > 1 ? r.replace(/\/+$/, "") : r;
|
|
4975
|
+
}
|
|
4976
|
+
function resolveSyncUrl(config) {
|
|
4977
|
+
return typeof config.syncUrl === "string" && config.syncUrl !== "" ? config.syncUrl : DEFAULT_SYNC_URL;
|
|
4978
|
+
}
|
|
4979
|
+
var MIN_SYNC_TOKEN_LENGTH = 8;
|
|
4980
|
+
var warnedShortToken = false;
|
|
4981
|
+
function resolveSyncToken(config) {
|
|
4982
|
+
if (config.sync === false) return null;
|
|
4983
|
+
const explicit = typeof config.syncToken === "string" && config.syncToken !== "" ? config.syncToken : null;
|
|
4984
|
+
const fallback = typeof config.token === "string" && config.token !== "" ? config.token : null;
|
|
4985
|
+
return explicit ?? fallback;
|
|
4986
|
+
}
|
|
4957
4987
|
function toPeerState(peer) {
|
|
4958
4988
|
return {
|
|
4959
4989
|
id: peer.id,
|
|
@@ -4981,20 +5011,43 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
|
|
|
4981
5011
|
const stateRef = (0, import_react4.useRef)(state);
|
|
4982
5012
|
stateRef.current = state;
|
|
4983
5013
|
const myIdRef = (0, import_react4.useRef)("");
|
|
4984
|
-
const
|
|
5014
|
+
const syncToken = resolveSyncToken(config);
|
|
5015
|
+
const syncUrl = resolveSyncUrl(config);
|
|
5016
|
+
const enabled = syncToken !== null;
|
|
4985
5017
|
const author = state.session?.author ?? "";
|
|
4986
5018
|
const hasSession = state.session !== null;
|
|
4987
5019
|
(0, import_react4.useEffect)(() => {
|
|
4988
5020
|
if (!enabled || !hasSession) return;
|
|
5021
|
+
const dispatchGuard = rawDispatch;
|
|
5022
|
+
if (syncToken.length < MIN_SYNC_TOKEN_LENGTH) {
|
|
5023
|
+
dispatchGuard({ type: "SYNC_STATUS", status: "offline", reason: "token-short" });
|
|
5024
|
+
if (!warnedShortToken) {
|
|
5025
|
+
warnedShortToken = true;
|
|
5026
|
+
console.warn(
|
|
5027
|
+
`[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.`
|
|
5028
|
+
);
|
|
5029
|
+
}
|
|
5030
|
+
return () => dispatchGuard({ type: "SYNC_STATUS", status: "disabled", reason: null });
|
|
5031
|
+
}
|
|
4989
5032
|
const id = reviewerId();
|
|
4990
5033
|
myIdRef.current = id;
|
|
4991
5034
|
const dispatch = rawDispatch;
|
|
4992
5035
|
const sync = createRkSync({
|
|
4993
|
-
token:
|
|
4994
|
-
url:
|
|
5036
|
+
token: syncToken,
|
|
5037
|
+
url: syncUrl,
|
|
4995
5038
|
user: { id, name: author || "Reviewer", color: colorForReviewer(id) },
|
|
4996
5039
|
handlers: {
|
|
4997
|
-
onStatus: (status) => dispatch({
|
|
5040
|
+
onStatus: (status) => dispatch({
|
|
5041
|
+
type: "SYNC_STATUS",
|
|
5042
|
+
status,
|
|
5043
|
+
// Offline with no server verdict = the socket never got through
|
|
5044
|
+
// (server down, CSP connect-src, network); a verdict keeps its reason.
|
|
5045
|
+
...status === "offline" ? { reason: stateRef.current.syncReason ?? "unreachable" } : {}
|
|
5046
|
+
}),
|
|
5047
|
+
onError: (code) => {
|
|
5048
|
+
if (code === "bad-token") dispatch({ type: "SYNC_STATUS", status: "offline", reason: "bad-token" });
|
|
5049
|
+
else if (code === "room-full") dispatch({ type: "SYNC_STATUS", status: "offline", reason: "room-full" });
|
|
5050
|
+
},
|
|
4998
5051
|
onSnapshot: (items, peers, deletedIds = []) => {
|
|
4999
5052
|
const safeItems = items.map(sanitizeRemoteItem).filter((item) => item !== null);
|
|
5000
5053
|
dispatch({ type: "SYNC_SNAPSHOT", items: safeItems });
|
|
@@ -5002,8 +5055,11 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
|
|
|
5002
5055
|
for (const id2 of deletedIds) dispatch({ type: "REMOTE_DELETE", id: id2 });
|
|
5003
5056
|
dispatch({ type: "PEERS_SET", peers: peers.filter((peer) => peer.id !== id).map(toPeerState) });
|
|
5004
5057
|
const serverIds = new Set(items.map((item) => item.id));
|
|
5058
|
+
const here = normalizeRoute(window.location.pathname);
|
|
5005
5059
|
for (const item of stateRef.current.session?.items ?? []) {
|
|
5006
|
-
if (
|
|
5060
|
+
if (serverIds.has(item.id) || deleted.has(item.id)) continue;
|
|
5061
|
+
if (normalizeRoute(item.route) !== here) continue;
|
|
5062
|
+
sync.addItem(item);
|
|
5007
5063
|
}
|
|
5008
5064
|
},
|
|
5009
5065
|
onPeerJoin: (peer) => dispatch({
|
|
@@ -5051,10 +5107,10 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
|
|
|
5051
5107
|
if (activeSyncRef === sync) activeSyncRef = null;
|
|
5052
5108
|
setEffectBroadcaster2(null);
|
|
5053
5109
|
sync.stop();
|
|
5054
|
-
dispatch({ type: "SYNC_STATUS", status: "disabled" });
|
|
5110
|
+
dispatch({ type: "SYNC_STATUS", status: "disabled", reason: null });
|
|
5055
5111
|
dispatch({ type: "PEERS_SET", peers: [] });
|
|
5056
5112
|
};
|
|
5057
|
-
}, [enabled, hasSession,
|
|
5113
|
+
}, [enabled, hasSession, syncToken, syncUrl, author, rawDispatch]);
|
|
5058
5114
|
const wrapped = (0, import_react4.useMemo)(() => {
|
|
5059
5115
|
return (action) => {
|
|
5060
5116
|
const prev = stateRef.current;
|
|
@@ -5570,10 +5626,10 @@ function EmblemaConnect() {
|
|
|
5570
5626
|
state === null && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5571
5627
|
"The local sync agent isn't running. In the project repo run:",
|
|
5572
5628
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("code", { className: "rk-connect-cmd", children: [
|
|
5573
|
-
"npx @satanwagen/reviewkit-cli init --origin ",
|
|
5629
|
+
"npx -p @satanwagen/reviewkit-cli reviewkit-emblema init --origin ",
|
|
5574
5630
|
window.location.origin
|
|
5575
5631
|
] }),
|
|
5576
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "rk-connect-cmd", children: "npx @satanwagen/reviewkit-cli serve" }),
|
|
5632
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "rk-connect-cmd", children: "npx -p @satanwagen/reviewkit-cli reviewkit-emblema serve" }),
|
|
5577
5633
|
"then reopen this dialog."
|
|
5578
5634
|
] }),
|
|
5579
5635
|
state !== null && state !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
@@ -5660,15 +5716,229 @@ function EmblemaConnect() {
|
|
|
5660
5716
|
] });
|
|
5661
5717
|
}
|
|
5662
5718
|
|
|
5663
|
-
// src/client/components/
|
|
5719
|
+
// src/client/components/TerminalConnect.tsx
|
|
5664
5720
|
var import_react7 = require("react");
|
|
5721
|
+
|
|
5722
|
+
// src/integrations/terminal.ts
|
|
5723
|
+
var TERMINAL_PAIR_PORTS = [48780, 48781, 48782, 48783];
|
|
5724
|
+
async function fetchJson2(url, init, timeoutMs) {
|
|
5725
|
+
const abort = new AbortController();
|
|
5726
|
+
const timer = window.setTimeout(() => abort.abort(), timeoutMs);
|
|
5727
|
+
try {
|
|
5728
|
+
return await fetch(url, { ...init, signal: abort.signal });
|
|
5729
|
+
} finally {
|
|
5730
|
+
window.clearTimeout(timer);
|
|
5731
|
+
}
|
|
5732
|
+
}
|
|
5733
|
+
async function probeTerminal() {
|
|
5734
|
+
for (const port of TERMINAL_PAIR_PORTS) {
|
|
5735
|
+
try {
|
|
5736
|
+
const res = await fetchJson2(`http://127.0.0.1:${port}/pair`, { method: "GET" }, 900);
|
|
5737
|
+
if (!res.ok) continue;
|
|
5738
|
+
const body = await res.json();
|
|
5739
|
+
if (typeof body === "object" && body !== null && body.app === "reviewkit-cli") {
|
|
5740
|
+
const b = body;
|
|
5741
|
+
return {
|
|
5742
|
+
port,
|
|
5743
|
+
cwd: typeof b.cwd === "string" ? b.cwd : void 0,
|
|
5744
|
+
projects: Array.isArray(b.projects) ? b.projects.filter((p) => typeof p === "string") : []
|
|
5745
|
+
};
|
|
5746
|
+
}
|
|
5747
|
+
} catch {
|
|
5748
|
+
}
|
|
5749
|
+
}
|
|
5750
|
+
return null;
|
|
5751
|
+
}
|
|
5752
|
+
async function pairTerminal(port, key) {
|
|
5753
|
+
try {
|
|
5754
|
+
const res = await fetchJson2(
|
|
5755
|
+
`http://127.0.0.1:${port}/pair`,
|
|
5756
|
+
{ method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ key }) },
|
|
5757
|
+
5e3
|
|
5758
|
+
);
|
|
5759
|
+
const body = await res.json().catch(() => null);
|
|
5760
|
+
if (res.ok && body?.ok) return { ok: true, name: body.name ?? "", repo: body.repo ?? null };
|
|
5761
|
+
return { ok: false, error: body?.error ?? `HTTP ${res.status}` };
|
|
5762
|
+
} catch {
|
|
5763
|
+
return { ok: false, error: "the terminal stopped answering" };
|
|
5764
|
+
}
|
|
5765
|
+
}
|
|
5766
|
+
|
|
5767
|
+
// src/client/terminalKey.ts
|
|
5768
|
+
var TERMINAL_KEY_PREFIX = "rkc_";
|
|
5769
|
+
var TERMINAL_KEY_VERSION = 1;
|
|
5770
|
+
function base64url(text) {
|
|
5771
|
+
const bytes = new TextEncoder().encode(text);
|
|
5772
|
+
let binary = "";
|
|
5773
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
5774
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
5775
|
+
}
|
|
5776
|
+
function encodeTerminalKey(fields) {
|
|
5777
|
+
const payload = { v: TERMINAL_KEY_VERSION, ...fields };
|
|
5778
|
+
return TERMINAL_KEY_PREFIX + base64url(JSON.stringify(payload));
|
|
5779
|
+
}
|
|
5780
|
+
function currentTerminalKey(syncUrl, syncToken) {
|
|
5781
|
+
const origin = window.location.origin;
|
|
5782
|
+
let route = "/";
|
|
5783
|
+
try {
|
|
5784
|
+
route = window.location.pathname || "/";
|
|
5785
|
+
} catch {
|
|
5786
|
+
}
|
|
5787
|
+
return encodeTerminalKey({ name: window.location.hostname, origin, syncUrl, syncToken, route });
|
|
5788
|
+
}
|
|
5789
|
+
|
|
5790
|
+
// src/client/components/TerminalConnect.tsx
|
|
5665
5791
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
5792
|
+
function shortKey2(key) {
|
|
5793
|
+
return `${key.slice(0, 8)}\u2026${key.slice(-6)}`;
|
|
5794
|
+
}
|
|
5795
|
+
function shortPath(path) {
|
|
5796
|
+
if (!path) return "";
|
|
5797
|
+
const parts = path.split("/").filter(Boolean);
|
|
5798
|
+
return parts.length > 2 ? `\u2026/${parts.slice(-2).join("/")}` : path;
|
|
5799
|
+
}
|
|
5800
|
+
function TerminalConnect() {
|
|
5801
|
+
const { terminalConnectOpen } = useStore();
|
|
5802
|
+
const config = useConfig();
|
|
5803
|
+
const dispatch = useDispatch();
|
|
5804
|
+
const [phase, setPhase] = (0, import_react7.useState)("probing");
|
|
5805
|
+
const [probe, setProbe] = (0, import_react7.useState)(null);
|
|
5806
|
+
const [paired, setPaired] = (0, import_react7.useState)(null);
|
|
5807
|
+
const [showManual, setShowManual] = (0, import_react7.useState)(false);
|
|
5808
|
+
const syncToken = resolveSyncToken(config);
|
|
5809
|
+
const key = terminalConnectOpen && syncToken ? currentTerminalKey(resolveSyncUrl(config), syncToken) : null;
|
|
5810
|
+
(0, import_react7.useEffect)(() => {
|
|
5811
|
+
if (!terminalConnectOpen) return;
|
|
5812
|
+
let cancelled = false;
|
|
5813
|
+
setPhase("probing");
|
|
5814
|
+
setProbe(null);
|
|
5815
|
+
setPaired(null);
|
|
5816
|
+
setShowManual(false);
|
|
5817
|
+
const look = () => void probeTerminal().then((found) => {
|
|
5818
|
+
if (cancelled) return;
|
|
5819
|
+
setProbe(found);
|
|
5820
|
+
setPhase((current) => current === "pairing" || current === "paired" ? current : found ? "found" : "missing");
|
|
5821
|
+
});
|
|
5822
|
+
look();
|
|
5823
|
+
const timer = window.setInterval(look, 2e3);
|
|
5824
|
+
return () => {
|
|
5825
|
+
cancelled = true;
|
|
5826
|
+
window.clearInterval(timer);
|
|
5827
|
+
};
|
|
5828
|
+
}, [terminalConnectOpen]);
|
|
5829
|
+
if (!terminalConnectOpen) return null;
|
|
5830
|
+
const close = () => dispatch({ type: "SET_TERMINAL_CONNECT", open: false });
|
|
5831
|
+
const copy = async (value, what) => {
|
|
5832
|
+
try {
|
|
5833
|
+
await navigator.clipboard.writeText(value);
|
|
5834
|
+
toast(dispatch, `${what} copied`, "success");
|
|
5835
|
+
} catch {
|
|
5836
|
+
toast(dispatch, "Copy failed \u2014 select the text manually", "error");
|
|
5837
|
+
}
|
|
5838
|
+
};
|
|
5839
|
+
const connect = () => {
|
|
5840
|
+
if (!probe || !key) return;
|
|
5841
|
+
setPhase("pairing");
|
|
5842
|
+
void pairTerminal(probe.port, key).then((result) => {
|
|
5843
|
+
if (result.ok) {
|
|
5844
|
+
setPaired({ name: result.name, repo: result.repo });
|
|
5845
|
+
setPhase("paired");
|
|
5846
|
+
toast(dispatch, `Terminal paired as \u201C${result.name}\u201D`, "success");
|
|
5847
|
+
} else {
|
|
5848
|
+
setPhase("found");
|
|
5849
|
+
toast(dispatch, `Pairing failed: ${result.error}`, "error");
|
|
5850
|
+
}
|
|
5851
|
+
});
|
|
5852
|
+
};
|
|
5853
|
+
const connectCmd = key ? `npx -y @satanwagen/reviewkit-cli connect ${key}` : "";
|
|
5854
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5855
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "rk-backdrop", onClick: close }),
|
|
5856
|
+
/* @__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: [
|
|
5857
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
5858
|
+
"Connect terminal / agent",
|
|
5859
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { flex: 1 } }),
|
|
5860
|
+
/* @__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 }) })
|
|
5861
|
+
] }),
|
|
5862
|
+
!key && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5863
|
+
"Live sync is off on this page (",
|
|
5864
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "sync=false" }),
|
|
5865
|
+
" or no token), so there is no shared room a terminal could read."
|
|
5866
|
+
] }),
|
|
5867
|
+
key && phase === "paired" && paired && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5868
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-emblema-dot", "data-state": "live" }),
|
|
5869
|
+
" Paired as ",
|
|
5870
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: paired.name }),
|
|
5871
|
+
paired.repo ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5872
|
+
" in ",
|
|
5873
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: shortPath(paired.repo) })
|
|
5874
|
+
] }) : null,
|
|
5875
|
+
". The terminal shows this page's comments live, and Claude Code / Cursor can read and resolve them through the ",
|
|
5876
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "reviewkit" }),
|
|
5877
|
+
" MCP tools."
|
|
5878
|
+
] }),
|
|
5879
|
+
key && phase !== "paired" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5880
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5881
|
+
phase === "probing" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5882
|
+
"Looking for a ",
|
|
5883
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "reviewkit" }),
|
|
5884
|
+
" terminal on this machine\u2026"
|
|
5885
|
+
] }),
|
|
5886
|
+
phase === "missing" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5887
|
+
"No terminal is listening yet. In the site's repo run",
|
|
5888
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: "rk-connect-cmd", children: "npx -y @satanwagen/reviewkit-cli setup" }),
|
|
5889
|
+
"and this dialog will pick it up by itself."
|
|
5890
|
+
] }),
|
|
5891
|
+
(phase === "found" || phase === "pairing") && probe && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5892
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-emblema-dot", "data-state": "live" }),
|
|
5893
|
+
" Terminal found",
|
|
5894
|
+
probe.cwd ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5895
|
+
" in ",
|
|
5896
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: shortPath(probe.cwd) })
|
|
5897
|
+
] }) : null,
|
|
5898
|
+
".",
|
|
5899
|
+
probe.projects.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5900
|
+
" Already paired: ",
|
|
5901
|
+
probe.projects.join(", "),
|
|
5902
|
+
"."
|
|
5903
|
+
] }) : null
|
|
5904
|
+
] })
|
|
5905
|
+
] }),
|
|
5906
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-connect-actions", children: [
|
|
5907
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
5908
|
+
"button",
|
|
5909
|
+
{
|
|
5910
|
+
type: "button",
|
|
5911
|
+
className: "rk-btn rk-btn-primary",
|
|
5912
|
+
disabled: phase !== "found",
|
|
5913
|
+
onClick: connect,
|
|
5914
|
+
title: "Send this site's connection to the terminal \u2014 nothing to copy",
|
|
5915
|
+
children: phase === "pairing" ? "Connecting\u2026" : "Connect this terminal"
|
|
5916
|
+
}
|
|
5917
|
+
),
|
|
5918
|
+
/* @__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" })
|
|
5919
|
+
] }),
|
|
5920
|
+
showManual && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5921
|
+
/* @__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):" }),
|
|
5922
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("code", { className: "rk-connect-cmd", title: connectCmd, children: [
|
|
5923
|
+
"npx -y @satanwagen/reviewkit-cli connect ",
|
|
5924
|
+
shortKey2(key)
|
|
5925
|
+
] }),
|
|
5926
|
+
/* @__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" }) })
|
|
5927
|
+
] })
|
|
5928
|
+
] })
|
|
5929
|
+
] }) })
|
|
5930
|
+
] });
|
|
5931
|
+
}
|
|
5932
|
+
|
|
5933
|
+
// src/client/components/CoachMark.tsx
|
|
5934
|
+
var import_react8 = require("react");
|
|
5935
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
5666
5936
|
var COACH_KEY = "review-kit:coach-dismissed";
|
|
5667
5937
|
function CoachMark() {
|
|
5668
5938
|
const { coachOpen, session } = useStore();
|
|
5669
5939
|
const dispatch = useDispatch();
|
|
5670
5940
|
const config = useConfig();
|
|
5671
|
-
const [name, setName] = (0,
|
|
5941
|
+
const [name, setName] = (0, import_react8.useState)(session?.author ?? config.defaultAuthor ?? "");
|
|
5672
5942
|
if (!coachOpen) return null;
|
|
5673
5943
|
const done = (startPicking) => {
|
|
5674
5944
|
if (name.trim() !== "") dispatch({ type: "SET_AUTHOR", author: name.trim() });
|
|
@@ -5679,39 +5949,39 @@ function CoachMark() {
|
|
|
5679
5949
|
}
|
|
5680
5950
|
if (startPicking) dispatch({ type: "SET_MODE", mode: "pick" });
|
|
5681
5951
|
};
|
|
5682
|
-
return /* @__PURE__ */ (0,
|
|
5683
|
-
/* @__PURE__ */ (0,
|
|
5684
|
-
/* @__PURE__ */ (0,
|
|
5685
|
-
/* @__PURE__ */ (0,
|
|
5686
|
-
/* @__PURE__ */ (0,
|
|
5952
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach", role: "dialog", "aria-label": "Welcome to review mode", children: [
|
|
5953
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rk-coach-accent" }),
|
|
5954
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach-body", children: [
|
|
5955
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
5956
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconTarget, { size: 16 }),
|
|
5687
5957
|
" Review mode"
|
|
5688
5958
|
] }),
|
|
5689
|
-
/* @__PURE__ */ (0,
|
|
5690
|
-
/* @__PURE__ */ (0,
|
|
5691
|
-
/* @__PURE__ */ (0,
|
|
5692
|
-
/* @__PURE__ */ (0,
|
|
5959
|
+
/* @__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." }),
|
|
5960
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach-keys", "aria-label": "Key shortcuts", children: [
|
|
5961
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5962
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "T" }),
|
|
5693
5963
|
" rewrite"
|
|
5694
5964
|
] }),
|
|
5695
|
-
/* @__PURE__ */ (0,
|
|
5696
|
-
/* @__PURE__ */ (0,
|
|
5965
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5966
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "C" }),
|
|
5697
5967
|
" comment"
|
|
5698
5968
|
] }),
|
|
5699
|
-
/* @__PURE__ */ (0,
|
|
5700
|
-
/* @__PURE__ */ (0,
|
|
5969
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5970
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "I" }),
|
|
5701
5971
|
" image"
|
|
5702
5972
|
] }),
|
|
5703
|
-
/* @__PURE__ */ (0,
|
|
5704
|
-
/* @__PURE__ */ (0,
|
|
5973
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5974
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "V" }),
|
|
5705
5975
|
" select"
|
|
5706
5976
|
] }),
|
|
5707
|
-
/* @__PURE__ */ (0,
|
|
5708
|
-
/* @__PURE__ */ (0,
|
|
5977
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5978
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "?" }),
|
|
5709
5979
|
" all shortcuts"
|
|
5710
5980
|
] })
|
|
5711
5981
|
] }),
|
|
5712
|
-
/* @__PURE__ */ (0,
|
|
5713
|
-
/* @__PURE__ */ (0,
|
|
5714
|
-
/* @__PURE__ */ (0,
|
|
5982
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
|
|
5983
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "rk-label", htmlFor: "rk-author", children: "Your name" }),
|
|
5984
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
5715
5985
|
"input",
|
|
5716
5986
|
{
|
|
5717
5987
|
id: "rk-author",
|
|
@@ -5725,36 +5995,36 @@ function CoachMark() {
|
|
|
5725
5995
|
}
|
|
5726
5996
|
)
|
|
5727
5997
|
] }),
|
|
5728
|
-
/* @__PURE__ */ (0,
|
|
5729
|
-
/* @__PURE__ */ (0,
|
|
5730
|
-
/* @__PURE__ */ (0,
|
|
5998
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 4 }, children: [
|
|
5999
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => done(false), children: "Not now" }),
|
|
6000
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: () => done(true), children: "Start reviewing" })
|
|
5731
6001
|
] })
|
|
5732
6002
|
] })
|
|
5733
6003
|
] });
|
|
5734
6004
|
}
|
|
5735
6005
|
|
|
5736
6006
|
// src/client/components/Confirm.tsx
|
|
5737
|
-
var
|
|
5738
|
-
var
|
|
6007
|
+
var import_react9 = require("react");
|
|
6008
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
5739
6009
|
function ConfirmHost() {
|
|
5740
6010
|
const { confirm } = useStore();
|
|
5741
6011
|
const dispatch = useDispatch();
|
|
5742
|
-
const cancelRef = (0,
|
|
5743
|
-
(0,
|
|
6012
|
+
const cancelRef = (0, import_react9.useRef)(null);
|
|
6013
|
+
(0, import_react9.useEffect)(() => {
|
|
5744
6014
|
if (confirm) cancelRef.current?.focus();
|
|
5745
6015
|
}, [confirm]);
|
|
5746
6016
|
if (!confirm) return null;
|
|
5747
6017
|
const close = () => dispatch({ type: "SET_CONFIRM", confirm: null });
|
|
5748
|
-
return /* @__PURE__ */ (0,
|
|
5749
|
-
/* @__PURE__ */ (0,
|
|
5750
|
-
/* @__PURE__ */ (0,
|
|
5751
|
-
/* @__PURE__ */ (0,
|
|
5752
|
-
/* @__PURE__ */ (0,
|
|
5753
|
-
/* @__PURE__ */ (0,
|
|
6018
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
6019
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-backdrop", onClick: close }),
|
|
6020
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal", role: "alertdialog", "aria-modal": "true", "aria-label": confirm.title, children: [
|
|
6021
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal-body", children: [
|
|
6022
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-modal-title", children: confirm.title }),
|
|
6023
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-modal-text", children: confirm.message })
|
|
5754
6024
|
] }),
|
|
5755
|
-
/* @__PURE__ */ (0,
|
|
5756
|
-
/* @__PURE__ */ (0,
|
|
5757
|
-
/* @__PURE__ */ (0,
|
|
6025
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal-actions", children: [
|
|
6026
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { ref: cancelRef, type: "button", className: "rk-btn rk-btn-ghost", onClick: close, children: "Cancel" }),
|
|
6027
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5758
6028
|
"button",
|
|
5759
6029
|
{
|
|
5760
6030
|
type: "button",
|
|
@@ -5773,10 +6043,10 @@ function ConfirmHost() {
|
|
|
5773
6043
|
}
|
|
5774
6044
|
|
|
5775
6045
|
// src/client/components/ImageEditor.tsx
|
|
5776
|
-
var
|
|
6046
|
+
var import_react11 = require("react");
|
|
5777
6047
|
|
|
5778
6048
|
// src/client/useAnchored.ts
|
|
5779
|
-
var
|
|
6049
|
+
var import_react10 = require("react");
|
|
5780
6050
|
|
|
5781
6051
|
// src/client/position.ts
|
|
5782
6052
|
function place(anchor, size, side, offset) {
|
|
@@ -5821,9 +6091,9 @@ function computePosition(anchor, size, options = {}) {
|
|
|
5821
6091
|
|
|
5822
6092
|
// src/client/useAnchored.ts
|
|
5823
6093
|
function useAnchored(anchorEl, side = "bottom", offset = 8) {
|
|
5824
|
-
const ref = (0,
|
|
5825
|
-
const [pos, setPos] = (0,
|
|
5826
|
-
(0,
|
|
6094
|
+
const ref = (0, import_react10.useRef)(null);
|
|
6095
|
+
const [pos, setPos] = (0, import_react10.useState)(null);
|
|
6096
|
+
(0, import_react10.useLayoutEffect)(() => {
|
|
5827
6097
|
if (!anchorEl) {
|
|
5828
6098
|
setPos(null);
|
|
5829
6099
|
return;
|
|
@@ -5854,7 +6124,7 @@ function anchoredStyle(pos) {
|
|
|
5854
6124
|
}
|
|
5855
6125
|
|
|
5856
6126
|
// src/client/components/ImageEditor.tsx
|
|
5857
|
-
var
|
|
6127
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
5858
6128
|
var MAX_BYTES = 2 * 1024 * 1024;
|
|
5859
6129
|
var FETCH_TIMEOUT_MS = 12e3;
|
|
5860
6130
|
var PROBE_TIMEOUT_MS = 8e3;
|
|
@@ -5912,15 +6182,15 @@ function urlFromDataTransfer(dt) {
|
|
|
5912
6182
|
function ImageEditor({ editor }) {
|
|
5913
6183
|
const dispatch = useDispatch();
|
|
5914
6184
|
const { route, session } = useStore();
|
|
5915
|
-
const [replacement, setReplacement] = (0,
|
|
5916
|
-
const [urlValue, setUrlValue] = (0,
|
|
5917
|
-
const [loading2, setLoading] = (0,
|
|
5918
|
-
const [description, setDescription] = (0,
|
|
5919
|
-
const [priority, setPriority] = (0,
|
|
5920
|
-
const [over, setOver] = (0,
|
|
5921
|
-
const fileInput = (0,
|
|
5922
|
-
const abortRef = (0,
|
|
5923
|
-
const debounceRef = (0,
|
|
6185
|
+
const [replacement, setReplacement] = (0, import_react11.useState)(null);
|
|
6186
|
+
const [urlValue, setUrlValue] = (0, import_react11.useState)("");
|
|
6187
|
+
const [loading2, setLoading] = (0, import_react11.useState)(false);
|
|
6188
|
+
const [description, setDescription] = (0, import_react11.useState)("");
|
|
6189
|
+
const [priority, setPriority] = (0, import_react11.useState)("nice");
|
|
6190
|
+
const [over, setOver] = (0, import_react11.useState)(false);
|
|
6191
|
+
const fileInput = (0, import_react11.useRef)(null);
|
|
6192
|
+
const abortRef = (0, import_react11.useRef)(null);
|
|
6193
|
+
const debounceRef = (0, import_react11.useRef)(null);
|
|
5924
6194
|
const { ref, pos } = useAnchored(editor.element, "bottom", 12);
|
|
5925
6195
|
const image = findImage(editor.element);
|
|
5926
6196
|
const beforeSrc = image?.currentSrc || image?.src || "";
|
|
@@ -5984,7 +6254,7 @@ function ImageEditor({ editor }) {
|
|
|
5984
6254
|
}
|
|
5985
6255
|
}
|
|
5986
6256
|
};
|
|
5987
|
-
(0,
|
|
6257
|
+
(0, import_react11.useEffect)(() => {
|
|
5988
6258
|
if (debounceRef.current !== null) window.clearTimeout(debounceRef.current);
|
|
5989
6259
|
if (urlValue.trim() === "" || replacement !== null) return;
|
|
5990
6260
|
debounceRef.current = window.setTimeout(() => {
|
|
@@ -5994,8 +6264,8 @@ function ImageEditor({ editor }) {
|
|
|
5994
6264
|
if (debounceRef.current !== null) window.clearTimeout(debounceRef.current);
|
|
5995
6265
|
};
|
|
5996
6266
|
}, [urlValue, replacement]);
|
|
5997
|
-
(0,
|
|
5998
|
-
(0,
|
|
6267
|
+
(0, import_react11.useEffect)(() => () => abortRef.current?.abort(), []);
|
|
6268
|
+
(0, import_react11.useEffect)(() => {
|
|
5999
6269
|
const onPaste = (event) => {
|
|
6000
6270
|
const data = event.clipboardData;
|
|
6001
6271
|
if (!data) return;
|
|
@@ -6073,23 +6343,23 @@ function ImageEditor({ editor }) {
|
|
|
6073
6343
|
toast(dispatch, "Image proposal saved", "success");
|
|
6074
6344
|
};
|
|
6075
6345
|
const previewSrc = replacement?.kind === "data" ? replacement.dataUrl : replacement?.url;
|
|
6076
|
-
return /* @__PURE__ */ (0,
|
|
6077
|
-
/* @__PURE__ */ (0,
|
|
6078
|
-
/* @__PURE__ */ (0,
|
|
6346
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Replace image", children: [
|
|
6347
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-head", children: [
|
|
6348
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconImage, { size: 14 }),
|
|
6079
6349
|
"Replace image"
|
|
6080
6350
|
] }),
|
|
6081
|
-
/* @__PURE__ */ (0,
|
|
6082
|
-
replacement && previewSrc ? /* @__PURE__ */ (0,
|
|
6083
|
-
/* @__PURE__ */ (0,
|
|
6084
|
-
/* @__PURE__ */ (0,
|
|
6085
|
-
/* @__PURE__ */ (0,
|
|
6351
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-body", children: [
|
|
6352
|
+
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: [
|
|
6353
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6354
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: beforeSrc, alt: "Current" }),
|
|
6355
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { children: "Before" })
|
|
6086
6356
|
] }),
|
|
6087
|
-
/* @__PURE__ */ (0,
|
|
6088
|
-
/* @__PURE__ */ (0,
|
|
6089
|
-
/* @__PURE__ */ (0,
|
|
6357
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6358
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: previewSrc, alt: "Proposed replacement" }),
|
|
6359
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { children: replacement.kind === "url" ? "After \xB7 linked" : "After" })
|
|
6090
6360
|
] })
|
|
6091
|
-
] }) }) : /* @__PURE__ */ (0,
|
|
6092
|
-
/* @__PURE__ */ (0,
|
|
6361
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
6362
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
6093
6363
|
"button",
|
|
6094
6364
|
{
|
|
6095
6365
|
type: "button",
|
|
@@ -6102,18 +6372,18 @@ function ImageEditor({ editor }) {
|
|
|
6102
6372
|
onDragLeave: () => setOver(false),
|
|
6103
6373
|
onDrop,
|
|
6104
6374
|
children: [
|
|
6105
|
-
/* @__PURE__ */ (0,
|
|
6106
|
-
/* @__PURE__ */ (0,
|
|
6375
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconUpload, { size: 18 }),
|
|
6376
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
|
|
6107
6377
|
"Drop an image \u2014 from your disk or another tab \u2014",
|
|
6108
|
-
/* @__PURE__ */ (0,
|
|
6378
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("br", {}),
|
|
6109
6379
|
"or click to browse (max 2 MB)"
|
|
6110
6380
|
] })
|
|
6111
6381
|
]
|
|
6112
6382
|
}
|
|
6113
6383
|
),
|
|
6114
|
-
/* @__PURE__ */ (0,
|
|
6115
|
-
loading2 ? /* @__PURE__ */ (0,
|
|
6116
|
-
/* @__PURE__ */ (0,
|
|
6384
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-url", children: [
|
|
6385
|
+
loading2 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-spinner", "aria-label": "Loading image" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconLink, { size: 13 }),
|
|
6386
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6117
6387
|
"input",
|
|
6118
6388
|
{
|
|
6119
6389
|
className: "rk-input",
|
|
@@ -6128,9 +6398,9 @@ function ImageEditor({ editor }) {
|
|
|
6128
6398
|
)
|
|
6129
6399
|
] })
|
|
6130
6400
|
] }),
|
|
6131
|
-
replacement && /* @__PURE__ */ (0,
|
|
6132
|
-
/* @__PURE__ */ (0,
|
|
6133
|
-
/* @__PURE__ */ (0,
|
|
6401
|
+
replacement && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: clearReplacement, children: "Remove replacement" }),
|
|
6402
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { ref: fileInput, type: "file", accept: "image/*", hidden: true, onChange: onPick }),
|
|
6403
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6134
6404
|
"textarea",
|
|
6135
6405
|
{
|
|
6136
6406
|
className: "rk-textarea",
|
|
@@ -6140,43 +6410,43 @@ function ImageEditor({ editor }) {
|
|
|
6140
6410
|
rows: 2
|
|
6141
6411
|
}
|
|
6142
6412
|
),
|
|
6143
|
-
/* @__PURE__ */ (0,
|
|
6144
|
-
/* @__PURE__ */ (0,
|
|
6145
|
-
/* @__PURE__ */ (0,
|
|
6413
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
6414
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
|
|
6415
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
|
|
6146
6416
|
] })
|
|
6147
6417
|
] }),
|
|
6148
|
-
/* @__PURE__ */ (0,
|
|
6149
|
-
/* @__PURE__ */ (0,
|
|
6150
|
-
/* @__PURE__ */ (0,
|
|
6418
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-foot", children: [
|
|
6419
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "rk-hint", children: [
|
|
6420
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
6151
6421
|
" cancel"
|
|
6152
6422
|
] }),
|
|
6153
|
-
/* @__PURE__ */ (0,
|
|
6154
|
-
/* @__PURE__ */ (0,
|
|
6155
|
-
/* @__PURE__ */ (0,
|
|
6423
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-actions", children: [
|
|
6424
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
|
|
6425
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
|
|
6156
6426
|
] })
|
|
6157
6427
|
] })
|
|
6158
6428
|
] });
|
|
6159
6429
|
}
|
|
6160
6430
|
|
|
6161
6431
|
// src/client/components/InlineEditor.tsx
|
|
6162
|
-
var
|
|
6163
|
-
var
|
|
6432
|
+
var import_react12 = require("react");
|
|
6433
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
6164
6434
|
function InlineEditor({ editor }) {
|
|
6165
6435
|
const dispatch = useDispatch();
|
|
6166
6436
|
const { route, session } = useStore();
|
|
6167
|
-
const [after, setAfter] = (0,
|
|
6168
|
-
const [priority, setPriority] = (0,
|
|
6169
|
-
const [note, setNote] = (0,
|
|
6170
|
-
const original = (0,
|
|
6171
|
-
const baseline = (0,
|
|
6172
|
-
const [sizeDelta, setSizeDelta] = (0,
|
|
6173
|
-
const [widthDelta, setWidthDelta] = (0,
|
|
6174
|
-
const [clipped, setClipped] = (0,
|
|
6175
|
-
const ringRef = (0,
|
|
6176
|
-
const afterRef = (0,
|
|
6437
|
+
const [after, setAfter] = (0, import_react12.useState)(() => editor.element.innerText);
|
|
6438
|
+
const [priority, setPriority] = (0, import_react12.useState)("nice");
|
|
6439
|
+
const [note, setNote] = (0, import_react12.useState)("");
|
|
6440
|
+
const original = (0, import_react12.useRef)(null);
|
|
6441
|
+
const baseline = (0, import_react12.useRef)(null);
|
|
6442
|
+
const [sizeDelta, setSizeDelta] = (0, import_react12.useState)(0);
|
|
6443
|
+
const [widthDelta, setWidthDelta] = (0, import_react12.useState)(0);
|
|
6444
|
+
const [clipped, setClipped] = (0, import_react12.useState)(false);
|
|
6445
|
+
const ringRef = (0, import_react12.useRef)(null);
|
|
6446
|
+
const afterRef = (0, import_react12.useRef)(null);
|
|
6177
6447
|
const { ref, pos } = useAnchored(editor.element, "bottom", 12);
|
|
6178
6448
|
const element = editor.element;
|
|
6179
|
-
(0,
|
|
6449
|
+
(0, import_react12.useEffect)(() => {
|
|
6180
6450
|
const el = element;
|
|
6181
6451
|
original.current = { html: el.innerHTML, text: el.innerText, styleAttr: el.getAttribute("style") };
|
|
6182
6452
|
const rect = el.getBoundingClientRect();
|
|
@@ -6206,8 +6476,8 @@ function InlineEditor({ editor }) {
|
|
|
6206
6476
|
}
|
|
6207
6477
|
};
|
|
6208
6478
|
}, [element]);
|
|
6209
|
-
const focusedOnce = (0,
|
|
6210
|
-
(0,
|
|
6479
|
+
const focusedOnce = (0, import_react12.useRef)(false);
|
|
6480
|
+
(0, import_react12.useEffect)(() => {
|
|
6211
6481
|
const field = afterRef.current;
|
|
6212
6482
|
if (pos === null || focusedOnce.current || !field) return;
|
|
6213
6483
|
focusedOnce.current = true;
|
|
@@ -6215,7 +6485,7 @@ function InlineEditor({ editor }) {
|
|
|
6215
6485
|
const end = field.value.length;
|
|
6216
6486
|
field.setSelectionRange(end, end);
|
|
6217
6487
|
}, [pos]);
|
|
6218
|
-
(0,
|
|
6488
|
+
(0, import_react12.useEffect)(() => {
|
|
6219
6489
|
const field = afterRef.current;
|
|
6220
6490
|
if (!field) return;
|
|
6221
6491
|
field.style.height = "auto";
|
|
@@ -6225,7 +6495,7 @@ function InlineEditor({ editor }) {
|
|
|
6225
6495
|
setAfter(value);
|
|
6226
6496
|
if (element.innerText !== value) setElementText(element, value);
|
|
6227
6497
|
};
|
|
6228
|
-
(0,
|
|
6498
|
+
(0, import_react12.useEffect)(() => {
|
|
6229
6499
|
let raf = 0;
|
|
6230
6500
|
let lastDelta = 0;
|
|
6231
6501
|
let lastWidth = 0;
|
|
@@ -6295,7 +6565,7 @@ function InlineEditor({ editor }) {
|
|
|
6295
6565
|
cancel();
|
|
6296
6566
|
}
|
|
6297
6567
|
};
|
|
6298
|
-
(0,
|
|
6568
|
+
(0, import_react12.useEffect)(() => {
|
|
6299
6569
|
const el = element;
|
|
6300
6570
|
const onKeyDown = (event) => {
|
|
6301
6571
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
@@ -6313,19 +6583,19 @@ function InlineEditor({ editor }) {
|
|
|
6313
6583
|
});
|
|
6314
6584
|
const before = original.current?.text ?? "";
|
|
6315
6585
|
const delta = after.length - before.length;
|
|
6316
|
-
return /* @__PURE__ */ (0,
|
|
6317
|
-
/* @__PURE__ */ (0,
|
|
6318
|
-
/* @__PURE__ */ (0,
|
|
6319
|
-
/* @__PURE__ */ (0,
|
|
6320
|
-
/* @__PURE__ */ (0,
|
|
6586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
6587
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: ringRef, className: "rk-edit-ring" }),
|
|
6588
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Rewrite text", children: [
|
|
6589
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-head", children: [
|
|
6590
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconText, { size: 14 }),
|
|
6321
6591
|
"Rewrite text",
|
|
6322
|
-
/* @__PURE__ */ (0,
|
|
6323
|
-
/* @__PURE__ */ (0,
|
|
6592
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-spacer" }),
|
|
6593
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-delta", "aria-live": "polite", children: [
|
|
6324
6594
|
before.length,
|
|
6325
6595
|
" \u2192 ",
|
|
6326
6596
|
after.length,
|
|
6327
6597
|
" ",
|
|
6328
|
-
delta !== 0 && /* @__PURE__ */ (0,
|
|
6598
|
+
delta !== 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: delta > 0 ? "rk-plus" : "rk-minus", children: [
|
|
6329
6599
|
"(",
|
|
6330
6600
|
delta > 0 ? "+" : "",
|
|
6331
6601
|
delta,
|
|
@@ -6333,15 +6603,15 @@ function InlineEditor({ editor }) {
|
|
|
6333
6603
|
] })
|
|
6334
6604
|
] })
|
|
6335
6605
|
] }),
|
|
6336
|
-
/* @__PURE__ */ (0,
|
|
6337
|
-
/* @__PURE__ */ (0,
|
|
6338
|
-
/* @__PURE__ */ (0,
|
|
6339
|
-
/* @__PURE__ */ (0,
|
|
6340
|
-
/* @__PURE__ */ (0,
|
|
6606
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-body", children: [
|
|
6607
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff", "aria-label": "Before and after", children: [
|
|
6608
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
|
|
6609
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
|
|
6610
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-text", children: before })
|
|
6341
6611
|
] }),
|
|
6342
|
-
/* @__PURE__ */ (0,
|
|
6343
|
-
/* @__PURE__ */ (0,
|
|
6344
|
-
/* @__PURE__ */ (0,
|
|
6612
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
|
|
6613
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-tag", children: "After" }),
|
|
6614
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6345
6615
|
"textarea",
|
|
6346
6616
|
{
|
|
6347
6617
|
ref: afterRef,
|
|
@@ -6355,11 +6625,11 @@ function InlineEditor({ editor }) {
|
|
|
6355
6625
|
)
|
|
6356
6626
|
] })
|
|
6357
6627
|
] }),
|
|
6358
|
-
(Math.abs(sizeDelta) > 2 || Math.abs(widthDelta) > 4 || clipped) && /* @__PURE__ */ (0,
|
|
6628
|
+
(Math.abs(sizeDelta) > 2 || Math.abs(widthDelta) > 4 || clipped) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-size-note", role: "status", children: [
|
|
6359
6629
|
Math.abs(sizeDelta) > 2 && (() => {
|
|
6360
6630
|
const lines = baseline.current ? Math.round(Math.abs(sizeDelta) / baseline.current.lineHeight) : 0;
|
|
6361
6631
|
const lineNote = lines >= 1 ? ` (~${lines} line${lines === 1 ? "" : "s"})` : "";
|
|
6362
|
-
return /* @__PURE__ */ (0,
|
|
6632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
6363
6633
|
"Block ",
|
|
6364
6634
|
sizeDelta > 0 ? "grew" : "shrank",
|
|
6365
6635
|
" by ",
|
|
@@ -6369,16 +6639,16 @@ function InlineEditor({ editor }) {
|
|
|
6369
6639
|
" \u2014 as it would with this text live."
|
|
6370
6640
|
] });
|
|
6371
6641
|
})(),
|
|
6372
|
-
Math.abs(sizeDelta) <= 2 && Math.abs(widthDelta) > 4 && /* @__PURE__ */ (0,
|
|
6642
|
+
Math.abs(sizeDelta) <= 2 && Math.abs(widthDelta) > 4 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
6373
6643
|
"Block got ",
|
|
6374
6644
|
widthDelta > 0 ? "wider" : "narrower",
|
|
6375
6645
|
" by ",
|
|
6376
6646
|
Math.abs(widthDelta),
|
|
6377
6647
|
" px \u2014 as it would with this text live."
|
|
6378
6648
|
] }),
|
|
6379
|
-
clipped && /* @__PURE__ */ (0,
|
|
6649
|
+
clipped && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-clip-note", children: "Text exceeds the visible crop here and will be cut off." })
|
|
6380
6650
|
] }),
|
|
6381
|
-
/* @__PURE__ */ (0,
|
|
6651
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6382
6652
|
"input",
|
|
6383
6653
|
{
|
|
6384
6654
|
className: "rk-input",
|
|
@@ -6387,24 +6657,24 @@ function InlineEditor({ editor }) {
|
|
|
6387
6657
|
onChange: (event) => setNote(event.target.value)
|
|
6388
6658
|
}
|
|
6389
6659
|
),
|
|
6390
|
-
/* @__PURE__ */ (0,
|
|
6391
|
-
/* @__PURE__ */ (0,
|
|
6392
|
-
/* @__PURE__ */ (0,
|
|
6660
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
6661
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
|
|
6662
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
|
|
6393
6663
|
] })
|
|
6394
6664
|
] }),
|
|
6395
|
-
/* @__PURE__ */ (0,
|
|
6396
|
-
/* @__PURE__ */ (0,
|
|
6397
|
-
/* @__PURE__ */ (0,
|
|
6665
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-foot", children: [
|
|
6666
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-hint", children: [
|
|
6667
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
|
|
6398
6668
|
" save \xB7 ",
|
|
6399
|
-
/* @__PURE__ */ (0,
|
|
6669
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u21E7\u21B5" }),
|
|
6400
6670
|
" newline \xB7",
|
|
6401
6671
|
" ",
|
|
6402
|
-
/* @__PURE__ */ (0,
|
|
6672
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
6403
6673
|
" cancel"
|
|
6404
6674
|
] }),
|
|
6405
|
-
/* @__PURE__ */ (0,
|
|
6406
|
-
/* @__PURE__ */ (0,
|
|
6407
|
-
/* @__PURE__ */ (0,
|
|
6675
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-actions", children: [
|
|
6676
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: cancel, children: "Cancel" }),
|
|
6677
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: commit, children: "Save" })
|
|
6408
6678
|
] })
|
|
6409
6679
|
] })
|
|
6410
6680
|
] })
|
|
@@ -6412,8 +6682,8 @@ function InlineEditor({ editor }) {
|
|
|
6412
6682
|
}
|
|
6413
6683
|
|
|
6414
6684
|
// src/client/components/NoteComposer.tsx
|
|
6415
|
-
var
|
|
6416
|
-
var
|
|
6685
|
+
var import_react13 = require("react");
|
|
6686
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
6417
6687
|
var TITLES = {
|
|
6418
6688
|
comment: "Comment",
|
|
6419
6689
|
delete: "Mark for deletion",
|
|
@@ -6429,14 +6699,14 @@ var PLACEHOLDERS = {
|
|
|
6429
6699
|
function NoteComposer({ editor }) {
|
|
6430
6700
|
const dispatch = useDispatch();
|
|
6431
6701
|
const { route, session } = useStore();
|
|
6432
|
-
const [text, setText] = (0,
|
|
6433
|
-
const [direction, setDirection] = (0,
|
|
6434
|
-
const [priority, setPriority] = (0,
|
|
6435
|
-
const textareaRef = (0,
|
|
6702
|
+
const [text, setText] = (0, import_react13.useState)("");
|
|
6703
|
+
const [direction, setDirection] = (0, import_react13.useState)(void 0);
|
|
6704
|
+
const [priority, setPriority] = (0, import_react13.useState)("nice");
|
|
6705
|
+
const textareaRef = (0, import_react13.useRef)(null);
|
|
6436
6706
|
const { ref, pos } = useAnchored(editor.element, "bottom", 12);
|
|
6437
6707
|
const { kind } = editor;
|
|
6438
|
-
const focusedOnce = (0,
|
|
6439
|
-
(0,
|
|
6708
|
+
const focusedOnce = (0, import_react13.useRef)(false);
|
|
6709
|
+
(0, import_react13.useEffect)(() => {
|
|
6440
6710
|
const field = textareaRef.current;
|
|
6441
6711
|
if (pos === null || focusedOnce.current || !field) return;
|
|
6442
6712
|
focusedOnce.current = true;
|
|
@@ -6495,13 +6765,13 @@ function NoteComposer({ editor }) {
|
|
|
6495
6765
|
save();
|
|
6496
6766
|
}
|
|
6497
6767
|
};
|
|
6498
|
-
return /* @__PURE__ */ (0,
|
|
6499
|
-
/* @__PURE__ */ (0,
|
|
6768
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": TITLES[kind], children: [
|
|
6769
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-head", children: [
|
|
6500
6770
|
iconForType(kind),
|
|
6501
6771
|
TITLES[kind]
|
|
6502
6772
|
] }),
|
|
6503
|
-
/* @__PURE__ */ (0,
|
|
6504
|
-
kind === "move" && /* @__PURE__ */ (0,
|
|
6773
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-body", children: [
|
|
6774
|
+
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)(
|
|
6505
6775
|
"button",
|
|
6506
6776
|
{
|
|
6507
6777
|
type: "button",
|
|
@@ -6511,7 +6781,7 @@ function NoteComposer({ editor }) {
|
|
|
6511
6781
|
},
|
|
6512
6782
|
option
|
|
6513
6783
|
)) }),
|
|
6514
|
-
/* @__PURE__ */ (0,
|
|
6784
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
6515
6785
|
"textarea",
|
|
6516
6786
|
{
|
|
6517
6787
|
ref: textareaRef,
|
|
@@ -6523,29 +6793,29 @@ function NoteComposer({ editor }) {
|
|
|
6523
6793
|
rows: 3
|
|
6524
6794
|
}
|
|
6525
6795
|
),
|
|
6526
|
-
/* @__PURE__ */ (0,
|
|
6527
|
-
/* @__PURE__ */ (0,
|
|
6528
|
-
/* @__PURE__ */ (0,
|
|
6796
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
6797
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
|
|
6798
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
|
|
6529
6799
|
] })
|
|
6530
6800
|
] }),
|
|
6531
|
-
/* @__PURE__ */ (0,
|
|
6532
|
-
/* @__PURE__ */ (0,
|
|
6533
|
-
/* @__PURE__ */ (0,
|
|
6801
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-foot", children: [
|
|
6802
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-hint", children: [
|
|
6803
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-kbd", children: "\u2318\u21B5" }),
|
|
6534
6804
|
" save \xB7 ",
|
|
6535
|
-
/* @__PURE__ */ (0,
|
|
6805
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
6536
6806
|
" cancel"
|
|
6537
6807
|
] }),
|
|
6538
|
-
/* @__PURE__ */ (0,
|
|
6539
|
-
/* @__PURE__ */ (0,
|
|
6540
|
-
/* @__PURE__ */ (0,
|
|
6808
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-actions", children: [
|
|
6809
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
|
|
6810
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
|
|
6541
6811
|
] })
|
|
6542
6812
|
] })
|
|
6543
6813
|
] });
|
|
6544
6814
|
}
|
|
6545
6815
|
|
|
6546
6816
|
// src/client/components/Panel.tsx
|
|
6547
|
-
var
|
|
6548
|
-
var
|
|
6817
|
+
var import_react14 = require("react");
|
|
6818
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
6549
6819
|
function changeSummary(item) {
|
|
6550
6820
|
if (isCopyItem(item)) return `\u201C${item.payload.after}\u201D`;
|
|
6551
6821
|
if (isImageItem(item)) {
|
|
@@ -6627,24 +6897,24 @@ function formatBytes(bytes) {
|
|
|
6627
6897
|
function CopyDiff({ before, after }) {
|
|
6628
6898
|
const parts = diffParts(before, after);
|
|
6629
6899
|
const delta = after.length - before.length;
|
|
6630
|
-
return /* @__PURE__ */ (0,
|
|
6631
|
-
/* @__PURE__ */ (0,
|
|
6632
|
-
/* @__PURE__ */ (0,
|
|
6633
|
-
/* @__PURE__ */ (0,
|
|
6900
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diffview", children: [
|
|
6901
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
|
|
6902
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
|
|
6903
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-diff-text", children: [
|
|
6634
6904
|
parts.prefix,
|
|
6635
|
-
parts.delMid && /* @__PURE__ */ (0,
|
|
6905
|
+
parts.delMid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("mark", { className: "rk-del", children: parts.delMid }),
|
|
6636
6906
|
parts.suffix
|
|
6637
6907
|
] })
|
|
6638
6908
|
] }),
|
|
6639
|
-
/* @__PURE__ */ (0,
|
|
6640
|
-
/* @__PURE__ */ (0,
|
|
6641
|
-
/* @__PURE__ */ (0,
|
|
6909
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
|
|
6910
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-diff-tag", children: "After" }),
|
|
6911
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-diff-text", children: [
|
|
6642
6912
|
parts.prefix,
|
|
6643
|
-
parts.insMid && /* @__PURE__ */ (0,
|
|
6913
|
+
parts.insMid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("mark", { className: "rk-ins", children: parts.insMid }),
|
|
6644
6914
|
parts.suffix
|
|
6645
6915
|
] })
|
|
6646
6916
|
] }),
|
|
6647
|
-
/* @__PURE__ */ (0,
|
|
6917
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-len", children: [
|
|
6648
6918
|
before.length,
|
|
6649
6919
|
" \u2192 ",
|
|
6650
6920
|
after.length,
|
|
@@ -6655,8 +6925,8 @@ function CopyDiff({ before, after }) {
|
|
|
6655
6925
|
}
|
|
6656
6926
|
function ImageDetail({ beforeSrc, afterSrc, afterDataUrl }) {
|
|
6657
6927
|
const replacement = afterDataUrl ?? afterSrc;
|
|
6658
|
-
const [dims, setDims] = (0,
|
|
6659
|
-
(0,
|
|
6928
|
+
const [dims, setDims] = (0, import_react14.useState)("");
|
|
6929
|
+
(0, import_react14.useEffect)(() => {
|
|
6660
6930
|
if (!replacement) return;
|
|
6661
6931
|
const img = new Image();
|
|
6662
6932
|
img.onload = () => setDims(`${img.naturalWidth}\xD7${img.naturalHeight}px`);
|
|
@@ -6681,55 +6951,67 @@ function ImageDetail({ beforeSrc, afterSrc, afterDataUrl }) {
|
|
|
6681
6951
|
window.open(replacement, "_blank", "noopener");
|
|
6682
6952
|
}
|
|
6683
6953
|
};
|
|
6684
|
-
return /* @__PURE__ */ (0,
|
|
6685
|
-
/* @__PURE__ */ (0,
|
|
6686
|
-
/* @__PURE__ */ (0,
|
|
6687
|
-
beforeSrc ? /* @__PURE__ */ (0,
|
|
6688
|
-
/* @__PURE__ */ (0,
|
|
6954
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail", children: [
|
|
6955
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-thumbs", children: [
|
|
6956
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6957
|
+
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" }),
|
|
6958
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { children: "Before" })
|
|
6689
6959
|
] }),
|
|
6690
|
-
/* @__PURE__ */ (0,
|
|
6691
|
-
/* @__PURE__ */ (0,
|
|
6692
|
-
/* @__PURE__ */ (0,
|
|
6960
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6961
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("img", { src: replacement, alt: "Proposed replacement" }),
|
|
6962
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figcaption", { children: [
|
|
6693
6963
|
"After",
|
|
6694
6964
|
embedded ? "" : " \xB7 linked"
|
|
6695
6965
|
] })
|
|
6696
6966
|
] })
|
|
6697
6967
|
] }),
|
|
6698
|
-
/* @__PURE__ */ (0,
|
|
6968
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail-meta", children: [
|
|
6699
6969
|
embedded ? "Embedded image" : "Linked image",
|
|
6700
6970
|
dims ? ` \xB7 ${dims}` : "",
|
|
6701
6971
|
bytes !== null ? ` \xB7 ${formatBytes(bytes)}` : ""
|
|
6702
6972
|
] }),
|
|
6703
|
-
!embedded && afterSrc && /* @__PURE__ */ (0,
|
|
6704
|
-
/* @__PURE__ */ (0,
|
|
6705
|
-
/* @__PURE__ */ (0,
|
|
6706
|
-
/* @__PURE__ */ (0,
|
|
6973
|
+
!embedded && afterSrc && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { className: "rk-imgdetail-url", href: afterSrc, target: "_blank", rel: "noopener noreferrer", title: afterSrc, children: afterSrc }),
|
|
6974
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail-actions", children: [
|
|
6975
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void download(), children: [
|
|
6976
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconDownload, { size: 12 }),
|
|
6707
6977
|
" Download"
|
|
6708
6978
|
] }),
|
|
6709
|
-
/* @__PURE__ */ (0,
|
|
6979
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => window.open(replacement, "_blank", "noopener"), children: "Open" })
|
|
6710
6980
|
] })
|
|
6711
6981
|
] });
|
|
6712
6982
|
}
|
|
6983
|
+
var SYNC_REASON_LABEL = {
|
|
6984
|
+
"token-short": "token too short",
|
|
6985
|
+
"bad-token": "token rejected",
|
|
6986
|
+
"room-full": "room full",
|
|
6987
|
+
unreachable: "server unreachable"
|
|
6988
|
+
};
|
|
6989
|
+
var SYNC_REASON_HELP = {
|
|
6990
|
+
"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.",
|
|
6991
|
+
"bad-token": "The sync server rejected the token. Check `syncToken` / `token` in <ReviewKit />.",
|
|
6992
|
+
"room-full": "This page already has the maximum number of reviewers online (16). Try again later.",
|
|
6993
|
+
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."
|
|
6994
|
+
};
|
|
6713
6995
|
function Panel() {
|
|
6714
|
-
const { session, panelOpen, activeItemId, badgeCorner, undoStack, preview, unapplied, syncStatus, emblemaPush, peers } = useStore();
|
|
6996
|
+
const { session, panelOpen, activeItemId, badgeCorner, undoStack, preview, unapplied, syncStatus, syncReason, emblemaPush, peers } = useStore();
|
|
6715
6997
|
const dispatch = useDispatch();
|
|
6716
6998
|
const config = useConfig();
|
|
6717
|
-
const [sticky, setStickyState] = (0,
|
|
6718
|
-
const [query, setQuery] = (0,
|
|
6719
|
-
const [typeFilter, setTypeFilter] = (0,
|
|
6720
|
-
const [prioFilter, setPrioFilter] = (0,
|
|
6721
|
-
const [statusFilter, setStatusFilter] = (0,
|
|
6722
|
-
const [filterOpen, setFilterOpen] = (0,
|
|
6723
|
-
const [settingsOpen, setSettingsOpen] = (0,
|
|
6724
|
-
const [emblemaAlive, setEmblemaAlive] = (0,
|
|
6725
|
-
const [emblemaSending, setEmblemaSending] = (0,
|
|
6726
|
-
const [emblemaSync, setEmblemaSync] = (0,
|
|
6727
|
-
const panelRef = (0,
|
|
6728
|
-
const searchRef = (0,
|
|
6729
|
-
const importRef = (0,
|
|
6730
|
-
const sheetDrag = (0,
|
|
6731
|
-
const items = (0,
|
|
6732
|
-
const { orphanIds, hiddenIds } = (0,
|
|
6999
|
+
const [sticky, setStickyState] = (0, import_react14.useState)(() => isStickyEnabled(config.token));
|
|
7000
|
+
const [query, setQuery] = (0, import_react14.useState)("");
|
|
7001
|
+
const [typeFilter, setTypeFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
7002
|
+
const [prioFilter, setPrioFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
7003
|
+
const [statusFilter, setStatusFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
7004
|
+
const [filterOpen, setFilterOpen] = (0, import_react14.useState)(false);
|
|
7005
|
+
const [settingsOpen, setSettingsOpen] = (0, import_react14.useState)(false);
|
|
7006
|
+
const [emblemaAlive, setEmblemaAlive] = (0, import_react14.useState)(null);
|
|
7007
|
+
const [emblemaSending, setEmblemaSending] = (0, import_react14.useState)(false);
|
|
7008
|
+
const [emblemaSync, setEmblemaSync] = (0, import_react14.useState)("unknown");
|
|
7009
|
+
const panelRef = (0, import_react14.useRef)(null);
|
|
7010
|
+
const searchRef = (0, import_react14.useRef)(null);
|
|
7011
|
+
const importRef = (0, import_react14.useRef)(null);
|
|
7012
|
+
const sheetDrag = (0, import_react14.useRef)(null);
|
|
7013
|
+
const items = (0, import_react14.useMemo)(() => session?.items ?? [], [session]);
|
|
7014
|
+
const { orphanIds, hiddenIds } = (0, import_react14.useMemo)(() => {
|
|
6733
7015
|
const orphans = /* @__PURE__ */ new Set();
|
|
6734
7016
|
const hiddens = /* @__PURE__ */ new Set();
|
|
6735
7017
|
for (const item of items) {
|
|
@@ -6740,15 +7022,15 @@ function Panel() {
|
|
|
6740
7022
|
}
|
|
6741
7023
|
return { orphanIds: orphans, hiddenIds: hiddens };
|
|
6742
7024
|
}, [items, panelOpen]);
|
|
6743
|
-
const activeFilter = (0,
|
|
7025
|
+
const activeFilter = (0, import_react14.useMemo)(
|
|
6744
7026
|
() => typeFilter.size + prioFilter.size + statusFilter.size > 0 ? { types: [...typeFilter], priorities: [...prioFilter], statuses: [...statusFilter] } : null,
|
|
6745
7027
|
[typeFilter, prioFilter, statusFilter]
|
|
6746
7028
|
);
|
|
6747
|
-
(0,
|
|
7029
|
+
(0, import_react14.useEffect)(() => {
|
|
6748
7030
|
dispatch({ type: "SET_FILTER", filter: activeFilter });
|
|
6749
7031
|
return () => dispatch({ type: "SET_FILTER", filter: null });
|
|
6750
7032
|
}, [activeFilter, dispatch]);
|
|
6751
|
-
const filtered = (0,
|
|
7033
|
+
const filtered = (0, import_react14.useMemo)(() => {
|
|
6752
7034
|
const q = query.trim().toLowerCase();
|
|
6753
7035
|
return items.map((item, index) => ({ item, number: index + 1 })).filter(({ item }) => {
|
|
6754
7036
|
if (!itemMatchesFilter(item, activeFilter)) return false;
|
|
@@ -6757,22 +7039,22 @@ function Panel() {
|
|
|
6757
7039
|
return haystack.includes(q);
|
|
6758
7040
|
});
|
|
6759
7041
|
}, [items, query, activeFilter]);
|
|
6760
|
-
const typeCounts = (0,
|
|
7042
|
+
const typeCounts = (0, import_react14.useMemo)(() => {
|
|
6761
7043
|
const counts = /* @__PURE__ */ new Map();
|
|
6762
7044
|
for (const item of items) counts.set(item.type, (counts.get(item.type) ?? 0) + 1);
|
|
6763
7045
|
return counts;
|
|
6764
7046
|
}, [items]);
|
|
6765
|
-
const prioCounts = (0,
|
|
7047
|
+
const prioCounts = (0, import_react14.useMemo)(() => {
|
|
6766
7048
|
const counts = /* @__PURE__ */ new Map();
|
|
6767
7049
|
for (const item of items) counts.set(item.priority, (counts.get(item.priority) ?? 0) + 1);
|
|
6768
7050
|
return counts;
|
|
6769
7051
|
}, [items]);
|
|
6770
|
-
const statusCounts = (0,
|
|
7052
|
+
const statusCounts = (0, import_react14.useMemo)(() => {
|
|
6771
7053
|
const counts = /* @__PURE__ */ new Map();
|
|
6772
7054
|
for (const item of items) counts.set(item.status, (counts.get(item.status) ?? 0) + 1);
|
|
6773
7055
|
return counts;
|
|
6774
7056
|
}, [items]);
|
|
6775
|
-
const groups = (0,
|
|
7057
|
+
const groups = (0, import_react14.useMemo)(() => {
|
|
6776
7058
|
const map = /* @__PURE__ */ new Map();
|
|
6777
7059
|
for (const entry of filtered) {
|
|
6778
7060
|
const list = map.get(entry.item.route) ?? [];
|
|
@@ -6781,7 +7063,7 @@ function Panel() {
|
|
|
6781
7063
|
}
|
|
6782
7064
|
return Array.from(map.entries());
|
|
6783
7065
|
}, [filtered]);
|
|
6784
|
-
(0,
|
|
7066
|
+
(0, import_react14.useEffect)(() => {
|
|
6785
7067
|
if (!filterOpen && !settingsOpen) return;
|
|
6786
7068
|
const onDown = (event) => {
|
|
6787
7069
|
const path = event.composedPath();
|
|
@@ -6792,7 +7074,7 @@ function Panel() {
|
|
|
6792
7074
|
document.addEventListener("pointerdown", onDown, true);
|
|
6793
7075
|
return () => document.removeEventListener("pointerdown", onDown, true);
|
|
6794
7076
|
}, [filterOpen, settingsOpen]);
|
|
6795
|
-
(0,
|
|
7077
|
+
(0, import_react14.useEffect)(() => {
|
|
6796
7078
|
if (!settingsOpen) return;
|
|
6797
7079
|
let alive = true;
|
|
6798
7080
|
const probe = () => {
|
|
@@ -6816,7 +7098,7 @@ function Panel() {
|
|
|
6816
7098
|
live: "paired",
|
|
6817
7099
|
off: "not paired"
|
|
6818
7100
|
}[emblemaPairState];
|
|
6819
|
-
(0,
|
|
7101
|
+
(0, import_react14.useEffect)(() => {
|
|
6820
7102
|
if (!panelOpen || activeItemId === null) return;
|
|
6821
7103
|
const row = panelRef.current?.querySelector(`[data-item-id="${activeItemId}"]`);
|
|
6822
7104
|
row?.scrollIntoView({ block: "nearest" });
|
|
@@ -6932,7 +7214,7 @@ function Panel() {
|
|
|
6932
7214
|
panel.style.transform = "";
|
|
6933
7215
|
if (dy > 110) dispatch({ type: "SET_PANEL", open: false });
|
|
6934
7216
|
};
|
|
6935
|
-
return /* @__PURE__ */ (0,
|
|
7217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
6936
7218
|
"div",
|
|
6937
7219
|
{
|
|
6938
7220
|
ref: panelRef,
|
|
@@ -6942,7 +7224,7 @@ function Panel() {
|
|
|
6942
7224
|
"aria-label": "Review feedback panel",
|
|
6943
7225
|
onKeyDown,
|
|
6944
7226
|
children: [
|
|
6945
|
-
/* @__PURE__ */ (0,
|
|
7227
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6946
7228
|
"div",
|
|
6947
7229
|
{
|
|
6948
7230
|
className: "rk-sheet-handle",
|
|
@@ -6953,34 +7235,41 @@ function Panel() {
|
|
|
6953
7235
|
onPointerCancel: onSheetHandleUp
|
|
6954
7236
|
}
|
|
6955
7237
|
),
|
|
6956
|
-
/* @__PURE__ */ (0,
|
|
6957
|
-
/* @__PURE__ */ (0,
|
|
6958
|
-
/* @__PURE__ */ (0,
|
|
6959
|
-
/* @__PURE__ */ (0,
|
|
7238
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-head", children: [
|
|
7239
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
7240
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-panel-title", children: "Feedback" }),
|
|
7241
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-sub", children: [
|
|
6960
7242
|
items.length,
|
|
6961
7243
|
" item",
|
|
6962
7244
|
items.length === 1 ? "" : "s",
|
|
6963
7245
|
session.author ? ` \xB7 ${session.author}` : "",
|
|
6964
|
-
syncStatus !== "disabled" && /* @__PURE__ */ (0,
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
7246
|
+
syncStatus !== "disabled" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7247
|
+
"span",
|
|
7248
|
+
{
|
|
7249
|
+
className: `rk-sync rk-sync-${syncStatus}${syncReason ? ` rk-sync-reason-${syncReason}` : ""}`,
|
|
7250
|
+
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"],
|
|
7251
|
+
children: [
|
|
7252
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-sync-dot" }),
|
|
7253
|
+
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"]}`
|
|
7254
|
+
]
|
|
7255
|
+
}
|
|
7256
|
+
),
|
|
7257
|
+
config.emblema && emblemaPush !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
6969
7258
|
"span",
|
|
6970
7259
|
{
|
|
6971
7260
|
className: `rk-sync rk-epush-${emblemaPush}`,
|
|
6972
7261
|
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",
|
|
6973
7262
|
children: [
|
|
6974
|
-
/* @__PURE__ */ (0,
|
|
7263
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-sync-dot" }),
|
|
6975
7264
|
emblemaPush === "ok" ? "emblema" : emblemaPush === "sending" ? "emblema\u2026" : emblemaPush === "rejected" ? "emblema rejected" : "emblema offline"
|
|
6976
7265
|
]
|
|
6977
7266
|
}
|
|
6978
7267
|
)
|
|
6979
7268
|
] })
|
|
6980
7269
|
] }),
|
|
6981
|
-
/* @__PURE__ */ (0,
|
|
6982
|
-
/* @__PURE__ */ (0,
|
|
6983
|
-
/* @__PURE__ */ (0,
|
|
7270
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-spacer" }),
|
|
7271
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
|
|
7272
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6984
7273
|
"button",
|
|
6985
7274
|
{
|
|
6986
7275
|
type: "button",
|
|
@@ -6996,11 +7285,11 @@ function Panel() {
|
|
|
6996
7285
|
void pingEmblema(config.emblema).then((port) => setEmblemaAlive(port !== null));
|
|
6997
7286
|
}
|
|
6998
7287
|
},
|
|
6999
|
-
children: /* @__PURE__ */ (0,
|
|
7288
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconGear, { size: 15 })
|
|
7000
7289
|
}
|
|
7001
7290
|
),
|
|
7002
|
-
settingsOpen && /* @__PURE__ */ (0,
|
|
7003
|
-
config.token && /* @__PURE__ */ (0,
|
|
7291
|
+
settingsOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Session settings", children: [
|
|
7292
|
+
config.token && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7004
7293
|
"button",
|
|
7005
7294
|
{
|
|
7006
7295
|
type: "button",
|
|
@@ -7015,12 +7304,12 @@ function Panel() {
|
|
|
7015
7304
|
toast(dispatch, next ? "Review stays on in this tab" : "Review active only via the link", "info");
|
|
7016
7305
|
},
|
|
7017
7306
|
children: [
|
|
7018
|
-
/* @__PURE__ */ (0,
|
|
7307
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${sticky ? " rk-on" : ""}` }),
|
|
7019
7308
|
"Keep review on in this tab"
|
|
7020
7309
|
]
|
|
7021
7310
|
}
|
|
7022
7311
|
),
|
|
7023
|
-
config.emblema && /* @__PURE__ */ (0,
|
|
7312
|
+
config.emblema && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7024
7313
|
"button",
|
|
7025
7314
|
{
|
|
7026
7315
|
type: "button",
|
|
@@ -7050,7 +7339,7 @@ function Panel() {
|
|
|
7050
7339
|
}).finally(() => setEmblemaSending(false));
|
|
7051
7340
|
},
|
|
7052
7341
|
children: [
|
|
7053
|
-
/* @__PURE__ */ (0,
|
|
7342
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7054
7343
|
"span",
|
|
7055
7344
|
{
|
|
7056
7345
|
className: "rk-emblema-dot",
|
|
@@ -7061,25 +7350,40 @@ function Panel() {
|
|
|
7061
7350
|
]
|
|
7062
7351
|
}
|
|
7063
7352
|
),
|
|
7064
|
-
/* @__PURE__ */ (0,
|
|
7353
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7065
7354
|
"button",
|
|
7066
7355
|
{
|
|
7067
7356
|
type: "button",
|
|
7068
7357
|
role: "menuitem",
|
|
7069
7358
|
className: "rk-menu-item",
|
|
7070
|
-
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",
|
|
7359
|
+
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",
|
|
7071
7360
|
onClick: () => {
|
|
7072
7361
|
setSettingsOpen(false);
|
|
7073
7362
|
dispatch({ type: "SET_EMBLEMA_CONNECT", open: true });
|
|
7074
7363
|
},
|
|
7075
7364
|
children: [
|
|
7076
|
-
/* @__PURE__ */ (0,
|
|
7365
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-emblema-dot", "data-state": emblemaPairState }),
|
|
7077
7366
|
"Connect to Emblema\u2026",
|
|
7078
|
-
/* @__PURE__ */ (0,
|
|
7367
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: emblemaPairLabel })
|
|
7079
7368
|
]
|
|
7080
7369
|
}
|
|
7081
7370
|
),
|
|
7082
|
-
/* @__PURE__ */ (0,
|
|
7371
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7372
|
+
"button",
|
|
7373
|
+
{
|
|
7374
|
+
type: "button",
|
|
7375
|
+
role: "menuitem",
|
|
7376
|
+
className: "rk-menu-item",
|
|
7377
|
+
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",
|
|
7378
|
+
disabled: !resolveSyncToken(config),
|
|
7379
|
+
onClick: () => {
|
|
7380
|
+
setSettingsOpen(false);
|
|
7381
|
+
dispatch({ type: "SET_TERMINAL_CONNECT", open: true });
|
|
7382
|
+
},
|
|
7383
|
+
children: "Connect terminal / agent\u2026"
|
|
7384
|
+
}
|
|
7385
|
+
),
|
|
7386
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7083
7387
|
"button",
|
|
7084
7388
|
{
|
|
7085
7389
|
type: "button",
|
|
@@ -7092,31 +7396,31 @@ function Panel() {
|
|
|
7092
7396
|
)
|
|
7093
7397
|
] })
|
|
7094
7398
|
] }),
|
|
7095
|
-
/* @__PURE__ */ (0,
|
|
7399
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7096
7400
|
"button",
|
|
7097
7401
|
{
|
|
7098
7402
|
type: "button",
|
|
7099
7403
|
className: "rk-icon-btn",
|
|
7100
7404
|
"aria-label": "Keyboard shortcuts",
|
|
7101
7405
|
onClick: () => dispatch({ type: "SET_CHEATSHEET", open: true }),
|
|
7102
|
-
children: /* @__PURE__ */ (0,
|
|
7406
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconKeyboard, { size: 15 })
|
|
7103
7407
|
}
|
|
7104
7408
|
),
|
|
7105
|
-
/* @__PURE__ */ (0,
|
|
7409
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7106
7410
|
"button",
|
|
7107
7411
|
{
|
|
7108
7412
|
type: "button",
|
|
7109
7413
|
className: "rk-icon-btn",
|
|
7110
7414
|
"aria-label": "Close panel",
|
|
7111
7415
|
onClick: () => dispatch({ type: "SET_PANEL", open: false }),
|
|
7112
|
-
children: /* @__PURE__ */ (0,
|
|
7416
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconClose, { size: 14 })
|
|
7113
7417
|
}
|
|
7114
7418
|
)
|
|
7115
7419
|
] }),
|
|
7116
|
-
/* @__PURE__ */ (0,
|
|
7117
|
-
/* @__PURE__ */ (0,
|
|
7118
|
-
/* @__PURE__ */ (0,
|
|
7119
|
-
/* @__PURE__ */ (0,
|
|
7420
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-view-row", children: [
|
|
7421
|
+
/* @__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" }) }),
|
|
7422
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-seg rk-view-toggle", role: "group", "aria-label": "Page view (P to toggle)", children: [
|
|
7423
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7120
7424
|
"button",
|
|
7121
7425
|
{
|
|
7122
7426
|
type: "button",
|
|
@@ -7126,7 +7430,7 @@ function Panel() {
|
|
|
7126
7430
|
children: "Original"
|
|
7127
7431
|
}
|
|
7128
7432
|
),
|
|
7129
|
-
/* @__PURE__ */ (0,
|
|
7433
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7130
7434
|
"button",
|
|
7131
7435
|
{
|
|
7132
7436
|
type: "button",
|
|
@@ -7138,8 +7442,8 @@ function Panel() {
|
|
|
7138
7442
|
)
|
|
7139
7443
|
] })
|
|
7140
7444
|
] }),
|
|
7141
|
-
/* @__PURE__ */ (0,
|
|
7142
|
-
/* @__PURE__ */ (0,
|
|
7445
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-tools", children: [
|
|
7446
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7143
7447
|
"button",
|
|
7144
7448
|
{
|
|
7145
7449
|
type: "button",
|
|
@@ -7150,15 +7454,15 @@ function Panel() {
|
|
|
7150
7454
|
dispatch({ type: "SET_MODE", mode: "pick" });
|
|
7151
7455
|
},
|
|
7152
7456
|
children: [
|
|
7153
|
-
/* @__PURE__ */ (0,
|
|
7457
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTarget, { size: 14 }),
|
|
7154
7458
|
" Pick an element"
|
|
7155
7459
|
]
|
|
7156
7460
|
}
|
|
7157
7461
|
),
|
|
7158
|
-
/* @__PURE__ */ (0,
|
|
7159
|
-
/* @__PURE__ */ (0,
|
|
7160
|
-
/* @__PURE__ */ (0,
|
|
7161
|
-
/* @__PURE__ */ (0,
|
|
7462
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-search-row", children: [
|
|
7463
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-search", children: [
|
|
7464
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconSearch, { size: 13 }),
|
|
7465
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7162
7466
|
"input",
|
|
7163
7467
|
{
|
|
7164
7468
|
ref: searchRef,
|
|
@@ -7170,8 +7474,8 @@ function Panel() {
|
|
|
7170
7474
|
}
|
|
7171
7475
|
)
|
|
7172
7476
|
] }),
|
|
7173
|
-
/* @__PURE__ */ (0,
|
|
7174
|
-
/* @__PURE__ */ (0,
|
|
7477
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
|
|
7478
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7175
7479
|
"button",
|
|
7176
7480
|
{
|
|
7177
7481
|
type: "button",
|
|
@@ -7183,15 +7487,15 @@ function Panel() {
|
|
|
7183
7487
|
setSettingsOpen(false);
|
|
7184
7488
|
},
|
|
7185
7489
|
children: [
|
|
7186
|
-
/* @__PURE__ */ (0,
|
|
7490
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFilter, { size: 13 }),
|
|
7187
7491
|
"Filter",
|
|
7188
|
-
typeFilter.size + prioFilter.size + statusFilter.size > 0 && /* @__PURE__ */ (0,
|
|
7492
|
+
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 })
|
|
7189
7493
|
]
|
|
7190
7494
|
}
|
|
7191
7495
|
),
|
|
7192
|
-
filterOpen && /* @__PURE__ */ (0,
|
|
7193
|
-
/* @__PURE__ */ (0,
|
|
7194
|
-
TYPE_FILTERS.map((type) => /* @__PURE__ */ (0,
|
|
7496
|
+
filterOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Filter items", children: [
|
|
7497
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Type" }),
|
|
7498
|
+
TYPE_FILTERS.map((type) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7195
7499
|
"button",
|
|
7196
7500
|
{
|
|
7197
7501
|
type: "button",
|
|
@@ -7205,16 +7509,16 @@ function Panel() {
|
|
|
7205
7509
|
setTypeFilter(next);
|
|
7206
7510
|
},
|
|
7207
7511
|
children: [
|
|
7208
|
-
/* @__PURE__ */ (0,
|
|
7512
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${typeFilter.has(type) ? " rk-on" : ""}` }),
|
|
7209
7513
|
iconForType(type, 12),
|
|
7210
|
-
/* @__PURE__ */ (0,
|
|
7211
|
-
/* @__PURE__ */ (0,
|
|
7514
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: type }),
|
|
7515
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: typeCounts.get(type) ?? 0 })
|
|
7212
7516
|
]
|
|
7213
7517
|
},
|
|
7214
7518
|
type
|
|
7215
7519
|
)),
|
|
7216
|
-
/* @__PURE__ */ (0,
|
|
7217
|
-
PRIORITY_FILTERS.map((priority) => /* @__PURE__ */ (0,
|
|
7520
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Priority" }),
|
|
7521
|
+
PRIORITY_FILTERS.map((priority) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7218
7522
|
"button",
|
|
7219
7523
|
{
|
|
7220
7524
|
type: "button",
|
|
@@ -7228,15 +7532,15 @@ function Panel() {
|
|
|
7228
7532
|
setPrioFilter(next);
|
|
7229
7533
|
},
|
|
7230
7534
|
children: [
|
|
7231
|
-
/* @__PURE__ */ (0,
|
|
7232
|
-
/* @__PURE__ */ (0,
|
|
7233
|
-
/* @__PURE__ */ (0,
|
|
7535
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${prioFilter.has(priority) ? " rk-on" : ""}` }),
|
|
7536
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: PRIORITY_LABELS[priority] }),
|
|
7537
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: prioCounts.get(priority) ?? 0 })
|
|
7234
7538
|
]
|
|
7235
7539
|
},
|
|
7236
7540
|
priority
|
|
7237
7541
|
)),
|
|
7238
|
-
/* @__PURE__ */ (0,
|
|
7239
|
-
STATUSES.map((status) => /* @__PURE__ */ (0,
|
|
7542
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Status" }),
|
|
7543
|
+
STATUSES.map((status) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7240
7544
|
"button",
|
|
7241
7545
|
{
|
|
7242
7546
|
type: "button",
|
|
@@ -7250,15 +7554,15 @@ function Panel() {
|
|
|
7250
7554
|
setStatusFilter(next);
|
|
7251
7555
|
},
|
|
7252
7556
|
children: [
|
|
7253
|
-
/* @__PURE__ */ (0,
|
|
7254
|
-
/* @__PURE__ */ (0,
|
|
7255
|
-
/* @__PURE__ */ (0,
|
|
7256
|
-
/* @__PURE__ */ (0,
|
|
7557
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${statusFilter.has(status) ? " rk-on" : ""}` }),
|
|
7558
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-status-dot rk-st-${status}` }),
|
|
7559
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: status }),
|
|
7560
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: statusCounts.get(status) ?? 0 })
|
|
7257
7561
|
]
|
|
7258
7562
|
},
|
|
7259
7563
|
status
|
|
7260
7564
|
)),
|
|
7261
|
-
/* @__PURE__ */ (0,
|
|
7565
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7262
7566
|
"button",
|
|
7263
7567
|
{
|
|
7264
7568
|
type: "button",
|
|
@@ -7278,24 +7582,24 @@ function Panel() {
|
|
|
7278
7582
|
] })
|
|
7279
7583
|
] })
|
|
7280
7584
|
] }),
|
|
7281
|
-
preview && unapplied > 0 && /* @__PURE__ */ (0,
|
|
7585
|
+
preview && unapplied > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-unplaced", role: "status", children: [
|
|
7282
7586
|
unapplied,
|
|
7283
7587
|
" saved change",
|
|
7284
7588
|
unapplied === 1 ? "" : "s",
|
|
7285
7589
|
" couldn\u2019t be placed on the current page \u2014 the page has changed since they were captured."
|
|
7286
7590
|
] }),
|
|
7287
|
-
/* @__PURE__ */ (0,
|
|
7288
|
-
/* @__PURE__ */ (0,
|
|
7289
|
-
/* @__PURE__ */ (0,
|
|
7290
|
-
/* @__PURE__ */ (0,
|
|
7291
|
-
] }) : groups.map(([route, entries]) => /* @__PURE__ */ (0,
|
|
7292
|
-
/* @__PURE__ */ (0,
|
|
7591
|
+
/* @__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: [
|
|
7592
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-art", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTarget, { size: 22 }) }),
|
|
7593
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-title", children: items.length === 0 ? "Nothing here yet" : "No matches" }),
|
|
7594
|
+
/* @__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." })
|
|
7595
|
+
] }) : groups.map(([route, entries]) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
7596
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-group-title", children: route }),
|
|
7293
7597
|
entries.map(({ item, number }) => {
|
|
7294
7598
|
const active2 = item.id === activeItemId;
|
|
7295
7599
|
const orphan = orphanIds.has(item.id);
|
|
7296
7600
|
const hiddenEl = hiddenIds.has(item.id);
|
|
7297
|
-
return /* @__PURE__ */ (0,
|
|
7298
|
-
/* @__PURE__ */ (0,
|
|
7601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
7602
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7299
7603
|
"div",
|
|
7300
7604
|
{
|
|
7301
7605
|
"data-item-id": item.id,
|
|
@@ -7310,18 +7614,18 @@ function Panel() {
|
|
|
7310
7614
|
}
|
|
7311
7615
|
},
|
|
7312
7616
|
children: [
|
|
7313
|
-
/* @__PURE__ */ (0,
|
|
7314
|
-
/* @__PURE__ */ (0,
|
|
7315
|
-
/* @__PURE__ */ (0,
|
|
7316
|
-
/* @__PURE__ */ (0,
|
|
7617
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-num", children: number }),
|
|
7618
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-icon", children: iconForType(item.type) }),
|
|
7619
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-body", children: [
|
|
7620
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-snippet", children: [
|
|
7317
7621
|
item.target.tagName,
|
|
7318
7622
|
" \xB7 ",
|
|
7319
7623
|
item.target.textSnippet || item.target.selector
|
|
7320
7624
|
] }),
|
|
7321
|
-
/* @__PURE__ */ (0,
|
|
7322
|
-
/* @__PURE__ */ (0,
|
|
7323
|
-
/* @__PURE__ */ (0,
|
|
7324
|
-
/* @__PURE__ */ (0,
|
|
7625
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-change", children: changeSummary(item) }),
|
|
7626
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-meta", children: [
|
|
7627
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-author", title: new Date(item.createdAt).toLocaleString(), children: [
|
|
7628
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7325
7629
|
"span",
|
|
7326
7630
|
{
|
|
7327
7631
|
className: "rk-author-dot",
|
|
@@ -7329,15 +7633,15 @@ function Panel() {
|
|
|
7329
7633
|
}
|
|
7330
7634
|
),
|
|
7331
7635
|
item.author?.name ?? "Unknown",
|
|
7332
|
-
/* @__PURE__ */ (0,
|
|
7636
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-time", children: [
|
|
7333
7637
|
" \xB7 ",
|
|
7334
7638
|
timeAgo(item.createdAt)
|
|
7335
7639
|
] })
|
|
7336
7640
|
] }),
|
|
7337
|
-
item.priority === "must" && /* @__PURE__ */ (0,
|
|
7338
|
-
item.status !== "open" && /* @__PURE__ */ (0,
|
|
7339
|
-
orphan && /* @__PURE__ */ (0,
|
|
7340
|
-
hiddenEl && /* @__PURE__ */ (0,
|
|
7641
|
+
item.priority === "must" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini rk-must", children: "must" }),
|
|
7642
|
+
item.status !== "open" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-badge-mini rk-${item.status}`, children: item.status }),
|
|
7643
|
+
orphan && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini rk-orphaned", children: "unanchored" }),
|
|
7644
|
+
hiddenEl && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7341
7645
|
"span",
|
|
7342
7646
|
{
|
|
7343
7647
|
className: "rk-badge-mini rk-hidden-el",
|
|
@@ -7345,14 +7649,14 @@ function Panel() {
|
|
|
7345
7649
|
children: "hidden"
|
|
7346
7650
|
}
|
|
7347
7651
|
),
|
|
7348
|
-
item.note && /* @__PURE__ */ (0,
|
|
7349
|
-
peers.filter((peer) => peer.typingActive && peer.typingItemId === item.id).map((peer) => /* @__PURE__ */ (0,
|
|
7652
|
+
item.note && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini", children: "note" }),
|
|
7653
|
+
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: [
|
|
7350
7654
|
peer.name || "peer",
|
|
7351
7655
|
" is writing\u2026"
|
|
7352
7656
|
] }, peer.id))
|
|
7353
7657
|
] })
|
|
7354
7658
|
] }),
|
|
7355
|
-
/* @__PURE__ */ (0,
|
|
7659
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-actions", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7356
7660
|
"button",
|
|
7357
7661
|
{
|
|
7358
7662
|
type: "button",
|
|
@@ -7367,15 +7671,15 @@ function Panel() {
|
|
|
7367
7671
|
"info"
|
|
7368
7672
|
);
|
|
7369
7673
|
},
|
|
7370
|
-
children: /* @__PURE__ */ (0,
|
|
7674
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTrash, { size: 13 })
|
|
7371
7675
|
}
|
|
7372
7676
|
) })
|
|
7373
7677
|
]
|
|
7374
7678
|
}
|
|
7375
7679
|
),
|
|
7376
|
-
active2 && /* @__PURE__ */ (0,
|
|
7377
|
-
/* @__PURE__ */ (0,
|
|
7378
|
-
/* @__PURE__ */ (0,
|
|
7680
|
+
active2 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-item-edit", children: [
|
|
7681
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-detail-byline", title: new Date(item.createdAt).toLocaleString(), children: [
|
|
7682
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7379
7683
|
"span",
|
|
7380
7684
|
{
|
|
7381
7685
|
className: "rk-author-dot",
|
|
@@ -7386,8 +7690,8 @@ function Panel() {
|
|
|
7386
7690
|
" \xB7 ",
|
|
7387
7691
|
timeAgo(item.createdAt)
|
|
7388
7692
|
] }),
|
|
7389
|
-
isCopyItem(item) && /* @__PURE__ */ (0,
|
|
7390
|
-
isImageItem(item) && /* @__PURE__ */ (0,
|
|
7693
|
+
isCopyItem(item) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CopyDiff, { before: item.payload.before, after: item.payload.after }),
|
|
7694
|
+
isImageItem(item) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7391
7695
|
ImageDetail,
|
|
7392
7696
|
{
|
|
7393
7697
|
beforeSrc: item.payload.beforeSrc,
|
|
@@ -7395,7 +7699,7 @@ function Panel() {
|
|
|
7395
7699
|
afterDataUrl: item.payload.afterDataUrl
|
|
7396
7700
|
}
|
|
7397
7701
|
),
|
|
7398
|
-
isKnownItemType(item.type) && item.type !== "move" && /* @__PURE__ */ (0,
|
|
7702
|
+
isKnownItemType(item.type) && item.type !== "move" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7399
7703
|
"textarea",
|
|
7400
7704
|
{
|
|
7401
7705
|
className: "rk-textarea",
|
|
@@ -7405,7 +7709,7 @@ function Panel() {
|
|
|
7405
7709
|
onChange: (event) => dispatch({ type: "UPDATE_ITEM", id: item.id, patch: withPayloadText(item, event.target.value) })
|
|
7406
7710
|
}
|
|
7407
7711
|
),
|
|
7408
|
-
/* @__PURE__ */ (0,
|
|
7712
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7409
7713
|
"input",
|
|
7410
7714
|
{
|
|
7411
7715
|
className: "rk-input",
|
|
@@ -7415,9 +7719,9 @@ function Panel() {
|
|
|
7415
7719
|
onChange: (event) => dispatch({ type: "UPDATE_ITEM", id: item.id, patch: { note: event.target.value } })
|
|
7416
7720
|
}
|
|
7417
7721
|
),
|
|
7418
|
-
/* @__PURE__ */ (0,
|
|
7419
|
-
/* @__PURE__ */ (0,
|
|
7420
|
-
/* @__PURE__ */ (0,
|
|
7722
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
|
|
7723
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
7724
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7421
7725
|
"button",
|
|
7422
7726
|
{
|
|
7423
7727
|
type: "button",
|
|
@@ -7426,7 +7730,7 @@ function Panel() {
|
|
|
7426
7730
|
children: "Must"
|
|
7427
7731
|
}
|
|
7428
7732
|
),
|
|
7429
|
-
/* @__PURE__ */ (0,
|
|
7733
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7430
7734
|
"button",
|
|
7431
7735
|
{
|
|
7432
7736
|
type: "button",
|
|
@@ -7436,7 +7740,7 @@ function Panel() {
|
|
|
7436
7740
|
}
|
|
7437
7741
|
)
|
|
7438
7742
|
] }),
|
|
7439
|
-
/* @__PURE__ */ (0,
|
|
7743
|
+
/* @__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)(
|
|
7440
7744
|
"button",
|
|
7441
7745
|
{
|
|
7442
7746
|
type: "button",
|
|
@@ -7451,22 +7755,22 @@ function Panel() {
|
|
|
7451
7755
|
] }, item.id);
|
|
7452
7756
|
})
|
|
7453
7757
|
] }, route)) }),
|
|
7454
|
-
/* @__PURE__ */ (0,
|
|
7455
|
-
/* @__PURE__ */ (0,
|
|
7456
|
-
/* @__PURE__ */ (0,
|
|
7758
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-foot", children: [
|
|
7759
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: onExport, disabled: items.length === 0, children: [
|
|
7760
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconDownload, { size: 13 }),
|
|
7457
7761
|
" Export"
|
|
7458
7762
|
] }),
|
|
7459
|
-
/* @__PURE__ */ (0,
|
|
7460
|
-
/* @__PURE__ */ (0,
|
|
7763
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void onCopy(), disabled: items.length === 0, children: [
|
|
7764
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconCopyClipboard, { size: 13 }),
|
|
7461
7765
|
" Copy"
|
|
7462
7766
|
] }),
|
|
7463
|
-
/* @__PURE__ */ (0,
|
|
7464
|
-
/* @__PURE__ */ (0,
|
|
7767
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => importRef.current?.click(), children: [
|
|
7768
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconUpload, { size: 13 }),
|
|
7465
7769
|
" Import"
|
|
7466
7770
|
] }),
|
|
7467
|
-
/* @__PURE__ */ (0,
|
|
7468
|
-
undoStack.length > 0 && /* @__PURE__ */ (0,
|
|
7469
|
-
/* @__PURE__ */ (0,
|
|
7771
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-spacer" }),
|
|
7772
|
+
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 }) }),
|
|
7773
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7470
7774
|
"button",
|
|
7471
7775
|
{
|
|
7472
7776
|
type: "button",
|
|
@@ -7477,7 +7781,7 @@ function Panel() {
|
|
|
7477
7781
|
children: "Clear"
|
|
7478
7782
|
}
|
|
7479
7783
|
),
|
|
7480
|
-
/* @__PURE__ */ (0,
|
|
7784
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7481
7785
|
"button",
|
|
7482
7786
|
{
|
|
7483
7787
|
type: "button",
|
|
@@ -7487,7 +7791,7 @@ function Panel() {
|
|
|
7487
7791
|
children: "Exit review"
|
|
7488
7792
|
}
|
|
7489
7793
|
),
|
|
7490
|
-
/* @__PURE__ */ (0,
|
|
7794
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7491
7795
|
"input",
|
|
7492
7796
|
{
|
|
7493
7797
|
ref: importRef,
|
|
@@ -7508,8 +7812,8 @@ function Panel() {
|
|
|
7508
7812
|
}
|
|
7509
7813
|
|
|
7510
7814
|
// src/client/components/Presence.tsx
|
|
7511
|
-
var
|
|
7512
|
-
var
|
|
7815
|
+
var import_react15 = require("react");
|
|
7816
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
7513
7817
|
function initials(name) {
|
|
7514
7818
|
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
7515
7819
|
if (parts.length === 0) return "\xB7";
|
|
@@ -7519,8 +7823,8 @@ function initials(name) {
|
|
|
7519
7823
|
function PresenceStrip() {
|
|
7520
7824
|
const { peers, syncStatus } = useStore();
|
|
7521
7825
|
if (syncStatus === "disabled" || peers.length === 0) return null;
|
|
7522
|
-
return /* @__PURE__ */ (0,
|
|
7523
|
-
peers.slice(0, 5).map((peer) => /* @__PURE__ */ (0,
|
|
7826
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rk-presence", "aria-label": `${peers.length} reviewer${peers.length === 1 ? "" : "s"} online`, children: [
|
|
7827
|
+
peers.slice(0, 5).map((peer) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7524
7828
|
"span",
|
|
7525
7829
|
{
|
|
7526
7830
|
className: "rk-avatar",
|
|
@@ -7530,7 +7834,7 @@ function PresenceStrip() {
|
|
|
7530
7834
|
},
|
|
7531
7835
|
peer.id
|
|
7532
7836
|
)),
|
|
7533
|
-
peers.length > 5 && /* @__PURE__ */ (0,
|
|
7837
|
+
peers.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "rk-avatar rk-avatar-more", children: [
|
|
7534
7838
|
"+",
|
|
7535
7839
|
peers.length - 5
|
|
7536
7840
|
] })
|
|
@@ -7538,13 +7842,13 @@ function PresenceStrip() {
|
|
|
7538
7842
|
}
|
|
7539
7843
|
function PeerCursors() {
|
|
7540
7844
|
const { peers } = useStore();
|
|
7541
|
-
const ringRefs = (0,
|
|
7542
|
-
const cursorRefs = (0,
|
|
7543
|
-
const motion = (0,
|
|
7845
|
+
const ringRefs = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
|
|
7846
|
+
const cursorRefs = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
|
|
7847
|
+
const motion = (0, import_react15.useRef)(
|
|
7544
7848
|
/* @__PURE__ */ new Map()
|
|
7545
7849
|
);
|
|
7546
|
-
const peersRef = (0,
|
|
7547
|
-
const seen = (0,
|
|
7850
|
+
const peersRef = (0, import_react15.useRef)(peers);
|
|
7851
|
+
const seen = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
|
|
7548
7852
|
for (const peer of peers) {
|
|
7549
7853
|
const sig = peer.cursor ? `${peer.cursor.x},${peer.cursor.y},${peer.cursor.ox},${peer.cursor.oy}` : "";
|
|
7550
7854
|
if (seen.current.get(peer.id) !== sig) {
|
|
@@ -7554,7 +7858,7 @@ function PeerCursors() {
|
|
|
7554
7858
|
}
|
|
7555
7859
|
}
|
|
7556
7860
|
peersRef.current = peers;
|
|
7557
|
-
(0,
|
|
7861
|
+
(0, import_react15.useEffect)(() => {
|
|
7558
7862
|
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
7559
7863
|
let raf = 0;
|
|
7560
7864
|
let last = performance.now();
|
|
@@ -7659,8 +7963,8 @@ function PeerCursors() {
|
|
|
7659
7963
|
return () => cancelAnimationFrame(raf);
|
|
7660
7964
|
}, []);
|
|
7661
7965
|
if (peers.length === 0) return null;
|
|
7662
|
-
return /* @__PURE__ */ (0,
|
|
7663
|
-
peers.map((peer) => /* @__PURE__ */ (0,
|
|
7966
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
7967
|
+
peers.map((peer) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7664
7968
|
"div",
|
|
7665
7969
|
{
|
|
7666
7970
|
ref: (el) => {
|
|
@@ -7672,7 +7976,7 @@ function PeerCursors() {
|
|
|
7672
7976
|
},
|
|
7673
7977
|
`ring-${peer.id}`
|
|
7674
7978
|
)),
|
|
7675
|
-
peers.map((peer, index) => /* @__PURE__ */ (0,
|
|
7979
|
+
peers.map((peer, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7676
7980
|
"div",
|
|
7677
7981
|
{
|
|
7678
7982
|
ref: (el) => {
|
|
@@ -7682,8 +7986,8 @@ function PeerCursors() {
|
|
|
7682
7986
|
className: "rk-peer-cursor",
|
|
7683
7987
|
style: { opacity: 0 },
|
|
7684
7988
|
children: [
|
|
7685
|
-
/* @__PURE__ */ (0,
|
|
7686
|
-
/* @__PURE__ */ (0,
|
|
7989
|
+
/* @__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" }) }),
|
|
7990
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7687
7991
|
"span",
|
|
7688
7992
|
{
|
|
7689
7993
|
className: "rk-peer-name",
|
|
@@ -7702,19 +8006,19 @@ function PeerCursors() {
|
|
|
7702
8006
|
}
|
|
7703
8007
|
|
|
7704
8008
|
// src/client/components/QuickComment.tsx
|
|
7705
|
-
var
|
|
7706
|
-
var
|
|
8009
|
+
var import_react16 = require("react");
|
|
8010
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
7707
8011
|
function QuickComment() {
|
|
7708
8012
|
const { quick } = useStore();
|
|
7709
8013
|
if (!quick) return null;
|
|
7710
|
-
return /* @__PURE__ */ (0,
|
|
8014
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(QuickComposerCard, { quick }, quick.id);
|
|
7711
8015
|
}
|
|
7712
8016
|
function QuickComposerCard({ quick }) {
|
|
7713
8017
|
const { route, session } = useStore();
|
|
7714
8018
|
const dispatch = useDispatch();
|
|
7715
|
-
const [text, setText] = (0,
|
|
7716
|
-
const fieldRef = (0,
|
|
7717
|
-
(0,
|
|
8019
|
+
const [text, setText] = (0, import_react16.useState)("");
|
|
8020
|
+
const fieldRef = (0, import_react16.useRef)(null);
|
|
8021
|
+
(0, import_react16.useEffect)(() => {
|
|
7718
8022
|
const field = fieldRef.current;
|
|
7719
8023
|
if (!field) return;
|
|
7720
8024
|
field.focus();
|
|
@@ -7767,18 +8071,18 @@ function QuickComposerCard({ quick }) {
|
|
|
7767
8071
|
};
|
|
7768
8072
|
const x = Math.min(Math.max(quick.x, 8), window.innerWidth - 288);
|
|
7769
8073
|
const y = Math.min(Math.max(quick.y + 12, 8), window.innerHeight - 108);
|
|
7770
|
-
return /* @__PURE__ */ (0,
|
|
7771
|
-
/* @__PURE__ */ (0,
|
|
7772
|
-
/* @__PURE__ */ (0,
|
|
7773
|
-
/* @__PURE__ */ (0,
|
|
7774
|
-
/* @__PURE__ */ (0,
|
|
7775
|
-
/* @__PURE__ */ (0,
|
|
8074
|
+
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: [
|
|
8075
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rk-quick-head", children: [
|
|
8076
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(IconComment, { size: 12 }),
|
|
8077
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Comment here" }),
|
|
8078
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "rk-hint", children: [
|
|
8079
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
|
|
7776
8080
|
" save \xB7 ",
|
|
7777
|
-
/* @__PURE__ */ (0,
|
|
8081
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
7778
8082
|
" cancel"
|
|
7779
8083
|
] })
|
|
7780
8084
|
] }),
|
|
7781
|
-
/* @__PURE__ */ (0,
|
|
8085
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7782
8086
|
"textarea",
|
|
7783
8087
|
{
|
|
7784
8088
|
ref: fieldRef,
|
|
@@ -7794,8 +8098,8 @@ function QuickComposerCard({ quick }) {
|
|
|
7794
8098
|
}
|
|
7795
8099
|
|
|
7796
8100
|
// src/client/components/PickLayer.tsx
|
|
7797
|
-
var
|
|
7798
|
-
var
|
|
8101
|
+
var import_react17 = require("react");
|
|
8102
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
7799
8103
|
function applyRect(el, rect, pad2 = 3) {
|
|
7800
8104
|
if (!el) return;
|
|
7801
8105
|
if (!rect) {
|
|
@@ -7810,14 +8114,14 @@ function applyRect(el, rect, pad2 = 3) {
|
|
|
7810
8114
|
function PickLayer() {
|
|
7811
8115
|
const { mode, selection, tool } = useStore();
|
|
7812
8116
|
const dispatch = useDispatch();
|
|
7813
|
-
const [hovered, setHovered] = (0,
|
|
7814
|
-
const outlineRef = (0,
|
|
7815
|
-
const labelRef = (0,
|
|
7816
|
-
const selectRef = (0,
|
|
7817
|
-
const hoveredRef = (0,
|
|
8117
|
+
const [hovered, setHovered] = (0, import_react17.useState)(null);
|
|
8118
|
+
const outlineRef = (0, import_react17.useRef)(null);
|
|
8119
|
+
const labelRef = (0, import_react17.useRef)(null);
|
|
8120
|
+
const selectRef = (0, import_react17.useRef)(null);
|
|
8121
|
+
const hoveredRef = (0, import_react17.useRef)(null);
|
|
7818
8122
|
hoveredRef.current = hovered;
|
|
7819
8123
|
const picking = mode === "pick";
|
|
7820
|
-
(0,
|
|
8124
|
+
(0, import_react17.useEffect)(() => {
|
|
7821
8125
|
if (!picking) {
|
|
7822
8126
|
setHovered(null);
|
|
7823
8127
|
return;
|
|
@@ -7861,7 +8165,7 @@ function PickLayer() {
|
|
|
7861
8165
|
document.removeEventListener("mousedown", swallow, true);
|
|
7862
8166
|
};
|
|
7863
8167
|
}, [picking, tool, dispatch]);
|
|
7864
|
-
(0,
|
|
8168
|
+
(0, import_react17.useEffect)(() => {
|
|
7865
8169
|
if (!picking) return;
|
|
7866
8170
|
const body = document.body;
|
|
7867
8171
|
const prev = body.style.cursor;
|
|
@@ -7871,7 +8175,7 @@ function PickLayer() {
|
|
|
7871
8175
|
if (body.getAttribute("style") === "") body.removeAttribute("style");
|
|
7872
8176
|
};
|
|
7873
8177
|
}, [picking, tool]);
|
|
7874
|
-
(0,
|
|
8178
|
+
(0, import_react17.useEffect)(() => {
|
|
7875
8179
|
let raf = 0;
|
|
7876
8180
|
const tick = () => {
|
|
7877
8181
|
const hoverEl = hoveredRef.current;
|
|
@@ -7897,21 +8201,21 @@ function PickLayer() {
|
|
|
7897
8201
|
raf = requestAnimationFrame(tick);
|
|
7898
8202
|
return () => cancelAnimationFrame(raf);
|
|
7899
8203
|
}, [picking, selection]);
|
|
7900
|
-
return /* @__PURE__ */ (0,
|
|
7901
|
-
picking && /* @__PURE__ */ (0,
|
|
7902
|
-
/* @__PURE__ */ (0,
|
|
7903
|
-
/* @__PURE__ */ (0,
|
|
7904
|
-
/* @__PURE__ */ (0,
|
|
7905
|
-
/* @__PURE__ */ (0,
|
|
7906
|
-
] }) : /* @__PURE__ */ (0,
|
|
8204
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
8205
|
+
picking && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
8206
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: outlineRef, className: "rk-outline", style: { opacity: 0 } }),
|
|
8207
|
+
/* @__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: [
|
|
8208
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rk-tag", children: hovered.tagName.toLowerCase() }),
|
|
8209
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: describeElement(hovered).replace(/^[a-z0-9]+ · /, "") })
|
|
8210
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Pick an element" }) })
|
|
7907
8211
|
] }),
|
|
7908
|
-
selection && /* @__PURE__ */ (0,
|
|
8212
|
+
selection && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: selectRef, className: "rk-select-ring", style: { opacity: 0 } })
|
|
7909
8213
|
] });
|
|
7910
8214
|
}
|
|
7911
8215
|
|
|
7912
8216
|
// src/client/components/Pins.tsx
|
|
7913
|
-
var
|
|
7914
|
-
var
|
|
8217
|
+
var import_react18 = require("react");
|
|
8218
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
7915
8219
|
var STATUS_LABELS = {
|
|
7916
8220
|
open: "open",
|
|
7917
8221
|
accepted: "accepted",
|
|
@@ -7923,22 +8227,22 @@ var RERESOLVE_MS = 800;
|
|
|
7923
8227
|
function Pins() {
|
|
7924
8228
|
const { session, route, activeItemId, editor, mode, filter } = useStore();
|
|
7925
8229
|
const dispatch = useDispatch();
|
|
7926
|
-
const [clusters, setClusters] = (0,
|
|
7927
|
-
const [orphanCount, setOrphanCount] = (0,
|
|
7928
|
-
const wrapRefs = (0,
|
|
7929
|
-
const visibleCache = (0,
|
|
7930
|
-
const highlightRef = (0,
|
|
7931
|
-
const hoveredItems = (0,
|
|
7932
|
-
const elementCache = (0,
|
|
7933
|
-
const lastResolve = (0,
|
|
7934
|
-
const [newestId, setNewestId] = (0,
|
|
7935
|
-
const prevCount = (0,
|
|
7936
|
-
const items = (0,
|
|
8230
|
+
const [clusters, setClusters] = (0, import_react18.useState)([]);
|
|
8231
|
+
const [orphanCount, setOrphanCount] = (0, import_react18.useState)(0);
|
|
8232
|
+
const wrapRefs = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
8233
|
+
const visibleCache = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
8234
|
+
const highlightRef = (0, import_react18.useRef)(null);
|
|
8235
|
+
const hoveredItems = (0, import_react18.useRef)(null);
|
|
8236
|
+
const elementCache = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
8237
|
+
const lastResolve = (0, import_react18.useRef)(0);
|
|
8238
|
+
const [newestId, setNewestId] = (0, import_react18.useState)(null);
|
|
8239
|
+
const prevCount = (0, import_react18.useRef)(0);
|
|
8240
|
+
const items = (0, import_react18.useMemo)(() => {
|
|
7937
8241
|
const all = session?.items ?? [];
|
|
7938
8242
|
return all.map((item, index) => ({ item, number: index + 1 })).filter(({ item }) => item.route === route);
|
|
7939
8243
|
}, [session, route]);
|
|
7940
8244
|
const byId = new Map(items.map(({ item }) => [item.id, item]));
|
|
7941
|
-
(0,
|
|
8245
|
+
(0, import_react18.useEffect)(() => {
|
|
7942
8246
|
const count = session?.items.length ?? 0;
|
|
7943
8247
|
if (count > prevCount.current && session && count > 0) {
|
|
7944
8248
|
const id = session.items[count - 1].id;
|
|
@@ -7949,7 +8253,7 @@ function Pins() {
|
|
|
7949
8253
|
}
|
|
7950
8254
|
prevCount.current = count;
|
|
7951
8255
|
}, [session]);
|
|
7952
|
-
(0,
|
|
8256
|
+
(0, import_react18.useEffect)(() => {
|
|
7953
8257
|
let raf = 0;
|
|
7954
8258
|
let lastSignature = "";
|
|
7955
8259
|
const tick = (time) => {
|
|
@@ -8033,8 +8337,8 @@ function Pins() {
|
|
|
8033
8337
|
dispatch({ type: "SET_ACTIVE_ITEM", id });
|
|
8034
8338
|
dispatch({ type: "SET_PANEL", open: true });
|
|
8035
8339
|
};
|
|
8036
|
-
return /* @__PURE__ */ (0,
|
|
8037
|
-
/* @__PURE__ */ (0,
|
|
8340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
8341
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref: highlightRef, className: "rk-hl-ring", style: { opacity: 0 } }),
|
|
8038
8342
|
clusters.map((cluster) => {
|
|
8039
8343
|
const isCluster = cluster.ids.length > 1;
|
|
8040
8344
|
const isActive = activeItemId !== null && cluster.ids.includes(activeItemId);
|
|
@@ -8044,7 +8348,7 @@ function Pins() {
|
|
|
8044
8348
|
const status = statuses.size === 1 ? members[0]?.status : void 0;
|
|
8045
8349
|
const dimmed = filter !== null && members.length > 0 && !members.some((item) => itemMatchesFilter(item, filter));
|
|
8046
8350
|
const statusHint = isCluster ? status ? ` \xB7 all ${STATUS_LABELS[status] ?? status}` : "" : ` \xB7 ${STATUS_LABELS[members[0]?.status ?? "open"] ?? members[0]?.status}`;
|
|
8047
|
-
return /* @__PURE__ */ (0,
|
|
8351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
8048
8352
|
"div",
|
|
8049
8353
|
{
|
|
8050
8354
|
ref: (el) => {
|
|
@@ -8052,7 +8356,7 @@ function Pins() {
|
|
|
8052
8356
|
else wrapRefs.current.delete(cluster.key);
|
|
8053
8357
|
},
|
|
8054
8358
|
className: `rk-pin-wrap${picking ? " rk-pin-ghost" : ""}`,
|
|
8055
|
-
children: /* @__PURE__ */ (0,
|
|
8359
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
8056
8360
|
"button",
|
|
8057
8361
|
{
|
|
8058
8362
|
type: "button",
|
|
@@ -8074,7 +8378,7 @@ function Pins() {
|
|
|
8074
8378
|
cluster.key
|
|
8075
8379
|
);
|
|
8076
8380
|
}),
|
|
8077
|
-
orphanCount > 0 && /* @__PURE__ */ (0,
|
|
8381
|
+
orphanCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
8078
8382
|
"button",
|
|
8079
8383
|
{
|
|
8080
8384
|
type: "button",
|
|
@@ -8082,7 +8386,7 @@ function Pins() {
|
|
|
8082
8386
|
style: { bottom: 16, left: "50%", transform: "translateX(-50%)" },
|
|
8083
8387
|
onClick: () => dispatch({ type: "SET_PANEL", open: true }),
|
|
8084
8388
|
children: [
|
|
8085
|
-
/* @__PURE__ */ (0,
|
|
8389
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconUnlink, { size: 13 }),
|
|
8086
8390
|
orphanCount,
|
|
8087
8391
|
" unanchored item",
|
|
8088
8392
|
orphanCount === 1 ? "" : "s"
|
|
@@ -8093,13 +8397,13 @@ function Pins() {
|
|
|
8093
8397
|
}
|
|
8094
8398
|
|
|
8095
8399
|
// src/client/components/Toolbar.tsx
|
|
8096
|
-
var
|
|
8097
|
-
var
|
|
8400
|
+
var import_react19 = require("react");
|
|
8401
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
8098
8402
|
var TOOLS = [
|
|
8099
|
-
{ tool: "select", hintId: "tool-select", label: "Select", icon: (n) => /* @__PURE__ */ (0,
|
|
8100
|
-
{ tool: "copy", hintId: "tool-copy", label: "Rewrite text", icon: (n) => /* @__PURE__ */ (0,
|
|
8101
|
-
{ tool: "comment", hintId: "tool-comment", label: "Comment", icon: (n) => /* @__PURE__ */ (0,
|
|
8102
|
-
{ tool: "image", hintId: "tool-image", label: "Replace image", icon: (n) => /* @__PURE__ */ (0,
|
|
8403
|
+
{ tool: "select", hintId: "tool-select", label: "Select", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconTarget, { size: n }) },
|
|
8404
|
+
{ tool: "copy", hintId: "tool-copy", label: "Rewrite text", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconText, { size: n }) },
|
|
8405
|
+
{ tool: "comment", hintId: "tool-comment", label: "Comment", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: n }) },
|
|
8406
|
+
{ tool: "image", hintId: "tool-image", label: "Replace image", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconImage, { size: n }) }
|
|
8103
8407
|
];
|
|
8104
8408
|
var POS_KEY2 = "review-kit:toolbar-pos";
|
|
8105
8409
|
var DRAG_THRESHOLD2 = 6;
|
|
@@ -8107,24 +8411,24 @@ function Toolbar() {
|
|
|
8107
8411
|
const { selection, editor, peers, syncStatus, mode, tool } = useStore();
|
|
8108
8412
|
const hasPeers = syncStatus !== "disabled" && peers.length > 0;
|
|
8109
8413
|
const dispatch = useDispatch();
|
|
8110
|
-
const ref = (0,
|
|
8111
|
-
const [pos, setPos] = (0,
|
|
8112
|
-
const drag = (0,
|
|
8113
|
-
const [dragging, setDragging] = (0,
|
|
8114
|
-
const justDragged = (0,
|
|
8414
|
+
const ref = (0, import_react19.useRef)(null);
|
|
8415
|
+
const [pos, setPos] = (0, import_react19.useState)(() => readStoredPos(POS_KEY2));
|
|
8416
|
+
const drag = (0, import_react19.useRef)(null);
|
|
8417
|
+
const [dragging, setDragging] = (0, import_react19.useState)(false);
|
|
8418
|
+
const justDragged = (0, import_react19.useRef)(false);
|
|
8115
8419
|
const visible = editor === null || selection !== null;
|
|
8116
8420
|
const applyPos = (next, persist) => {
|
|
8117
8421
|
if (next === null && ref.current) ref.current.style.bottom = "";
|
|
8118
8422
|
setPos(next);
|
|
8119
8423
|
if (persist) storePos(POS_KEY2, next);
|
|
8120
8424
|
};
|
|
8121
|
-
(0,
|
|
8425
|
+
(0, import_react19.useLayoutEffect)(() => {
|
|
8122
8426
|
const el = ref.current;
|
|
8123
8427
|
if (!el || pos === null) return;
|
|
8124
8428
|
const clamped = clampPos(pos.x, pos.y, el.offsetWidth, el.offsetHeight);
|
|
8125
8429
|
if (clamped.x !== pos.x || clamped.y !== pos.y) applyPos(clamped, true);
|
|
8126
8430
|
}, [pos, selection, hasPeers, visible]);
|
|
8127
|
-
(0,
|
|
8431
|
+
(0, import_react19.useEffect)(() => {
|
|
8128
8432
|
const onResize = () => {
|
|
8129
8433
|
const el = ref.current;
|
|
8130
8434
|
const current = readStoredPos(POS_KEY2);
|
|
@@ -8237,7 +8541,7 @@ function Toolbar() {
|
|
|
8237
8541
|
mode === "pick" && selection === null ? "rk-ghost" : ""
|
|
8238
8542
|
].filter(Boolean).join(" ");
|
|
8239
8543
|
const style = pos !== null ? { left: 0, top: 0, translate: `${pos.x}px ${pos.y}px` } : void 0;
|
|
8240
|
-
return /* @__PURE__ */ (0,
|
|
8544
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8241
8545
|
"div",
|
|
8242
8546
|
{
|
|
8243
8547
|
ref,
|
|
@@ -8248,7 +8552,7 @@ function Toolbar() {
|
|
|
8248
8552
|
onPointerDown,
|
|
8249
8553
|
onClickCapture,
|
|
8250
8554
|
children: [
|
|
8251
|
-
/* @__PURE__ */ (0,
|
|
8555
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
8252
8556
|
"button",
|
|
8253
8557
|
{
|
|
8254
8558
|
type: "button",
|
|
@@ -8256,19 +8560,19 @@ function Toolbar() {
|
|
|
8256
8560
|
"aria-label": "Move the toolbar \u2014 drag, or use arrow keys; double-click to reset its position",
|
|
8257
8561
|
onKeyDown: onGripKeyDown,
|
|
8258
8562
|
onDoubleClick: () => applyPos(null, true),
|
|
8259
|
-
children: /* @__PURE__ */ (0,
|
|
8260
|
-
/* @__PURE__ */ (0,
|
|
8261
|
-
/* @__PURE__ */ (0,
|
|
8262
|
-
/* @__PURE__ */ (0,
|
|
8263
|
-
/* @__PURE__ */ (0,
|
|
8264
|
-
/* @__PURE__ */ (0,
|
|
8265
|
-
/* @__PURE__ */ (0,
|
|
8563
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("svg", { width: "8", height: "14", viewBox: "0 0 8 14", "aria-hidden": "true", fill: "currentColor", children: [
|
|
8564
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "2", r: "1.1" }),
|
|
8565
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "2", r: "1.1" }),
|
|
8566
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "7", r: "1.1" }),
|
|
8567
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "7", r: "1.1" }),
|
|
8568
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "12", r: "1.1" }),
|
|
8569
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "12", r: "1.1" })
|
|
8266
8570
|
] })
|
|
8267
8571
|
}
|
|
8268
8572
|
),
|
|
8269
|
-
/* @__PURE__ */ (0,
|
|
8270
|
-
hasPeers && /* @__PURE__ */ (0,
|
|
8271
|
-
/* @__PURE__ */ (0,
|
|
8573
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PresenceStrip, {}),
|
|
8574
|
+
hasPeers && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
|
|
8575
|
+
/* @__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)(
|
|
8272
8576
|
"button",
|
|
8273
8577
|
{
|
|
8274
8578
|
type: "button",
|
|
@@ -8280,9 +8584,9 @@ function Toolbar() {
|
|
|
8280
8584
|
},
|
|
8281
8585
|
entry.tool
|
|
8282
8586
|
)) }),
|
|
8283
|
-
selection && /* @__PURE__ */ (0,
|
|
8284
|
-
selection && /* @__PURE__ */ (0,
|
|
8285
|
-
/* @__PURE__ */ (0,
|
|
8587
|
+
selection && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
|
|
8588
|
+
selection && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
8589
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8286
8590
|
"button",
|
|
8287
8591
|
{
|
|
8288
8592
|
type: "button",
|
|
@@ -8291,12 +8595,12 @@ function Toolbar() {
|
|
|
8291
8595
|
title: `Rewrite text${keyHint("tool-copy")}`,
|
|
8292
8596
|
onClick: () => open("copy"),
|
|
8293
8597
|
children: [
|
|
8294
|
-
/* @__PURE__ */ (0,
|
|
8598
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconText, { size: 14 }),
|
|
8295
8599
|
" Rewrite"
|
|
8296
8600
|
]
|
|
8297
8601
|
}
|
|
8298
8602
|
),
|
|
8299
|
-
hasImage && /* @__PURE__ */ (0,
|
|
8603
|
+
hasImage && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8300
8604
|
"button",
|
|
8301
8605
|
{
|
|
8302
8606
|
type: "button",
|
|
@@ -8305,12 +8609,12 @@ function Toolbar() {
|
|
|
8305
8609
|
title: `Replace image${keyHint("tool-image")}`,
|
|
8306
8610
|
onClick: () => open("image"),
|
|
8307
8611
|
children: [
|
|
8308
|
-
/* @__PURE__ */ (0,
|
|
8612
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconImage, { size: 14 }),
|
|
8309
8613
|
" Image"
|
|
8310
8614
|
]
|
|
8311
8615
|
}
|
|
8312
8616
|
),
|
|
8313
|
-
/* @__PURE__ */ (0,
|
|
8617
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8314
8618
|
"button",
|
|
8315
8619
|
{
|
|
8316
8620
|
type: "button",
|
|
@@ -8319,32 +8623,32 @@ function Toolbar() {
|
|
|
8319
8623
|
title: `Comment${keyHint("tool-comment")}`,
|
|
8320
8624
|
onClick: () => open("comment"),
|
|
8321
8625
|
children: [
|
|
8322
|
-
/* @__PURE__ */ (0,
|
|
8626
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: 14 }),
|
|
8323
8627
|
" Comment"
|
|
8324
8628
|
]
|
|
8325
8629
|
}
|
|
8326
8630
|
),
|
|
8327
|
-
/* @__PURE__ */ (0,
|
|
8328
|
-
/* @__PURE__ */ (0,
|
|
8631
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("style"), children: [
|
|
8632
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconStyle, { size: 14 }),
|
|
8329
8633
|
" Style"
|
|
8330
8634
|
] }),
|
|
8331
|
-
/* @__PURE__ */ (0,
|
|
8332
|
-
/* @__PURE__ */ (0,
|
|
8635
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("move"), children: [
|
|
8636
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconMove, { size: 14 }),
|
|
8333
8637
|
" Move"
|
|
8334
8638
|
] }),
|
|
8335
|
-
/* @__PURE__ */ (0,
|
|
8336
|
-
/* @__PURE__ */ (0,
|
|
8639
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn rk-danger", onClick: () => open("delete"), children: [
|
|
8640
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconTrash, { size: 14 }),
|
|
8337
8641
|
" Delete"
|
|
8338
8642
|
] }),
|
|
8339
|
-
/* @__PURE__ */ (0,
|
|
8340
|
-
/* @__PURE__ */ (0,
|
|
8643
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
|
|
8644
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
8341
8645
|
"button",
|
|
8342
8646
|
{
|
|
8343
8647
|
type: "button",
|
|
8344
8648
|
className: "rk-icon-btn",
|
|
8345
8649
|
"aria-label": "Deselect",
|
|
8346
8650
|
onClick: () => dispatch({ type: "SELECT", selection: null }),
|
|
8347
|
-
children: /* @__PURE__ */ (0,
|
|
8651
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconClose, { size: 13 })
|
|
8348
8652
|
}
|
|
8349
8653
|
)
|
|
8350
8654
|
] })
|
|
@@ -8354,40 +8658,40 @@ function Toolbar() {
|
|
|
8354
8658
|
}
|
|
8355
8659
|
|
|
8356
8660
|
// src/client/components/Toast.tsx
|
|
8357
|
-
var
|
|
8358
|
-
var
|
|
8661
|
+
var import_react20 = require("react");
|
|
8662
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
8359
8663
|
function ToastRow({ toast: toast2 }) {
|
|
8360
8664
|
const dispatch = useDispatch();
|
|
8361
|
-
(0,
|
|
8665
|
+
(0, import_react20.useEffect)(() => {
|
|
8362
8666
|
const timer = window.setTimeout(() => dispatch({ type: "DISMISS_TOAST", id: toast2.id }), 3500);
|
|
8363
8667
|
return () => window.clearTimeout(timer);
|
|
8364
8668
|
}, [toast2.id, dispatch]);
|
|
8365
|
-
return /* @__PURE__ */ (0,
|
|
8366
|
-
toast2.tone === "success" ? /* @__PURE__ */ (0,
|
|
8669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `rk-toast rk-${toast2.tone}`, role: "status", children: [
|
|
8670
|
+
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 }),
|
|
8367
8671
|
toast2.message
|
|
8368
8672
|
] });
|
|
8369
8673
|
}
|
|
8370
8674
|
function ToastHost() {
|
|
8371
8675
|
const { toasts } = useStore();
|
|
8372
8676
|
if (toasts.length === 0) return null;
|
|
8373
|
-
return /* @__PURE__ */ (0,
|
|
8677
|
+
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)) });
|
|
8374
8678
|
}
|
|
8375
8679
|
|
|
8376
8680
|
// src/client/App.tsx
|
|
8377
|
-
var
|
|
8681
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
8378
8682
|
function App() {
|
|
8379
8683
|
const state = useStore();
|
|
8380
8684
|
const rawDispatch = useDispatch();
|
|
8381
8685
|
const config = useConfig();
|
|
8382
8686
|
const dispatch = useRealtimeSync(state, rawDispatch, config, reducer);
|
|
8383
|
-
const saveTimer = (0,
|
|
8687
|
+
const saveTimer = (0, import_react21.useRef)(null);
|
|
8384
8688
|
const storageKey = config.storageKey ?? defaultStorageKey();
|
|
8385
8689
|
useAppliedPreview(state, dispatch);
|
|
8386
8690
|
useEmblemaAutoPush(state, dispatch, config);
|
|
8387
|
-
(0,
|
|
8691
|
+
(0, import_react21.useEffect)(() => {
|
|
8388
8692
|
setEffectAssetsUrl(config.fxAssetsUrl);
|
|
8389
8693
|
}, [config.fxAssetsUrl]);
|
|
8390
|
-
(0,
|
|
8694
|
+
(0, import_react21.useEffect)(() => {
|
|
8391
8695
|
let cancelled = false;
|
|
8392
8696
|
void loadSession(storageKey).then((stored) => {
|
|
8393
8697
|
if (cancelled) return;
|
|
@@ -8405,7 +8709,7 @@ function App() {
|
|
|
8405
8709
|
};
|
|
8406
8710
|
}, [storageKey, config.defaultAuthor, dispatch]);
|
|
8407
8711
|
const { session } = state;
|
|
8408
|
-
(0,
|
|
8712
|
+
(0, import_react21.useEffect)(() => {
|
|
8409
8713
|
if (!session) return;
|
|
8410
8714
|
if (saveTimer.current !== null) window.clearTimeout(saveTimer.current);
|
|
8411
8715
|
saveTimer.current = window.setTimeout(() => {
|
|
@@ -8416,9 +8720,9 @@ function App() {
|
|
|
8416
8720
|
if (saveTimer.current !== null) window.clearTimeout(saveTimer.current);
|
|
8417
8721
|
};
|
|
8418
8722
|
}, [session, storageKey, config]);
|
|
8419
|
-
(0,
|
|
8420
|
-
const focusHandled = (0,
|
|
8421
|
-
(0,
|
|
8723
|
+
(0, import_react21.useEffect)(() => trackPointer(), []);
|
|
8724
|
+
const focusHandled = (0, import_react21.useRef)(false);
|
|
8725
|
+
(0, import_react21.useEffect)(() => {
|
|
8422
8726
|
if (!session || focusHandled.current) return;
|
|
8423
8727
|
focusHandled.current = true;
|
|
8424
8728
|
const id = takeFocusItem();
|
|
@@ -8443,7 +8747,7 @@ function App() {
|
|
|
8443
8747
|
cancelled = true;
|
|
8444
8748
|
};
|
|
8445
8749
|
}, [session, dispatch]);
|
|
8446
|
-
(0,
|
|
8750
|
+
(0, import_react21.useEffect)(() => {
|
|
8447
8751
|
let last = window.location.pathname;
|
|
8448
8752
|
const check = () => {
|
|
8449
8753
|
if (window.location.pathname !== last) {
|
|
@@ -8458,9 +8762,9 @@ function App() {
|
|
|
8458
8762
|
window.removeEventListener("popstate", check);
|
|
8459
8763
|
};
|
|
8460
8764
|
}, [dispatch]);
|
|
8461
|
-
const stateRef = (0,
|
|
8765
|
+
const stateRef = (0, import_react21.useRef)(state);
|
|
8462
8766
|
stateRef.current = state;
|
|
8463
|
-
(0,
|
|
8767
|
+
(0, import_react21.useEffect)(() => {
|
|
8464
8768
|
const onKeyDown = (event) => {
|
|
8465
8769
|
const current = stateRef.current;
|
|
8466
8770
|
for (const def of SHORTCUTS) {
|
|
@@ -8475,7 +8779,7 @@ function App() {
|
|
|
8475
8779
|
document.addEventListener("keydown", onKeyDown);
|
|
8476
8780
|
return () => document.removeEventListener("keydown", onKeyDown);
|
|
8477
8781
|
}, [dispatch]);
|
|
8478
|
-
(0,
|
|
8782
|
+
(0, import_react21.useEffect)(() => {
|
|
8479
8783
|
if (!state.editor) return;
|
|
8480
8784
|
const editorEl = state.editor.element;
|
|
8481
8785
|
const onPointerDown = (event) => {
|
|
@@ -8488,32 +8792,33 @@ function App() {
|
|
|
8488
8792
|
}, [state.editor, dispatch]);
|
|
8489
8793
|
if (!session) return null;
|
|
8490
8794
|
if (state.hidden) {
|
|
8491
|
-
return /* @__PURE__ */ (0,
|
|
8795
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DispatchContext.Provider, { value: dispatch, children: null });
|
|
8492
8796
|
}
|
|
8493
|
-
return /* @__PURE__ */ (0,
|
|
8494
|
-
/* @__PURE__ */ (0,
|
|
8495
|
-
/* @__PURE__ */ (0,
|
|
8496
|
-
/* @__PURE__ */ (0,
|
|
8497
|
-
state.editor?.kind === "copy" && /* @__PURE__ */ (0,
|
|
8498
|
-
state.editor?.kind === "image" && /* @__PURE__ */ (0,
|
|
8499
|
-
state.editor && state.editor.kind !== "copy" && state.editor.kind !== "image" && /* @__PURE__ */ (0,
|
|
8500
|
-
/* @__PURE__ */ (0,
|
|
8501
|
-
/* @__PURE__ */ (0,
|
|
8502
|
-
/* @__PURE__ */ (0,
|
|
8503
|
-
/* @__PURE__ */ (0,
|
|
8504
|
-
/* @__PURE__ */ (0,
|
|
8505
|
-
/* @__PURE__ */ (0,
|
|
8506
|
-
/* @__PURE__ */ (0,
|
|
8507
|
-
/* @__PURE__ */ (0,
|
|
8508
|
-
/* @__PURE__ */ (0,
|
|
8797
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DispatchContext.Provider, { value: dispatch, children: [
|
|
8798
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PickLayer, {}),
|
|
8799
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PeerCursors, {}),
|
|
8800
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Toolbar, {}),
|
|
8801
|
+
state.editor?.kind === "copy" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InlineEditor, { editor: state.editor }),
|
|
8802
|
+
state.editor?.kind === "image" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ImageEditor, { editor: state.editor }),
|
|
8803
|
+
state.editor && state.editor.kind !== "copy" && state.editor.kind !== "image" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NoteComposer, { editor: state.editor }),
|
|
8804
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pins, {}),
|
|
8805
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(QuickComment, {}),
|
|
8806
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Panel, {}),
|
|
8807
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Badge, {}),
|
|
8808
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CoachMark, {}),
|
|
8809
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CheatSheet, {}),
|
|
8810
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmblemaConnect, {}),
|
|
8811
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TerminalConnect, {}),
|
|
8812
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ConfirmHost, {}),
|
|
8813
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ToastHost, {})
|
|
8509
8814
|
] });
|
|
8510
8815
|
}
|
|
8511
8816
|
|
|
8512
8817
|
// src/client/ReviewKit.tsx
|
|
8513
|
-
var
|
|
8818
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
8514
8819
|
function ShadowHost({ config }) {
|
|
8515
|
-
const [mount, setMount] = (0,
|
|
8516
|
-
(0,
|
|
8820
|
+
const [mount, setMount] = (0, import_react22.useState)(null);
|
|
8821
|
+
(0, import_react22.useEffect)(() => {
|
|
8517
8822
|
const host = document.createElement("div");
|
|
8518
8823
|
host.setAttribute(HOST_ATTR, "");
|
|
8519
8824
|
host.style.position = "fixed";
|
|
@@ -8549,15 +8854,15 @@ function ShadowHost({ config }) {
|
|
|
8549
8854
|
}, []);
|
|
8550
8855
|
if (!mount) return null;
|
|
8551
8856
|
return (0, import_react_dom.createPortal)(
|
|
8552
|
-
/* @__PURE__ */ (0,
|
|
8857
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StoreProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(App, {}) }),
|
|
8553
8858
|
mount
|
|
8554
8859
|
);
|
|
8555
8860
|
}
|
|
8556
8861
|
function ReviewKit(props) {
|
|
8557
|
-
const [active2, setActive] = (0,
|
|
8862
|
+
const [active2, setActive] = (0, import_react22.useState)(false);
|
|
8558
8863
|
const { enabled, token, allowedHosts, devAutoOn } = props;
|
|
8559
8864
|
const hostsKey = allowedHosts?.join("\0") ?? "";
|
|
8560
|
-
(0,
|
|
8865
|
+
(0, import_react22.useEffect)(() => {
|
|
8561
8866
|
if (enabled === false) {
|
|
8562
8867
|
setActive(false);
|
|
8563
8868
|
return;
|
|
@@ -8568,7 +8873,7 @@ function ReviewKit(props) {
|
|
|
8568
8873
|
return () => window.removeEventListener(DEACTIVATE_EVENT, onDeactivate);
|
|
8569
8874
|
}, [enabled, token, devAutoOn, hostsKey]);
|
|
8570
8875
|
if (enabled === false || !active2) return null;
|
|
8571
|
-
return /* @__PURE__ */ (0,
|
|
8876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ShadowHost, { config: props });
|
|
8572
8877
|
}
|
|
8573
8878
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8574
8879
|
0 && (module.exports = {
|