wenay-react2 1.0.49 → 1.0.51

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.
Files changed (54) hide show
  1. package/README.md +14 -14
  2. package/doc/EXAMPLE_USAGE.md +48 -0
  3. package/doc/PROJECT_FUNCTIONALITY.md +13 -2
  4. package/doc/PROJECT_RULES.md +27 -27
  5. package/doc/WENAY_REACT2_RENAMES.md +170 -170
  6. package/doc/changes/v1.0.41.md +35 -35
  7. package/doc/changes/v1.0.42.md +26 -26
  8. package/doc/changes/v1.0.43.md +10 -10
  9. package/doc/changes/v1.0.44.md +14 -14
  10. package/doc/changes/v1.0.45.md +8 -8
  11. package/doc/changes/v1.0.46.md +11 -11
  12. package/doc/changes/v1.0.47.md +9 -9
  13. package/doc/changes/v1.0.48.md +8 -8
  14. package/doc/changes/v1.0.49.md +7 -7
  15. package/doc/changes/v1.0.50.md +7 -0
  16. package/doc/changes/v1.0.51.md +10 -0
  17. package/doc/examples/README.md +1 -1
  18. package/doc/examples/conference-client.html +34 -34
  19. package/doc/examples/conference-client.ts +212 -212
  20. package/doc/examples/conference-server.mjs +150 -150
  21. package/doc/examples/peer-call-media.tsx +7 -7
  22. package/doc/examples/stand.tsx +5 -5
  23. package/doc/native.md +37 -37
  24. package/doc/progress/README.md +13 -13
  25. package/doc/progress/architecture-fix-queue.md +74 -74
  26. package/doc/progress/column-state-present-gate.md +28 -28
  27. package/doc/progress/common2-adoption-1.0.73.md +28 -28
  28. package/doc/progress/common2-adoption-1.0.74.md +24 -24
  29. package/doc/progress/common2-adoption-1.0.75.md +120 -0
  30. package/doc/progress/hook-controller-opportunities.md +363 -363
  31. package/doc/progress/hook-extraction-audit.md +195 -195
  32. package/doc/progress/public-surface-normalization.md +351 -351
  33. package/doc/progress/qa-stand-walkthrough-2026-07-12.md +62 -62
  34. package/doc/progress/stand-as-examples-audit.md +20 -20
  35. package/doc/progress/style-system-normalization.md +121 -121
  36. package/doc/target/README.md +32 -32
  37. package/doc/target/my.md +11 -3
  38. package/doc/wenay-react2-rare.md +11 -7
  39. package/doc/wenay-react2.md +2 -2
  40. package/lib/common/src/grid/agGrid4/core.js +7 -2
  41. package/lib/common/src/hooks/useReplay.js +13 -2
  42. package/lib/common/src/logs/logs.d.ts +4 -1
  43. package/lib/common/src/logs/logs.js +19 -11
  44. package/lib/common/testUseReact/replayVideo.d.ts +5 -0
  45. package/lib/common/testUseReact/replayVideo.js +98 -1
  46. package/lib/style/menuRight.css +19 -19
  47. package/lib/style/style.css +23 -23
  48. package/lib/style/tokens.css +184 -184
  49. package/package.json +54 -54
  50. package/doc/changes/v1.0.35.md +0 -26
  51. package/doc/changes/v1.0.37.md +0 -13
  52. package/doc/changes/v1.0.38.md +0 -48
  53. package/doc/changes/v1.0.39.md +0 -35
  54. package/doc/changes/v1.0.40.md +0 -15
