@cevek/screentest 0.2.5 → 0.3.1
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/README.md +52 -36
- package/dist/global-setup.js +7 -0
- package/dist/index.js +334 -182
- package/dist/runner.js +20 -15
- package/dist/templates/Dockerfile.firefox-server +25 -0
- package/dist/templates/launch-server.mjs +22 -0
- package/dist/web/assets/{index-DMJ0v7v-.css → index-Bi-jx470.css} +1 -1
- package/dist/web/assets/{index-DIlEhyib.js → index-nQ8FCC_F.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +3 -2
- package/dist/templates/Dockerfile.npm.tests +0 -16
- package/dist/templates/Dockerfile.pnpm.tests +0 -27
- package/dist/templates/Dockerfile.yarn.tests +0 -20
package/dist/runner.js
CHANGED
|
@@ -5,18 +5,29 @@ import { dirname, join as join2 } from "path";
|
|
|
5
5
|
import { expect } from "vitest";
|
|
6
6
|
|
|
7
7
|
// src/runner/paths.ts
|
|
8
|
-
import {
|
|
8
|
+
import { existsSync } from "fs";
|
|
9
|
+
import { isAbsolute, join, resolve } from "path";
|
|
9
10
|
function resolveRunnerPaths(cwd = process.cwd()) {
|
|
10
11
|
const projectRoot = resolve(cwd);
|
|
11
12
|
const cacheDir = join(projectRoot, "node_modules", ".cache", "screentest");
|
|
12
13
|
return {
|
|
13
14
|
projectRoot,
|
|
14
|
-
snapshotFile:
|
|
15
|
+
snapshotFile: resolveSnapshotFile(projectRoot),
|
|
15
16
|
cacheDir,
|
|
16
17
|
actualDir: join(cacheDir, "actual"),
|
|
17
18
|
docFile: join(cacheDir, "doc.json")
|
|
18
19
|
};
|
|
19
20
|
}
|
|
21
|
+
function resolveSnapshotFile(projectRoot) {
|
|
22
|
+
const envPath = process.env.SCREENTEST_SNAPSHOT_FILE;
|
|
23
|
+
if (envPath) {
|
|
24
|
+
return isAbsolute(envPath) ? envPath : join(projectRoot, envPath);
|
|
25
|
+
}
|
|
26
|
+
const legacyRoot = join(projectRoot, "snapshot.json");
|
|
27
|
+
const insideTests = join(projectRoot, "tests", "snapshot.json");
|
|
28
|
+
if (existsSync(legacyRoot) && !existsSync(insideTests)) return legacyRoot;
|
|
29
|
+
return insideTests;
|
|
30
|
+
}
|
|
20
31
|
|
|
21
32
|
// src/runner/stabilize.ts
|
|
22
33
|
async function freezeDate(ctx, when) {
|
|
@@ -181,19 +192,10 @@ async function compareSnapshot(target, name, opts = {}) {
|
|
|
181
192
|
|
|
182
193
|
// src/runner/browser.ts
|
|
183
194
|
import { inject } from "vitest";
|
|
184
|
-
import {
|
|
185
|
-
firefox
|
|
186
|
-
} from "playwright";
|
|
187
|
-
var browserPromise = null;
|
|
188
|
-
async function getBrowser() {
|
|
189
|
-
if (!browserPromise) {
|
|
190
|
-
const wsEndpoint = inject("wsEndpoint");
|
|
191
|
-
browserPromise = firefox.connect(wsEndpoint);
|
|
192
|
-
}
|
|
193
|
-
return browserPromise;
|
|
194
|
-
}
|
|
195
|
+
import { firefox } from "playwright";
|
|
195
196
|
async function newPage(opts = {}) {
|
|
196
|
-
const
|
|
197
|
+
const wsEndpoint = inject("wsEndpoint");
|
|
198
|
+
const browser = await firefox.connect(wsEndpoint);
|
|
197
199
|
const ctx = await browser.newContext({
|
|
198
200
|
viewport: { width: 1280, height: 800 },
|
|
199
201
|
deviceScaleFactor: 1,
|
|
@@ -205,7 +207,10 @@ async function newPage(opts = {}) {
|
|
|
205
207
|
ctx,
|
|
206
208
|
page,
|
|
207
209
|
cleanup: async () => {
|
|
208
|
-
await ctx.close()
|
|
210
|
+
await ctx.close().catch(() => {
|
|
211
|
+
});
|
|
212
|
+
await browser.close().catch(() => {
|
|
213
|
+
});
|
|
209
214
|
}
|
|
210
215
|
};
|
|
211
216
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Universal screentest Firefox browser-server image.
|
|
2
|
+
#
|
|
3
|
+
# Used by `screentest serve` to run a long-lived headless Firefox in a Linux
|
|
4
|
+
# container. Your tests run on the host (native vitest) and connect via
|
|
5
|
+
# WebSocket — so PNG bytes are baked by Linux Firefox (CI-parity) while the
|
|
6
|
+
# rest of your toolchain (TypeScript, deps, watch mode) stays on the host.
|
|
7
|
+
#
|
|
8
|
+
# The image is project-agnostic: it ONLY contains Playwright + Firefox + a
|
|
9
|
+
# 10-line launch script. Rebuild only when the Playwright version pinned
|
|
10
|
+
# below moves.
|
|
11
|
+
|
|
12
|
+
FROM mcr.microsoft.com/playwright:v1.60.0-noble
|
|
13
|
+
|
|
14
|
+
WORKDIR /work
|
|
15
|
+
|
|
16
|
+
# Browsers are pre-installed at /ms-playwright in the base image; we only
|
|
17
|
+
# need the JS package to use `firefox.launchServer(...)`.
|
|
18
|
+
RUN npm init -y >/dev/null \
|
|
19
|
+
&& npm install --no-audit --no-fund --no-progress playwright@1.60.0
|
|
20
|
+
|
|
21
|
+
COPY launch-server.mjs ./
|
|
22
|
+
|
|
23
|
+
EXPOSE 5180
|
|
24
|
+
|
|
25
|
+
CMD ["node", "launch-server.mjs"]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Long-lived headless Firefox browser-server. Tests on the host connect via
|
|
2
|
+
// WS, see playwright.dev/docs/api/class-browsertype#browser-type-launch-server
|
|
3
|
+
import { firefox } from 'playwright';
|
|
4
|
+
|
|
5
|
+
const port = Number.parseInt(process.env.SCREENTEST_PORT ?? '5180', 10);
|
|
6
|
+
const wsPath = process.env.SCREENTEST_WS_PATH ?? 'screentest-firefox';
|
|
7
|
+
|
|
8
|
+
const server = await firefox.launchServer({
|
|
9
|
+
port,
|
|
10
|
+
host: '0.0.0.0',
|
|
11
|
+
wsPath,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
console.log(`[screentest] firefox browser-server ready: ${server.wsEndpoint()}`);
|
|
15
|
+
|
|
16
|
+
const shutdown = async (signal) => {
|
|
17
|
+
console.log(`[screentest] received ${signal}, closing browser-server`);
|
|
18
|
+
await server.close();
|
|
19
|
+
process.exit(0);
|
|
20
|
+
};
|
|
21
|
+
process.on('SIGTERM', () => void shutdown('SIGTERM'));
|
|
22
|
+
process.on('SIGINT', () => void shutdown('SIGINT'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
._viewport_1obvw_1{z-index:1000;outline:none;flex-direction:column;gap:8px;width:360px;max-width:calc(100vw - 32px);margin:0;padding:0;list-style:none;display:flex;position:fixed;bottom:16px;right:16px}._toast_1obvw_17{background:var(--bg-elev-2);border:1px solid var(--border-strong);border-left:3px solid var(--accent);box-shadow:var(--shadow);border-radius:6px;padding:10px 14px}._toast_1obvw_17[data-state=open]{animation:.16s ease-out _slideIn_1obvw_1}._toast_1obvw_17[data-state=closed]{animation:.12s ease-in forwards _fadeOut_1obvw_1}._toast_1obvw_17._error_1obvw_32{border-left-color:var(--red)}._toast_1obvw_17._success_1obvw_36{border-left-color:var(--green)}._toast_1obvw_17._info_1obvw_40{border-left-color:var(--accent)}._title_1obvw_44{margin:0 0 2px;font-size:13px;font-weight:600}._desc_1obvw_50{color:var(--text-dim);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:12px}@keyframes _slideIn_1obvw_1{0%{opacity:0;transform:translate(8px)}to{opacity:1;transform:translate(0)}}@keyframes _fadeOut_1obvw_1{0%{opacity:1}to{opacity:0}}._tree_4auq3_1{margin:0;padding:0;list-style:none}._groupLi_4auq3_7,._leafLi_4auq3_8{list-style:none}._group_4auq3_7,._leaf_4auq3_8{width:100%;color:var(--text);text-align:left;border-radius:4px;align-items:center;gap:6px;min-width:0;padding:4px 8px 4px 6px;font-size:12.5px;display:flex}._group_4auq3_7:hover,._leaf_4auq3_8:hover{background:var(--bg-elev-2)}._chevron_4auq3_31{color:var(--text-faint);flex:none;transition:transform .12s}._chevronOpen_4auq3_37{transform:rotate(90deg)}._groupName_4auq3_41,._leafName_4auq3_42{white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}._groupName_4auq3_41{color:var(--text-dim);font-weight:500}._staleBadge_4auq3_55{background:var(--orange);color:#1a1408;border-radius:8px;flex:none;padding:1px 6px;font-size:10px;font-weight:700;line-height:1.4}._leaf_4auq3_8{cursor:pointer}._leafSelected_4auq3_70{background:#6ea8ff29}._leafSelected_4auq3_70:hover{background:#6ea8ff38}._icon_4auq3_78{flex:none}._acceptInline_4auq3_82{opacity:0;width:18px;height:18px;color:var(--text-dim);border-radius:3px;flex:none;justify-content:center;align-items:center;display:inline-flex}._leaf_4auq3_8:hover ._acceptInline_4auq3_82{opacity:1}._acceptInline_4auq3_82:hover{background:var(--bg);color:var(--green)}._toneGreen_4auq3_103{color:var(--green)}._toneYellow_4auq3_107{color:var(--yellow)}._toneOrange_4auq3_111{color:var(--orange)}._toneRed_4auq3_115{color:var(--red)}._toneRedDim_4auq3_119{color:var(--red-dim)}._toneBlueGrey_4auq3_123{color:var(--blue-grey)}._toneAccent_4auq3_127{color:var(--accent)}._spin_4auq3_131{animation:.9s linear infinite _spin_4auq3_131}@keyframes _spin_4auq3_131{to{transform:rotate(360deg)}}._root_12w7q_1{border-bottom:1px solid var(--border);background:var(--bg-elev);flex-direction:column;gap:8px;padding:10px 12px;display:flex}._row_12w7q_10{align-items:center;gap:6px;display:flex}._action_12w7q_16{border:1px solid var(--border-strong);background:var(--bg-elev-2);color:var(--text);border-radius:4px;align-items:center;gap:6px;padding:5px 10px;font-size:12px;display:inline-flex}._action_12w7q_16:hover:not(:disabled){background:var(--bg);border-color:var(--accent)}._actionCount_12w7q_33{background:var(--border-strong);color:var(--text-dim);border-radius:8px;padding:1px 6px;font-size:10px}._stop_12w7q_41{border:1px solid var(--red-dim);color:var(--red);background:0 0;border-radius:4px;align-items:center;gap:6px;padding:5px 10px;font-size:12px;display:inline-flex}._stop_12w7q_41:hover{background:#e35d5d1a}._progressOuter_12w7q_57{background:var(--bg);border-radius:4px;width:100%;height:8px;position:relative;overflow:hidden}._progressInner_12w7q_66{background:var(--accent);transition:width 80ms;position:absolute;inset:0 auto 0 0}._progressLabel_12w7q_73{color:var(--text-dim);font-size:10px;position:absolute;top:-18px;right:4px}._counts_12w7q_81{color:var(--text-dim);font-size:11px}._tip_12w7q_86{background:var(--bg-elev-2);border:1px solid var(--border-strong);color:var(--text);max-width:260px;box-shadow:var(--shadow);z-index:1000;border-radius:4px;padding:6px 10px;font-size:11px}._root_1x09j_1{flex-direction:column;min-width:0;height:100%;display:flex}._scroll_1x09j_8{flex:auto;padding:4px 0 24px;overflow:hidden auto}._section_1x09j_15{margin:6px 0 4px}._sectionTitle_1x09j_19{text-transform:uppercase;letter-spacing:.06em;color:var(--text-faint);padding:8px 12px 4px;font-size:11px;font-weight:600}._sectionEmpty_1x09j_28{color:var(--text-faint);padding:4px 12px 8px;font-size:12px;font-style:italic}._sectionBody_1x09j_35{padding:0 4px}._shell_wtjyy_1{background:var(--bg);grid-template-columns:320px 1fr;height:100vh;display:grid}._aside_wtjyy_8{background:var(--bg-elev);border-right:1px solid var(--border);flex-direction:column;min-width:0;height:100vh;display:flex;overflow:hidden}._main_wtjyy_18{flex-direction:column;min-width:0;height:100vh;display:flex;overflow:hidden}._splash_wtjyy_26{background:var(--bg);height:100vh;color:var(--text-dim);flex-direction:column;justify-content:center;align-items:center;gap:12px;display:flex}._spinner_wtjyy_37{border:3px solid var(--border-strong);border-top-color:var(--accent);border-radius:50%;width:28px;height:28px;animation:.9s linear infinite _spin_wtjyy_37}._errorTitle_wtjyy_46{color:var(--text);font-weight:600}._errorMsg_wtjyy_51{color:var(--red);text-align:center;max-width:600px}._retry_wtjyy_57{border:1px solid var(--border-strong);background:var(--bg-elev);color:var(--text);border-radius:4px;margin-top:8px;padding:6px 14px}._retry_wtjyy_57:hover{background:var(--bg-elev-2)}@keyframes _spin_wtjyy_37{to{transform:rotate(360deg)}}._stageWrap_1ppm4_1{background-color:#14171e;background-image:linear-gradient(45deg,#1a1d27 25%,#0000 25%),linear-gradient(-45deg,#1a1d27 25%,#0000 25%),linear-gradient(45deg,#0000 75%,#1a1d27 75%),linear-gradient(-45deg,#0000 75%,#1a1d27 75%);background-position:0 0,0 10px,10px -10px,-10px 0;background-repeat:repeat,repeat,repeat,repeat;background-size:20px 20px;background-attachment:scroll,scroll,scroll,scroll;background-origin:padding-box,padding-box,padding-box,padding-box;background-clip:border-box,border-box,border-box,border-box;flex:auto;justify-content:center;align-items:center;min-width:0;min-height:0;display:flex;position:relative;overflow:auto}._canvas_1ppm4_17{min-width:1px;min-height:1px;image-rendering:pixelated;flex:none;margin:auto;position:relative}._canvasInteractive_1ppm4_27{cursor:col-resize}._canvasDragging_1ppm4_31{cursor:col-resize;-webkit-user-select:none;user-select:none}._layer_1ppm4_36{-webkit-user-select:none;user-select:none;pointer-events:none;image-rendering:pixelated;background:0 0;position:absolute;top:0;left:0}._hiddenProbe_1ppm4_46{opacity:0;pointer-events:none;width:1px;height:1px;position:absolute}._diffLayer_1ppm4_54{image-rendering:pixelated;pointer-events:none;position:absolute;top:0;left:0}._sliderLine_1ppm4_62{background:var(--accent);pointer-events:none;width:1px;position:absolute;top:0;bottom:0;box-shadow:0 0 0 1px #0006}._sliderHandle_1ppm4_72{background:var(--accent);border:2px solid var(--bg);width:12px;height:12px;box-shadow:0 0 0 1px var(--accent);border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}._plate_1ppm4_85{border:1px solid var(--border-strong);color:var(--text);z-index:5;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background:#0f1115d9;border-radius:4px;padding:6px 10px;font-size:11.5px;position:absolute;top:12px;left:50%;transform:translate(-50%)}._root_j601s_1{flex-direction:column;min-width:0;height:100%;display:flex}._header_j601s_8{border-bottom:1px solid var(--border);background:var(--bg-elev);flex-shrink:0;align-items:center;gap:8px;padding:8px 14px;display:flex}._spacer_j601s_18{flex:auto}._badges_j601s_22{align-items:center;gap:6px;display:flex}._badge_j601s_22{letter-spacing:.06em;border:1px solid #0000;border-radius:4px;align-items:center;padding:2px 8px;font-size:10.5px;font-weight:700;display:inline-flex}._badgeNew_j601s_39{color:var(--green);background:#5fd27326;border-color:#5fd27366}._badgeChange_j601s_45{color:var(--yellow);background:#e5c45426;border-color:#e5c45466}._badgeStale_j601s_51{color:var(--orange);background:#f08b4a26;border-color:#f08b4a66}._badgeDeleted_j601s_57{color:var(--red);background:#e35d5d26;border-color:#e35d5d66}._badgeDeletedStale_j601s_63{color:var(--red-dim);background:#8b48482e;border-color:#8b484866}._badgeAccepted_j601s_69{color:var(--blue-grey);background:#8aa0c026;border-color:#8aa0c066}._headerBtn_j601s_75{border:1px solid var(--border-strong);background:var(--bg-elev-2);color:var(--text);border-radius:4px;align-items:center;gap:6px;padding:5px 10px;font-size:12px;display:inline-flex}._headerBtn_j601s_75:hover:not(:disabled){background:var(--bg);border-color:var(--accent)}._acceptBtn_j601s_92:not(:disabled){color:var(--green);border-color:#5fd27380}._acceptBtn_j601s_92:not(:disabled):hover{background:#5fd2731a}._tip_j601s_101{background:var(--bg-elev-2);border:1px solid var(--border-strong);color:var(--text);max-width:280px;box-shadow:var(--shadow);z-index:1000;border-radius:4px;padding:6px 10px;font-size:11px}._spin_j601s_113{animation:.9s linear infinite _spin_j601s_113}@keyframes _spin_j601s_113{to{transform:rotate(360deg)}}._notFound_15r13_1{height:100%;color:var(--text-dim);justify-content:center;align-items:center;display:flex}._empty_19hhh_1{height:100%;color:var(--text-dim);justify-content:center;align-items:center;font-size:14px;display:flex}:root{--bg:#0f1115;--bg-elev:#161922;--bg-elev-2:#1d2230;--border:#262b38;--border-strong:#353c4f;--text:#e6e8ee;--text-dim:#9099b0;--text-faint:#5f6679;--accent:#6ea8ff;--accent-hover:#8ab8ff;--green:#5fd273;--yellow:#e5c454;--orange:#f08b4a;--red:#e35d5d;--red-dim:#8b4848;--blue-grey:#8aa0c0;--purple:#a855f7;--shadow:0 4px 16px #00000059;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*,:before,:after{box-sizing:border-box}html,body,#root{background:var(--bg);height:100%;color:var(--text);margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:13px;line-height:1.4}button{font:inherit;color:inherit;cursor:pointer;background:0 0;border:0;padding:0}button:disabled{cursor:not-allowed;opacity:.5}a{color:var(--accent)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:#4a5266}
|
|
1
|
+
._viewport_1obvw_1{z-index:1000;outline:none;flex-direction:column;gap:8px;width:360px;max-width:calc(100vw - 32px);margin:0;padding:0;list-style:none;display:flex;position:fixed;bottom:16px;right:16px}._toast_1obvw_17{background:var(--bg-elev-2);border:1px solid var(--border-strong);border-left:3px solid var(--accent);box-shadow:var(--shadow);border-radius:6px;padding:10px 14px}._toast_1obvw_17[data-state=open]{animation:.16s ease-out _slideIn_1obvw_1}._toast_1obvw_17[data-state=closed]{animation:.12s ease-in forwards _fadeOut_1obvw_1}._toast_1obvw_17._error_1obvw_32{border-left-color:var(--red)}._toast_1obvw_17._success_1obvw_36{border-left-color:var(--green)}._toast_1obvw_17._info_1obvw_40{border-left-color:var(--accent)}._title_1obvw_44{margin:0 0 2px;font-size:13px;font-weight:600}._desc_1obvw_50{color:var(--text-dim);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:12px}@keyframes _slideIn_1obvw_1{0%{opacity:0;transform:translate(8px)}to{opacity:1;transform:translate(0)}}@keyframes _fadeOut_1obvw_1{0%{opacity:1}to{opacity:0}}._tree_4auq3_1{margin:0;padding:0;list-style:none}._groupLi_4auq3_7,._leafLi_4auq3_8{list-style:none}._group_4auq3_7,._leaf_4auq3_8{width:100%;color:var(--text);text-align:left;border-radius:4px;align-items:center;gap:6px;min-width:0;padding:4px 8px 4px 6px;font-size:12.5px;display:flex}._group_4auq3_7:hover,._leaf_4auq3_8:hover{background:var(--bg-elev-2)}._chevron_4auq3_31{color:var(--text-faint);flex:none;transition:transform .12s}._chevronOpen_4auq3_37{transform:rotate(90deg)}._groupName_4auq3_41,._leafName_4auq3_42{white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}._groupName_4auq3_41{color:var(--text-dim);font-weight:500}._staleBadge_4auq3_55{background:var(--orange);color:#1a1408;border-radius:8px;flex:none;padding:1px 6px;font-size:10px;font-weight:700;line-height:1.4}._leaf_4auq3_8{cursor:pointer}._leafSelected_4auq3_70{background:#6ea8ff29}._leafSelected_4auq3_70:hover{background:#6ea8ff38}._icon_4auq3_78{flex:none}._acceptInline_4auq3_82{opacity:0;width:18px;height:18px;color:var(--text-dim);border-radius:3px;flex:none;justify-content:center;align-items:center;display:inline-flex}._leaf_4auq3_8:hover ._acceptInline_4auq3_82{opacity:1}._acceptInline_4auq3_82:hover{background:var(--bg);color:var(--green)}._toneGreen_4auq3_103{color:var(--green)}._toneYellow_4auq3_107{color:var(--yellow)}._toneOrange_4auq3_111{color:var(--orange)}._toneRed_4auq3_115{color:var(--red)}._toneRedDim_4auq3_119{color:var(--red-dim)}._toneBlueGrey_4auq3_123{color:var(--blue-grey)}._toneAccent_4auq3_127{color:var(--accent)}._spin_4auq3_131{animation:.9s linear infinite _spin_4auq3_131}@keyframes _spin_4auq3_131{to{transform:rotate(360deg)}}._root_12w7q_1{border-bottom:1px solid var(--border);background:var(--bg-elev);flex-direction:column;gap:8px;padding:10px 12px;display:flex}._row_12w7q_10{align-items:center;gap:6px;display:flex}._action_12w7q_16{border:1px solid var(--border-strong);background:var(--bg-elev-2);color:var(--text);border-radius:4px;align-items:center;gap:6px;padding:5px 10px;font-size:12px;display:inline-flex}._action_12w7q_16:hover:not(:disabled){background:var(--bg);border-color:var(--accent)}._actionCount_12w7q_33{background:var(--border-strong);color:var(--text-dim);border-radius:8px;padding:1px 6px;font-size:10px}._stop_12w7q_41{border:1px solid var(--red-dim);color:var(--red);background:0 0;border-radius:4px;align-items:center;gap:6px;padding:5px 10px;font-size:12px;display:inline-flex}._stop_12w7q_41:hover{background:#e35d5d1a}._progressOuter_12w7q_57{background:var(--bg);border-radius:4px;width:100%;height:8px;position:relative;overflow:hidden}._progressInner_12w7q_66{background:var(--accent);transition:width 80ms;position:absolute;inset:0 auto 0 0}._progressLabel_12w7q_73{color:var(--text-dim);font-size:10px;position:absolute;top:-18px;right:4px}._counts_12w7q_81{color:var(--text-dim);font-size:11px}._tip_12w7q_86{background:var(--bg-elev-2);border:1px solid var(--border-strong);color:var(--text);max-width:260px;box-shadow:var(--shadow);z-index:1000;border-radius:4px;padding:6px 10px;font-size:11px}._root_1d1kr_1{flex-direction:column;min-width:0;height:100%;display:flex}._projectHeader_1d1kr_8{border-bottom:1px solid var(--border);flex-direction:column;gap:2px;min-width:0;padding:8px 12px 6px;display:flex}._projectName_1d1kr_17{color:var(--text);white-space:nowrap;text-overflow:ellipsis;font-size:12.5px;font-weight:600;overflow:hidden}._projectBranch_1d1kr_26{color:var(--text-dim);white-space:nowrap;text-overflow:ellipsis;align-items:center;gap:4px;font-size:11px;display:inline-flex;overflow:hidden}._scroll_1d1kr_37{flex:auto;padding:4px 0 24px;overflow:hidden auto}._section_1d1kr_44{margin:6px 0 4px}._sectionTitle_1d1kr_48{text-transform:uppercase;letter-spacing:.06em;color:var(--text-faint);padding:8px 12px 4px;font-size:11px;font-weight:600}._sectionEmpty_1d1kr_57{color:var(--text-faint);padding:4px 12px 8px;font-size:12px;font-style:italic}._sectionBody_1d1kr_64{padding:0 4px}._versionFooter_1d1kr_68{border-top:1px solid var(--border);color:var(--text-faint);font-variant-numeric:tabular-nums;text-align:right;letter-spacing:.02em;flex:none;padding:6px 12px 8px;font-size:10.5px}._shell_wtjyy_1{background:var(--bg);grid-template-columns:320px 1fr;height:100vh;display:grid}._aside_wtjyy_8{background:var(--bg-elev);border-right:1px solid var(--border);flex-direction:column;min-width:0;height:100vh;display:flex;overflow:hidden}._main_wtjyy_18{flex-direction:column;min-width:0;height:100vh;display:flex;overflow:hidden}._splash_wtjyy_26{background:var(--bg);height:100vh;color:var(--text-dim);flex-direction:column;justify-content:center;align-items:center;gap:12px;display:flex}._spinner_wtjyy_37{border:3px solid var(--border-strong);border-top-color:var(--accent);border-radius:50%;width:28px;height:28px;animation:.9s linear infinite _spin_wtjyy_37}._errorTitle_wtjyy_46{color:var(--text);font-weight:600}._errorMsg_wtjyy_51{color:var(--red);text-align:center;max-width:600px}._retry_wtjyy_57{border:1px solid var(--border-strong);background:var(--bg-elev);color:var(--text);border-radius:4px;margin-top:8px;padding:6px 14px}._retry_wtjyy_57:hover{background:var(--bg-elev-2)}@keyframes _spin_wtjyy_37{to{transform:rotate(360deg)}}._stageWrap_byixq_2{background-color:#14171e;background-image:linear-gradient(45deg,#1a1d27 25%,#0000 25%),linear-gradient(-45deg,#1a1d27 25%,#0000 25%),linear-gradient(45deg,#0000 75%,#1a1d27 75%),linear-gradient(-45deg,#0000 75%,#1a1d27 75%);background-position:0 0,0 10px,10px -10px,-10px 0;background-repeat:repeat,repeat,repeat,repeat;background-size:20px 20px;background-attachment:scroll,scroll,scroll,scroll;background-origin:padding-box,padding-box,padding-box,padding-box;background-clip:border-box,border-box,border-box,border-box;flex:auto;justify-content:safe center;align-items:safe center;min-width:0;min-height:0;display:flex;position:relative;overflow:auto}._canvas_byixq_21{min-width:1px;min-height:1px;image-rendering:pixelated;flex:none;position:relative}._canvasInteractive_byixq_30{cursor:col-resize}._canvasDragging_byixq_34{cursor:col-resize;-webkit-user-select:none;user-select:none}._layer_byixq_39{-webkit-user-select:none;user-select:none;pointer-events:none;image-rendering:pixelated;background:0 0;position:absolute;top:0;left:0}._hiddenProbe_byixq_49{opacity:0;pointer-events:none;width:1px;height:1px;position:absolute}._diffLayer_byixq_57{image-rendering:pixelated;pointer-events:none;position:absolute;top:0;left:0}._sliderLine_byixq_65{background:var(--accent);pointer-events:none;width:1px;position:absolute;top:0;bottom:0;box-shadow:0 0 0 1px #0006}._sliderHandle_byixq_75{background:var(--accent);border:2px solid var(--bg);width:12px;height:12px;box-shadow:0 0 0 1px var(--accent);border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}._plate_byixq_88{border:1px solid var(--border-strong);color:var(--text);z-index:5;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background:#0f1115d9;border-radius:4px;padding:6px 10px;font-size:11.5px;position:absolute;top:12px;left:50%;transform:translate(-50%)}._root_j601s_1{flex-direction:column;min-width:0;height:100%;display:flex}._header_j601s_8{border-bottom:1px solid var(--border);background:var(--bg-elev);flex-shrink:0;align-items:center;gap:8px;padding:8px 14px;display:flex}._spacer_j601s_18{flex:auto}._badges_j601s_22{align-items:center;gap:6px;display:flex}._badge_j601s_22{letter-spacing:.06em;border:1px solid #0000;border-radius:4px;align-items:center;padding:2px 8px;font-size:10.5px;font-weight:700;display:inline-flex}._badgeNew_j601s_39{color:var(--green);background:#5fd27326;border-color:#5fd27366}._badgeChange_j601s_45{color:var(--yellow);background:#e5c45426;border-color:#e5c45466}._badgeStale_j601s_51{color:var(--orange);background:#f08b4a26;border-color:#f08b4a66}._badgeDeleted_j601s_57{color:var(--red);background:#e35d5d26;border-color:#e35d5d66}._badgeDeletedStale_j601s_63{color:var(--red-dim);background:#8b48482e;border-color:#8b484866}._badgeAccepted_j601s_69{color:var(--blue-grey);background:#8aa0c026;border-color:#8aa0c066}._headerBtn_j601s_75{border:1px solid var(--border-strong);background:var(--bg-elev-2);color:var(--text);border-radius:4px;align-items:center;gap:6px;padding:5px 10px;font-size:12px;display:inline-flex}._headerBtn_j601s_75:hover:not(:disabled){background:var(--bg);border-color:var(--accent)}._acceptBtn_j601s_92:not(:disabled){color:var(--green);border-color:#5fd27380}._acceptBtn_j601s_92:not(:disabled):hover{background:#5fd2731a}._tip_j601s_101{background:var(--bg-elev-2);border:1px solid var(--border-strong);color:var(--text);max-width:280px;box-shadow:var(--shadow);z-index:1000;border-radius:4px;padding:6px 10px;font-size:11px}._spin_j601s_113{animation:.9s linear infinite _spin_j601s_113}@keyframes _spin_j601s_113{to{transform:rotate(360deg)}}._notFound_15r13_1{height:100%;color:var(--text-dim);justify-content:center;align-items:center;display:flex}._empty_19hhh_1{height:100%;color:var(--text-dim);justify-content:center;align-items:center;font-size:14px;display:flex}:root{--bg:#0f1115;--bg-elev:#161922;--bg-elev-2:#1d2230;--border:#262b38;--border-strong:#353c4f;--text:#e6e8ee;--text-dim:#9099b0;--text-faint:#5f6679;--accent:#6ea8ff;--accent-hover:#8ab8ff;--green:#5fd273;--yellow:#e5c454;--orange:#f08b4a;--red:#e35d5d;--red-dim:#8b4848;--blue-grey:#8aa0c0;--purple:#a855f7;--shadow:0 4px 16px #00000059;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*,:before,:after{box-sizing:border-box}html,body,#root{background:var(--bg);height:100%;color:var(--text);margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:13px;line-height:1.4}button{font:inherit;color:inherit;cursor:pointer;background:0 0;border:0;padding:0}button:disabled{cursor:not-allowed;opacity:.5}a{color:var(--accent)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:#4a5266}
|