From d9d2e4dd59add6d2ddd7466401db616880d827d9 Mon Sep 17 00:00:00 2001 From: Louis Date: Tue, 28 Jul 2026 14:47:39 +0200 Subject: [PATCH] fix: detect NetBox theme for topology cable highlights --- .../css/rack_elevation.css | 10 ++-------- netbox_topology_views/static_dev/css/app.scss | 3 +-- .../netbox_topology_views/rack_elevation.html | 20 ++++++++++++++++--- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/netbox_topology_views/static/netbox_topology_views/css/rack_elevation.css b/netbox_topology_views/static/netbox_topology_views/css/rack_elevation.css index cd81c24..78885d8 100644 --- a/netbox_topology_views/static/netbox_topology_views/css/rack_elevation.css +++ b/netbox_topology_views/static/netbox_topology_views/css/rack_elevation.css @@ -100,18 +100,12 @@ html[data-netbox-color-mode="dark"] .rack-device { transition: opacity .12s, stroke .12s, filter .12s, stroke-width .12s; } .rack-topology-edge.is-highlighted { - stroke: #22c55e !important; + stroke: var(--topology-highlight-color, #22c55e) !important; stroke-width: 5; opacity: 1; - filter: drop-shadow(0 0 5px #22c55e); + filter: drop-shadow(0 0 5px var(--topology-highlight-color, #22c55e)); } .rack-topology-edge.is-dimmed { opacity: .12; } -html[data-bs-theme="dark"] .rack-topology-edge.is-highlighted, -body[data-bs-theme="dark"] .rack-topology-edge.is-highlighted, -html[data-netbox-color-mode="dark"] .rack-topology-edge.is-highlighted { - stroke: #fff !important; - filter: drop-shadow(0 0 5px #fff); -} .rack-topology-edge.is-wireless { stroke-dasharray: 7 7; stroke-linecap: round; diff --git a/netbox_topology_views/static_dev/css/app.scss b/netbox_topology_views/static_dev/css/app.scss index 16fe810..04356d2 100644 --- a/netbox_topology_views/static_dev/css/app.scss +++ b/netbox_topology_views/static_dev/css/app.scss @@ -62,7 +62,7 @@ html[data-netbox-color-mode=dark] #visgraph { .rack-topology-node strong, .rack-topology-node small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .rack-topology-node small { opacity: .7; } .rack-topology-edge { fill: none; stroke-width: 3; opacity: .8; pointer-events: stroke; cursor: pointer; transition: opacity .12s, stroke .12s, filter .12s, stroke-width .12s; } -.rack-topology-edge.is-highlighted { stroke: #22c55e !important; stroke-width: 5; opacity: 1; filter: drop-shadow(0 0 5px #22c55e); } +.rack-topology-edge.is-highlighted { stroke: var(--topology-highlight-color, #22c55e) !important; stroke-width: 5; opacity: 1; filter: drop-shadow(0 0 5px var(--topology-highlight-color, #22c55e)); } .rack-topology-edge.is-dimmed { opacity: .12; } .rack-topology-tooltip { display: none; position: absolute; z-index: 10; width: max-content; max-width: 28rem; padding: .65rem .8rem; border: 1px solid var(--tblr-border-color, #ced4da); border-radius: .35rem; background: var(--tblr-bg-surface, #fff); box-shadow: 0 4px 18px rgba(0,0,0,.25); pointer-events: none; } .rack-topology-tooltip.is-visible { display: block; } @@ -85,7 +85,6 @@ html[data-netbox-color-mode=dark] #visgraph { html[data-bs-theme="dark"], body[data-bs-theme="dark"], html[data-netbox-color-mode="dark"] { .rack-frame { border-color: #3b4654; background-color: #212b36; } .rack-device { background: #162e45; color: #fff; } - .rack-topology-edge.is-highlighted { stroke: #fff !important; filter: drop-shadow(0 0 5px #fff); } } @media (max-width: 700px) { diff --git a/netbox_topology_views/templates/netbox_topology_views/rack_elevation.html b/netbox_topology_views/templates/netbox_topology_views/rack_elevation.html index 6f460b3..69d578b 100644 --- a/netbox_topology_views/templates/netbox_topology_views/rack_elevation.html +++ b/netbox_topology_views/templates/netbox_topology_views/rack_elevation.html @@ -160,6 +160,22 @@ const zoomResetButton = document.getElementById('rack-topology-zoom-reset'); const zoomLabel = document.getElementById('rack-topology-zoom-label'); let topologyZoom = 1; + const activeNetBoxTheme = () => document.body.dataset.bsTheme || + document.documentElement.dataset.bsTheme || + document.documentElement.dataset.netboxColorMode || 'light'; + const applyTopologyTheme = () => { + root.style.setProperty( + '--topology-highlight-color', + activeNetBoxTheme() === 'dark' ? '#ffffff' : '#22c55e' + ); + }; + applyTopologyTheme(); + const topologyThemeObserver = new MutationObserver(applyTopologyTheme); + topologyThemeObserver.observe(document.body, {attributes: true, attributeFilter: ['data-bs-theme']}); + topologyThemeObserver.observe(document.documentElement, { + attributes: true, + attributeFilter: ['data-bs-theme', 'data-netbox-color-mode'], + }); const storageKey = `netbox-rack-topology-v2:${window.location.pathname}${window.location.search}`; let storedPositions = {}; try { storedPositions = JSON.parse(localStorage.getItem(storageKey) || '{}'); } catch (_) {} @@ -354,9 +370,7 @@ })[char]); const safeName = value => String(value || 'export').replace(/[^a-z0-9._-]+/gi, '-').replace(/^-|-$/g, ''); const exportPalette = () => { - const declaredTheme = document.body.dataset.bsTheme || - document.documentElement.dataset.bsTheme || - document.documentElement.dataset.netboxColorMode || ''; + const declaredTheme = activeNetBoxTheme(); const dark = declaredTheme === 'dark' || (!declaredTheme && window.matchMedia('(prefers-color-scheme: dark)').matches); return dark ? { frame: '#52606d', grid: '#667382', heading: '#8fc8ff', muted: '#a9b7c6',