@@ -60,7 +60,12 @@ export function createGridBuffer(deps) {
60
60
  if (seen.has(id))
61
61
  continue;
62
62
  seen.add(id);
63
- const merged = buf[id];
63
+ // AG Grid replaces a transaction row. Overlay streams may send a
64
+ // Partial<T>, so preserve static fields from the rowData-owned row.
65
+ const node = mode == 'overlay' ? api.getRowNode?.(id) : undefined;
66
+ const merged = node?.data
67
+ ? Object.assign({}, node.data, buf[id])
68
+ : buf[id];
64
69
  if (gridHas(id))
65
70
  toUpdate.push(merged);
66
71
  else
@@ -104,7 +109,7 @@ export function createGridBuffer(deps) {
104
109
  return;
105
110
  const id = getId(node.data);
106
111
  if (buf[id])
107
- update.push(buf[id]);
112
+ update.push(Object.assign({}, node.data, buf[id]));
108
113
  });
109
114
  if (update.length)
110
115
  api.applyTransaction({ update });
@@ -49,10 +49,18 @@ export function useReplaySubscribe(remote, cb, options = {}) {
49
49
  useEffect(() => {
50
50
  if (!remote || !enabled)
51
51
  return;
52
+ if (!remote.line || typeof remote.line.on != 'function') {
53
+ const error = new Error('Replay remote is missing its line surface');
54
+ setReady(false);
55
+ setError(error);
56
+ hooksRef.current.onError?.(error);
57
+ return;
58
+ }
52
59
  if (lastRemoteRef.current !== undefined && lastRemoteRef.current !== remote)
53
60
  seqRef.current = undefined; // a different line — old seq is meaningless
54
61
  lastRemoteRef.current = remote;
55
62
  let alive = true;
63
+ let failed = false;
56
64
  setReady(false);
57
65
  setError(null);
58
66
  // stale is NOT reset here: it re-syncs from common2 after the first delivery (a stale
@@ -68,8 +76,11 @@ export function useReplaySubscribe(remote, cb, options = {}) {
68
76
  hooksRef.current.onSeq?.(seq);
69
77
  },
70
78
  onError: e => {
71
- if (alive)
79
+ failed = true;
80
+ if (alive) {
72
81
  setError(e);
82
+ setReady(false);
83
+ }
73
84
  hooksRef.current.onError?.(e);
74
85
  },
75
86
  ...(staleMs !== undefined ? {
@@ -83,7 +94,7 @@ export function useReplaySubscribe(remote, cb, options = {}) {
83
94
  });
84
95
  subRef.current = off;
85
96
  off.ready.then(() => {
86
- if (!alive)
97
+ if (!alive || failed)
87
98
  return;
88
99
  setReady(true);
89
100
  if (staleMs !== undefined)
@@ -55,7 +55,7 @@ export declare function useLogsPageTable(state?: LogsViewState): {
55
55
  getApi: () => GridReadyEvent<any, any> | null;
56
56
  fit: () => void;
57
57
  applyImportanceFilter: (min?: number) => void;
58
- appendRow: (row: LogRow) => void;
58
+ syncRows: () => void;
59
59
  onGridReady: (a: GridReadyEvent<LogRow>) => void;
60
60
  columnDefs: ({
61
61
  field: string;
@@ -96,6 +96,9 @@ export declare function useLogsPageTable(state?: LogsViewState): {
96
96
  rowHeight: number;
97
97
  autoSizePadding: number;
98
98
  rowData: any[];
99
+ getRowId: (p: {
100
+ data: LogRow;
101
+ }) => string;
99
102
  columnDefs: ({
100
103
  field: string;
101
104
  sort: "desc";
@@ -80,10 +80,10 @@ function InputSettingLogs({ settings }) {
80
80
  export function useLogsPageTable(state) {
81
81
  const setting = state?.settings ?? memoryGetOrCreate("settingLogs", settingLogs);
82
82
  const full = state?.full ?? datumConst;
83
- const mini = state?.mini ?? datumMiniConst;
84
83
  const apiGrid = useRef(null);
85
84
  // mount-time snapshot: the live grid is fed by transactions, not re-renders
86
85
  const [rowData] = useState(() => [...full.map.values()].flat());
86
+ const shownRows = useRef(new Map(rowData.map(row => [row.num, row])));
87
87
  const getApi = useCallback(() => apiGrid.current, []);
88
88
  const fit = useCallback(() => { apiGrid.current?.api.sizeColumnsToFit(); }, []);
89
89
  const applyImportanceFilter = useCallback((min) => {
@@ -103,26 +103,33 @@ export function useLogsPageTable(state) {
103
103
  api.destroyFilter("var");
104
104
  }
105
105
  }, []);
106
- const appendRow = useCallback((row) => {
107
- apiGrid.current?.api.applyTransactionAsync({ add: [row] });
108
- }, []);
106
+ const syncRows = useCallback(() => {
107
+ const api = apiGrid.current?.api;
108
+ if (!api)
109
+ return;
110
+ const next = new Map([...full.map.values()].flat().map(row => [row.num, row]));
111
+ const add = [...next].filter(([num]) => !shownRows.current.has(num)).map(([, row]) => row);
112
+ const remove = [...shownRows.current].filter(([num]) => !next.has(num)).map(([, row]) => row);
113
+ shownRows.current = next;
114
+ if (add.length || remove.length)
115
+ api.applyTransactionAsync({ add, remove });
116
+ }, [full]);
109
117
  // settings change -> single filter method (no re-render: updateBy with a callback)
110
118
  updateBy(setting, () => {
111
119
  applyImportanceFilter(setting.params.minVarLogs);
112
120
  });
113
- // new mini-feed entry -> async append, copy like before (row identity per event)
114
- updateBy(mini, () => {
115
- const data = mini.last[0];
116
- if (data)
117
- appendRow({ ...data });
121
+ // The full state owns retention, so reconcile additions and evictions together.
122
+ updateBy(full, () => {
123
+ syncRows();
118
124
  });
119
125
  const onGridReady = useCallback((a) => {
120
126
  apiGrid.current = a;
127
+ syncRows();
121
128
  fit();
122
129
  // fresh grid has no filter - only apply when the setting asks for one
123
130
  if (setting.params.minVarLogs)
124
131
  applyImportanceFilter(setting.params.minVarLogs);
125
- }, [applyImportanceFilter, fit, setting]);
132
+ }, [applyImportanceFilter, fit, setting, syncRows]);
126
133
  const columnDefs = useMemo(() => [
127
134
  {
128
135
  field: "time",
@@ -169,6 +176,7 @@ export function useLogsPageTable(state) {
169
176
  rowHeight: 26,
170
177
  autoSizePadding: 1,
171
178
  rowData,
179
+ getRowId: (p) => String(p.data.num),
172
180
  columnDefs,
173
181
  onCellMouseDown: (e) => {
174
182
  if (e.event instanceof MouseEvent && e.event.button == 2) {
@@ -180,7 +188,7 @@ export function useLogsPageTable(state) {
180
188
  }
181
189
  },
182
190
  }), [columnDefs, onGridReady, rowData]);
183
- return { getApi, fit, applyImportanceFilter, appendRow, onGridReady, columnDefs, gridProps };
191
+ return { getApi, fit, applyImportanceFilter, syncRows, onGridReady, columnDefs, gridProps };
184
192
  }
185
193
  export function PageLogs({ update, state }) {
186
194
  const table = useLogsPageTable(state);
@@ -10,5 +10,10 @@ export declare const videoResolutions: readonly [{
10
10
  }];
11
11
  export declare const ReplayRouteDemo: () => import("react/jsx-runtime").JSX.Element;
12
12
  export declare const ReplayVideoDemo: () => import("react/jsx-runtime").JSX.Element;
13
+ /**
14
+ * Real browser transport regression card. The server endpoint is the Vite-only
15
+ * `qaReplay` RPC facade; this component receives only its stable common2 remote.
16
+ */
17
+ export declare const ReplayRpcReconnectDemo: () => import("react/jsx-runtime").JSX.Element;
13
18
  export declare const ReplayStoreDemo: () => import("react/jsx-runtime").JSX.Element;
14
19
  export declare const ReplayStoreEachDemo: () => import("react/jsx-runtime").JSX.Element;
@@ -8,7 +8,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  * these cards exercise the React lifecycle side.
9
9
  */
10
10
  import React, { StrictMode, useEffect, useMemo, useRef, useState } from "react";
11
- import { Observe, Replay } from "wenay-common2";
11
+ import { createRpcClientHub, Observe, Replay } from "wenay-common2";
12
+ import { io } from "socket.io-client";
12
13
  import { useReplaySubscribe, useReplayRouteSubscribe, useReplayFrame, useReplayHistory, useStoreReplayMirror, useStoreReplayEach, useStoreNode, useStoreKeys } from "../src/hooks";
13
14
  const FPS = 10;
14
15
  export const videoResolutions = [{ w: 160, h: 90 }, { w: 320, h: 180 }, { w: 640, h: 360 }];
@@ -233,6 +234,102 @@ export const ReplayVideoDemo = () => {
233
234
  ? _jsx(LiveClient, { remote: demo.remoteDirect, since: lastSeqA.current, onSeq: seq => { lastSeqA.current = seq; } })
234
235
  : _jsxs("div", { style: { ...canvasStyle, height: 180, display: "flex", alignItems: "center", justifyContent: "center", color: "#8b949e" }, children: ["unmounted \u00B7 kept seq ", lastSeqA.current ?? "-"] })] }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 700, marginBottom: 4 }, children: "B: slow wire + conflateReplay gate" }), _jsx(LiveClient, { remote: demo.wire.remote }), _jsxs("div", { style: statLine, children: ["wire buffer ", demo.wire.buffered(), " \u00B7 conflating ", String(wireStats.conflating), _jsx("br", {}), "dropped ", wireStats.dropped, " \u00B7 coalesced ", wireStats.coalesced, " \u00B7 recoveries ", wireStats.flushes, " (keyframes ", wireStats.keyframes, ")"] })] }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 700, marginBottom: 4 }, children: "C: time travel (archive + openHistory)" }), _jsx("canvas", { ref: ttCanvasRef, style: canvasStyle }), _jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", marginTop: 4 }, children: [_jsx("button", { onClick: () => tt.live ? tt.pause() : tt.play(), children: tt.live ? "⏸ pause" : "▶ live" }), _jsx("input", { type: "range", style: { width: 200 }, min: Math.max(0, tt.head - 550), max: Math.max(0, tt.head), value: tt.seq < 0 ? 0 : tt.seq, onChange: e => tt.seek({ seq: Number(e.target.value) }) }), _jsxs("span", { style: { fontSize: 12, fontFamily: "monospace" }, children: [tt.seq, "/", tt.head, " ", tt.live ? "live" : "paused"] })] })] }), _jsxs("div", { children: [_jsxs("div", { style: { fontSize: 13, fontWeight: 700, marginBottom: 4 }, children: ["D: freshness (staleMs=", STALE_MS, ", StrictMode)", " ", _jsx("button", { onClick: () => setGenD(v => v + 1), children: "new client (keyframe)" })] }), _jsx(StrictMode, { children: _jsx(StaleClient, { remote: demo.remoteDirect, staleMs: STALE_MS }, genD) }), _jsx("div", { style: { fontSize: 12, color: "#57606a", maxWidth: 320, marginTop: 4 }, children: "counters refresh only on fresh\u2194stale flips: a flat \"renders\" while frames grow is the no-per-event-render proof" })] }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: 13, fontWeight: 700, marginBottom: 4 }, children: "E: pull at own pace (useReplayFrame)" }), _jsx(PullClient, { remote: demo.remoteDirect })] })] })] });
235
236
  };
237
+ const RpcReplayConsumer = React.memo(function RpcReplayConsumer(p) {
238
+ p.metrics.current.renders++;
239
+ const sub = useReplaySubscribe(p.remote, value => {
240
+ // This is intentionally an append-only QA probe. It reports duplicates; it never
241
+ // suppresses them, so a green card is evidence from the real transport instead of
242
+ // a React-side dedupe mask.
243
+ p.metrics.current.values.push(value);
244
+ p.metrics.current.latestCallbackRevision = p.callbackRevision;
245
+ }, {
246
+ since: 0,
247
+ policy: "queue",
248
+ onSeq: () => { },
249
+ onError: error => { p.metrics.current.errors.push(String(error)); },
250
+ onStale: () => { },
251
+ hint: { callbackRevision: p.callbackRevision },
252
+ });
253
+ p.metrics.current.seq = sub.seq;
254
+ p.metrics.current.ready = sub.ready;
255
+ return null;
256
+ });
257
+ /**
258
+ * Real browser transport regression card. The server endpoint is the Vite-only
259
+ * `qaReplay` RPC facade; this component receives only its stable common2 remote.
260
+ */
261
+ export const ReplayRpcReconnectDemo = () => {
262
+ const hub = useMemo(() => createRpcClientHub(() => io({ path: "/__qa/replay-rpc", transports: ["websocket"], reconnection: false }), rpc => ({ qaReplay: rpc("qaReplay") })), []);
263
+ const metrics = useRef({ values: [], errors: [], renders: 0, latestCallbackRevision: -1, seq: () => -1, ready: false });
264
+ const firstRemote = useRef(null);
265
+ const [remote, setRemote] = useState(null);
266
+ const [mounted, setMounted] = useState(true);
267
+ const [callbackRevision, setCallbackRevision] = useState(0);
268
+ const [connected, setConnected] = useState(false);
269
+ const [snapshot, setSnapshot] = useState({ produced: 0, head: -1, listeners: 0, producing: false, received: 0, missing: 0, duplicates: 0, ordered: true, renders: 0, seq: -1, ready: false, errors: 0 });
270
+ const refresh = async () => {
271
+ const api = hub.facade.qaReplay?.func;
272
+ let server = { produced: 0, head: -1, listeners: 0, producing: false };
273
+ try {
274
+ if (api)
275
+ server = await api.stats();
276
+ }
277
+ catch { /* offline: retain local transport evidence */ }
278
+ const values = metrics.current.values;
279
+ const seen = new Set(values);
280
+ const missing = Array.from({ length: server.produced }, (_, i) => i + 1).filter(value => !seen.has(value)).length;
281
+ const duplicates = values.length - seen.size;
282
+ setSnapshot({
283
+ ...server,
284
+ received: values.length,
285
+ missing,
286
+ duplicates,
287
+ ordered: values.every((value, index) => index == 0 || values[index - 1] < value),
288
+ renders: metrics.current.renders,
289
+ seq: metrics.current.seq(),
290
+ ready: metrics.current.ready,
291
+ errors: metrics.current.errors.length,
292
+ });
293
+ };
294
+ useEffect(() => {
295
+ let alive = true;
296
+ const offConnect = hub.connectListen(() => { if (alive) {
297
+ setConnected(true);
298
+ void refresh();
299
+ } });
300
+ const offDisconnect = hub.disconnectListen(() => { if (alive) {
301
+ setConnected(false);
302
+ void refresh();
303
+ } });
304
+ void hub.setToken(null).then(clients => {
305
+ if (!alive)
306
+ return;
307
+ const next = clients.qaReplay.func.events;
308
+ firstRemote.current ??= next;
309
+ setRemote(next);
310
+ setConnected(true);
311
+ void refresh();
312
+ }).catch(error => { metrics.current.errors.push(String(error)); void refresh(); });
313
+ return () => {
314
+ alive = false;
315
+ offConnect();
316
+ offDisconnect();
317
+ hub.socket?.disconnect?.();
318
+ };
319
+ // The hub is intentionally one logical transport for the life of this card.
320
+ // eslint-disable-next-line react-hooks/exhaustive-deps
321
+ }, [hub]);
322
+ const api = hub.facade.qaReplay?.func;
323
+ const run = (work) => {
324
+ if (!work)
325
+ return;
326
+ void work().then(() => refresh()).catch(error => { metrics.current.errors.push(String(error)); void refresh(); });
327
+ };
328
+ const green = snapshot.produced > 0 && snapshot.missing == 0 && snapshot.duplicates == 0 && snapshot.ordered && snapshot.seq >= snapshot.head && snapshot.listeners == 1 && snapshot.errors == 0;
329
+ const statusStyle = { padding: "3px 8px", borderRadius: 5, color: "#fff", background: green ? "#2da44e" : "#cf222e", fontWeight: 700, fontSize: 12 };
330
+ return _jsxs("div", { style: { display: "grid", gap: 8 }, children: [_jsx("div", { style: { fontSize: 13, color: "#57606a", maxWidth: 760 }, children: "Keep this tab visible: background-tab throttling delays browser work and is not transport lag. Start the producer, wait for delivery, disconnect while it keeps running, rerender, then reconnect the same socket. No restart, key change, remount, or remote replacement is used for recovery." }), _jsxs("div", { style: { display: "flex", gap: 6, flexWrap: "wrap", alignItems: "center" }, children: [_jsx("button", { onClick: () => run(api ? () => api.start() : undefined), children: "start producer (20/s)" }), _jsx("button", { onClick: () => run(api ? () => api.stop() : undefined), children: "stop producer" }), _jsx("button", { onClick: () => { hub.socket?.disconnect?.(); void refresh(); }, children: "disconnect transport" }), _jsx("button", { onClick: () => { hub.socket?.connect?.(); }, children: "reconnect transport" }), _jsx("button", { onClick: () => { for (let i = 1; i <= 8; i++)
331
+ window.setTimeout(() => setCallbackRevision(value => value + 1), i * 20); }, children: "parent rerender burst" }), _jsx("button", { onClick: () => run(api ? () => api.burst(5_000) : undefined), children: "burst 5,000" }), _jsx("button", { onClick: () => void refresh(), children: "refresh metrics" }), _jsx("button", { onClick: () => { setMounted(value => !value); window.setTimeout(() => void refresh(), 0); }, children: mounted ? "unmount consumer" : "mount consumer" }), _jsx("span", { style: statusStyle, children: green ? "PASS: exact replay" : "waiting / mismatch" })] }), remote && mounted && _jsx(StrictMode, { children: _jsx(RpcReplayConsumer, { remote: remote, metrics: metrics, callbackRevision: callbackRevision }) }), _jsxs("div", { style: { ...statLine, whiteSpace: "normal" }, children: ["transport ", connected ? "connected" : "disconnected", " \u00B7 stable remote ", String(remote != null && remote === firstRemote.current), " \u00B7 producer ", snapshot.producing ? "running" : "stopped", _jsx("br", {}), "produced ", snapshot.produced, " \u00B7 received ", snapshot.received, " \u00B7 seq ", snapshot.seq, "/", snapshot.head, " \u00B7 missing ", snapshot.missing, " \u00B7 duplicates ", snapshot.duplicates, " \u00B7 ordered ", String(snapshot.ordered), _jsx("br", {}), "consumer renders ", snapshot.renders, " \u00B7 latest callback revision ", metrics.current.latestCallbackRevision, "/", callbackRevision, " \u00B7 server listeners ", snapshot.listeners, " \u00B7 ready ", String(snapshot.ready), " \u00B7 errors ", snapshot.errors] }), _jsx("div", { style: { fontSize: 12, color: "#57606a" }, children: "The 5,000-event burst is lossless (`policy: queue`): use refresh after it drains. The consumer records deliveries in a ref, so delivery itself does not trigger React renders; only lifecycle/UI controls do. Unmount then refresh to confirm server listeners reaches 0." })] });
332
+ };
236
333
  function createStoreReplayDemo() {
237
334
  let stalled = false;
238
335
  const store = Observe.createStore({ ticks: 0, price: 100, note: "start", bag: { a: 1 } });
@@ -43,25 +43,25 @@
43
43
  width: max-content;
44
44
  }
45
45
 
46
- .menu-item {
47
- min-height: 30px;
48
- padding: 10px;
49
- position: relative;
50
- cursor: pointer;
51
- color: var(--menu-item-color, #fff);
52
- border-bottom: var(--menu-border, 1px solid rgba(255, 255, 255, 0.41));
53
- transition: background 0.3s, color 0.3s;
54
- }
55
-
56
- .menu-item:hover,
57
- .menu-item.force-hover {
58
- background: var(--menu-item-hover-bg-color, #fff);
59
- color: var(--menu-item-hover-color, #101010);
60
- }
61
-
62
- .menu-item:active {
63
- background: var(--menu-item-pressed-bg-color, #f2c94c);
64
- color: var(--menu-item-pressed-color, #101010);
46
+ .menu-item {
47
+ min-height: 30px;
48
+ padding: 10px;
49
+ position: relative;
50
+ cursor: pointer;
51
+ color: var(--menu-item-color, #fff);
52
+ border-bottom: var(--menu-border, 1px solid rgba(255, 255, 255, 0.41));
53
+ transition: background 0.3s, color 0.3s;
54
+ }
55
+
56
+ .menu-item:hover,
57
+ .menu-item.force-hover {
58
+ background: var(--menu-item-hover-bg-color, #fff);
59
+ color: var(--menu-item-hover-color, #101010);
60
+ }
61
+
62
+ .menu-item:active {
63
+ background: var(--menu-item-pressed-bg-color, #f2c94c);
64
+ color: var(--menu-item-pressed-color, #101010);
65
65
  }
66
66
 
67
67
  .submenu {
@@ -1058,29 +1058,29 @@ body {
1058
1058
  color: var(--cols-card-accent-color, #0969da);
1059
1059
  white-space: nowrap;
1060
1060
  }
1061
- .wenayCardListFields {
1062
- display: block;
1063
- }
1064
- .wenayCardListItem_compact .wenayCardListFields {
1065
- display: grid;
1066
- grid-template-columns: repeat(2, minmax(0, 1fr));
1067
- gap: 4px 8px;
1068
- }
1069
- .wenayCardListItem_compact .wenayCardListField {
1070
- min-width: 0;
1071
- padding: 2px 6px;
1072
- border-radius: 5px;
1073
- background: var(--cols-card-field-bg, #f6f8fa);
1074
- line-height: 1.45;
1075
- }
1076
- .wenayCardListItem_compact .wenayCardListLabel {
1077
- min-width: 0;
1078
- font-size: 10px;
1079
- text-transform: uppercase;
1080
- letter-spacing: .03em;
1081
- }
1082
- @media (max-width: 320px) {
1083
- .wenayCardListItem_compact .wenayCardListFields { grid-template-columns: 1fr; }
1061
+ .wenayCardListFields {
1062
+ display: block;
1063
+ }
1064
+ .wenayCardListItem_compact .wenayCardListFields {
1065
+ display: grid;
1066
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1067
+ gap: 4px 8px;
1068
+ }
1069
+ .wenayCardListItem_compact .wenayCardListField {
1070
+ min-width: 0;
1071
+ padding: 2px 6px;
1072
+ border-radius: 5px;
1073
+ background: var(--cols-card-field-bg, #f6f8fa);
1074
+ line-height: 1.45;
1075
+ }
1076
+ .wenayCardListItem_compact .wenayCardListLabel {
1077
+ min-width: 0;
1078
+ font-size: 10px;
1079
+ text-transform: uppercase;
1080
+ letter-spacing: .03em;
1081
+ }
1082
+ @media (max-width: 320px) {
1083
+ .wenayCardListItem_compact .wenayCardListFields { grid-template-columns: 1fr; }
1084
1084
  }
1085
1085
  .wenayCardListField {
1086
1086
  display: flex;