Switch topology canvas and left chrome to a dark theme.

Align the default canvas background, region list, and canvas name styles with the dark ops shell, and migrate the old light canvas default.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-08-05 00:16:20 +08:00
parent 2de8786f85
commit 2a650ca09b
2 changed files with 90 additions and 58 deletions

View file

@ -4186,7 +4186,7 @@ pre {
}
}
/* ---- Topology — light sidebar + canvas (shared chrome tokens) ---- */
/* ---- Topology — dark sidebar + canvas (shared chrome tokens) ---- */
.topo-page {
display: grid;
grid-template-columns: 260px 1fr;
@ -5050,8 +5050,8 @@ pre {
gap: 8px;
min-height: 168px;
border-style: dashed;
border-color: #b7c4d4;
background: rgba(255, 255, 255, 0.55);
border-color: rgba(148, 163, 184, 0.35);
background: rgba(15, 23, 42, 0.45);
color: var(--nm-accent);
font-size: 13px;
font-weight: 600;
@ -5059,10 +5059,10 @@ pre {
box-shadow: none;
}
.topo-map-card--add:hover {
background: #fff;
background: rgba(37, 99, 235, 0.14);
border-color: var(--nm-accent);
color: var(--nm-brand);
box-shadow: 0 2px 8px rgba(15, 39, 68, 0.06);
color: #93c5fd;
box-shadow: none;
}
.topo-map-card__add-plus {
width: 36px;
@ -5090,14 +5090,14 @@ pre {
font-weight: 550;
letter-spacing: -0.01em;
line-height: 1.3;
color: var(--nm-brand, #0f1b2d);
color: var(--nm-brand, #f1f5f9);
}
.app-main .topo-breadcrumb__link,
.topo-breadcrumb__link {
border: 0 !important;
background: transparent !important;
box-shadow: none !important;
color: #5b6b7c !important;
color: #94a3b8 !important;
cursor: pointer;
padding: 0 !important;
margin: 0;
@ -5475,20 +5475,20 @@ pre {
.topo-region-list .topo-map-list__row:hover,
.topo-region-list__block.is-hot > .topo-region-list__row,
.topo-region-list__maps > li.is-hot > .topo-map-list__row {
background: rgba(255, 255, 255, 0.78);
background: var(--nm-nav-hover, #152033);
}
/* Selected = deep wash + left accent */
.topo-region-list__block.is-active > .topo-region-list__row,
.topo-region-list__maps > li.is-active > .topo-map-list__row {
border: 0;
background: #8eb6e3;
box-shadow: inset 3px 0 0 #0f3f7a;
background: var(--nm-nav-active, #1a2740);
box-shadow: inset 3px 0 0 var(--nm-accent, #3b82f6);
}
.topo-region-list__block.is-branch-active > .topo-region-list__row {
border: 0;
background: rgba(142, 182, 227, 0.35);
background: rgba(37, 99, 235, 0.16);
box-shadow: none;
}
@ -5505,14 +5505,14 @@ pre {
height: 22px;
margin-right: 2px;
border-radius: 6px;
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
background: rgba(45, 212, 191, 0.12);
color: #5eead4;
flex: 0 0 auto;
}
.topo-region-list__maps .topo-region-list__glyph {
background: rgba(26, 86, 168, 0.1);
color: #1a56a8;
background: rgba(59, 130, 246, 0.18);
color: #93c5fd;
}
.topo-region-list__maps {
@ -5595,7 +5595,7 @@ pre {
.app-main .topo-region-list .topo-map-list__icon:hover:not(:disabled),
.topo-region-list .topo-map-list__icon:hover:not(:disabled) {
background: rgba(15, 27, 45, 0.08) !important;
background: rgba(148, 163, 184, 0.16) !important;
color: var(--nm-brand);
}
@ -5615,7 +5615,7 @@ pre {
white-space: nowrap;
font-size: 13px;
font-weight: 650;
color: var(--nm-brand, #0f1b2d);
color: var(--nm-brand, #f1f5f9);
}
.topo-region-list__maps .topo-map-list__title {
@ -5645,7 +5645,7 @@ pre {
.topo-region-list__block.is-active .topo-map-list__count,
.topo-region-list__maps > li.is-active .topo-map-list__count {
background: transparent;
color: #0f1b2d;
color: #cbd5e1;
}
.topo-region-list__block.is-hot:not(.is-active) .topo-map-list__count,
@ -5656,13 +5656,13 @@ pre {
.topo-region-list__block.is-active .topo-map-list__title,
.topo-region-list__maps > li.is-active .topo-map-list__title {
color: #0a274f;
color: #f1f5f9;
font-weight: 700;
}
.topo-region-list__maps > li.is-active .topo-region-list__glyph {
background: #0f3f7a;
color: #fff;
background: rgba(37, 99, 235, 0.35);
color: #dbeafe;
}
.topo-map-list li,
@ -5699,24 +5699,24 @@ pre {
.topo-region-list__block.is-active > .topo-map-list__row,
.topo-region-list__maps > li.is-active > .topo-map-list__row {
border: 0 !important;
background: #8eb6e3 !important;
box-shadow: inset 3px 0 0 #0f3f7a !important;
background: var(--nm-nav-active, #1a2740) !important;
box-shadow: inset 3px 0 0 var(--nm-accent, #3b82f6) !important;
}
.topo-region-list__block.is-active > .topo-map-list__row:hover,
.topo-region-list__maps > li.is-active > .topo-map-list__row:hover {
background: #7aa8db !important;
background: #243552 !important;
}
.topo-region-list__block.is-branch-active > .topo-map-list__row {
border: 0 !important;
background: rgba(142, 182, 227, 0.35) !important;
background: rgba(37, 99, 235, 0.16) !important;
box-shadow: none !important;
}
.topo-region-list__block.is-hot:not(.is-active):not(.is-branch-active) > .topo-map-list__row,
.topo-region-list__maps > li.is-hot:not(.is-active) > .topo-map-list__row {
background: #c5daf3 !important;
background: rgba(59, 130, 246, 0.14) !important;
}
.topo-palette > li.is-on-canvas .topo-palette__row {
@ -5772,18 +5772,18 @@ pre {
}
.topo-map-list li.is-active .topo-map-list__item:hover {
background: #c9daf0;
background: rgba(37, 99, 235, 0.12);
}
.topo-map-list__actions {
display: flex;
align-items: stretch;
flex: 0 0 auto;
border-left: 1px solid #cdd6e2;
border-left: 1px solid rgba(148, 163, 184, 0.22);
}
.topo-map-list li.is-active .topo-map-list__actions {
border-left-color: #93b4e0;
border-left-color: rgba(59, 130, 246, 0.35);
}
.topo-map-list__icon {
@ -6134,9 +6134,9 @@ pre {
}
.topo-toolbar__display[open] > summary {
border-color: #1a56a8;
background: #d6e4f5;
color: #1a56a8;
border-color: rgba(59, 130, 246, 0.55);
background: rgba(37, 99, 235, 0.22);
color: #93c5fd;
}
.topo-toolbar__display .topo-display-toggles {
@ -6148,10 +6148,11 @@ pre {
gap: 6px;
min-width: 260px;
padding: 8px 10px;
border: 1px solid #c0cad6;
border: 1px solid rgba(148, 163, 184, 0.28);
border-radius: 8px;
background: #fff;
box-shadow: 0 8px 20px rgba(15, 39, 68, 0.14);
background: #0f172a;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
color: #e2e8f0;
}
.topo-mode-hint {
@ -6865,20 +6866,45 @@ pre {
position: relative;
flex: 1;
min-height: 0;
background: var(--topo-canvas-bg, #dbeafe);
background: var(--topo-canvas-bg, #0f172a);
}
.topo-canvas:fullscreen,
.topo-canvas.is-fullscreen:fullscreen {
width: 100vw;
height: 100vh;
background: var(--topo-canvas-bg, #dbeafe);
background: var(--topo-canvas-bg, #0f172a);
}
/* Place fullscreen above zoom-in (+); Controls renders custom children last. */
.topo-canvas .react-flow__controls {
display: flex;
flex-direction: column;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
border: 1px solid rgba(148, 163, 184, 0.28);
border-radius: 6px;
overflow: hidden;
}
.topo-canvas .react-flow__controls-button {
background: #0f172a;
border-bottom-color: rgba(148, 163, 184, 0.22);
fill: #cbd5e1;
}
.topo-canvas .react-flow__controls-button:hover {
background: #1e293b;
}
.topo-canvas .react-flow__controls-button svg {
fill: #cbd5e1;
}
.topo-canvas .react-flow__minimap {
background: #0b1220;
border: 1px solid rgba(148, 163, 184, 0.28);
border-radius: 6px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
}
.topo-canvas .react-flow__controls-button.topo-fs-control {
@ -6900,9 +6926,9 @@ pre {
gap: 6px;
padding: 8px;
border-radius: 10px;
background: rgba(255, 255, 255, 0.92);
border: 1px solid rgba(15, 23, 42, 0.12);
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
background: rgba(15, 23, 42, 0.92);
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
pointer-events: auto;
}
@ -6912,21 +6938,21 @@ pre {
gap: 6px;
padding: 6px 10px;
border-radius: 8px;
border: 1px solid rgba(15, 23, 42, 0.12);
background: #fff;
color: #0f172a;
border: 1px solid rgba(148, 163, 184, 0.28);
background: #0b1220;
color: #e2e8f0;
font-size: 12px;
cursor: pointer;
}
.topo-fs-toolbar__btn:hover {
background: #f8fafc;
background: #152033;
}
.topo-fs-toolbar__btn.is-active {
border-color: #0ea5e9;
background: #e0f2fe;
color: #075985;
border-color: #3b82f6;
background: rgba(37, 99, 235, 0.28);
color: #93c5fd;
}
.topo-fs-toolbar__btn kbd {
@ -7149,27 +7175,27 @@ pre {
}
.react-flow__edge-textbg {
fill: #ffffff;
fill: #0f172a;
}
.react-flow__edge-text {
fill: #475569;
fill: #cbd5e1;
font-size: 11px;
}
.topo-edge-label {
font-size: 11px;
color: #475569;
background: rgba(255, 255, 255, 0.92);
border: 1px solid #e2e8f0;
color: #cbd5e1;
background: rgba(15, 23, 42, 0.92);
border: 1px solid rgba(148, 163, 184, 0.28);
border-radius: 4px;
padding: 1px 6px;
white-space: nowrap;
}
.topo-edge-label.is-selected {
color: #1d4ed8;
border-color: #93c5fd;
color: #93c5fd;
border-color: rgba(59, 130, 246, 0.55);
font-weight: 600;
}

View file

@ -452,12 +452,18 @@ const DISCOVER_AUTO_ADD_KEY = "netx.topology.discoverAutoAddUnmatched";
const DISCOVER_PROJECT_NEIGHBORS_KEY = "netx.topology.discoverProjectNeighbors";
const SCALE_BUNDLE_WIDTH_KEY = "netx.topology.scaleBundleWidth";
const CANVAS_BG_KEY = "netx.topology.canvasBg";
const DEFAULT_CANVAS_BG = "#dbeafe";
const DEFAULT_CANVAS_BG = "#0f172a";
/** Previous light default — migrate so existing sessions pick up dark canvas. */
const LEGACY_CANVAS_BG = "#dbeafe";
function loadCanvasBg(): string {
try {
const raw = String(localStorage.getItem(CANVAS_BG_KEY) || "").trim();
if (/^#[0-9a-fA-F]{6}$/.test(raw)) return raw.toLowerCase();
const raw = String(localStorage.getItem(CANVAS_BG_KEY) || "").trim().toLowerCase();
if (raw === LEGACY_CANVAS_BG) {
persistCanvasBg(DEFAULT_CANVAS_BG);
return DEFAULT_CANVAS_BG;
}
if (/^#[0-9a-fA-F]{6}$/i.test(raw)) return raw;
} catch {
/* ignore */
}