reactoradar 1.5.8 → 1.5.10
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/app.js +226 -33
- package/package.json +1 -1
- package/styles.css +15 -1
package/app.js
CHANGED
|
@@ -67,7 +67,7 @@ function renderJSON(val) {
|
|
|
67
67
|
try {
|
|
68
68
|
const str = typeof val === 'string' ? val : JSON.stringify(val, null, 2);
|
|
69
69
|
return syntaxHighlight(esc(str));
|
|
70
|
-
} catch { return esc(String(val)); }
|
|
70
|
+
} catch { return esc(typeof val === 'object' ? JSON.stringify(val) : String(val)); }
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
function tryURL(url) { try { return new URL(url); } catch { return null; } }
|
|
@@ -239,7 +239,7 @@ if (window.electronAPI) {
|
|
|
239
239
|
window.electronAPI.on('clear-all-ui', clearAll);
|
|
240
240
|
|
|
241
241
|
// Cmd+F — focus the search input for the active panel
|
|
242
|
-
|
|
242
|
+
function _handleFind() {
|
|
243
243
|
const searchMap = {
|
|
244
244
|
console: 'consoleSearch',
|
|
245
245
|
network: 'netSearchInput',
|
|
@@ -257,6 +257,14 @@ if (window.electronAPI) {
|
|
|
257
257
|
const bar = $('consoleFindBar');
|
|
258
258
|
if (bar) { bar.style.display = 'flex'; $('consoleFindInput')?.focus(); }
|
|
259
259
|
}
|
|
260
|
+
}
|
|
261
|
+
window.electronAPI.on('focus-search', _handleFind);
|
|
262
|
+
// Direct keyboard fallback — Electron menu accelerators can miss in some contexts
|
|
263
|
+
document.addEventListener('keydown', (e) => {
|
|
264
|
+
if ((e.metaKey || e.ctrlKey) && e.key === 'f') {
|
|
265
|
+
e.preventDefault();
|
|
266
|
+
_handleFind();
|
|
267
|
+
}
|
|
260
268
|
});
|
|
261
269
|
|
|
262
270
|
window.electronAPI.on('app-version', (version) => {
|
|
@@ -688,6 +696,14 @@ function createTreeNode(key, val, startCollapsed) {
|
|
|
688
696
|
return container;
|
|
689
697
|
}
|
|
690
698
|
|
|
699
|
+
function _safeStr(val) {
|
|
700
|
+
if (val === null) return 'null';
|
|
701
|
+
if (val === undefined) return 'undefined';
|
|
702
|
+
if (typeof val === 'string') return val;
|
|
703
|
+
if (typeof val === 'number' || typeof val === 'boolean') return String(val);
|
|
704
|
+
try { return JSON.stringify(val, null, 2); } catch { return String(val); }
|
|
705
|
+
}
|
|
706
|
+
|
|
691
707
|
function createPrimitiveSpan(val) {
|
|
692
708
|
const s = document.createElement('span');
|
|
693
709
|
if (val === null) { s.className = 'ov-null'; s.textContent = 'null'; }
|
|
@@ -695,7 +711,7 @@ function createPrimitiveSpan(val) {
|
|
|
695
711
|
else if (typeof val === 'string') { s.className = 'ov-str'; s.textContent = `"${val}"`; }
|
|
696
712
|
else if (typeof val === 'number') { s.className = 'ov-num'; s.textContent = String(val); }
|
|
697
713
|
else if (typeof val === 'boolean') { s.className = 'ov-bool'; s.textContent = String(val); }
|
|
698
|
-
else { s.textContent =
|
|
714
|
+
else { s.textContent = _safeStr(val); }
|
|
699
715
|
return s;
|
|
700
716
|
}
|
|
701
717
|
|
|
@@ -705,7 +721,7 @@ function renderConsoleArg(arg) {
|
|
|
705
721
|
// Backward compat: raw string
|
|
706
722
|
const s = document.createElement('span');
|
|
707
723
|
s.className = 'ov-str';
|
|
708
|
-
s.textContent =
|
|
724
|
+
s.textContent = _safeStr(arg);
|
|
709
725
|
return s;
|
|
710
726
|
}
|
|
711
727
|
const { t, v } = arg;
|
|
@@ -723,7 +739,7 @@ function renderConsoleArg(arg) {
|
|
|
723
739
|
return createTreeNode(null, v, false);
|
|
724
740
|
}
|
|
725
741
|
const s = document.createElement('span');
|
|
726
|
-
s.textContent =
|
|
742
|
+
s.textContent = _safeStr(v);
|
|
727
743
|
return s;
|
|
728
744
|
}
|
|
729
745
|
|
|
@@ -1972,6 +1988,94 @@ function _findLeafChanges(oldVal, newVal, basePath, maxDepth) {
|
|
|
1972
1988
|
return changes;
|
|
1973
1989
|
}
|
|
1974
1990
|
|
|
1991
|
+
// Create a tree node with changed paths highlighted in a different color
|
|
1992
|
+
function _createHighlightedTree(key, val, changedPaths, currentPath, isOld) {
|
|
1993
|
+
const isArray = Array.isArray(val);
|
|
1994
|
+
const isObj = val !== null && typeof val === 'object';
|
|
1995
|
+
const myPath = key !== null ? (currentPath ? `${currentPath}.${key}` : String(key)) : currentPath;
|
|
1996
|
+
const isChanged = changedPaths.has(myPath);
|
|
1997
|
+
|
|
1998
|
+
if (!isObj) {
|
|
1999
|
+
// Leaf value
|
|
2000
|
+
const row = document.createElement('div');
|
|
2001
|
+
row.className = 'ov-leaf' + (isChanged ? ' rdx-highlight' : '');
|
|
2002
|
+
if (isChanged) row.style.cssText = isOld
|
|
2003
|
+
? 'background:rgba(255,94,114,.12);border-radius:3px;padding:1px 4px;'
|
|
2004
|
+
: 'background:rgba(61,214,140,.12);border-radius:3px;padding:1px 4px;';
|
|
2005
|
+
if (key !== null) {
|
|
2006
|
+
const k = document.createElement('span');
|
|
2007
|
+
k.className = 'ov-key';
|
|
2008
|
+
k.style.color = isChanged ? (isOld ? 'var(--red)' : 'var(--green)') : '';
|
|
2009
|
+
k.textContent = `${key}: `;
|
|
2010
|
+
row.appendChild(k);
|
|
2011
|
+
}
|
|
2012
|
+
const v = document.createElement('span');
|
|
2013
|
+
v.className = 'ov-prim';
|
|
2014
|
+
if (isChanged) v.style.fontWeight = '700';
|
|
2015
|
+
if (val === null) { v.textContent = 'null'; v.style.color = isChanged ? (isOld ? 'var(--red)' : 'var(--green)') : 'var(--text-dim)'; }
|
|
2016
|
+
else if (typeof val === 'string') { v.textContent = `"${val}"`; v.style.color = isChanged ? (isOld ? 'var(--red)' : 'var(--green)') : 'var(--green)'; }
|
|
2017
|
+
else if (typeof val === 'number') { v.textContent = String(val); v.style.color = isChanged ? (isOld ? 'var(--red)' : 'var(--green)') : 'var(--accent2)'; }
|
|
2018
|
+
else if (typeof val === 'boolean') { v.textContent = String(val); v.style.color = isChanged ? (isOld ? 'var(--red)' : 'var(--green)') : 'var(--accent2)'; }
|
|
2019
|
+
else { v.textContent = _safeStr(val); }
|
|
2020
|
+
row.appendChild(v);
|
|
2021
|
+
return row;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
// Object/Array — check if any descendants changed
|
|
2025
|
+
const hasChangedDescendant = [...changedPaths].some(p => p === myPath || p.startsWith(myPath ? myPath + '.' : ''));
|
|
2026
|
+
const container = document.createElement('div');
|
|
2027
|
+
container.className = 'ov-node';
|
|
2028
|
+
|
|
2029
|
+
const header = document.createElement('div');
|
|
2030
|
+
header.className = 'ov-header';
|
|
2031
|
+
|
|
2032
|
+
const arrow = document.createElement('span');
|
|
2033
|
+
arrow.className = 'ov-arrow';
|
|
2034
|
+
arrow.textContent = '\u25B6';
|
|
2035
|
+
header.appendChild(arrow);
|
|
2036
|
+
|
|
2037
|
+
if (key !== null) {
|
|
2038
|
+
const k = document.createElement('span');
|
|
2039
|
+
k.className = 'ov-key';
|
|
2040
|
+
if (hasChangedDescendant) k.style.color = isOld ? 'var(--red)' : 'var(--green)';
|
|
2041
|
+
k.textContent = `${key}: `;
|
|
2042
|
+
header.appendChild(k);
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
const preview = document.createElement('span');
|
|
2046
|
+
preview.className = 'ov-preview';
|
|
2047
|
+
preview.textContent = isArray ? `Array(${val.length})` : `{${Object.keys(val).length} keys}`;
|
|
2048
|
+
header.appendChild(preview);
|
|
2049
|
+
|
|
2050
|
+
container.appendChild(header);
|
|
2051
|
+
|
|
2052
|
+
const children = document.createElement('div');
|
|
2053
|
+
children.className = 'ov-children';
|
|
2054
|
+
// Always start collapsed — user expands what they need
|
|
2055
|
+
children.style.display = 'none';
|
|
2056
|
+
|
|
2057
|
+
let populated = false;
|
|
2058
|
+
function populate() {
|
|
2059
|
+
if (populated) return;
|
|
2060
|
+
populated = true;
|
|
2061
|
+
const entries = isArray ? val.map((v, i) => [i, v]) : Object.entries(val);
|
|
2062
|
+
entries.forEach(([k, v]) => {
|
|
2063
|
+
children.appendChild(_createHighlightedTree(k, v, changedPaths, myPath, isOld));
|
|
2064
|
+
});
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2067
|
+
header.addEventListener('click', (e) => {
|
|
2068
|
+
e.stopPropagation();
|
|
2069
|
+
const open = children.style.display !== 'none';
|
|
2070
|
+
children.style.display = open ? 'none' : 'block';
|
|
2071
|
+
arrow.textContent = open ? '\u25B6' : '\u25BC';
|
|
2072
|
+
if (!open) populate();
|
|
2073
|
+
});
|
|
2074
|
+
|
|
2075
|
+
container.appendChild(children);
|
|
2076
|
+
return container;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
1975
2079
|
function handleReduxEvent(event) {
|
|
1976
2080
|
if (event.type !== 'redux') return;
|
|
1977
2081
|
const { action, nextState } = event;
|
|
@@ -2004,6 +2108,29 @@ function handleReduxEvent(event) {
|
|
|
2004
2108
|
}
|
|
2005
2109
|
}
|
|
2006
2110
|
|
|
2111
|
+
// Assign a consistent color to each Redux action category (e.g. ANALYTICS, CART, USER)
|
|
2112
|
+
const _reduxCatColors = {};
|
|
2113
|
+
const _reduxColorPalette = [
|
|
2114
|
+
'var(--accent)', // blue
|
|
2115
|
+
'var(--green)', // green
|
|
2116
|
+
'var(--orange)', // orange
|
|
2117
|
+
'var(--accent2)', // purple
|
|
2118
|
+
'#e06c75', // coral
|
|
2119
|
+
'#56b6c2', // teal
|
|
2120
|
+
'#c678dd', // magenta
|
|
2121
|
+
'#d19a66', // gold
|
|
2122
|
+
'#98c379', // lime
|
|
2123
|
+
'#e5c07b', // yellow
|
|
2124
|
+
];
|
|
2125
|
+
let _reduxColorIdx = 0;
|
|
2126
|
+
function _reduxCategoryColor(category) {
|
|
2127
|
+
if (!_reduxCatColors[category]) {
|
|
2128
|
+
_reduxCatColors[category] = _reduxColorPalette[_reduxColorIdx % _reduxColorPalette.length];
|
|
2129
|
+
_reduxColorIdx++;
|
|
2130
|
+
}
|
|
2131
|
+
return _reduxCatColors[category];
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2007
2134
|
function renderRedux() {
|
|
2008
2135
|
const content = $('reduxContent');
|
|
2009
2136
|
const empty = $('reduxEmpty');
|
|
@@ -2031,12 +2158,32 @@ function renderRedux() {
|
|
|
2031
2158
|
const header = document.createElement('div');
|
|
2032
2159
|
header.className = 'rdx-entry-header';
|
|
2033
2160
|
const changesBadge = a.changedKeys?.length ? `<span class="rdx-changes">${a.changedKeys.length} changed</span>` : '';
|
|
2034
|
-
|
|
2161
|
+
// Color-code action type by category prefix (e.g. ANALYTICS/, CART/, USER/)
|
|
2162
|
+
const typeParts = a.type.split('/');
|
|
2163
|
+
let typeHtml;
|
|
2164
|
+
if (typeParts.length >= 2) {
|
|
2165
|
+
const catColor = _reduxCategoryColor(typeParts[0]);
|
|
2166
|
+
typeHtml = `<span class="rdx-type-cat" style="color:${catColor}">${esc(typeParts[0])}/</span><span class="rdx-type-name">${esc(typeParts.slice(1).join('/'))}</span>`;
|
|
2167
|
+
} else {
|
|
2168
|
+
typeHtml = `<span class="rdx-type">${esc(a.type)}</span>`;
|
|
2169
|
+
}
|
|
2170
|
+
header.innerHTML = `<span class="rdx-index">#${a.index}</span>${typeHtml}<span class="rdx-header-right">${changesBadge}<span class="rdx-time">${ts(a.ts)}</span></span>`;
|
|
2035
2171
|
// Toggle: click to expand, click again to collapse
|
|
2036
2172
|
header.addEventListener('click', () => {
|
|
2037
2173
|
state.redux.selected = isSelected ? -1 : a.index;
|
|
2038
2174
|
renderRedux();
|
|
2039
2175
|
});
|
|
2176
|
+
// Right-click to copy action type
|
|
2177
|
+
header.addEventListener('contextmenu', (e) => {
|
|
2178
|
+
e.preventDefault();
|
|
2179
|
+
e.stopPropagation();
|
|
2180
|
+
showContextMenu(e, [
|
|
2181
|
+
{ label: 'Copy Action Type', action: () => navigator.clipboard.writeText(a.type) },
|
|
2182
|
+
{ label: 'Copy Action Payload', action: () => navigator.clipboard.writeText(JSON.stringify(a.payload, null, 2)) },
|
|
2183
|
+
]);
|
|
2184
|
+
});
|
|
2185
|
+
// Allow text selection on the action type
|
|
2186
|
+
header.style.userSelect = 'text';
|
|
2040
2187
|
entry.appendChild(header);
|
|
2041
2188
|
|
|
2042
2189
|
// Expanded detail — only for explicitly selected action
|
|
@@ -2044,6 +2191,18 @@ function renderRedux() {
|
|
|
2044
2191
|
const detail = document.createElement('div');
|
|
2045
2192
|
detail.className = 'rdx-entry-detail';
|
|
2046
2193
|
|
|
2194
|
+
// Close button
|
|
2195
|
+
const closeBtn = document.createElement('button');
|
|
2196
|
+
closeBtn.className = 'rdx-close-btn';
|
|
2197
|
+
closeBtn.textContent = '✕';
|
|
2198
|
+
closeBtn.title = 'Close';
|
|
2199
|
+
closeBtn.addEventListener('click', (e) => {
|
|
2200
|
+
e.stopPropagation();
|
|
2201
|
+
state.redux.selected = -1;
|
|
2202
|
+
renderRedux();
|
|
2203
|
+
});
|
|
2204
|
+
detail.appendChild(closeBtn);
|
|
2205
|
+
|
|
2047
2206
|
// Changed keys badges
|
|
2048
2207
|
if (a.changedKeys?.length > 0) {
|
|
2049
2208
|
const keysEl = document.createElement('div');
|
|
@@ -2062,18 +2221,14 @@ function renderRedux() {
|
|
|
2062
2221
|
detail.appendChild(createTreeNode(null, a.payload, false));
|
|
2063
2222
|
}
|
|
2064
2223
|
|
|
2065
|
-
// Store changes —
|
|
2224
|
+
// Store changes — two-column layout: Previous | Current
|
|
2066
2225
|
const prevS = a.index > 0 ? states[a.index - 1] : null;
|
|
2067
2226
|
const currS = states[a.index];
|
|
2068
2227
|
if (currS && typeof currS === 'object' && a.changedKeys?.length > 0) {
|
|
2069
|
-
const sLabel = document.createElement('div');
|
|
2070
|
-
sLabel.className = 'redux-section-title';
|
|
2071
|
-
sLabel.textContent = 'Store Changes';
|
|
2072
|
-
detail.appendChild(sLabel);
|
|
2073
|
-
|
|
2074
2228
|
a.changedKeys.forEach(key => {
|
|
2075
2229
|
const keyWrap = document.createElement('div');
|
|
2076
2230
|
keyWrap.className = 'rdx-store-diff';
|
|
2231
|
+
|
|
2077
2232
|
const kLabel = document.createElement('div');
|
|
2078
2233
|
kLabel.className = 'rdx-store-key-label';
|
|
2079
2234
|
kLabel.textContent = key;
|
|
@@ -2082,29 +2237,67 @@ function renderRedux() {
|
|
|
2082
2237
|
const oldVal = prevS ? prevS[key] : undefined;
|
|
2083
2238
|
const newVal = currS[key];
|
|
2084
2239
|
|
|
2085
|
-
//
|
|
2086
|
-
const
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2240
|
+
// Find which sub-keys changed (for highlighting)
|
|
2241
|
+
const changedPaths = new Set();
|
|
2242
|
+
_findLeafChanges(oldVal, newVal, '').forEach(c => changedPaths.add(c.path));
|
|
2243
|
+
|
|
2244
|
+
// Two-column grid: Previous | Current
|
|
2245
|
+
const grid = document.createElement('div');
|
|
2246
|
+
grid.className = 'rdx-diff-grid';
|
|
2247
|
+
|
|
2248
|
+
// Previous column
|
|
2249
|
+
const prevCol = document.createElement('div');
|
|
2250
|
+
prevCol.className = 'rdx-diff-col prev';
|
|
2251
|
+
const prevLabel = document.createElement('div');
|
|
2252
|
+
prevLabel.className = 'rdx-state-label prev';
|
|
2253
|
+
prevLabel.textContent = '- Previous';
|
|
2254
|
+
prevCol.appendChild(prevLabel);
|
|
2255
|
+
if (oldVal !== undefined) {
|
|
2256
|
+
prevCol.appendChild(_createHighlightedTree(null, oldVal, changedPaths, '', true));
|
|
2257
|
+
} else {
|
|
2258
|
+
const na = document.createElement('span');
|
|
2259
|
+
na.style.cssText = 'color:var(--text-dim);font-size:10px;font-style:italic';
|
|
2260
|
+
na.textContent = 'undefined';
|
|
2261
|
+
prevCol.appendChild(na);
|
|
2262
|
+
}
|
|
2263
|
+
grid.appendChild(prevCol);
|
|
2264
|
+
|
|
2265
|
+
// Current column
|
|
2266
|
+
const currCol = document.createElement('div');
|
|
2267
|
+
currCol.className = 'rdx-diff-col curr';
|
|
2268
|
+
const currLabel = document.createElement('div');
|
|
2269
|
+
currLabel.className = 'rdx-state-label curr';
|
|
2270
|
+
currLabel.textContent = '+ Current';
|
|
2271
|
+
currCol.appendChild(currLabel);
|
|
2272
|
+
if (newVal !== undefined) {
|
|
2273
|
+
currCol.appendChild(_createHighlightedTree(null, newVal, changedPaths, '', false));
|
|
2097
2274
|
} else {
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
const newStr = newVal === undefined ? 'undefined' : (typeof newVal === 'object' ? JSON.stringify(newVal) : String(newVal));
|
|
2103
|
-
row.innerHTML = `<span class="rdx-diff-old">${esc(oldStr)}</span>`
|
|
2104
|
-
+ `<span class="rdx-diff-arrow">→</span>`
|
|
2105
|
-
+ `<span class="rdx-diff-new">${esc(newStr)}</span>`;
|
|
2106
|
-
keyWrap.appendChild(row);
|
|
2275
|
+
const na = document.createElement('span');
|
|
2276
|
+
na.style.cssText = 'color:var(--text-dim);font-size:10px;font-style:italic';
|
|
2277
|
+
na.textContent = 'undefined';
|
|
2278
|
+
currCol.appendChild(na);
|
|
2107
2279
|
}
|
|
2280
|
+
grid.appendChild(currCol);
|
|
2281
|
+
|
|
2282
|
+
// Right-click to copy on each column
|
|
2283
|
+
prevCol.addEventListener('contextmenu', (e) => {
|
|
2284
|
+
e.preventDefault(); e.stopPropagation();
|
|
2285
|
+
showContextMenu(e, [
|
|
2286
|
+
{ label: 'Copy Previous Value', action: () => navigator.clipboard.writeText(JSON.stringify(oldVal, null, 2)) },
|
|
2287
|
+
{ label: 'Copy Current Value', action: () => navigator.clipboard.writeText(JSON.stringify(newVal, null, 2)) },
|
|
2288
|
+
{ label: `Copy "${key}" key`, action: () => navigator.clipboard.writeText(key) },
|
|
2289
|
+
]);
|
|
2290
|
+
});
|
|
2291
|
+
currCol.addEventListener('contextmenu', (e) => {
|
|
2292
|
+
e.preventDefault(); e.stopPropagation();
|
|
2293
|
+
showContextMenu(e, [
|
|
2294
|
+
{ label: 'Copy Current Value', action: () => navigator.clipboard.writeText(JSON.stringify(newVal, null, 2)) },
|
|
2295
|
+
{ label: 'Copy Previous Value', action: () => navigator.clipboard.writeText(JSON.stringify(oldVal, null, 2)) },
|
|
2296
|
+
{ label: `Copy "${key}" key`, action: () => navigator.clipboard.writeText(key) },
|
|
2297
|
+
]);
|
|
2298
|
+
});
|
|
2299
|
+
|
|
2300
|
+
keyWrap.appendChild(grid);
|
|
2108
2301
|
detail.appendChild(keyWrap);
|
|
2109
2302
|
});
|
|
2110
2303
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reactoradar",
|
|
3
3
|
"productName": "ReactoRadar",
|
|
4
|
-
"version": "1.5.
|
|
4
|
+
"version": "1.5.10",
|
|
5
5
|
"description": "macOS debugger for React Native — Console, Sources, Network, Performance, Memory, Redux, AsyncStorage, React tree. Supports RN 0.74+ with Hermes and New Architecture.",
|
|
6
6
|
"main": "main.js",
|
|
7
7
|
"bin": {
|
package/styles.css
CHANGED
|
@@ -924,7 +924,10 @@ body {
|
|
|
924
924
|
.rdx-entry-header:hover { background: var(--bg3); }
|
|
925
925
|
.rdx-entry.selected .rdx-entry-header { border-left: 3px solid var(--accent); }
|
|
926
926
|
.rdx-index { font-size: 9px; color: var(--text-dim); min-width: 20px; text-align: right; flex-shrink: 0; }
|
|
927
|
-
.rdx-type {
|
|
927
|
+
.rdx-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-bright); font-weight: 500; }
|
|
928
|
+
.rdx-type-cat { font-weight: 700; }
|
|
929
|
+
.rdx-type-name { color: var(--text-bright); font-weight: 500; }
|
|
930
|
+
.rdx-header-right { margin-left: auto; display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
|
928
931
|
.rdx-changes {
|
|
929
932
|
font-size: 8px; font-weight: 700; padding: 1px 5px; border-radius: 8px;
|
|
930
933
|
background: rgba(255,94,114,.12); color: var(--red); flex-shrink: 0;
|
|
@@ -968,6 +971,17 @@ body {
|
|
|
968
971
|
.rdx-diff-old { color: var(--red); text-decoration: line-through; opacity: 0.8; word-break: break-all; }
|
|
969
972
|
.rdx-diff-arrow { color: var(--text-dim); font-size: 10px; flex-shrink: 0; }
|
|
970
973
|
.rdx-diff-new { color: var(--green); font-weight: 600; word-break: break-all; }
|
|
974
|
+
.rdx-state-label { font-size: 10px; font-weight: 700; padding: 4px 0 2px; letter-spacing: 0.5px; }
|
|
975
|
+
.rdx-state-label.prev { color: var(--red); }
|
|
976
|
+
.rdx-state-label.curr { color: var(--green); }
|
|
977
|
+
.rdx-diff-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 4px; }
|
|
978
|
+
.rdx-diff-col { min-width: 0; overflow: auto; max-height: 400px; padding: 4px; border-radius: 4px; font-size: 11px; }
|
|
979
|
+
.rdx-diff-col.prev { background: rgba(255,94,114,.04); border: 1px solid rgba(255,94,114,.12); }
|
|
980
|
+
.rdx-diff-col.curr { background: rgba(61,214,140,.04); border: 1px solid rgba(61,214,140,.12); }
|
|
981
|
+
.rdx-close-btn { position: absolute; top: 6px; right: 8px; background: var(--bg3); border: 1px solid var(--border); color: var(--text-dim); font-size: 11px; width: 22px; height: 22px; border-radius: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; z-index: 1; }
|
|
982
|
+
.rdx-close-btn:hover { background: var(--bg4); color: var(--text); }
|
|
983
|
+
.rdx-entry-detail { position: relative; }
|
|
984
|
+
.rdx-highlight { font-weight: 600; }
|
|
971
985
|
.rdx-diff-sign { font-weight: 700; font-size: 11px; flex-shrink: 0; width: 14px; text-align: center; }
|
|
972
986
|
.rdx-diff-row.removed .rdx-diff-sign { color: var(--red); }
|
|
973
987
|
.rdx-diff-row.added .rdx-diff-sign { color: var(--green); }
|