@satanwagen/reviewkit 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -1
- package/README.md +41 -18
- package/dist/{chunk-NSXRFM75.js → chunk-5MAFDRUI.js} +746 -449
- package/dist/chunk-5MAFDRUI.js.map +1 -0
- package/dist/{chunk-Q7U43PXE.js → chunk-EOX3UJNP.js} +1 -1
- package/dist/client/index.cjs +794 -497
- 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 +794 -497
- 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 +840 -520
- 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 +840 -520
- 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-EOX3UJNP.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,18 @@ 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 resolveSyncUrl(config) {
|
|
4972
|
+
return typeof config.syncUrl === "string" && config.syncUrl !== "" ? config.syncUrl : DEFAULT_SYNC_URL;
|
|
4973
|
+
}
|
|
4974
|
+
var MIN_SYNC_TOKEN_LENGTH = 8;
|
|
4975
|
+
var warnedShortToken = false;
|
|
4976
|
+
function resolveSyncToken(config) {
|
|
4977
|
+
if (config.sync === false) return null;
|
|
4978
|
+
const explicit = typeof config.syncToken === "string" && config.syncToken !== "" ? config.syncToken : null;
|
|
4979
|
+
const fallback = typeof config.token === "string" && config.token !== "" ? config.token : null;
|
|
4980
|
+
return explicit ?? fallback;
|
|
4981
|
+
}
|
|
4957
4982
|
function toPeerState(peer) {
|
|
4958
4983
|
return {
|
|
4959
4984
|
id: peer.id,
|
|
@@ -4981,20 +5006,43 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
|
|
|
4981
5006
|
const stateRef = (0, import_react4.useRef)(state);
|
|
4982
5007
|
stateRef.current = state;
|
|
4983
5008
|
const myIdRef = (0, import_react4.useRef)("");
|
|
4984
|
-
const
|
|
5009
|
+
const syncToken = resolveSyncToken(config);
|
|
5010
|
+
const syncUrl = resolveSyncUrl(config);
|
|
5011
|
+
const enabled = syncToken !== null;
|
|
4985
5012
|
const author = state.session?.author ?? "";
|
|
4986
5013
|
const hasSession = state.session !== null;
|
|
4987
5014
|
(0, import_react4.useEffect)(() => {
|
|
4988
5015
|
if (!enabled || !hasSession) return;
|
|
5016
|
+
const dispatchGuard = rawDispatch;
|
|
5017
|
+
if (syncToken.length < MIN_SYNC_TOKEN_LENGTH) {
|
|
5018
|
+
dispatchGuard({ type: "SYNC_STATUS", status: "offline", reason: "token-short" });
|
|
5019
|
+
if (!warnedShortToken) {
|
|
5020
|
+
warnedShortToken = true;
|
|
5021
|
+
console.warn(
|
|
5022
|
+
`[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.`
|
|
5023
|
+
);
|
|
5024
|
+
}
|
|
5025
|
+
return () => dispatchGuard({ type: "SYNC_STATUS", status: "disabled", reason: null });
|
|
5026
|
+
}
|
|
4989
5027
|
const id = reviewerId();
|
|
4990
5028
|
myIdRef.current = id;
|
|
4991
5029
|
const dispatch = rawDispatch;
|
|
4992
5030
|
const sync = createRkSync({
|
|
4993
|
-
token:
|
|
4994
|
-
url:
|
|
5031
|
+
token: syncToken,
|
|
5032
|
+
url: syncUrl,
|
|
4995
5033
|
user: { id, name: author || "Reviewer", color: colorForReviewer(id) },
|
|
4996
5034
|
handlers: {
|
|
4997
|
-
onStatus: (status) => dispatch({
|
|
5035
|
+
onStatus: (status) => dispatch({
|
|
5036
|
+
type: "SYNC_STATUS",
|
|
5037
|
+
status,
|
|
5038
|
+
// Offline with no server verdict = the socket never got through
|
|
5039
|
+
// (server down, CSP connect-src, network); a verdict keeps its reason.
|
|
5040
|
+
...status === "offline" ? { reason: stateRef.current.syncReason ?? "unreachable" } : {}
|
|
5041
|
+
}),
|
|
5042
|
+
onError: (code) => {
|
|
5043
|
+
if (code === "bad-token") dispatch({ type: "SYNC_STATUS", status: "offline", reason: "bad-token" });
|
|
5044
|
+
else if (code === "room-full") dispatch({ type: "SYNC_STATUS", status: "offline", reason: "room-full" });
|
|
5045
|
+
},
|
|
4998
5046
|
onSnapshot: (items, peers, deletedIds = []) => {
|
|
4999
5047
|
const safeItems = items.map(sanitizeRemoteItem).filter((item) => item !== null);
|
|
5000
5048
|
dispatch({ type: "SYNC_SNAPSHOT", items: safeItems });
|
|
@@ -5051,10 +5099,10 @@ function useRealtimeSync(state, rawDispatch, config, reducer2) {
|
|
|
5051
5099
|
if (activeSyncRef === sync) activeSyncRef = null;
|
|
5052
5100
|
setEffectBroadcaster2(null);
|
|
5053
5101
|
sync.stop();
|
|
5054
|
-
dispatch({ type: "SYNC_STATUS", status: "disabled" });
|
|
5102
|
+
dispatch({ type: "SYNC_STATUS", status: "disabled", reason: null });
|
|
5055
5103
|
dispatch({ type: "PEERS_SET", peers: [] });
|
|
5056
5104
|
};
|
|
5057
|
-
}, [enabled, hasSession,
|
|
5105
|
+
}, [enabled, hasSession, syncToken, syncUrl, author, rawDispatch]);
|
|
5058
5106
|
const wrapped = (0, import_react4.useMemo)(() => {
|
|
5059
5107
|
return (action) => {
|
|
5060
5108
|
const prev = stateRef.current;
|
|
@@ -5570,10 +5618,10 @@ function EmblemaConnect() {
|
|
|
5570
5618
|
state === null && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5571
5619
|
"The local sync agent isn't running. In the project repo run:",
|
|
5572
5620
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("code", { className: "rk-connect-cmd", children: [
|
|
5573
|
-
"npx @satanwagen/reviewkit-cli init --origin ",
|
|
5621
|
+
"npx -p @satanwagen/reviewkit-cli reviewkit-emblema init --origin ",
|
|
5574
5622
|
window.location.origin
|
|
5575
5623
|
] }),
|
|
5576
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "rk-connect-cmd", children: "npx @satanwagen/reviewkit-cli serve" }),
|
|
5624
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "rk-connect-cmd", children: "npx -p @satanwagen/reviewkit-cli reviewkit-emblema serve" }),
|
|
5577
5625
|
"then reopen this dialog."
|
|
5578
5626
|
] }),
|
|
5579
5627
|
state !== null && state !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
@@ -5660,15 +5708,229 @@ function EmblemaConnect() {
|
|
|
5660
5708
|
] });
|
|
5661
5709
|
}
|
|
5662
5710
|
|
|
5663
|
-
// src/client/components/
|
|
5711
|
+
// src/client/components/TerminalConnect.tsx
|
|
5664
5712
|
var import_react7 = require("react");
|
|
5713
|
+
|
|
5714
|
+
// src/integrations/terminal.ts
|
|
5715
|
+
var TERMINAL_PAIR_PORTS = [48780, 48781, 48782, 48783];
|
|
5716
|
+
async function fetchJson2(url, init, timeoutMs) {
|
|
5717
|
+
const abort = new AbortController();
|
|
5718
|
+
const timer = window.setTimeout(() => abort.abort(), timeoutMs);
|
|
5719
|
+
try {
|
|
5720
|
+
return await fetch(url, { ...init, signal: abort.signal });
|
|
5721
|
+
} finally {
|
|
5722
|
+
window.clearTimeout(timer);
|
|
5723
|
+
}
|
|
5724
|
+
}
|
|
5725
|
+
async function probeTerminal() {
|
|
5726
|
+
for (const port of TERMINAL_PAIR_PORTS) {
|
|
5727
|
+
try {
|
|
5728
|
+
const res = await fetchJson2(`http://127.0.0.1:${port}/pair`, { method: "GET" }, 900);
|
|
5729
|
+
if (!res.ok) continue;
|
|
5730
|
+
const body = await res.json();
|
|
5731
|
+
if (typeof body === "object" && body !== null && body.app === "reviewkit-cli") {
|
|
5732
|
+
const b = body;
|
|
5733
|
+
return {
|
|
5734
|
+
port,
|
|
5735
|
+
cwd: typeof b.cwd === "string" ? b.cwd : void 0,
|
|
5736
|
+
projects: Array.isArray(b.projects) ? b.projects.filter((p) => typeof p === "string") : []
|
|
5737
|
+
};
|
|
5738
|
+
}
|
|
5739
|
+
} catch {
|
|
5740
|
+
}
|
|
5741
|
+
}
|
|
5742
|
+
return null;
|
|
5743
|
+
}
|
|
5744
|
+
async function pairTerminal(port, key) {
|
|
5745
|
+
try {
|
|
5746
|
+
const res = await fetchJson2(
|
|
5747
|
+
`http://127.0.0.1:${port}/pair`,
|
|
5748
|
+
{ method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ key }) },
|
|
5749
|
+
5e3
|
|
5750
|
+
);
|
|
5751
|
+
const body = await res.json().catch(() => null);
|
|
5752
|
+
if (res.ok && body?.ok) return { ok: true, name: body.name ?? "", repo: body.repo ?? null };
|
|
5753
|
+
return { ok: false, error: body?.error ?? `HTTP ${res.status}` };
|
|
5754
|
+
} catch {
|
|
5755
|
+
return { ok: false, error: "the terminal stopped answering" };
|
|
5756
|
+
}
|
|
5757
|
+
}
|
|
5758
|
+
|
|
5759
|
+
// src/client/terminalKey.ts
|
|
5760
|
+
var TERMINAL_KEY_PREFIX = "rkc_";
|
|
5761
|
+
var TERMINAL_KEY_VERSION = 1;
|
|
5762
|
+
function base64url(text) {
|
|
5763
|
+
const bytes = new TextEncoder().encode(text);
|
|
5764
|
+
let binary = "";
|
|
5765
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
5766
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
5767
|
+
}
|
|
5768
|
+
function encodeTerminalKey(fields) {
|
|
5769
|
+
const payload = { v: TERMINAL_KEY_VERSION, ...fields };
|
|
5770
|
+
return TERMINAL_KEY_PREFIX + base64url(JSON.stringify(payload));
|
|
5771
|
+
}
|
|
5772
|
+
function currentTerminalKey(syncUrl, syncToken) {
|
|
5773
|
+
const origin = window.location.origin;
|
|
5774
|
+
let route = "/";
|
|
5775
|
+
try {
|
|
5776
|
+
route = window.location.pathname || "/";
|
|
5777
|
+
} catch {
|
|
5778
|
+
}
|
|
5779
|
+
return encodeTerminalKey({ name: window.location.hostname, origin, syncUrl, syncToken, route });
|
|
5780
|
+
}
|
|
5781
|
+
|
|
5782
|
+
// src/client/components/TerminalConnect.tsx
|
|
5665
5783
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
5784
|
+
function shortKey2(key) {
|
|
5785
|
+
return `${key.slice(0, 8)}\u2026${key.slice(-6)}`;
|
|
5786
|
+
}
|
|
5787
|
+
function shortPath(path) {
|
|
5788
|
+
if (!path) return "";
|
|
5789
|
+
const parts = path.split("/").filter(Boolean);
|
|
5790
|
+
return parts.length > 2 ? `\u2026/${parts.slice(-2).join("/")}` : path;
|
|
5791
|
+
}
|
|
5792
|
+
function TerminalConnect() {
|
|
5793
|
+
const { terminalConnectOpen } = useStore();
|
|
5794
|
+
const config = useConfig();
|
|
5795
|
+
const dispatch = useDispatch();
|
|
5796
|
+
const [phase, setPhase] = (0, import_react7.useState)("probing");
|
|
5797
|
+
const [probe, setProbe] = (0, import_react7.useState)(null);
|
|
5798
|
+
const [paired, setPaired] = (0, import_react7.useState)(null);
|
|
5799
|
+
const [showManual, setShowManual] = (0, import_react7.useState)(false);
|
|
5800
|
+
const syncToken = resolveSyncToken(config);
|
|
5801
|
+
const key = terminalConnectOpen && syncToken ? currentTerminalKey(resolveSyncUrl(config), syncToken) : null;
|
|
5802
|
+
(0, import_react7.useEffect)(() => {
|
|
5803
|
+
if (!terminalConnectOpen) return;
|
|
5804
|
+
let cancelled = false;
|
|
5805
|
+
setPhase("probing");
|
|
5806
|
+
setProbe(null);
|
|
5807
|
+
setPaired(null);
|
|
5808
|
+
setShowManual(false);
|
|
5809
|
+
const look = () => void probeTerminal().then((found) => {
|
|
5810
|
+
if (cancelled) return;
|
|
5811
|
+
setProbe(found);
|
|
5812
|
+
setPhase((current) => current === "pairing" || current === "paired" ? current : found ? "found" : "missing");
|
|
5813
|
+
});
|
|
5814
|
+
look();
|
|
5815
|
+
const timer = window.setInterval(look, 2e3);
|
|
5816
|
+
return () => {
|
|
5817
|
+
cancelled = true;
|
|
5818
|
+
window.clearInterval(timer);
|
|
5819
|
+
};
|
|
5820
|
+
}, [terminalConnectOpen]);
|
|
5821
|
+
if (!terminalConnectOpen) return null;
|
|
5822
|
+
const close = () => dispatch({ type: "SET_TERMINAL_CONNECT", open: false });
|
|
5823
|
+
const copy = async (value, what) => {
|
|
5824
|
+
try {
|
|
5825
|
+
await navigator.clipboard.writeText(value);
|
|
5826
|
+
toast(dispatch, `${what} copied`, "success");
|
|
5827
|
+
} catch {
|
|
5828
|
+
toast(dispatch, "Copy failed \u2014 select the text manually", "error");
|
|
5829
|
+
}
|
|
5830
|
+
};
|
|
5831
|
+
const connect = () => {
|
|
5832
|
+
if (!probe || !key) return;
|
|
5833
|
+
setPhase("pairing");
|
|
5834
|
+
void pairTerminal(probe.port, key).then((result) => {
|
|
5835
|
+
if (result.ok) {
|
|
5836
|
+
setPaired({ name: result.name, repo: result.repo });
|
|
5837
|
+
setPhase("paired");
|
|
5838
|
+
toast(dispatch, `Terminal paired as \u201C${result.name}\u201D`, "success");
|
|
5839
|
+
} else {
|
|
5840
|
+
setPhase("found");
|
|
5841
|
+
toast(dispatch, `Pairing failed: ${result.error}`, "error");
|
|
5842
|
+
}
|
|
5843
|
+
});
|
|
5844
|
+
};
|
|
5845
|
+
const connectCmd = key ? `npx -y @satanwagen/reviewkit-cli connect ${key}` : "";
|
|
5846
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5847
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "rk-backdrop", onClick: close }),
|
|
5848
|
+
/* @__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: [
|
|
5849
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
5850
|
+
"Connect terminal / agent",
|
|
5851
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { flex: 1 } }),
|
|
5852
|
+
/* @__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 }) })
|
|
5853
|
+
] }),
|
|
5854
|
+
!key && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5855
|
+
"Live sync is off on this page (",
|
|
5856
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "sync=false" }),
|
|
5857
|
+
" or no token), so there is no shared room a terminal could read."
|
|
5858
|
+
] }),
|
|
5859
|
+
key && phase === "paired" && paired && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5860
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-emblema-dot", "data-state": "live" }),
|
|
5861
|
+
" Paired as ",
|
|
5862
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: paired.name }),
|
|
5863
|
+
paired.repo ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5864
|
+
" in ",
|
|
5865
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: shortPath(paired.repo) })
|
|
5866
|
+
] }) : null,
|
|
5867
|
+
". The terminal shows this page's comments live, and Claude Code / Cursor can read and resolve them through the ",
|
|
5868
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "reviewkit" }),
|
|
5869
|
+
" MCP tools."
|
|
5870
|
+
] }),
|
|
5871
|
+
key && phase !== "paired" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5872
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-modal-text", children: [
|
|
5873
|
+
phase === "probing" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5874
|
+
"Looking for a ",
|
|
5875
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "reviewkit" }),
|
|
5876
|
+
" terminal on this machine\u2026"
|
|
5877
|
+
] }),
|
|
5878
|
+
phase === "missing" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5879
|
+
"No terminal is listening yet. In the site's repo run",
|
|
5880
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: "rk-connect-cmd", children: "npx -y @satanwagen/reviewkit-cli setup" }),
|
|
5881
|
+
"and this dialog will pick it up by itself."
|
|
5882
|
+
] }),
|
|
5883
|
+
(phase === "found" || phase === "pairing") && probe && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5884
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rk-emblema-dot", "data-state": "live" }),
|
|
5885
|
+
" Terminal found",
|
|
5886
|
+
probe.cwd ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5887
|
+
" in ",
|
|
5888
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: shortPath(probe.cwd) })
|
|
5889
|
+
] }) : null,
|
|
5890
|
+
".",
|
|
5891
|
+
probe.projects.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5892
|
+
" Already paired: ",
|
|
5893
|
+
probe.projects.join(", "),
|
|
5894
|
+
"."
|
|
5895
|
+
] }) : null
|
|
5896
|
+
] })
|
|
5897
|
+
] }),
|
|
5898
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rk-connect-actions", children: [
|
|
5899
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
5900
|
+
"button",
|
|
5901
|
+
{
|
|
5902
|
+
type: "button",
|
|
5903
|
+
className: "rk-btn rk-btn-primary",
|
|
5904
|
+
disabled: phase !== "found",
|
|
5905
|
+
onClick: connect,
|
|
5906
|
+
title: "Send this site's connection to the terminal \u2014 nothing to copy",
|
|
5907
|
+
children: phase === "pairing" ? "Connecting\u2026" : "Connect this terminal"
|
|
5908
|
+
}
|
|
5909
|
+
),
|
|
5910
|
+
/* @__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" })
|
|
5911
|
+
] }),
|
|
5912
|
+
showManual && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
5913
|
+
/* @__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):" }),
|
|
5914
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("code", { className: "rk-connect-cmd", title: connectCmd, children: [
|
|
5915
|
+
"npx -y @satanwagen/reviewkit-cli connect ",
|
|
5916
|
+
shortKey2(key)
|
|
5917
|
+
] }),
|
|
5918
|
+
/* @__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" }) })
|
|
5919
|
+
] })
|
|
5920
|
+
] })
|
|
5921
|
+
] }) })
|
|
5922
|
+
] });
|
|
5923
|
+
}
|
|
5924
|
+
|
|
5925
|
+
// src/client/components/CoachMark.tsx
|
|
5926
|
+
var import_react8 = require("react");
|
|
5927
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
5666
5928
|
var COACH_KEY = "review-kit:coach-dismissed";
|
|
5667
5929
|
function CoachMark() {
|
|
5668
5930
|
const { coachOpen, session } = useStore();
|
|
5669
5931
|
const dispatch = useDispatch();
|
|
5670
5932
|
const config = useConfig();
|
|
5671
|
-
const [name, setName] = (0,
|
|
5933
|
+
const [name, setName] = (0, import_react8.useState)(session?.author ?? config.defaultAuthor ?? "");
|
|
5672
5934
|
if (!coachOpen) return null;
|
|
5673
5935
|
const done = (startPicking) => {
|
|
5674
5936
|
if (name.trim() !== "") dispatch({ type: "SET_AUTHOR", author: name.trim() });
|
|
@@ -5679,39 +5941,39 @@ function CoachMark() {
|
|
|
5679
5941
|
}
|
|
5680
5942
|
if (startPicking) dispatch({ type: "SET_MODE", mode: "pick" });
|
|
5681
5943
|
};
|
|
5682
|
-
return /* @__PURE__ */ (0,
|
|
5683
|
-
/* @__PURE__ */ (0,
|
|
5684
|
-
/* @__PURE__ */ (0,
|
|
5685
|
-
/* @__PURE__ */ (0,
|
|
5686
|
-
/* @__PURE__ */ (0,
|
|
5944
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach", role: "dialog", "aria-label": "Welcome to review mode", children: [
|
|
5945
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rk-coach-accent" }),
|
|
5946
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach-body", children: [
|
|
5947
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-modal-title", style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
5948
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconTarget, { size: 16 }),
|
|
5687
5949
|
" Review mode"
|
|
5688
5950
|
] }),
|
|
5689
|
-
/* @__PURE__ */ (0,
|
|
5690
|
-
/* @__PURE__ */ (0,
|
|
5691
|
-
/* @__PURE__ */ (0,
|
|
5692
|
-
/* @__PURE__ */ (0,
|
|
5951
|
+
/* @__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." }),
|
|
5952
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "rk-coach-keys", "aria-label": "Key shortcuts", children: [
|
|
5953
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5954
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "T" }),
|
|
5693
5955
|
" rewrite"
|
|
5694
5956
|
] }),
|
|
5695
|
-
/* @__PURE__ */ (0,
|
|
5696
|
-
/* @__PURE__ */ (0,
|
|
5957
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5958
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "C" }),
|
|
5697
5959
|
" comment"
|
|
5698
5960
|
] }),
|
|
5699
|
-
/* @__PURE__ */ (0,
|
|
5700
|
-
/* @__PURE__ */ (0,
|
|
5961
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5962
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "I" }),
|
|
5701
5963
|
" image"
|
|
5702
5964
|
] }),
|
|
5703
|
-
/* @__PURE__ */ (0,
|
|
5704
|
-
/* @__PURE__ */ (0,
|
|
5965
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5966
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "V" }),
|
|
5705
5967
|
" select"
|
|
5706
5968
|
] }),
|
|
5707
|
-
/* @__PURE__ */ (0,
|
|
5708
|
-
/* @__PURE__ */ (0,
|
|
5969
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
5970
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rk-kbd", children: "?" }),
|
|
5709
5971
|
" all shortcuts"
|
|
5710
5972
|
] })
|
|
5711
5973
|
] }),
|
|
5712
|
-
/* @__PURE__ */ (0,
|
|
5713
|
-
/* @__PURE__ */ (0,
|
|
5714
|
-
/* @__PURE__ */ (0,
|
|
5974
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
|
|
5975
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "rk-label", htmlFor: "rk-author", children: "Your name" }),
|
|
5976
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
5715
5977
|
"input",
|
|
5716
5978
|
{
|
|
5717
5979
|
id: "rk-author",
|
|
@@ -5725,36 +5987,36 @@ function CoachMark() {
|
|
|
5725
5987
|
}
|
|
5726
5988
|
)
|
|
5727
5989
|
] }),
|
|
5728
|
-
/* @__PURE__ */ (0,
|
|
5729
|
-
/* @__PURE__ */ (0,
|
|
5730
|
-
/* @__PURE__ */ (0,
|
|
5990
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 4 }, children: [
|
|
5991
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => done(false), children: "Not now" }),
|
|
5992
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: () => done(true), children: "Start reviewing" })
|
|
5731
5993
|
] })
|
|
5732
5994
|
] })
|
|
5733
5995
|
] });
|
|
5734
5996
|
}
|
|
5735
5997
|
|
|
5736
5998
|
// src/client/components/Confirm.tsx
|
|
5737
|
-
var
|
|
5738
|
-
var
|
|
5999
|
+
var import_react9 = require("react");
|
|
6000
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
5739
6001
|
function ConfirmHost() {
|
|
5740
6002
|
const { confirm } = useStore();
|
|
5741
6003
|
const dispatch = useDispatch();
|
|
5742
|
-
const cancelRef = (0,
|
|
5743
|
-
(0,
|
|
6004
|
+
const cancelRef = (0, import_react9.useRef)(null);
|
|
6005
|
+
(0, import_react9.useEffect)(() => {
|
|
5744
6006
|
if (confirm) cancelRef.current?.focus();
|
|
5745
6007
|
}, [confirm]);
|
|
5746
6008
|
if (!confirm) return null;
|
|
5747
6009
|
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,
|
|
6010
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
6011
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-backdrop", onClick: close }),
|
|
6012
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal", role: "alertdialog", "aria-modal": "true", "aria-label": confirm.title, children: [
|
|
6013
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal-body", children: [
|
|
6014
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-modal-title", children: confirm.title }),
|
|
6015
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rk-modal-text", children: confirm.message })
|
|
5754
6016
|
] }),
|
|
5755
|
-
/* @__PURE__ */ (0,
|
|
5756
|
-
/* @__PURE__ */ (0,
|
|
5757
|
-
/* @__PURE__ */ (0,
|
|
6017
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rk-modal-actions", children: [
|
|
6018
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { ref: cancelRef, type: "button", className: "rk-btn rk-btn-ghost", onClick: close, children: "Cancel" }),
|
|
6019
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5758
6020
|
"button",
|
|
5759
6021
|
{
|
|
5760
6022
|
type: "button",
|
|
@@ -5773,10 +6035,10 @@ function ConfirmHost() {
|
|
|
5773
6035
|
}
|
|
5774
6036
|
|
|
5775
6037
|
// src/client/components/ImageEditor.tsx
|
|
5776
|
-
var
|
|
6038
|
+
var import_react11 = require("react");
|
|
5777
6039
|
|
|
5778
6040
|
// src/client/useAnchored.ts
|
|
5779
|
-
var
|
|
6041
|
+
var import_react10 = require("react");
|
|
5780
6042
|
|
|
5781
6043
|
// src/client/position.ts
|
|
5782
6044
|
function place(anchor, size, side, offset) {
|
|
@@ -5821,9 +6083,9 @@ function computePosition(anchor, size, options = {}) {
|
|
|
5821
6083
|
|
|
5822
6084
|
// src/client/useAnchored.ts
|
|
5823
6085
|
function useAnchored(anchorEl, side = "bottom", offset = 8) {
|
|
5824
|
-
const ref = (0,
|
|
5825
|
-
const [pos, setPos] = (0,
|
|
5826
|
-
(0,
|
|
6086
|
+
const ref = (0, import_react10.useRef)(null);
|
|
6087
|
+
const [pos, setPos] = (0, import_react10.useState)(null);
|
|
6088
|
+
(0, import_react10.useLayoutEffect)(() => {
|
|
5827
6089
|
if (!anchorEl) {
|
|
5828
6090
|
setPos(null);
|
|
5829
6091
|
return;
|
|
@@ -5854,7 +6116,7 @@ function anchoredStyle(pos) {
|
|
|
5854
6116
|
}
|
|
5855
6117
|
|
|
5856
6118
|
// src/client/components/ImageEditor.tsx
|
|
5857
|
-
var
|
|
6119
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
5858
6120
|
var MAX_BYTES = 2 * 1024 * 1024;
|
|
5859
6121
|
var FETCH_TIMEOUT_MS = 12e3;
|
|
5860
6122
|
var PROBE_TIMEOUT_MS = 8e3;
|
|
@@ -5912,15 +6174,15 @@ function urlFromDataTransfer(dt) {
|
|
|
5912
6174
|
function ImageEditor({ editor }) {
|
|
5913
6175
|
const dispatch = useDispatch();
|
|
5914
6176
|
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,
|
|
6177
|
+
const [replacement, setReplacement] = (0, import_react11.useState)(null);
|
|
6178
|
+
const [urlValue, setUrlValue] = (0, import_react11.useState)("");
|
|
6179
|
+
const [loading2, setLoading] = (0, import_react11.useState)(false);
|
|
6180
|
+
const [description, setDescription] = (0, import_react11.useState)("");
|
|
6181
|
+
const [priority, setPriority] = (0, import_react11.useState)("nice");
|
|
6182
|
+
const [over, setOver] = (0, import_react11.useState)(false);
|
|
6183
|
+
const fileInput = (0, import_react11.useRef)(null);
|
|
6184
|
+
const abortRef = (0, import_react11.useRef)(null);
|
|
6185
|
+
const debounceRef = (0, import_react11.useRef)(null);
|
|
5924
6186
|
const { ref, pos } = useAnchored(editor.element, "bottom", 12);
|
|
5925
6187
|
const image = findImage(editor.element);
|
|
5926
6188
|
const beforeSrc = image?.currentSrc || image?.src || "";
|
|
@@ -5984,7 +6246,7 @@ function ImageEditor({ editor }) {
|
|
|
5984
6246
|
}
|
|
5985
6247
|
}
|
|
5986
6248
|
};
|
|
5987
|
-
(0,
|
|
6249
|
+
(0, import_react11.useEffect)(() => {
|
|
5988
6250
|
if (debounceRef.current !== null) window.clearTimeout(debounceRef.current);
|
|
5989
6251
|
if (urlValue.trim() === "" || replacement !== null) return;
|
|
5990
6252
|
debounceRef.current = window.setTimeout(() => {
|
|
@@ -5994,8 +6256,8 @@ function ImageEditor({ editor }) {
|
|
|
5994
6256
|
if (debounceRef.current !== null) window.clearTimeout(debounceRef.current);
|
|
5995
6257
|
};
|
|
5996
6258
|
}, [urlValue, replacement]);
|
|
5997
|
-
(0,
|
|
5998
|
-
(0,
|
|
6259
|
+
(0, import_react11.useEffect)(() => () => abortRef.current?.abort(), []);
|
|
6260
|
+
(0, import_react11.useEffect)(() => {
|
|
5999
6261
|
const onPaste = (event) => {
|
|
6000
6262
|
const data = event.clipboardData;
|
|
6001
6263
|
if (!data) return;
|
|
@@ -6073,23 +6335,23 @@ function ImageEditor({ editor }) {
|
|
|
6073
6335
|
toast(dispatch, "Image proposal saved", "success");
|
|
6074
6336
|
};
|
|
6075
6337
|
const previewSrc = replacement?.kind === "data" ? replacement.dataUrl : replacement?.url;
|
|
6076
|
-
return /* @__PURE__ */ (0,
|
|
6077
|
-
/* @__PURE__ */ (0,
|
|
6078
|
-
/* @__PURE__ */ (0,
|
|
6338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Replace image", children: [
|
|
6339
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-head", children: [
|
|
6340
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconImage, { size: 14 }),
|
|
6079
6341
|
"Replace image"
|
|
6080
6342
|
] }),
|
|
6081
|
-
/* @__PURE__ */ (0,
|
|
6082
|
-
replacement && previewSrc ? /* @__PURE__ */ (0,
|
|
6083
|
-
/* @__PURE__ */ (0,
|
|
6084
|
-
/* @__PURE__ */ (0,
|
|
6085
|
-
/* @__PURE__ */ (0,
|
|
6343
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-body", children: [
|
|
6344
|
+
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: [
|
|
6345
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6346
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: beforeSrc, alt: "Current" }),
|
|
6347
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { children: "Before" })
|
|
6086
6348
|
] }),
|
|
6087
|
-
/* @__PURE__ */ (0,
|
|
6088
|
-
/* @__PURE__ */ (0,
|
|
6089
|
-
/* @__PURE__ */ (0,
|
|
6349
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6350
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("img", { src: previewSrc, alt: "Proposed replacement" }),
|
|
6351
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("figcaption", { children: replacement.kind === "url" ? "After \xB7 linked" : "After" })
|
|
6090
6352
|
] })
|
|
6091
|
-
] }) }) : /* @__PURE__ */ (0,
|
|
6092
|
-
/* @__PURE__ */ (0,
|
|
6353
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
6354
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
6093
6355
|
"button",
|
|
6094
6356
|
{
|
|
6095
6357
|
type: "button",
|
|
@@ -6102,18 +6364,18 @@ function ImageEditor({ editor }) {
|
|
|
6102
6364
|
onDragLeave: () => setOver(false),
|
|
6103
6365
|
onDrop,
|
|
6104
6366
|
children: [
|
|
6105
|
-
/* @__PURE__ */ (0,
|
|
6106
|
-
/* @__PURE__ */ (0,
|
|
6367
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconUpload, { size: 18 }),
|
|
6368
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
|
|
6107
6369
|
"Drop an image \u2014 from your disk or another tab \u2014",
|
|
6108
|
-
/* @__PURE__ */ (0,
|
|
6370
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("br", {}),
|
|
6109
6371
|
"or click to browse (max 2 MB)"
|
|
6110
6372
|
] })
|
|
6111
6373
|
]
|
|
6112
6374
|
}
|
|
6113
6375
|
),
|
|
6114
|
-
/* @__PURE__ */ (0,
|
|
6115
|
-
loading2 ? /* @__PURE__ */ (0,
|
|
6116
|
-
/* @__PURE__ */ (0,
|
|
6376
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-url", children: [
|
|
6377
|
+
loading2 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-spinner", "aria-label": "Loading image" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconLink, { size: 13 }),
|
|
6378
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6117
6379
|
"input",
|
|
6118
6380
|
{
|
|
6119
6381
|
className: "rk-input",
|
|
@@ -6128,9 +6390,9 @@ function ImageEditor({ editor }) {
|
|
|
6128
6390
|
)
|
|
6129
6391
|
] })
|
|
6130
6392
|
] }),
|
|
6131
|
-
replacement && /* @__PURE__ */ (0,
|
|
6132
|
-
/* @__PURE__ */ (0,
|
|
6133
|
-
/* @__PURE__ */ (0,
|
|
6393
|
+
replacement && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: clearReplacement, children: "Remove replacement" }),
|
|
6394
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { ref: fileInput, type: "file", accept: "image/*", hidden: true, onChange: onPick }),
|
|
6395
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6134
6396
|
"textarea",
|
|
6135
6397
|
{
|
|
6136
6398
|
className: "rk-textarea",
|
|
@@ -6140,43 +6402,43 @@ function ImageEditor({ editor }) {
|
|
|
6140
6402
|
rows: 2
|
|
6141
6403
|
}
|
|
6142
6404
|
),
|
|
6143
|
-
/* @__PURE__ */ (0,
|
|
6144
|
-
/* @__PURE__ */ (0,
|
|
6145
|
-
/* @__PURE__ */ (0,
|
|
6405
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
6406
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
|
|
6407
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
|
|
6146
6408
|
] })
|
|
6147
6409
|
] }),
|
|
6148
|
-
/* @__PURE__ */ (0,
|
|
6149
|
-
/* @__PURE__ */ (0,
|
|
6150
|
-
/* @__PURE__ */ (0,
|
|
6410
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-card-foot", children: [
|
|
6411
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "rk-hint", children: [
|
|
6412
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
6151
6413
|
" cancel"
|
|
6152
6414
|
] }),
|
|
6153
|
-
/* @__PURE__ */ (0,
|
|
6154
|
-
/* @__PURE__ */ (0,
|
|
6155
|
-
/* @__PURE__ */ (0,
|
|
6415
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "rk-actions", children: [
|
|
6416
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
|
|
6417
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
|
|
6156
6418
|
] })
|
|
6157
6419
|
] })
|
|
6158
6420
|
] });
|
|
6159
6421
|
}
|
|
6160
6422
|
|
|
6161
6423
|
// src/client/components/InlineEditor.tsx
|
|
6162
|
-
var
|
|
6163
|
-
var
|
|
6424
|
+
var import_react12 = require("react");
|
|
6425
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
6164
6426
|
function InlineEditor({ editor }) {
|
|
6165
6427
|
const dispatch = useDispatch();
|
|
6166
6428
|
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,
|
|
6429
|
+
const [after, setAfter] = (0, import_react12.useState)(() => editor.element.innerText);
|
|
6430
|
+
const [priority, setPriority] = (0, import_react12.useState)("nice");
|
|
6431
|
+
const [note, setNote] = (0, import_react12.useState)("");
|
|
6432
|
+
const original = (0, import_react12.useRef)(null);
|
|
6433
|
+
const baseline = (0, import_react12.useRef)(null);
|
|
6434
|
+
const [sizeDelta, setSizeDelta] = (0, import_react12.useState)(0);
|
|
6435
|
+
const [widthDelta, setWidthDelta] = (0, import_react12.useState)(0);
|
|
6436
|
+
const [clipped, setClipped] = (0, import_react12.useState)(false);
|
|
6437
|
+
const ringRef = (0, import_react12.useRef)(null);
|
|
6438
|
+
const afterRef = (0, import_react12.useRef)(null);
|
|
6177
6439
|
const { ref, pos } = useAnchored(editor.element, "bottom", 12);
|
|
6178
6440
|
const element = editor.element;
|
|
6179
|
-
(0,
|
|
6441
|
+
(0, import_react12.useEffect)(() => {
|
|
6180
6442
|
const el = element;
|
|
6181
6443
|
original.current = { html: el.innerHTML, text: el.innerText, styleAttr: el.getAttribute("style") };
|
|
6182
6444
|
const rect = el.getBoundingClientRect();
|
|
@@ -6206,8 +6468,8 @@ function InlineEditor({ editor }) {
|
|
|
6206
6468
|
}
|
|
6207
6469
|
};
|
|
6208
6470
|
}, [element]);
|
|
6209
|
-
const focusedOnce = (0,
|
|
6210
|
-
(0,
|
|
6471
|
+
const focusedOnce = (0, import_react12.useRef)(false);
|
|
6472
|
+
(0, import_react12.useEffect)(() => {
|
|
6211
6473
|
const field = afterRef.current;
|
|
6212
6474
|
if (pos === null || focusedOnce.current || !field) return;
|
|
6213
6475
|
focusedOnce.current = true;
|
|
@@ -6215,7 +6477,7 @@ function InlineEditor({ editor }) {
|
|
|
6215
6477
|
const end = field.value.length;
|
|
6216
6478
|
field.setSelectionRange(end, end);
|
|
6217
6479
|
}, [pos]);
|
|
6218
|
-
(0,
|
|
6480
|
+
(0, import_react12.useEffect)(() => {
|
|
6219
6481
|
const field = afterRef.current;
|
|
6220
6482
|
if (!field) return;
|
|
6221
6483
|
field.style.height = "auto";
|
|
@@ -6225,7 +6487,7 @@ function InlineEditor({ editor }) {
|
|
|
6225
6487
|
setAfter(value);
|
|
6226
6488
|
if (element.innerText !== value) setElementText(element, value);
|
|
6227
6489
|
};
|
|
6228
|
-
(0,
|
|
6490
|
+
(0, import_react12.useEffect)(() => {
|
|
6229
6491
|
let raf = 0;
|
|
6230
6492
|
let lastDelta = 0;
|
|
6231
6493
|
let lastWidth = 0;
|
|
@@ -6295,7 +6557,7 @@ function InlineEditor({ editor }) {
|
|
|
6295
6557
|
cancel();
|
|
6296
6558
|
}
|
|
6297
6559
|
};
|
|
6298
|
-
(0,
|
|
6560
|
+
(0, import_react12.useEffect)(() => {
|
|
6299
6561
|
const el = element;
|
|
6300
6562
|
const onKeyDown = (event) => {
|
|
6301
6563
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
@@ -6313,19 +6575,19 @@ function InlineEditor({ editor }) {
|
|
|
6313
6575
|
});
|
|
6314
6576
|
const before = original.current?.text ?? "";
|
|
6315
6577
|
const delta = after.length - before.length;
|
|
6316
|
-
return /* @__PURE__ */ (0,
|
|
6317
|
-
/* @__PURE__ */ (0,
|
|
6318
|
-
/* @__PURE__ */ (0,
|
|
6319
|
-
/* @__PURE__ */ (0,
|
|
6320
|
-
/* @__PURE__ */ (0,
|
|
6578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
6579
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: ringRef, className: "rk-edit-ring" }),
|
|
6580
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": "Rewrite text", children: [
|
|
6581
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-head", children: [
|
|
6582
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IconText, { size: 14 }),
|
|
6321
6583
|
"Rewrite text",
|
|
6322
|
-
/* @__PURE__ */ (0,
|
|
6323
|
-
/* @__PURE__ */ (0,
|
|
6584
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-spacer" }),
|
|
6585
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-delta", "aria-live": "polite", children: [
|
|
6324
6586
|
before.length,
|
|
6325
6587
|
" \u2192 ",
|
|
6326
6588
|
after.length,
|
|
6327
6589
|
" ",
|
|
6328
|
-
delta !== 0 && /* @__PURE__ */ (0,
|
|
6590
|
+
delta !== 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: delta > 0 ? "rk-plus" : "rk-minus", children: [
|
|
6329
6591
|
"(",
|
|
6330
6592
|
delta > 0 ? "+" : "",
|
|
6331
6593
|
delta,
|
|
@@ -6333,15 +6595,15 @@ function InlineEditor({ editor }) {
|
|
|
6333
6595
|
] })
|
|
6334
6596
|
] })
|
|
6335
6597
|
] }),
|
|
6336
|
-
/* @__PURE__ */ (0,
|
|
6337
|
-
/* @__PURE__ */ (0,
|
|
6338
|
-
/* @__PURE__ */ (0,
|
|
6339
|
-
/* @__PURE__ */ (0,
|
|
6340
|
-
/* @__PURE__ */ (0,
|
|
6598
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-body", children: [
|
|
6599
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff", "aria-label": "Before and after", children: [
|
|
6600
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
|
|
6601
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
|
|
6602
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-text", children: before })
|
|
6341
6603
|
] }),
|
|
6342
|
-
/* @__PURE__ */ (0,
|
|
6343
|
-
/* @__PURE__ */ (0,
|
|
6344
|
-
/* @__PURE__ */ (0,
|
|
6604
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
|
|
6605
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-diff-tag", children: "After" }),
|
|
6606
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6345
6607
|
"textarea",
|
|
6346
6608
|
{
|
|
6347
6609
|
ref: afterRef,
|
|
@@ -6355,11 +6617,11 @@ function InlineEditor({ editor }) {
|
|
|
6355
6617
|
)
|
|
6356
6618
|
] })
|
|
6357
6619
|
] }),
|
|
6358
|
-
(Math.abs(sizeDelta) > 2 || Math.abs(widthDelta) > 4 || clipped) && /* @__PURE__ */ (0,
|
|
6620
|
+
(Math.abs(sizeDelta) > 2 || Math.abs(widthDelta) > 4 || clipped) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-size-note", role: "status", children: [
|
|
6359
6621
|
Math.abs(sizeDelta) > 2 && (() => {
|
|
6360
6622
|
const lines = baseline.current ? Math.round(Math.abs(sizeDelta) / baseline.current.lineHeight) : 0;
|
|
6361
6623
|
const lineNote = lines >= 1 ? ` (~${lines} line${lines === 1 ? "" : "s"})` : "";
|
|
6362
|
-
return /* @__PURE__ */ (0,
|
|
6624
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
6363
6625
|
"Block ",
|
|
6364
6626
|
sizeDelta > 0 ? "grew" : "shrank",
|
|
6365
6627
|
" by ",
|
|
@@ -6369,16 +6631,16 @@ function InlineEditor({ editor }) {
|
|
|
6369
6631
|
" \u2014 as it would with this text live."
|
|
6370
6632
|
] });
|
|
6371
6633
|
})(),
|
|
6372
|
-
Math.abs(sizeDelta) <= 2 && Math.abs(widthDelta) > 4 && /* @__PURE__ */ (0,
|
|
6634
|
+
Math.abs(sizeDelta) <= 2 && Math.abs(widthDelta) > 4 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
6373
6635
|
"Block got ",
|
|
6374
6636
|
widthDelta > 0 ? "wider" : "narrower",
|
|
6375
6637
|
" by ",
|
|
6376
6638
|
Math.abs(widthDelta),
|
|
6377
6639
|
" px \u2014 as it would with this text live."
|
|
6378
6640
|
] }),
|
|
6379
|
-
clipped && /* @__PURE__ */ (0,
|
|
6641
|
+
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
6642
|
] }),
|
|
6381
|
-
/* @__PURE__ */ (0,
|
|
6643
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6382
6644
|
"input",
|
|
6383
6645
|
{
|
|
6384
6646
|
className: "rk-input",
|
|
@@ -6387,24 +6649,24 @@ function InlineEditor({ editor }) {
|
|
|
6387
6649
|
onChange: (event) => setNote(event.target.value)
|
|
6388
6650
|
}
|
|
6389
6651
|
),
|
|
6390
|
-
/* @__PURE__ */ (0,
|
|
6391
|
-
/* @__PURE__ */ (0,
|
|
6392
|
-
/* @__PURE__ */ (0,
|
|
6652
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
6653
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
|
|
6654
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
|
|
6393
6655
|
] })
|
|
6394
6656
|
] }),
|
|
6395
|
-
/* @__PURE__ */ (0,
|
|
6396
|
-
/* @__PURE__ */ (0,
|
|
6397
|
-
/* @__PURE__ */ (0,
|
|
6657
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-card-foot", children: [
|
|
6658
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "rk-hint", children: [
|
|
6659
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
|
|
6398
6660
|
" save \xB7 ",
|
|
6399
|
-
/* @__PURE__ */ (0,
|
|
6661
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "\u21E7\u21B5" }),
|
|
6400
6662
|
" newline \xB7",
|
|
6401
6663
|
" ",
|
|
6402
|
-
/* @__PURE__ */ (0,
|
|
6664
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
6403
6665
|
" cancel"
|
|
6404
6666
|
] }),
|
|
6405
|
-
/* @__PURE__ */ (0,
|
|
6406
|
-
/* @__PURE__ */ (0,
|
|
6407
|
-
/* @__PURE__ */ (0,
|
|
6667
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "rk-actions", children: [
|
|
6668
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: cancel, children: "Cancel" }),
|
|
6669
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: commit, children: "Save" })
|
|
6408
6670
|
] })
|
|
6409
6671
|
] })
|
|
6410
6672
|
] })
|
|
@@ -6412,8 +6674,8 @@ function InlineEditor({ editor }) {
|
|
|
6412
6674
|
}
|
|
6413
6675
|
|
|
6414
6676
|
// src/client/components/NoteComposer.tsx
|
|
6415
|
-
var
|
|
6416
|
-
var
|
|
6677
|
+
var import_react13 = require("react");
|
|
6678
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
6417
6679
|
var TITLES = {
|
|
6418
6680
|
comment: "Comment",
|
|
6419
6681
|
delete: "Mark for deletion",
|
|
@@ -6429,14 +6691,14 @@ var PLACEHOLDERS = {
|
|
|
6429
6691
|
function NoteComposer({ editor }) {
|
|
6430
6692
|
const dispatch = useDispatch();
|
|
6431
6693
|
const { route, session } = useStore();
|
|
6432
|
-
const [text, setText] = (0,
|
|
6433
|
-
const [direction, setDirection] = (0,
|
|
6434
|
-
const [priority, setPriority] = (0,
|
|
6435
|
-
const textareaRef = (0,
|
|
6694
|
+
const [text, setText] = (0, import_react13.useState)("");
|
|
6695
|
+
const [direction, setDirection] = (0, import_react13.useState)(void 0);
|
|
6696
|
+
const [priority, setPriority] = (0, import_react13.useState)("nice");
|
|
6697
|
+
const textareaRef = (0, import_react13.useRef)(null);
|
|
6436
6698
|
const { ref, pos } = useAnchored(editor.element, "bottom", 12);
|
|
6437
6699
|
const { kind } = editor;
|
|
6438
|
-
const focusedOnce = (0,
|
|
6439
|
-
(0,
|
|
6700
|
+
const focusedOnce = (0, import_react13.useRef)(false);
|
|
6701
|
+
(0, import_react13.useEffect)(() => {
|
|
6440
6702
|
const field = textareaRef.current;
|
|
6441
6703
|
if (pos === null || focusedOnce.current || !field) return;
|
|
6442
6704
|
focusedOnce.current = true;
|
|
@@ -6495,13 +6757,13 @@ function NoteComposer({ editor }) {
|
|
|
6495
6757
|
save();
|
|
6496
6758
|
}
|
|
6497
6759
|
};
|
|
6498
|
-
return /* @__PURE__ */ (0,
|
|
6499
|
-
/* @__PURE__ */ (0,
|
|
6760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { ref, className: "rk-card", style: anchoredStyle(pos), role: "dialog", "aria-label": TITLES[kind], children: [
|
|
6761
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-head", children: [
|
|
6500
6762
|
iconForType(kind),
|
|
6501
6763
|
TITLES[kind]
|
|
6502
6764
|
] }),
|
|
6503
|
-
/* @__PURE__ */ (0,
|
|
6504
|
-
kind === "move" && /* @__PURE__ */ (0,
|
|
6765
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-body", children: [
|
|
6766
|
+
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
6767
|
"button",
|
|
6506
6768
|
{
|
|
6507
6769
|
type: "button",
|
|
@@ -6511,7 +6773,7 @@ function NoteComposer({ editor }) {
|
|
|
6511
6773
|
},
|
|
6512
6774
|
option
|
|
6513
6775
|
)) }),
|
|
6514
|
-
/* @__PURE__ */ (0,
|
|
6776
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
6515
6777
|
"textarea",
|
|
6516
6778
|
{
|
|
6517
6779
|
ref: textareaRef,
|
|
@@ -6523,29 +6785,29 @@ function NoteComposer({ editor }) {
|
|
|
6523
6785
|
rows: 3
|
|
6524
6786
|
}
|
|
6525
6787
|
),
|
|
6526
|
-
/* @__PURE__ */ (0,
|
|
6527
|
-
/* @__PURE__ */ (0,
|
|
6528
|
-
/* @__PURE__ */ (0,
|
|
6788
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
6789
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": priority === "must", onClick: () => setPriority("must"), children: "Must" }),
|
|
6790
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", "aria-pressed": priority === "nice", onClick: () => setPriority("nice"), children: "Nice to have" })
|
|
6529
6791
|
] })
|
|
6530
6792
|
] }),
|
|
6531
|
-
/* @__PURE__ */ (0,
|
|
6532
|
-
/* @__PURE__ */ (0,
|
|
6533
|
-
/* @__PURE__ */ (0,
|
|
6793
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-card-foot", children: [
|
|
6794
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "rk-hint", children: [
|
|
6795
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-kbd", children: "\u2318\u21B5" }),
|
|
6534
6796
|
" save \xB7 ",
|
|
6535
|
-
/* @__PURE__ */ (0,
|
|
6797
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
6536
6798
|
" cancel"
|
|
6537
6799
|
] }),
|
|
6538
|
-
/* @__PURE__ */ (0,
|
|
6539
|
-
/* @__PURE__ */ (0,
|
|
6540
|
-
/* @__PURE__ */ (0,
|
|
6800
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rk-actions", children: [
|
|
6801
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => dispatch({ type: "CLOSE_EDITOR" }), children: "Cancel" }),
|
|
6802
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "rk-btn rk-btn-primary", onClick: save, children: "Save" })
|
|
6541
6803
|
] })
|
|
6542
6804
|
] })
|
|
6543
6805
|
] });
|
|
6544
6806
|
}
|
|
6545
6807
|
|
|
6546
6808
|
// src/client/components/Panel.tsx
|
|
6547
|
-
var
|
|
6548
|
-
var
|
|
6809
|
+
var import_react14 = require("react");
|
|
6810
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
6549
6811
|
function changeSummary(item) {
|
|
6550
6812
|
if (isCopyItem(item)) return `\u201C${item.payload.after}\u201D`;
|
|
6551
6813
|
if (isImageItem(item)) {
|
|
@@ -6627,24 +6889,24 @@ function formatBytes(bytes) {
|
|
|
6627
6889
|
function CopyDiff({ before, after }) {
|
|
6628
6890
|
const parts = diffParts(before, after);
|
|
6629
6891
|
const delta = after.length - before.length;
|
|
6630
|
-
return /* @__PURE__ */ (0,
|
|
6631
|
-
/* @__PURE__ */ (0,
|
|
6632
|
-
/* @__PURE__ */ (0,
|
|
6633
|
-
/* @__PURE__ */ (0,
|
|
6892
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diffview", children: [
|
|
6893
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-row rk-diff-before", children: [
|
|
6894
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-diff-tag", children: "Before" }),
|
|
6895
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-diff-text", children: [
|
|
6634
6896
|
parts.prefix,
|
|
6635
|
-
parts.delMid && /* @__PURE__ */ (0,
|
|
6897
|
+
parts.delMid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("mark", { className: "rk-del", children: parts.delMid }),
|
|
6636
6898
|
parts.suffix
|
|
6637
6899
|
] })
|
|
6638
6900
|
] }),
|
|
6639
|
-
/* @__PURE__ */ (0,
|
|
6640
|
-
/* @__PURE__ */ (0,
|
|
6641
|
-
/* @__PURE__ */ (0,
|
|
6901
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-row rk-diff-after", children: [
|
|
6902
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-diff-tag", children: "After" }),
|
|
6903
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-diff-text", children: [
|
|
6642
6904
|
parts.prefix,
|
|
6643
|
-
parts.insMid && /* @__PURE__ */ (0,
|
|
6905
|
+
parts.insMid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("mark", { className: "rk-ins", children: parts.insMid }),
|
|
6644
6906
|
parts.suffix
|
|
6645
6907
|
] })
|
|
6646
6908
|
] }),
|
|
6647
|
-
/* @__PURE__ */ (0,
|
|
6909
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-diff-len", children: [
|
|
6648
6910
|
before.length,
|
|
6649
6911
|
" \u2192 ",
|
|
6650
6912
|
after.length,
|
|
@@ -6655,8 +6917,8 @@ function CopyDiff({ before, after }) {
|
|
|
6655
6917
|
}
|
|
6656
6918
|
function ImageDetail({ beforeSrc, afterSrc, afterDataUrl }) {
|
|
6657
6919
|
const replacement = afterDataUrl ?? afterSrc;
|
|
6658
|
-
const [dims, setDims] = (0,
|
|
6659
|
-
(0,
|
|
6920
|
+
const [dims, setDims] = (0, import_react14.useState)("");
|
|
6921
|
+
(0, import_react14.useEffect)(() => {
|
|
6660
6922
|
if (!replacement) return;
|
|
6661
6923
|
const img = new Image();
|
|
6662
6924
|
img.onload = () => setDims(`${img.naturalWidth}\xD7${img.naturalHeight}px`);
|
|
@@ -6681,55 +6943,67 @@ function ImageDetail({ beforeSrc, afterSrc, afterDataUrl }) {
|
|
|
6681
6943
|
window.open(replacement, "_blank", "noopener");
|
|
6682
6944
|
}
|
|
6683
6945
|
};
|
|
6684
|
-
return /* @__PURE__ */ (0,
|
|
6685
|
-
/* @__PURE__ */ (0,
|
|
6686
|
-
/* @__PURE__ */ (0,
|
|
6687
|
-
beforeSrc ? /* @__PURE__ */ (0,
|
|
6688
|
-
/* @__PURE__ */ (0,
|
|
6946
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail", children: [
|
|
6947
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-thumbs", children: [
|
|
6948
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6949
|
+
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" }),
|
|
6950
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { children: "Before" })
|
|
6689
6951
|
] }),
|
|
6690
|
-
/* @__PURE__ */ (0,
|
|
6691
|
-
/* @__PURE__ */ (0,
|
|
6692
|
-
/* @__PURE__ */ (0,
|
|
6952
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "rk-thumb", children: [
|
|
6953
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("img", { src: replacement, alt: "Proposed replacement" }),
|
|
6954
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figcaption", { children: [
|
|
6693
6955
|
"After",
|
|
6694
6956
|
embedded ? "" : " \xB7 linked"
|
|
6695
6957
|
] })
|
|
6696
6958
|
] })
|
|
6697
6959
|
] }),
|
|
6698
|
-
/* @__PURE__ */ (0,
|
|
6960
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail-meta", children: [
|
|
6699
6961
|
embedded ? "Embedded image" : "Linked image",
|
|
6700
6962
|
dims ? ` \xB7 ${dims}` : "",
|
|
6701
6963
|
bytes !== null ? ` \xB7 ${formatBytes(bytes)}` : ""
|
|
6702
6964
|
] }),
|
|
6703
|
-
!embedded && afterSrc && /* @__PURE__ */ (0,
|
|
6704
|
-
/* @__PURE__ */ (0,
|
|
6705
|
-
/* @__PURE__ */ (0,
|
|
6706
|
-
/* @__PURE__ */ (0,
|
|
6965
|
+
!embedded && afterSrc && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { className: "rk-imgdetail-url", href: afterSrc, target: "_blank", rel: "noopener noreferrer", title: afterSrc, children: afterSrc }),
|
|
6966
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-imgdetail-actions", children: [
|
|
6967
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void download(), children: [
|
|
6968
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconDownload, { size: 12 }),
|
|
6707
6969
|
" Download"
|
|
6708
6970
|
] }),
|
|
6709
|
-
/* @__PURE__ */ (0,
|
|
6971
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => window.open(replacement, "_blank", "noopener"), children: "Open" })
|
|
6710
6972
|
] })
|
|
6711
6973
|
] });
|
|
6712
6974
|
}
|
|
6975
|
+
var SYNC_REASON_LABEL = {
|
|
6976
|
+
"token-short": "token too short",
|
|
6977
|
+
"bad-token": "token rejected",
|
|
6978
|
+
"room-full": "room full",
|
|
6979
|
+
unreachable: "server unreachable"
|
|
6980
|
+
};
|
|
6981
|
+
var SYNC_REASON_HELP = {
|
|
6982
|
+
"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.",
|
|
6983
|
+
"bad-token": "The sync server rejected the token. Check `syncToken` / `token` in <ReviewKit />.",
|
|
6984
|
+
"room-full": "This page already has the maximum number of reviewers online (16). Try again later.",
|
|
6985
|
+
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."
|
|
6986
|
+
};
|
|
6713
6987
|
function Panel() {
|
|
6714
|
-
const { session, panelOpen, activeItemId, badgeCorner, undoStack, preview, unapplied, syncStatus, emblemaPush, peers } = useStore();
|
|
6988
|
+
const { session, panelOpen, activeItemId, badgeCorner, undoStack, preview, unapplied, syncStatus, syncReason, emblemaPush, peers } = useStore();
|
|
6715
6989
|
const dispatch = useDispatch();
|
|
6716
6990
|
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,
|
|
6991
|
+
const [sticky, setStickyState] = (0, import_react14.useState)(() => isStickyEnabled(config.token));
|
|
6992
|
+
const [query, setQuery] = (0, import_react14.useState)("");
|
|
6993
|
+
const [typeFilter, setTypeFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
6994
|
+
const [prioFilter, setPrioFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
6995
|
+
const [statusFilter, setStatusFilter] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
|
|
6996
|
+
const [filterOpen, setFilterOpen] = (0, import_react14.useState)(false);
|
|
6997
|
+
const [settingsOpen, setSettingsOpen] = (0, import_react14.useState)(false);
|
|
6998
|
+
const [emblemaAlive, setEmblemaAlive] = (0, import_react14.useState)(null);
|
|
6999
|
+
const [emblemaSending, setEmblemaSending] = (0, import_react14.useState)(false);
|
|
7000
|
+
const [emblemaSync, setEmblemaSync] = (0, import_react14.useState)("unknown");
|
|
7001
|
+
const panelRef = (0, import_react14.useRef)(null);
|
|
7002
|
+
const searchRef = (0, import_react14.useRef)(null);
|
|
7003
|
+
const importRef = (0, import_react14.useRef)(null);
|
|
7004
|
+
const sheetDrag = (0, import_react14.useRef)(null);
|
|
7005
|
+
const items = (0, import_react14.useMemo)(() => session?.items ?? [], [session]);
|
|
7006
|
+
const { orphanIds, hiddenIds } = (0, import_react14.useMemo)(() => {
|
|
6733
7007
|
const orphans = /* @__PURE__ */ new Set();
|
|
6734
7008
|
const hiddens = /* @__PURE__ */ new Set();
|
|
6735
7009
|
for (const item of items) {
|
|
@@ -6740,15 +7014,15 @@ function Panel() {
|
|
|
6740
7014
|
}
|
|
6741
7015
|
return { orphanIds: orphans, hiddenIds: hiddens };
|
|
6742
7016
|
}, [items, panelOpen]);
|
|
6743
|
-
const activeFilter = (0,
|
|
7017
|
+
const activeFilter = (0, import_react14.useMemo)(
|
|
6744
7018
|
() => typeFilter.size + prioFilter.size + statusFilter.size > 0 ? { types: [...typeFilter], priorities: [...prioFilter], statuses: [...statusFilter] } : null,
|
|
6745
7019
|
[typeFilter, prioFilter, statusFilter]
|
|
6746
7020
|
);
|
|
6747
|
-
(0,
|
|
7021
|
+
(0, import_react14.useEffect)(() => {
|
|
6748
7022
|
dispatch({ type: "SET_FILTER", filter: activeFilter });
|
|
6749
7023
|
return () => dispatch({ type: "SET_FILTER", filter: null });
|
|
6750
7024
|
}, [activeFilter, dispatch]);
|
|
6751
|
-
const filtered = (0,
|
|
7025
|
+
const filtered = (0, import_react14.useMemo)(() => {
|
|
6752
7026
|
const q = query.trim().toLowerCase();
|
|
6753
7027
|
return items.map((item, index) => ({ item, number: index + 1 })).filter(({ item }) => {
|
|
6754
7028
|
if (!itemMatchesFilter(item, activeFilter)) return false;
|
|
@@ -6757,22 +7031,22 @@ function Panel() {
|
|
|
6757
7031
|
return haystack.includes(q);
|
|
6758
7032
|
});
|
|
6759
7033
|
}, [items, query, activeFilter]);
|
|
6760
|
-
const typeCounts = (0,
|
|
7034
|
+
const typeCounts = (0, import_react14.useMemo)(() => {
|
|
6761
7035
|
const counts = /* @__PURE__ */ new Map();
|
|
6762
7036
|
for (const item of items) counts.set(item.type, (counts.get(item.type) ?? 0) + 1);
|
|
6763
7037
|
return counts;
|
|
6764
7038
|
}, [items]);
|
|
6765
|
-
const prioCounts = (0,
|
|
7039
|
+
const prioCounts = (0, import_react14.useMemo)(() => {
|
|
6766
7040
|
const counts = /* @__PURE__ */ new Map();
|
|
6767
7041
|
for (const item of items) counts.set(item.priority, (counts.get(item.priority) ?? 0) + 1);
|
|
6768
7042
|
return counts;
|
|
6769
7043
|
}, [items]);
|
|
6770
|
-
const statusCounts = (0,
|
|
7044
|
+
const statusCounts = (0, import_react14.useMemo)(() => {
|
|
6771
7045
|
const counts = /* @__PURE__ */ new Map();
|
|
6772
7046
|
for (const item of items) counts.set(item.status, (counts.get(item.status) ?? 0) + 1);
|
|
6773
7047
|
return counts;
|
|
6774
7048
|
}, [items]);
|
|
6775
|
-
const groups = (0,
|
|
7049
|
+
const groups = (0, import_react14.useMemo)(() => {
|
|
6776
7050
|
const map = /* @__PURE__ */ new Map();
|
|
6777
7051
|
for (const entry of filtered) {
|
|
6778
7052
|
const list = map.get(entry.item.route) ?? [];
|
|
@@ -6781,7 +7055,7 @@ function Panel() {
|
|
|
6781
7055
|
}
|
|
6782
7056
|
return Array.from(map.entries());
|
|
6783
7057
|
}, [filtered]);
|
|
6784
|
-
(0,
|
|
7058
|
+
(0, import_react14.useEffect)(() => {
|
|
6785
7059
|
if (!filterOpen && !settingsOpen) return;
|
|
6786
7060
|
const onDown = (event) => {
|
|
6787
7061
|
const path = event.composedPath();
|
|
@@ -6792,7 +7066,7 @@ function Panel() {
|
|
|
6792
7066
|
document.addEventListener("pointerdown", onDown, true);
|
|
6793
7067
|
return () => document.removeEventListener("pointerdown", onDown, true);
|
|
6794
7068
|
}, [filterOpen, settingsOpen]);
|
|
6795
|
-
(0,
|
|
7069
|
+
(0, import_react14.useEffect)(() => {
|
|
6796
7070
|
if (!settingsOpen) return;
|
|
6797
7071
|
let alive = true;
|
|
6798
7072
|
const probe = () => {
|
|
@@ -6816,7 +7090,7 @@ function Panel() {
|
|
|
6816
7090
|
live: "paired",
|
|
6817
7091
|
off: "not paired"
|
|
6818
7092
|
}[emblemaPairState];
|
|
6819
|
-
(0,
|
|
7093
|
+
(0, import_react14.useEffect)(() => {
|
|
6820
7094
|
if (!panelOpen || activeItemId === null) return;
|
|
6821
7095
|
const row = panelRef.current?.querySelector(`[data-item-id="${activeItemId}"]`);
|
|
6822
7096
|
row?.scrollIntoView({ block: "nearest" });
|
|
@@ -6932,7 +7206,7 @@ function Panel() {
|
|
|
6932
7206
|
panel.style.transform = "";
|
|
6933
7207
|
if (dy > 110) dispatch({ type: "SET_PANEL", open: false });
|
|
6934
7208
|
};
|
|
6935
|
-
return /* @__PURE__ */ (0,
|
|
7209
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
6936
7210
|
"div",
|
|
6937
7211
|
{
|
|
6938
7212
|
ref: panelRef,
|
|
@@ -6942,7 +7216,7 @@ function Panel() {
|
|
|
6942
7216
|
"aria-label": "Review feedback panel",
|
|
6943
7217
|
onKeyDown,
|
|
6944
7218
|
children: [
|
|
6945
|
-
/* @__PURE__ */ (0,
|
|
7219
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6946
7220
|
"div",
|
|
6947
7221
|
{
|
|
6948
7222
|
className: "rk-sheet-handle",
|
|
@@ -6953,34 +7227,41 @@ function Panel() {
|
|
|
6953
7227
|
onPointerCancel: onSheetHandleUp
|
|
6954
7228
|
}
|
|
6955
7229
|
),
|
|
6956
|
-
/* @__PURE__ */ (0,
|
|
6957
|
-
/* @__PURE__ */ (0,
|
|
6958
|
-
/* @__PURE__ */ (0,
|
|
6959
|
-
/* @__PURE__ */ (0,
|
|
7230
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-head", children: [
|
|
7231
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
7232
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-panel-title", children: "Feedback" }),
|
|
7233
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-sub", children: [
|
|
6960
7234
|
items.length,
|
|
6961
7235
|
" item",
|
|
6962
7236
|
items.length === 1 ? "" : "s",
|
|
6963
7237
|
session.author ? ` \xB7 ${session.author}` : "",
|
|
6964
|
-
syncStatus !== "disabled" && /* @__PURE__ */ (0,
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
7238
|
+
syncStatus !== "disabled" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7239
|
+
"span",
|
|
7240
|
+
{
|
|
7241
|
+
className: `rk-sync rk-sync-${syncStatus}${syncReason ? ` rk-sync-reason-${syncReason}` : ""}`,
|
|
7242
|
+
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"],
|
|
7243
|
+
children: [
|
|
7244
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-sync-dot" }),
|
|
7245
|
+
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"]}`
|
|
7246
|
+
]
|
|
7247
|
+
}
|
|
7248
|
+
),
|
|
7249
|
+
config.emblema && emblemaPush !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
6969
7250
|
"span",
|
|
6970
7251
|
{
|
|
6971
7252
|
className: `rk-sync rk-epush-${emblemaPush}`,
|
|
6972
7253
|
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
7254
|
children: [
|
|
6974
|
-
/* @__PURE__ */ (0,
|
|
7255
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-sync-dot" }),
|
|
6975
7256
|
emblemaPush === "ok" ? "emblema" : emblemaPush === "sending" ? "emblema\u2026" : emblemaPush === "rejected" ? "emblema rejected" : "emblema offline"
|
|
6976
7257
|
]
|
|
6977
7258
|
}
|
|
6978
7259
|
)
|
|
6979
7260
|
] })
|
|
6980
7261
|
] }),
|
|
6981
|
-
/* @__PURE__ */ (0,
|
|
6982
|
-
/* @__PURE__ */ (0,
|
|
6983
|
-
/* @__PURE__ */ (0,
|
|
7262
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-spacer" }),
|
|
7263
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
|
|
7264
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6984
7265
|
"button",
|
|
6985
7266
|
{
|
|
6986
7267
|
type: "button",
|
|
@@ -6996,11 +7277,11 @@ function Panel() {
|
|
|
6996
7277
|
void pingEmblema(config.emblema).then((port) => setEmblemaAlive(port !== null));
|
|
6997
7278
|
}
|
|
6998
7279
|
},
|
|
6999
|
-
children: /* @__PURE__ */ (0,
|
|
7280
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconGear, { size: 15 })
|
|
7000
7281
|
}
|
|
7001
7282
|
),
|
|
7002
|
-
settingsOpen && /* @__PURE__ */ (0,
|
|
7003
|
-
config.token && /* @__PURE__ */ (0,
|
|
7283
|
+
settingsOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Session settings", children: [
|
|
7284
|
+
config.token && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7004
7285
|
"button",
|
|
7005
7286
|
{
|
|
7006
7287
|
type: "button",
|
|
@@ -7015,12 +7296,12 @@ function Panel() {
|
|
|
7015
7296
|
toast(dispatch, next ? "Review stays on in this tab" : "Review active only via the link", "info");
|
|
7016
7297
|
},
|
|
7017
7298
|
children: [
|
|
7018
|
-
/* @__PURE__ */ (0,
|
|
7299
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${sticky ? " rk-on" : ""}` }),
|
|
7019
7300
|
"Keep review on in this tab"
|
|
7020
7301
|
]
|
|
7021
7302
|
}
|
|
7022
7303
|
),
|
|
7023
|
-
config.emblema && /* @__PURE__ */ (0,
|
|
7304
|
+
config.emblema && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7024
7305
|
"button",
|
|
7025
7306
|
{
|
|
7026
7307
|
type: "button",
|
|
@@ -7050,7 +7331,7 @@ function Panel() {
|
|
|
7050
7331
|
}).finally(() => setEmblemaSending(false));
|
|
7051
7332
|
},
|
|
7052
7333
|
children: [
|
|
7053
|
-
/* @__PURE__ */ (0,
|
|
7334
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7054
7335
|
"span",
|
|
7055
7336
|
{
|
|
7056
7337
|
className: "rk-emblema-dot",
|
|
@@ -7061,25 +7342,40 @@ function Panel() {
|
|
|
7061
7342
|
]
|
|
7062
7343
|
}
|
|
7063
7344
|
),
|
|
7064
|
-
/* @__PURE__ */ (0,
|
|
7345
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7065
7346
|
"button",
|
|
7066
7347
|
{
|
|
7067
7348
|
type: "button",
|
|
7068
7349
|
role: "menuitem",
|
|
7069
7350
|
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",
|
|
7351
|
+
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
7352
|
onClick: () => {
|
|
7072
7353
|
setSettingsOpen(false);
|
|
7073
7354
|
dispatch({ type: "SET_EMBLEMA_CONNECT", open: true });
|
|
7074
7355
|
},
|
|
7075
7356
|
children: [
|
|
7076
|
-
/* @__PURE__ */ (0,
|
|
7357
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-emblema-dot", "data-state": emblemaPairState }),
|
|
7077
7358
|
"Connect to Emblema\u2026",
|
|
7078
|
-
/* @__PURE__ */ (0,
|
|
7359
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: emblemaPairLabel })
|
|
7079
7360
|
]
|
|
7080
7361
|
}
|
|
7081
7362
|
),
|
|
7082
|
-
/* @__PURE__ */ (0,
|
|
7363
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7364
|
+
"button",
|
|
7365
|
+
{
|
|
7366
|
+
type: "button",
|
|
7367
|
+
role: "menuitem",
|
|
7368
|
+
className: "rk-menu-item",
|
|
7369
|
+
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",
|
|
7370
|
+
disabled: !resolveSyncToken(config),
|
|
7371
|
+
onClick: () => {
|
|
7372
|
+
setSettingsOpen(false);
|
|
7373
|
+
dispatch({ type: "SET_TERMINAL_CONNECT", open: true });
|
|
7374
|
+
},
|
|
7375
|
+
children: "Connect terminal / agent\u2026"
|
|
7376
|
+
}
|
|
7377
|
+
),
|
|
7378
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7083
7379
|
"button",
|
|
7084
7380
|
{
|
|
7085
7381
|
type: "button",
|
|
@@ -7092,31 +7388,31 @@ function Panel() {
|
|
|
7092
7388
|
)
|
|
7093
7389
|
] })
|
|
7094
7390
|
] }),
|
|
7095
|
-
/* @__PURE__ */ (0,
|
|
7391
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7096
7392
|
"button",
|
|
7097
7393
|
{
|
|
7098
7394
|
type: "button",
|
|
7099
7395
|
className: "rk-icon-btn",
|
|
7100
7396
|
"aria-label": "Keyboard shortcuts",
|
|
7101
7397
|
onClick: () => dispatch({ type: "SET_CHEATSHEET", open: true }),
|
|
7102
|
-
children: /* @__PURE__ */ (0,
|
|
7398
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconKeyboard, { size: 15 })
|
|
7103
7399
|
}
|
|
7104
7400
|
),
|
|
7105
|
-
/* @__PURE__ */ (0,
|
|
7401
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7106
7402
|
"button",
|
|
7107
7403
|
{
|
|
7108
7404
|
type: "button",
|
|
7109
7405
|
className: "rk-icon-btn",
|
|
7110
7406
|
"aria-label": "Close panel",
|
|
7111
7407
|
onClick: () => dispatch({ type: "SET_PANEL", open: false }),
|
|
7112
|
-
children: /* @__PURE__ */ (0,
|
|
7408
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconClose, { size: 14 })
|
|
7113
7409
|
}
|
|
7114
7410
|
)
|
|
7115
7411
|
] }),
|
|
7116
|
-
/* @__PURE__ */ (0,
|
|
7117
|
-
/* @__PURE__ */ (0,
|
|
7118
|
-
/* @__PURE__ */ (0,
|
|
7119
|
-
/* @__PURE__ */ (0,
|
|
7412
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-view-row", children: [
|
|
7413
|
+
/* @__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" }) }),
|
|
7414
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-seg rk-view-toggle", role: "group", "aria-label": "Page view (P to toggle)", children: [
|
|
7415
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7120
7416
|
"button",
|
|
7121
7417
|
{
|
|
7122
7418
|
type: "button",
|
|
@@ -7126,7 +7422,7 @@ function Panel() {
|
|
|
7126
7422
|
children: "Original"
|
|
7127
7423
|
}
|
|
7128
7424
|
),
|
|
7129
|
-
/* @__PURE__ */ (0,
|
|
7425
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7130
7426
|
"button",
|
|
7131
7427
|
{
|
|
7132
7428
|
type: "button",
|
|
@@ -7138,8 +7434,8 @@ function Panel() {
|
|
|
7138
7434
|
)
|
|
7139
7435
|
] })
|
|
7140
7436
|
] }),
|
|
7141
|
-
/* @__PURE__ */ (0,
|
|
7142
|
-
/* @__PURE__ */ (0,
|
|
7437
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-tools", children: [
|
|
7438
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7143
7439
|
"button",
|
|
7144
7440
|
{
|
|
7145
7441
|
type: "button",
|
|
@@ -7150,15 +7446,15 @@ function Panel() {
|
|
|
7150
7446
|
dispatch({ type: "SET_MODE", mode: "pick" });
|
|
7151
7447
|
},
|
|
7152
7448
|
children: [
|
|
7153
|
-
/* @__PURE__ */ (0,
|
|
7449
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTarget, { size: 14 }),
|
|
7154
7450
|
" Pick an element"
|
|
7155
7451
|
]
|
|
7156
7452
|
}
|
|
7157
7453
|
),
|
|
7158
|
-
/* @__PURE__ */ (0,
|
|
7159
|
-
/* @__PURE__ */ (0,
|
|
7160
|
-
/* @__PURE__ */ (0,
|
|
7161
|
-
/* @__PURE__ */ (0,
|
|
7454
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-search-row", children: [
|
|
7455
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-search", children: [
|
|
7456
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconSearch, { size: 13 }),
|
|
7457
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7162
7458
|
"input",
|
|
7163
7459
|
{
|
|
7164
7460
|
ref: searchRef,
|
|
@@ -7170,8 +7466,8 @@ function Panel() {
|
|
|
7170
7466
|
}
|
|
7171
7467
|
)
|
|
7172
7468
|
] }),
|
|
7173
|
-
/* @__PURE__ */ (0,
|
|
7174
|
-
/* @__PURE__ */ (0,
|
|
7469
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu-scope rk-menu-anchor", children: [
|
|
7470
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7175
7471
|
"button",
|
|
7176
7472
|
{
|
|
7177
7473
|
type: "button",
|
|
@@ -7183,15 +7479,15 @@ function Panel() {
|
|
|
7183
7479
|
setSettingsOpen(false);
|
|
7184
7480
|
},
|
|
7185
7481
|
children: [
|
|
7186
|
-
/* @__PURE__ */ (0,
|
|
7482
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFilter, { size: 13 }),
|
|
7187
7483
|
"Filter",
|
|
7188
|
-
typeFilter.size + prioFilter.size + statusFilter.size > 0 && /* @__PURE__ */ (0,
|
|
7484
|
+
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
7485
|
]
|
|
7190
7486
|
}
|
|
7191
7487
|
),
|
|
7192
|
-
filterOpen && /* @__PURE__ */ (0,
|
|
7193
|
-
/* @__PURE__ */ (0,
|
|
7194
|
-
TYPE_FILTERS.map((type) => /* @__PURE__ */ (0,
|
|
7488
|
+
filterOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-menu", role: "menu", "aria-label": "Filter items", children: [
|
|
7489
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Type" }),
|
|
7490
|
+
TYPE_FILTERS.map((type) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7195
7491
|
"button",
|
|
7196
7492
|
{
|
|
7197
7493
|
type: "button",
|
|
@@ -7205,16 +7501,16 @@ function Panel() {
|
|
|
7205
7501
|
setTypeFilter(next);
|
|
7206
7502
|
},
|
|
7207
7503
|
children: [
|
|
7208
|
-
/* @__PURE__ */ (0,
|
|
7504
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${typeFilter.has(type) ? " rk-on" : ""}` }),
|
|
7209
7505
|
iconForType(type, 12),
|
|
7210
|
-
/* @__PURE__ */ (0,
|
|
7211
|
-
/* @__PURE__ */ (0,
|
|
7506
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: type }),
|
|
7507
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: typeCounts.get(type) ?? 0 })
|
|
7212
7508
|
]
|
|
7213
7509
|
},
|
|
7214
7510
|
type
|
|
7215
7511
|
)),
|
|
7216
|
-
/* @__PURE__ */ (0,
|
|
7217
|
-
PRIORITY_FILTERS.map((priority) => /* @__PURE__ */ (0,
|
|
7512
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Priority" }),
|
|
7513
|
+
PRIORITY_FILTERS.map((priority) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7218
7514
|
"button",
|
|
7219
7515
|
{
|
|
7220
7516
|
type: "button",
|
|
@@ -7228,15 +7524,15 @@ function Panel() {
|
|
|
7228
7524
|
setPrioFilter(next);
|
|
7229
7525
|
},
|
|
7230
7526
|
children: [
|
|
7231
|
-
/* @__PURE__ */ (0,
|
|
7232
|
-
/* @__PURE__ */ (0,
|
|
7233
|
-
/* @__PURE__ */ (0,
|
|
7527
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${prioFilter.has(priority) ? " rk-on" : ""}` }),
|
|
7528
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: PRIORITY_LABELS[priority] }),
|
|
7529
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: prioCounts.get(priority) ?? 0 })
|
|
7234
7530
|
]
|
|
7235
7531
|
},
|
|
7236
7532
|
priority
|
|
7237
7533
|
)),
|
|
7238
|
-
/* @__PURE__ */ (0,
|
|
7239
|
-
STATUSES.map((status) => /* @__PURE__ */ (0,
|
|
7534
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-menu-title", children: "Status" }),
|
|
7535
|
+
STATUSES.map((status) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7240
7536
|
"button",
|
|
7241
7537
|
{
|
|
7242
7538
|
type: "button",
|
|
@@ -7250,15 +7546,15 @@ function Panel() {
|
|
|
7250
7546
|
setStatusFilter(next);
|
|
7251
7547
|
},
|
|
7252
7548
|
children: [
|
|
7253
|
-
/* @__PURE__ */ (0,
|
|
7254
|
-
/* @__PURE__ */ (0,
|
|
7255
|
-
/* @__PURE__ */ (0,
|
|
7256
|
-
/* @__PURE__ */ (0,
|
|
7549
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-menu-check${statusFilter.has(status) ? " rk-on" : ""}` }),
|
|
7550
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-status-dot rk-st-${status}` }),
|
|
7551
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-label", children: status }),
|
|
7552
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-menu-count", children: statusCounts.get(status) ?? 0 })
|
|
7257
7553
|
]
|
|
7258
7554
|
},
|
|
7259
7555
|
status
|
|
7260
7556
|
)),
|
|
7261
|
-
/* @__PURE__ */ (0,
|
|
7557
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7262
7558
|
"button",
|
|
7263
7559
|
{
|
|
7264
7560
|
type: "button",
|
|
@@ -7278,24 +7574,24 @@ function Panel() {
|
|
|
7278
7574
|
] })
|
|
7279
7575
|
] })
|
|
7280
7576
|
] }),
|
|
7281
|
-
preview && unapplied > 0 && /* @__PURE__ */ (0,
|
|
7577
|
+
preview && unapplied > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-unplaced", role: "status", children: [
|
|
7282
7578
|
unapplied,
|
|
7283
7579
|
" saved change",
|
|
7284
7580
|
unapplied === 1 ? "" : "s",
|
|
7285
7581
|
" couldn\u2019t be placed on the current page \u2014 the page has changed since they were captured."
|
|
7286
7582
|
] }),
|
|
7287
|
-
/* @__PURE__ */ (0,
|
|
7288
|
-
/* @__PURE__ */ (0,
|
|
7289
|
-
/* @__PURE__ */ (0,
|
|
7290
|
-
/* @__PURE__ */ (0,
|
|
7291
|
-
] }) : groups.map(([route, entries]) => /* @__PURE__ */ (0,
|
|
7292
|
-
/* @__PURE__ */ (0,
|
|
7583
|
+
/* @__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: [
|
|
7584
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-art", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTarget, { size: 22 }) }),
|
|
7585
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-empty-title", children: items.length === 0 ? "Nothing here yet" : "No matches" }),
|
|
7586
|
+
/* @__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." })
|
|
7587
|
+
] }) : groups.map(([route, entries]) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
7588
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rk-group-title", children: route }),
|
|
7293
7589
|
entries.map(({ item, number }) => {
|
|
7294
7590
|
const active2 = item.id === activeItemId;
|
|
7295
7591
|
const orphan = orphanIds.has(item.id);
|
|
7296
7592
|
const hiddenEl = hiddenIds.has(item.id);
|
|
7297
|
-
return /* @__PURE__ */ (0,
|
|
7298
|
-
/* @__PURE__ */ (0,
|
|
7593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
7594
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7299
7595
|
"div",
|
|
7300
7596
|
{
|
|
7301
7597
|
"data-item-id": item.id,
|
|
@@ -7310,18 +7606,18 @@ function Panel() {
|
|
|
7310
7606
|
}
|
|
7311
7607
|
},
|
|
7312
7608
|
children: [
|
|
7313
|
-
/* @__PURE__ */ (0,
|
|
7314
|
-
/* @__PURE__ */ (0,
|
|
7315
|
-
/* @__PURE__ */ (0,
|
|
7316
|
-
/* @__PURE__ */ (0,
|
|
7609
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-num", children: number }),
|
|
7610
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-icon", children: iconForType(item.type) }),
|
|
7611
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-body", children: [
|
|
7612
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-snippet", children: [
|
|
7317
7613
|
item.target.tagName,
|
|
7318
7614
|
" \xB7 ",
|
|
7319
7615
|
item.target.textSnippet || item.target.selector
|
|
7320
7616
|
] }),
|
|
7321
|
-
/* @__PURE__ */ (0,
|
|
7322
|
-
/* @__PURE__ */ (0,
|
|
7323
|
-
/* @__PURE__ */ (0,
|
|
7324
|
-
/* @__PURE__ */ (0,
|
|
7617
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-change", children: changeSummary(item) }),
|
|
7618
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-item-meta", children: [
|
|
7619
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-author", title: new Date(item.createdAt).toLocaleString(), children: [
|
|
7620
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7325
7621
|
"span",
|
|
7326
7622
|
{
|
|
7327
7623
|
className: "rk-author-dot",
|
|
@@ -7329,15 +7625,15 @@ function Panel() {
|
|
|
7329
7625
|
}
|
|
7330
7626
|
),
|
|
7331
7627
|
item.author?.name ?? "Unknown",
|
|
7332
|
-
/* @__PURE__ */ (0,
|
|
7628
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "rk-time", children: [
|
|
7333
7629
|
" \xB7 ",
|
|
7334
7630
|
timeAgo(item.createdAt)
|
|
7335
7631
|
] })
|
|
7336
7632
|
] }),
|
|
7337
|
-
item.priority === "must" && /* @__PURE__ */ (0,
|
|
7338
|
-
item.status !== "open" && /* @__PURE__ */ (0,
|
|
7339
|
-
orphan && /* @__PURE__ */ (0,
|
|
7340
|
-
hiddenEl && /* @__PURE__ */ (0,
|
|
7633
|
+
item.priority === "must" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini rk-must", children: "must" }),
|
|
7634
|
+
item.status !== "open" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rk-badge-mini rk-${item.status}`, children: item.status }),
|
|
7635
|
+
orphan && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini rk-orphaned", children: "unanchored" }),
|
|
7636
|
+
hiddenEl && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7341
7637
|
"span",
|
|
7342
7638
|
{
|
|
7343
7639
|
className: "rk-badge-mini rk-hidden-el",
|
|
@@ -7345,14 +7641,14 @@ function Panel() {
|
|
|
7345
7641
|
children: "hidden"
|
|
7346
7642
|
}
|
|
7347
7643
|
),
|
|
7348
|
-
item.note && /* @__PURE__ */ (0,
|
|
7349
|
-
peers.filter((peer) => peer.typingActive && peer.typingItemId === item.id).map((peer) => /* @__PURE__ */ (0,
|
|
7644
|
+
item.note && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-badge-mini", children: "note" }),
|
|
7645
|
+
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
7646
|
peer.name || "peer",
|
|
7351
7647
|
" is writing\u2026"
|
|
7352
7648
|
] }, peer.id))
|
|
7353
7649
|
] })
|
|
7354
7650
|
] }),
|
|
7355
|
-
/* @__PURE__ */ (0,
|
|
7651
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-item-actions", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7356
7652
|
"button",
|
|
7357
7653
|
{
|
|
7358
7654
|
type: "button",
|
|
@@ -7367,15 +7663,15 @@ function Panel() {
|
|
|
7367
7663
|
"info"
|
|
7368
7664
|
);
|
|
7369
7665
|
},
|
|
7370
|
-
children: /* @__PURE__ */ (0,
|
|
7666
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconTrash, { size: 13 })
|
|
7371
7667
|
}
|
|
7372
7668
|
) })
|
|
7373
7669
|
]
|
|
7374
7670
|
}
|
|
7375
7671
|
),
|
|
7376
|
-
active2 && /* @__PURE__ */ (0,
|
|
7377
|
-
/* @__PURE__ */ (0,
|
|
7378
|
-
/* @__PURE__ */ (0,
|
|
7672
|
+
active2 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-item-edit", children: [
|
|
7673
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-detail-byline", title: new Date(item.createdAt).toLocaleString(), children: [
|
|
7674
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7379
7675
|
"span",
|
|
7380
7676
|
{
|
|
7381
7677
|
className: "rk-author-dot",
|
|
@@ -7386,8 +7682,8 @@ function Panel() {
|
|
|
7386
7682
|
" \xB7 ",
|
|
7387
7683
|
timeAgo(item.createdAt)
|
|
7388
7684
|
] }),
|
|
7389
|
-
isCopyItem(item) && /* @__PURE__ */ (0,
|
|
7390
|
-
isImageItem(item) && /* @__PURE__ */ (0,
|
|
7685
|
+
isCopyItem(item) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CopyDiff, { before: item.payload.before, after: item.payload.after }),
|
|
7686
|
+
isImageItem(item) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7391
7687
|
ImageDetail,
|
|
7392
7688
|
{
|
|
7393
7689
|
beforeSrc: item.payload.beforeSrc,
|
|
@@ -7395,7 +7691,7 @@ function Panel() {
|
|
|
7395
7691
|
afterDataUrl: item.payload.afterDataUrl
|
|
7396
7692
|
}
|
|
7397
7693
|
),
|
|
7398
|
-
isKnownItemType(item.type) && item.type !== "move" && /* @__PURE__ */ (0,
|
|
7694
|
+
isKnownItemType(item.type) && item.type !== "move" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7399
7695
|
"textarea",
|
|
7400
7696
|
{
|
|
7401
7697
|
className: "rk-textarea",
|
|
@@ -7405,7 +7701,7 @@ function Panel() {
|
|
|
7405
7701
|
onChange: (event) => dispatch({ type: "UPDATE_ITEM", id: item.id, patch: withPayloadText(item, event.target.value) })
|
|
7406
7702
|
}
|
|
7407
7703
|
),
|
|
7408
|
-
/* @__PURE__ */ (0,
|
|
7704
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7409
7705
|
"input",
|
|
7410
7706
|
{
|
|
7411
7707
|
className: "rk-input",
|
|
@@ -7415,9 +7711,9 @@ function Panel() {
|
|
|
7415
7711
|
onChange: (event) => dispatch({ type: "UPDATE_ITEM", id: item.id, patch: { note: event.target.value } })
|
|
7416
7712
|
}
|
|
7417
7713
|
),
|
|
7418
|
-
/* @__PURE__ */ (0,
|
|
7419
|
-
/* @__PURE__ */ (0,
|
|
7420
|
-
/* @__PURE__ */ (0,
|
|
7714
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
|
|
7715
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-seg", role: "group", "aria-label": "Priority", children: [
|
|
7716
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7421
7717
|
"button",
|
|
7422
7718
|
{
|
|
7423
7719
|
type: "button",
|
|
@@ -7426,7 +7722,7 @@ function Panel() {
|
|
|
7426
7722
|
children: "Must"
|
|
7427
7723
|
}
|
|
7428
7724
|
),
|
|
7429
|
-
/* @__PURE__ */ (0,
|
|
7725
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7430
7726
|
"button",
|
|
7431
7727
|
{
|
|
7432
7728
|
type: "button",
|
|
@@ -7436,7 +7732,7 @@ function Panel() {
|
|
|
7436
7732
|
}
|
|
7437
7733
|
)
|
|
7438
7734
|
] }),
|
|
7439
|
-
/* @__PURE__ */ (0,
|
|
7735
|
+
/* @__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
7736
|
"button",
|
|
7441
7737
|
{
|
|
7442
7738
|
type: "button",
|
|
@@ -7451,22 +7747,22 @@ function Panel() {
|
|
|
7451
7747
|
] }, item.id);
|
|
7452
7748
|
})
|
|
7453
7749
|
] }, route)) }),
|
|
7454
|
-
/* @__PURE__ */ (0,
|
|
7455
|
-
/* @__PURE__ */ (0,
|
|
7456
|
-
/* @__PURE__ */ (0,
|
|
7750
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rk-panel-foot", children: [
|
|
7751
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: onExport, disabled: items.length === 0, children: [
|
|
7752
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconDownload, { size: 13 }),
|
|
7457
7753
|
" Export"
|
|
7458
7754
|
] }),
|
|
7459
|
-
/* @__PURE__ */ (0,
|
|
7460
|
-
/* @__PURE__ */ (0,
|
|
7755
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => void onCopy(), disabled: items.length === 0, children: [
|
|
7756
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconCopyClipboard, { size: 13 }),
|
|
7461
7757
|
" Copy"
|
|
7462
7758
|
] }),
|
|
7463
|
-
/* @__PURE__ */ (0,
|
|
7464
|
-
/* @__PURE__ */ (0,
|
|
7759
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "button", className: "rk-btn rk-btn-ghost", onClick: () => importRef.current?.click(), children: [
|
|
7760
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconUpload, { size: 13 }),
|
|
7465
7761
|
" Import"
|
|
7466
7762
|
] }),
|
|
7467
|
-
/* @__PURE__ */ (0,
|
|
7468
|
-
undoStack.length > 0 && /* @__PURE__ */ (0,
|
|
7469
|
-
/* @__PURE__ */ (0,
|
|
7763
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rk-spacer" }),
|
|
7764
|
+
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 }) }),
|
|
7765
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7470
7766
|
"button",
|
|
7471
7767
|
{
|
|
7472
7768
|
type: "button",
|
|
@@ -7477,7 +7773,7 @@ function Panel() {
|
|
|
7477
7773
|
children: "Clear"
|
|
7478
7774
|
}
|
|
7479
7775
|
),
|
|
7480
|
-
/* @__PURE__ */ (0,
|
|
7776
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7481
7777
|
"button",
|
|
7482
7778
|
{
|
|
7483
7779
|
type: "button",
|
|
@@ -7487,7 +7783,7 @@ function Panel() {
|
|
|
7487
7783
|
children: "Exit review"
|
|
7488
7784
|
}
|
|
7489
7785
|
),
|
|
7490
|
-
/* @__PURE__ */ (0,
|
|
7786
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
7491
7787
|
"input",
|
|
7492
7788
|
{
|
|
7493
7789
|
ref: importRef,
|
|
@@ -7508,8 +7804,8 @@ function Panel() {
|
|
|
7508
7804
|
}
|
|
7509
7805
|
|
|
7510
7806
|
// src/client/components/Presence.tsx
|
|
7511
|
-
var
|
|
7512
|
-
var
|
|
7807
|
+
var import_react15 = require("react");
|
|
7808
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
7513
7809
|
function initials(name) {
|
|
7514
7810
|
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
7515
7811
|
if (parts.length === 0) return "\xB7";
|
|
@@ -7519,8 +7815,8 @@ function initials(name) {
|
|
|
7519
7815
|
function PresenceStrip() {
|
|
7520
7816
|
const { peers, syncStatus } = useStore();
|
|
7521
7817
|
if (syncStatus === "disabled" || peers.length === 0) return null;
|
|
7522
|
-
return /* @__PURE__ */ (0,
|
|
7523
|
-
peers.slice(0, 5).map((peer) => /* @__PURE__ */ (0,
|
|
7818
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rk-presence", "aria-label": `${peers.length} reviewer${peers.length === 1 ? "" : "s"} online`, children: [
|
|
7819
|
+
peers.slice(0, 5).map((peer) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7524
7820
|
"span",
|
|
7525
7821
|
{
|
|
7526
7822
|
className: "rk-avatar",
|
|
@@ -7530,7 +7826,7 @@ function PresenceStrip() {
|
|
|
7530
7826
|
},
|
|
7531
7827
|
peer.id
|
|
7532
7828
|
)),
|
|
7533
|
-
peers.length > 5 && /* @__PURE__ */ (0,
|
|
7829
|
+
peers.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "rk-avatar rk-avatar-more", children: [
|
|
7534
7830
|
"+",
|
|
7535
7831
|
peers.length - 5
|
|
7536
7832
|
] })
|
|
@@ -7538,13 +7834,13 @@ function PresenceStrip() {
|
|
|
7538
7834
|
}
|
|
7539
7835
|
function PeerCursors() {
|
|
7540
7836
|
const { peers } = useStore();
|
|
7541
|
-
const ringRefs = (0,
|
|
7542
|
-
const cursorRefs = (0,
|
|
7543
|
-
const motion = (0,
|
|
7837
|
+
const ringRefs = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
|
|
7838
|
+
const cursorRefs = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
|
|
7839
|
+
const motion = (0, import_react15.useRef)(
|
|
7544
7840
|
/* @__PURE__ */ new Map()
|
|
7545
7841
|
);
|
|
7546
|
-
const peersRef = (0,
|
|
7547
|
-
const seen = (0,
|
|
7842
|
+
const peersRef = (0, import_react15.useRef)(peers);
|
|
7843
|
+
const seen = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
|
|
7548
7844
|
for (const peer of peers) {
|
|
7549
7845
|
const sig = peer.cursor ? `${peer.cursor.x},${peer.cursor.y},${peer.cursor.ox},${peer.cursor.oy}` : "";
|
|
7550
7846
|
if (seen.current.get(peer.id) !== sig) {
|
|
@@ -7554,7 +7850,7 @@ function PeerCursors() {
|
|
|
7554
7850
|
}
|
|
7555
7851
|
}
|
|
7556
7852
|
peersRef.current = peers;
|
|
7557
|
-
(0,
|
|
7853
|
+
(0, import_react15.useEffect)(() => {
|
|
7558
7854
|
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
7559
7855
|
let raf = 0;
|
|
7560
7856
|
let last = performance.now();
|
|
@@ -7659,8 +7955,8 @@ function PeerCursors() {
|
|
|
7659
7955
|
return () => cancelAnimationFrame(raf);
|
|
7660
7956
|
}, []);
|
|
7661
7957
|
if (peers.length === 0) return null;
|
|
7662
|
-
return /* @__PURE__ */ (0,
|
|
7663
|
-
peers.map((peer) => /* @__PURE__ */ (0,
|
|
7958
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
7959
|
+
peers.map((peer) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7664
7960
|
"div",
|
|
7665
7961
|
{
|
|
7666
7962
|
ref: (el) => {
|
|
@@ -7672,7 +7968,7 @@ function PeerCursors() {
|
|
|
7672
7968
|
},
|
|
7673
7969
|
`ring-${peer.id}`
|
|
7674
7970
|
)),
|
|
7675
|
-
peers.map((peer, index) => /* @__PURE__ */ (0,
|
|
7971
|
+
peers.map((peer, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7676
7972
|
"div",
|
|
7677
7973
|
{
|
|
7678
7974
|
ref: (el) => {
|
|
@@ -7682,8 +7978,8 @@ function PeerCursors() {
|
|
|
7682
7978
|
className: "rk-peer-cursor",
|
|
7683
7979
|
style: { opacity: 0 },
|
|
7684
7980
|
children: [
|
|
7685
|
-
/* @__PURE__ */ (0,
|
|
7686
|
-
/* @__PURE__ */ (0,
|
|
7981
|
+
/* @__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" }) }),
|
|
7982
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7687
7983
|
"span",
|
|
7688
7984
|
{
|
|
7689
7985
|
className: "rk-peer-name",
|
|
@@ -7702,19 +7998,19 @@ function PeerCursors() {
|
|
|
7702
7998
|
}
|
|
7703
7999
|
|
|
7704
8000
|
// src/client/components/QuickComment.tsx
|
|
7705
|
-
var
|
|
7706
|
-
var
|
|
8001
|
+
var import_react16 = require("react");
|
|
8002
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
7707
8003
|
function QuickComment() {
|
|
7708
8004
|
const { quick } = useStore();
|
|
7709
8005
|
if (!quick) return null;
|
|
7710
|
-
return /* @__PURE__ */ (0,
|
|
8006
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(QuickComposerCard, { quick }, quick.id);
|
|
7711
8007
|
}
|
|
7712
8008
|
function QuickComposerCard({ quick }) {
|
|
7713
8009
|
const { route, session } = useStore();
|
|
7714
8010
|
const dispatch = useDispatch();
|
|
7715
|
-
const [text, setText] = (0,
|
|
7716
|
-
const fieldRef = (0,
|
|
7717
|
-
(0,
|
|
8011
|
+
const [text, setText] = (0, import_react16.useState)("");
|
|
8012
|
+
const fieldRef = (0, import_react16.useRef)(null);
|
|
8013
|
+
(0, import_react16.useEffect)(() => {
|
|
7718
8014
|
const field = fieldRef.current;
|
|
7719
8015
|
if (!field) return;
|
|
7720
8016
|
field.focus();
|
|
@@ -7767,18 +8063,18 @@ function QuickComposerCard({ quick }) {
|
|
|
7767
8063
|
};
|
|
7768
8064
|
const x = Math.min(Math.max(quick.x, 8), window.innerWidth - 288);
|
|
7769
8065
|
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,
|
|
8066
|
+
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: [
|
|
8067
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rk-quick-head", children: [
|
|
8068
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(IconComment, { size: 12 }),
|
|
8069
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Comment here" }),
|
|
8070
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "rk-hint", children: [
|
|
8071
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-kbd", children: "\u21B5" }),
|
|
7776
8072
|
" save \xB7 ",
|
|
7777
|
-
/* @__PURE__ */ (0,
|
|
8073
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "rk-kbd", children: "esc" }),
|
|
7778
8074
|
" cancel"
|
|
7779
8075
|
] })
|
|
7780
8076
|
] }),
|
|
7781
|
-
/* @__PURE__ */ (0,
|
|
8077
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7782
8078
|
"textarea",
|
|
7783
8079
|
{
|
|
7784
8080
|
ref: fieldRef,
|
|
@@ -7794,8 +8090,8 @@ function QuickComposerCard({ quick }) {
|
|
|
7794
8090
|
}
|
|
7795
8091
|
|
|
7796
8092
|
// src/client/components/PickLayer.tsx
|
|
7797
|
-
var
|
|
7798
|
-
var
|
|
8093
|
+
var import_react17 = require("react");
|
|
8094
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
7799
8095
|
function applyRect(el, rect, pad2 = 3) {
|
|
7800
8096
|
if (!el) return;
|
|
7801
8097
|
if (!rect) {
|
|
@@ -7810,14 +8106,14 @@ function applyRect(el, rect, pad2 = 3) {
|
|
|
7810
8106
|
function PickLayer() {
|
|
7811
8107
|
const { mode, selection, tool } = useStore();
|
|
7812
8108
|
const dispatch = useDispatch();
|
|
7813
|
-
const [hovered, setHovered] = (0,
|
|
7814
|
-
const outlineRef = (0,
|
|
7815
|
-
const labelRef = (0,
|
|
7816
|
-
const selectRef = (0,
|
|
7817
|
-
const hoveredRef = (0,
|
|
8109
|
+
const [hovered, setHovered] = (0, import_react17.useState)(null);
|
|
8110
|
+
const outlineRef = (0, import_react17.useRef)(null);
|
|
8111
|
+
const labelRef = (0, import_react17.useRef)(null);
|
|
8112
|
+
const selectRef = (0, import_react17.useRef)(null);
|
|
8113
|
+
const hoveredRef = (0, import_react17.useRef)(null);
|
|
7818
8114
|
hoveredRef.current = hovered;
|
|
7819
8115
|
const picking = mode === "pick";
|
|
7820
|
-
(0,
|
|
8116
|
+
(0, import_react17.useEffect)(() => {
|
|
7821
8117
|
if (!picking) {
|
|
7822
8118
|
setHovered(null);
|
|
7823
8119
|
return;
|
|
@@ -7861,7 +8157,7 @@ function PickLayer() {
|
|
|
7861
8157
|
document.removeEventListener("mousedown", swallow, true);
|
|
7862
8158
|
};
|
|
7863
8159
|
}, [picking, tool, dispatch]);
|
|
7864
|
-
(0,
|
|
8160
|
+
(0, import_react17.useEffect)(() => {
|
|
7865
8161
|
if (!picking) return;
|
|
7866
8162
|
const body = document.body;
|
|
7867
8163
|
const prev = body.style.cursor;
|
|
@@ -7871,7 +8167,7 @@ function PickLayer() {
|
|
|
7871
8167
|
if (body.getAttribute("style") === "") body.removeAttribute("style");
|
|
7872
8168
|
};
|
|
7873
8169
|
}, [picking, tool]);
|
|
7874
|
-
(0,
|
|
8170
|
+
(0, import_react17.useEffect)(() => {
|
|
7875
8171
|
let raf = 0;
|
|
7876
8172
|
const tick = () => {
|
|
7877
8173
|
const hoverEl = hoveredRef.current;
|
|
@@ -7897,21 +8193,21 @@ function PickLayer() {
|
|
|
7897
8193
|
raf = requestAnimationFrame(tick);
|
|
7898
8194
|
return () => cancelAnimationFrame(raf);
|
|
7899
8195
|
}, [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,
|
|
8196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
8197
|
+
picking && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
8198
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: outlineRef, className: "rk-outline", style: { opacity: 0 } }),
|
|
8199
|
+
/* @__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: [
|
|
8200
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rk-tag", children: hovered.tagName.toLowerCase() }),
|
|
8201
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: describeElement(hovered).replace(/^[a-z0-9]+ · /, "") })
|
|
8202
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Pick an element" }) })
|
|
7907
8203
|
] }),
|
|
7908
|
-
selection && /* @__PURE__ */ (0,
|
|
8204
|
+
selection && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: selectRef, className: "rk-select-ring", style: { opacity: 0 } })
|
|
7909
8205
|
] });
|
|
7910
8206
|
}
|
|
7911
8207
|
|
|
7912
8208
|
// src/client/components/Pins.tsx
|
|
7913
|
-
var
|
|
7914
|
-
var
|
|
8209
|
+
var import_react18 = require("react");
|
|
8210
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
7915
8211
|
var STATUS_LABELS = {
|
|
7916
8212
|
open: "open",
|
|
7917
8213
|
accepted: "accepted",
|
|
@@ -7923,22 +8219,22 @@ var RERESOLVE_MS = 800;
|
|
|
7923
8219
|
function Pins() {
|
|
7924
8220
|
const { session, route, activeItemId, editor, mode, filter } = useStore();
|
|
7925
8221
|
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,
|
|
8222
|
+
const [clusters, setClusters] = (0, import_react18.useState)([]);
|
|
8223
|
+
const [orphanCount, setOrphanCount] = (0, import_react18.useState)(0);
|
|
8224
|
+
const wrapRefs = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
8225
|
+
const visibleCache = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
8226
|
+
const highlightRef = (0, import_react18.useRef)(null);
|
|
8227
|
+
const hoveredItems = (0, import_react18.useRef)(null);
|
|
8228
|
+
const elementCache = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
8229
|
+
const lastResolve = (0, import_react18.useRef)(0);
|
|
8230
|
+
const [newestId, setNewestId] = (0, import_react18.useState)(null);
|
|
8231
|
+
const prevCount = (0, import_react18.useRef)(0);
|
|
8232
|
+
const items = (0, import_react18.useMemo)(() => {
|
|
7937
8233
|
const all = session?.items ?? [];
|
|
7938
8234
|
return all.map((item, index) => ({ item, number: index + 1 })).filter(({ item }) => item.route === route);
|
|
7939
8235
|
}, [session, route]);
|
|
7940
8236
|
const byId = new Map(items.map(({ item }) => [item.id, item]));
|
|
7941
|
-
(0,
|
|
8237
|
+
(0, import_react18.useEffect)(() => {
|
|
7942
8238
|
const count = session?.items.length ?? 0;
|
|
7943
8239
|
if (count > prevCount.current && session && count > 0) {
|
|
7944
8240
|
const id = session.items[count - 1].id;
|
|
@@ -7949,7 +8245,7 @@ function Pins() {
|
|
|
7949
8245
|
}
|
|
7950
8246
|
prevCount.current = count;
|
|
7951
8247
|
}, [session]);
|
|
7952
|
-
(0,
|
|
8248
|
+
(0, import_react18.useEffect)(() => {
|
|
7953
8249
|
let raf = 0;
|
|
7954
8250
|
let lastSignature = "";
|
|
7955
8251
|
const tick = (time) => {
|
|
@@ -8033,8 +8329,8 @@ function Pins() {
|
|
|
8033
8329
|
dispatch({ type: "SET_ACTIVE_ITEM", id });
|
|
8034
8330
|
dispatch({ type: "SET_PANEL", open: true });
|
|
8035
8331
|
};
|
|
8036
|
-
return /* @__PURE__ */ (0,
|
|
8037
|
-
/* @__PURE__ */ (0,
|
|
8332
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
8333
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref: highlightRef, className: "rk-hl-ring", style: { opacity: 0 } }),
|
|
8038
8334
|
clusters.map((cluster) => {
|
|
8039
8335
|
const isCluster = cluster.ids.length > 1;
|
|
8040
8336
|
const isActive = activeItemId !== null && cluster.ids.includes(activeItemId);
|
|
@@ -8044,7 +8340,7 @@ function Pins() {
|
|
|
8044
8340
|
const status = statuses.size === 1 ? members[0]?.status : void 0;
|
|
8045
8341
|
const dimmed = filter !== null && members.length > 0 && !members.some((item) => itemMatchesFilter(item, filter));
|
|
8046
8342
|
const statusHint = isCluster ? status ? ` \xB7 all ${STATUS_LABELS[status] ?? status}` : "" : ` \xB7 ${STATUS_LABELS[members[0]?.status ?? "open"] ?? members[0]?.status}`;
|
|
8047
|
-
return /* @__PURE__ */ (0,
|
|
8343
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
8048
8344
|
"div",
|
|
8049
8345
|
{
|
|
8050
8346
|
ref: (el) => {
|
|
@@ -8052,7 +8348,7 @@ function Pins() {
|
|
|
8052
8348
|
else wrapRefs.current.delete(cluster.key);
|
|
8053
8349
|
},
|
|
8054
8350
|
className: `rk-pin-wrap${picking ? " rk-pin-ghost" : ""}`,
|
|
8055
|
-
children: /* @__PURE__ */ (0,
|
|
8351
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
8056
8352
|
"button",
|
|
8057
8353
|
{
|
|
8058
8354
|
type: "button",
|
|
@@ -8074,7 +8370,7 @@ function Pins() {
|
|
|
8074
8370
|
cluster.key
|
|
8075
8371
|
);
|
|
8076
8372
|
}),
|
|
8077
|
-
orphanCount > 0 && /* @__PURE__ */ (0,
|
|
8373
|
+
orphanCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
8078
8374
|
"button",
|
|
8079
8375
|
{
|
|
8080
8376
|
type: "button",
|
|
@@ -8082,7 +8378,7 @@ function Pins() {
|
|
|
8082
8378
|
style: { bottom: 16, left: "50%", transform: "translateX(-50%)" },
|
|
8083
8379
|
onClick: () => dispatch({ type: "SET_PANEL", open: true }),
|
|
8084
8380
|
children: [
|
|
8085
|
-
/* @__PURE__ */ (0,
|
|
8381
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconUnlink, { size: 13 }),
|
|
8086
8382
|
orphanCount,
|
|
8087
8383
|
" unanchored item",
|
|
8088
8384
|
orphanCount === 1 ? "" : "s"
|
|
@@ -8093,13 +8389,13 @@ function Pins() {
|
|
|
8093
8389
|
}
|
|
8094
8390
|
|
|
8095
8391
|
// src/client/components/Toolbar.tsx
|
|
8096
|
-
var
|
|
8097
|
-
var
|
|
8392
|
+
var import_react19 = require("react");
|
|
8393
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
8098
8394
|
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,
|
|
8395
|
+
{ tool: "select", hintId: "tool-select", label: "Select", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconTarget, { size: n }) },
|
|
8396
|
+
{ tool: "copy", hintId: "tool-copy", label: "Rewrite text", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconText, { size: n }) },
|
|
8397
|
+
{ tool: "comment", hintId: "tool-comment", label: "Comment", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: n }) },
|
|
8398
|
+
{ tool: "image", hintId: "tool-image", label: "Replace image", icon: (n) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconImage, { size: n }) }
|
|
8103
8399
|
];
|
|
8104
8400
|
var POS_KEY2 = "review-kit:toolbar-pos";
|
|
8105
8401
|
var DRAG_THRESHOLD2 = 6;
|
|
@@ -8107,24 +8403,24 @@ function Toolbar() {
|
|
|
8107
8403
|
const { selection, editor, peers, syncStatus, mode, tool } = useStore();
|
|
8108
8404
|
const hasPeers = syncStatus !== "disabled" && peers.length > 0;
|
|
8109
8405
|
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,
|
|
8406
|
+
const ref = (0, import_react19.useRef)(null);
|
|
8407
|
+
const [pos, setPos] = (0, import_react19.useState)(() => readStoredPos(POS_KEY2));
|
|
8408
|
+
const drag = (0, import_react19.useRef)(null);
|
|
8409
|
+
const [dragging, setDragging] = (0, import_react19.useState)(false);
|
|
8410
|
+
const justDragged = (0, import_react19.useRef)(false);
|
|
8115
8411
|
const visible = editor === null || selection !== null;
|
|
8116
8412
|
const applyPos = (next, persist) => {
|
|
8117
8413
|
if (next === null && ref.current) ref.current.style.bottom = "";
|
|
8118
8414
|
setPos(next);
|
|
8119
8415
|
if (persist) storePos(POS_KEY2, next);
|
|
8120
8416
|
};
|
|
8121
|
-
(0,
|
|
8417
|
+
(0, import_react19.useLayoutEffect)(() => {
|
|
8122
8418
|
const el = ref.current;
|
|
8123
8419
|
if (!el || pos === null) return;
|
|
8124
8420
|
const clamped = clampPos(pos.x, pos.y, el.offsetWidth, el.offsetHeight);
|
|
8125
8421
|
if (clamped.x !== pos.x || clamped.y !== pos.y) applyPos(clamped, true);
|
|
8126
8422
|
}, [pos, selection, hasPeers, visible]);
|
|
8127
|
-
(0,
|
|
8423
|
+
(0, import_react19.useEffect)(() => {
|
|
8128
8424
|
const onResize = () => {
|
|
8129
8425
|
const el = ref.current;
|
|
8130
8426
|
const current = readStoredPos(POS_KEY2);
|
|
@@ -8237,7 +8533,7 @@ function Toolbar() {
|
|
|
8237
8533
|
mode === "pick" && selection === null ? "rk-ghost" : ""
|
|
8238
8534
|
].filter(Boolean).join(" ");
|
|
8239
8535
|
const style = pos !== null ? { left: 0, top: 0, translate: `${pos.x}px ${pos.y}px` } : void 0;
|
|
8240
|
-
return /* @__PURE__ */ (0,
|
|
8536
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8241
8537
|
"div",
|
|
8242
8538
|
{
|
|
8243
8539
|
ref,
|
|
@@ -8248,7 +8544,7 @@ function Toolbar() {
|
|
|
8248
8544
|
onPointerDown,
|
|
8249
8545
|
onClickCapture,
|
|
8250
8546
|
children: [
|
|
8251
|
-
/* @__PURE__ */ (0,
|
|
8547
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
8252
8548
|
"button",
|
|
8253
8549
|
{
|
|
8254
8550
|
type: "button",
|
|
@@ -8256,19 +8552,19 @@ function Toolbar() {
|
|
|
8256
8552
|
"aria-label": "Move the toolbar \u2014 drag, or use arrow keys; double-click to reset its position",
|
|
8257
8553
|
onKeyDown: onGripKeyDown,
|
|
8258
8554
|
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,
|
|
8555
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("svg", { width: "8", height: "14", viewBox: "0 0 8 14", "aria-hidden": "true", fill: "currentColor", children: [
|
|
8556
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "2", r: "1.1" }),
|
|
8557
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "2", r: "1.1" }),
|
|
8558
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "7", r: "1.1" }),
|
|
8559
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "7", r: "1.1" }),
|
|
8560
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "2", cy: "12", r: "1.1" }),
|
|
8561
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "6", cy: "12", r: "1.1" })
|
|
8266
8562
|
] })
|
|
8267
8563
|
}
|
|
8268
8564
|
),
|
|
8269
|
-
/* @__PURE__ */ (0,
|
|
8270
|
-
hasPeers && /* @__PURE__ */ (0,
|
|
8271
|
-
/* @__PURE__ */ (0,
|
|
8565
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PresenceStrip, {}),
|
|
8566
|
+
hasPeers && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
|
|
8567
|
+
/* @__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
8568
|
"button",
|
|
8273
8569
|
{
|
|
8274
8570
|
type: "button",
|
|
@@ -8280,9 +8576,9 @@ function Toolbar() {
|
|
|
8280
8576
|
},
|
|
8281
8577
|
entry.tool
|
|
8282
8578
|
)) }),
|
|
8283
|
-
selection && /* @__PURE__ */ (0,
|
|
8284
|
-
selection && /* @__PURE__ */ (0,
|
|
8285
|
-
/* @__PURE__ */ (0,
|
|
8579
|
+
selection && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
|
|
8580
|
+
selection && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
8581
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8286
8582
|
"button",
|
|
8287
8583
|
{
|
|
8288
8584
|
type: "button",
|
|
@@ -8291,12 +8587,12 @@ function Toolbar() {
|
|
|
8291
8587
|
title: `Rewrite text${keyHint("tool-copy")}`,
|
|
8292
8588
|
onClick: () => open("copy"),
|
|
8293
8589
|
children: [
|
|
8294
|
-
/* @__PURE__ */ (0,
|
|
8590
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconText, { size: 14 }),
|
|
8295
8591
|
" Rewrite"
|
|
8296
8592
|
]
|
|
8297
8593
|
}
|
|
8298
8594
|
),
|
|
8299
|
-
hasImage && /* @__PURE__ */ (0,
|
|
8595
|
+
hasImage && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8300
8596
|
"button",
|
|
8301
8597
|
{
|
|
8302
8598
|
type: "button",
|
|
@@ -8305,12 +8601,12 @@ function Toolbar() {
|
|
|
8305
8601
|
title: `Replace image${keyHint("tool-image")}`,
|
|
8306
8602
|
onClick: () => open("image"),
|
|
8307
8603
|
children: [
|
|
8308
|
-
/* @__PURE__ */ (0,
|
|
8604
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconImage, { size: 14 }),
|
|
8309
8605
|
" Image"
|
|
8310
8606
|
]
|
|
8311
8607
|
}
|
|
8312
8608
|
),
|
|
8313
|
-
/* @__PURE__ */ (0,
|
|
8609
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
8314
8610
|
"button",
|
|
8315
8611
|
{
|
|
8316
8612
|
type: "button",
|
|
@@ -8319,32 +8615,32 @@ function Toolbar() {
|
|
|
8319
8615
|
title: `Comment${keyHint("tool-comment")}`,
|
|
8320
8616
|
onClick: () => open("comment"),
|
|
8321
8617
|
children: [
|
|
8322
|
-
/* @__PURE__ */ (0,
|
|
8618
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconComment, { size: 14 }),
|
|
8323
8619
|
" Comment"
|
|
8324
8620
|
]
|
|
8325
8621
|
}
|
|
8326
8622
|
),
|
|
8327
|
-
/* @__PURE__ */ (0,
|
|
8328
|
-
/* @__PURE__ */ (0,
|
|
8623
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("style"), children: [
|
|
8624
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconStyle, { size: 14 }),
|
|
8329
8625
|
" Style"
|
|
8330
8626
|
] }),
|
|
8331
|
-
/* @__PURE__ */ (0,
|
|
8332
|
-
/* @__PURE__ */ (0,
|
|
8627
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn", onClick: () => open("move"), children: [
|
|
8628
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconMove, { size: 14 }),
|
|
8333
8629
|
" Move"
|
|
8334
8630
|
] }),
|
|
8335
|
-
/* @__PURE__ */ (0,
|
|
8336
|
-
/* @__PURE__ */ (0,
|
|
8631
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", role: "menuitem", className: "rk-toolbar-btn rk-danger", onClick: () => open("delete"), children: [
|
|
8632
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconTrash, { size: 14 }),
|
|
8337
8633
|
" Delete"
|
|
8338
8634
|
] }),
|
|
8339
|
-
/* @__PURE__ */ (0,
|
|
8340
|
-
/* @__PURE__ */ (0,
|
|
8635
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "rk-toolbar-sep" }),
|
|
8636
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
8341
8637
|
"button",
|
|
8342
8638
|
{
|
|
8343
8639
|
type: "button",
|
|
8344
8640
|
className: "rk-icon-btn",
|
|
8345
8641
|
"aria-label": "Deselect",
|
|
8346
8642
|
onClick: () => dispatch({ type: "SELECT", selection: null }),
|
|
8347
|
-
children: /* @__PURE__ */ (0,
|
|
8643
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconClose, { size: 13 })
|
|
8348
8644
|
}
|
|
8349
8645
|
)
|
|
8350
8646
|
] })
|
|
@@ -8354,40 +8650,40 @@ function Toolbar() {
|
|
|
8354
8650
|
}
|
|
8355
8651
|
|
|
8356
8652
|
// src/client/components/Toast.tsx
|
|
8357
|
-
var
|
|
8358
|
-
var
|
|
8653
|
+
var import_react20 = require("react");
|
|
8654
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
8359
8655
|
function ToastRow({ toast: toast2 }) {
|
|
8360
8656
|
const dispatch = useDispatch();
|
|
8361
|
-
(0,
|
|
8657
|
+
(0, import_react20.useEffect)(() => {
|
|
8362
8658
|
const timer = window.setTimeout(() => dispatch({ type: "DISMISS_TOAST", id: toast2.id }), 3500);
|
|
8363
8659
|
return () => window.clearTimeout(timer);
|
|
8364
8660
|
}, [toast2.id, dispatch]);
|
|
8365
|
-
return /* @__PURE__ */ (0,
|
|
8366
|
-
toast2.tone === "success" ? /* @__PURE__ */ (0,
|
|
8661
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `rk-toast rk-${toast2.tone}`, role: "status", children: [
|
|
8662
|
+
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
8663
|
toast2.message
|
|
8368
8664
|
] });
|
|
8369
8665
|
}
|
|
8370
8666
|
function ToastHost() {
|
|
8371
8667
|
const { toasts } = useStore();
|
|
8372
8668
|
if (toasts.length === 0) return null;
|
|
8373
|
-
return /* @__PURE__ */ (0,
|
|
8669
|
+
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
8670
|
}
|
|
8375
8671
|
|
|
8376
8672
|
// src/client/App.tsx
|
|
8377
|
-
var
|
|
8673
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
8378
8674
|
function App() {
|
|
8379
8675
|
const state = useStore();
|
|
8380
8676
|
const rawDispatch = useDispatch();
|
|
8381
8677
|
const config = useConfig();
|
|
8382
8678
|
const dispatch = useRealtimeSync(state, rawDispatch, config, reducer);
|
|
8383
|
-
const saveTimer = (0,
|
|
8679
|
+
const saveTimer = (0, import_react21.useRef)(null);
|
|
8384
8680
|
const storageKey = config.storageKey ?? defaultStorageKey();
|
|
8385
8681
|
useAppliedPreview(state, dispatch);
|
|
8386
8682
|
useEmblemaAutoPush(state, dispatch, config);
|
|
8387
|
-
(0,
|
|
8683
|
+
(0, import_react21.useEffect)(() => {
|
|
8388
8684
|
setEffectAssetsUrl(config.fxAssetsUrl);
|
|
8389
8685
|
}, [config.fxAssetsUrl]);
|
|
8390
|
-
(0,
|
|
8686
|
+
(0, import_react21.useEffect)(() => {
|
|
8391
8687
|
let cancelled = false;
|
|
8392
8688
|
void loadSession(storageKey).then((stored) => {
|
|
8393
8689
|
if (cancelled) return;
|
|
@@ -8405,7 +8701,7 @@ function App() {
|
|
|
8405
8701
|
};
|
|
8406
8702
|
}, [storageKey, config.defaultAuthor, dispatch]);
|
|
8407
8703
|
const { session } = state;
|
|
8408
|
-
(0,
|
|
8704
|
+
(0, import_react21.useEffect)(() => {
|
|
8409
8705
|
if (!session) return;
|
|
8410
8706
|
if (saveTimer.current !== null) window.clearTimeout(saveTimer.current);
|
|
8411
8707
|
saveTimer.current = window.setTimeout(() => {
|
|
@@ -8416,9 +8712,9 @@ function App() {
|
|
|
8416
8712
|
if (saveTimer.current !== null) window.clearTimeout(saveTimer.current);
|
|
8417
8713
|
};
|
|
8418
8714
|
}, [session, storageKey, config]);
|
|
8419
|
-
(0,
|
|
8420
|
-
const focusHandled = (0,
|
|
8421
|
-
(0,
|
|
8715
|
+
(0, import_react21.useEffect)(() => trackPointer(), []);
|
|
8716
|
+
const focusHandled = (0, import_react21.useRef)(false);
|
|
8717
|
+
(0, import_react21.useEffect)(() => {
|
|
8422
8718
|
if (!session || focusHandled.current) return;
|
|
8423
8719
|
focusHandled.current = true;
|
|
8424
8720
|
const id = takeFocusItem();
|
|
@@ -8443,7 +8739,7 @@ function App() {
|
|
|
8443
8739
|
cancelled = true;
|
|
8444
8740
|
};
|
|
8445
8741
|
}, [session, dispatch]);
|
|
8446
|
-
(0,
|
|
8742
|
+
(0, import_react21.useEffect)(() => {
|
|
8447
8743
|
let last = window.location.pathname;
|
|
8448
8744
|
const check = () => {
|
|
8449
8745
|
if (window.location.pathname !== last) {
|
|
@@ -8458,9 +8754,9 @@ function App() {
|
|
|
8458
8754
|
window.removeEventListener("popstate", check);
|
|
8459
8755
|
};
|
|
8460
8756
|
}, [dispatch]);
|
|
8461
|
-
const stateRef = (0,
|
|
8757
|
+
const stateRef = (0, import_react21.useRef)(state);
|
|
8462
8758
|
stateRef.current = state;
|
|
8463
|
-
(0,
|
|
8759
|
+
(0, import_react21.useEffect)(() => {
|
|
8464
8760
|
const onKeyDown = (event) => {
|
|
8465
8761
|
const current = stateRef.current;
|
|
8466
8762
|
for (const def of SHORTCUTS) {
|
|
@@ -8475,7 +8771,7 @@ function App() {
|
|
|
8475
8771
|
document.addEventListener("keydown", onKeyDown);
|
|
8476
8772
|
return () => document.removeEventListener("keydown", onKeyDown);
|
|
8477
8773
|
}, [dispatch]);
|
|
8478
|
-
(0,
|
|
8774
|
+
(0, import_react21.useEffect)(() => {
|
|
8479
8775
|
if (!state.editor) return;
|
|
8480
8776
|
const editorEl = state.editor.element;
|
|
8481
8777
|
const onPointerDown = (event) => {
|
|
@@ -8488,32 +8784,33 @@ function App() {
|
|
|
8488
8784
|
}, [state.editor, dispatch]);
|
|
8489
8785
|
if (!session) return null;
|
|
8490
8786
|
if (state.hidden) {
|
|
8491
|
-
return /* @__PURE__ */ (0,
|
|
8787
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DispatchContext.Provider, { value: dispatch, children: null });
|
|
8492
8788
|
}
|
|
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,
|
|
8789
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DispatchContext.Provider, { value: dispatch, children: [
|
|
8790
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PickLayer, {}),
|
|
8791
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PeerCursors, {}),
|
|
8792
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Toolbar, {}),
|
|
8793
|
+
state.editor?.kind === "copy" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InlineEditor, { editor: state.editor }),
|
|
8794
|
+
state.editor?.kind === "image" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ImageEditor, { editor: state.editor }),
|
|
8795
|
+
state.editor && state.editor.kind !== "copy" && state.editor.kind !== "image" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(NoteComposer, { editor: state.editor }),
|
|
8796
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pins, {}),
|
|
8797
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(QuickComment, {}),
|
|
8798
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Panel, {}),
|
|
8799
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Badge, {}),
|
|
8800
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CoachMark, {}),
|
|
8801
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CheatSheet, {}),
|
|
8802
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmblemaConnect, {}),
|
|
8803
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TerminalConnect, {}),
|
|
8804
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ConfirmHost, {}),
|
|
8805
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ToastHost, {})
|
|
8509
8806
|
] });
|
|
8510
8807
|
}
|
|
8511
8808
|
|
|
8512
8809
|
// src/client/ReviewKit.tsx
|
|
8513
|
-
var
|
|
8810
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
8514
8811
|
function ShadowHost({ config }) {
|
|
8515
|
-
const [mount, setMount] = (0,
|
|
8516
|
-
(0,
|
|
8812
|
+
const [mount, setMount] = (0, import_react22.useState)(null);
|
|
8813
|
+
(0, import_react22.useEffect)(() => {
|
|
8517
8814
|
const host = document.createElement("div");
|
|
8518
8815
|
host.setAttribute(HOST_ATTR, "");
|
|
8519
8816
|
host.style.position = "fixed";
|
|
@@ -8549,15 +8846,15 @@ function ShadowHost({ config }) {
|
|
|
8549
8846
|
}, []);
|
|
8550
8847
|
if (!mount) return null;
|
|
8551
8848
|
return (0, import_react_dom.createPortal)(
|
|
8552
|
-
/* @__PURE__ */ (0,
|
|
8849
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StoreProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(App, {}) }),
|
|
8553
8850
|
mount
|
|
8554
8851
|
);
|
|
8555
8852
|
}
|
|
8556
8853
|
function ReviewKit(props) {
|
|
8557
|
-
const [active2, setActive] = (0,
|
|
8854
|
+
const [active2, setActive] = (0, import_react22.useState)(false);
|
|
8558
8855
|
const { enabled, token, allowedHosts, devAutoOn } = props;
|
|
8559
8856
|
const hostsKey = allowedHosts?.join("\0") ?? "";
|
|
8560
|
-
(0,
|
|
8857
|
+
(0, import_react22.useEffect)(() => {
|
|
8561
8858
|
if (enabled === false) {
|
|
8562
8859
|
setActive(false);
|
|
8563
8860
|
return;
|
|
@@ -8568,7 +8865,7 @@ function ReviewKit(props) {
|
|
|
8568
8865
|
return () => window.removeEventListener(DEACTIVATE_EVENT, onDeactivate);
|
|
8569
8866
|
}, [enabled, token, devAutoOn, hostsKey]);
|
|
8570
8867
|
if (enabled === false || !active2) return null;
|
|
8571
|
-
return /* @__PURE__ */ (0,
|
|
8868
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ShadowHost, { config: props });
|
|
8572
8869
|
}
|
|
8573
8870
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8574
8871
|
0 && (module.exports = {
|