@@ -230,55 +230,62 @@ def _find_list_key(data: dict) -> Optional[str]:
230230# ── JSON Tree Viewer ──────────────────────────────────────────────────────────
231231_TREE_CSS = (
232232 "@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap');"
233- "html{margin:0;padding:0;background:#050810;height:100%;overflow:hidden;}"
234- "body{margin:0;padding:0;background:#050810;height:100%;overflow:auto;}"
233+ ":root{"
234+ "--t-bg:#050810;--t-text:#94a3b8;--t-text-hi:#e2e8f0;--t-muted:#475569;"
235+ "--t-border:rgba(255,255,255,.07);--t-accent:#00d4ff;"
236+ "--t-key:#60a5fa;--t-str:#86efac;--t-num:#fbbf24;--t-bool:#c084fc;--t-null:#94a3b8;"
237+ "--t-punc:#64748b;--t-btn-bg:rgba(0,212,255,.07);--t-btn-border:rgba(0,212,255,.2);"
238+ "--t-input-bg:rgba(255,255,255,.06);--t-input-border:rgba(255,255,255,.12);"
239+ "--t-scroll:rgba(255,255,255,.12);--t-tip-bg:#1e293b;--t-mark:#7c3aed;--t-mark-cur:#f59e0b;"
240+ "}"
241+ "html{margin:0;padding:0;background:var(--t-bg);height:100%;overflow:hidden;}"
242+ "body{margin:0;padding:0;background:var(--t-bg);height:100%;overflow:auto;}"
235243 "body{font-family:'JetBrains Mono','Fira Code',ui-monospace,monospace;"
236- "font-size:12px;line-height:1.7;color:#94a3b8 ;}"
237- "#toolbar{position:sticky;top:0;background:#050810 ;border-bottom:1px solid rgba(255,255,255,.07 );"
244+ "font-size:12px;line-height:1.7;color:var(--t-text) ;}"
245+ "#toolbar{position:sticky;top:0;background:var(--t-bg) ;border-bottom:1px solid var(--t-border );"
238246 "padding:5px 14px;display:flex;align-items:center;gap:6px;z-index:10;}"
239- "#depth-label{color:#475569 ;font-size:11px;font-style:italic;flex:1;}"
240- ".depth-btn{background:rgba(0,212,255,.07 );border:1px solid rgba(0,212,255,.2 );color:#00d4ff ;"
247+ "#depth-label{color:var(--t-muted) ;font-size:11px;font-style:italic;flex:1;}"
248+ ".depth-btn{background:var(--t-btn-bg );border:1px solid var(--t-btn-border );color:var(--t-accent) ;"
241249 "border-radius:4px;width:22px;height:22px;font-size:15px;line-height:1;cursor:pointer;"
242250 "display:inline-flex;align-items:center;justify-content:center;padding:0;flex-shrink:0;}"
243- ".depth-btn:hover{background:rgba(0,212,255,.18);border-color:rgba(0,212,255,.45) ;}"
251+ ".depth-btn:hover{opacity:.85 ;}"
244252 ".depth-btn:disabled{opacity:.3;cursor:default;}"
245253 "#root{padding:10px 14px;}"
246254 ".tree-node{display:block;}"
247255 ".node-header{display:block;}"
248256 ".toggle{display:inline-block;width:14px;text-align:center;cursor:pointer;"
249- "user-select:none;color:#475569 ;transition:color .1s;}"
250- ".toggle:hover{color:#00d4ff ;}"
251- ".preview{color:#475569 ;font-style:italic;}"
257+ "user-select:none;color:var(--t-muted) ;transition:color .1s;}"
258+ ".toggle:hover{color:var(--t-accent) ;}"
259+ ".preview{color:var(--t-muted) ;font-style:italic;}"
252260 ".tree-node:not(.collapsed)>.node-header>.preview{display:none;}"
253261 ".children{margin-left:20px;display:block;}"
254262 ".close-line{display:block;}"
255263 ".tree-node.collapsed>.children,.tree-node.collapsed>.close-line{display:none;}"
256264 ".kv,.item{display:block;}"
257- ".jk{color:#60a5fa }.jv{color:#86efac }.jn{color:#fbbf24 }"
258- ".jb{color:#c084fc }.jbn{color:#94a3b8 }.jp{color:#64748b }"
265+ ".jk{color:var(--t-key) }.jv{color:var(--t-str) }.jn{color:var(--t-num) }"
266+ ".jb{color:var(--t-bool) }.jbn{color:var(--t-null) }.jp{color:var(--t-punc) }"
259267 ".id-link{cursor:pointer;border-bottom:1px dashed currentColor;}"
260- ".id-link:hover{color:#00d4ff!important;border-bottom-color:#00d4ff;"
261- "text-shadow:0 0 6px rgba(0,212,255,.5);}"
262- ".jts{position:relative;cursor:default;border-bottom:1px dotted #fbbf24;}"
268+ ".id-link:hover{color:var(--t-accent)!important;border-bottom-color:var(--t-accent);}"
269+ ".jts{position:relative;cursor:default;border-bottom:1px dotted var(--t-num);}"
263270 ".jts:hover .ts-tip{visibility:visible;opacity:1;}"
264271 ".ts-tip{visibility:hidden;opacity:0;position:absolute;bottom:calc(100% + 4px);left:50%;"
265- "transform:translateX(-50%);background:#1e293b ;color:#e2e8f0 ;font-size:11px;"
272+ "transform:translateX(-50%);background:var(--t-tip-bg) ;color:var(--t-text-hi) ;font-size:11px;"
266273 "padding:3px 8px;border-radius:4px;white-space:nowrap;pointer-events:none;"
267- "border:1px solid rgba(0,212,255,.25 );z-index:100;"
274+ "border:1px solid var(--t-btn-border );z-index:100;"
268275 "transition:opacity .15s;}"
269276 "::-webkit-scrollbar{width:6px;height:6px}"
270- "::-webkit-scrollbar-thumb{background:rgba(255,255,255,.12 );border-radius:3px}"
277+ "::-webkit-scrollbar-thumb{background:var(--t-scroll );border-radius:3px}"
271278 "::-webkit-scrollbar-track{background:transparent}"
272- "*{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.12 ) transparent}"
273- "#search-box{flex:1;background:rgba(255,255,255,.06 );border:1px solid rgba(255,255,255,.12 );"
274- "color:#e2e8f0 ;border-radius:4px;padding:2px 8px;font-family:inherit;font-size:11px;"
279+ "*{scrollbar-width:thin;scrollbar-color:var(--t-scroll ) transparent}"
280+ "#search-box{flex:1;background:var(--t-input-bg );border:1px solid var(--t-input-border );"
281+ "color:var(--t-text-hi) ;border-radius:4px;padding:2px 8px;font-family:inherit;font-size:11px;"
275282 "outline:none;min-width:80px;}"
276- "#search-box:focus{border-color:rgba(0,212,255,.4);background:rgba(0,212,255,.05 );}"
277- "#search-box::placeholder{color:#475569 ;}"
278- "#sc{color:#94a3b8 ;font-size:11px;white-space:nowrap;flex-shrink:0;min-width:44px;text-align:center;}"
279- "mark.sh{background:#7c3aed ;color:#fff;border-radius:2px;padding:0 1px;}"
280- "mark.sh.cur{background:#f59e0b ;color:#050810;}"
281- ".sep{width:1px;height:16px;background:rgba(255,255,255,.12 );flex-shrink:0;}"
283+ "#search-box:focus{border-color:var(--t-btn-border );}"
284+ "#search-box::placeholder{color:var(--t-muted) ;}"
285+ "#sc{color:var(--t-text) ;font-size:11px;white-space:nowrap;flex-shrink:0;min-width:44px;text-align:center;}"
286+ "mark.sh{background:var(--t-mark) ;color:#fff;border-radius:2px;padding:0 1px;}"
287+ "mark.sh.cur{background:var(--t-mark-cur) ;color:#050810;}"
288+ ".sep{width:1px;height:16px;background:var(--t-scroll );flex-shrink:0;}"
282289)
283290
284291# Raw string — no Python escape processing; JS unicode escapes work as-is in browser.
@@ -1027,48 +1034,55 @@ def build_sidebar() -> html.Div:
10271034_THEMES = {
10281035 "midnight" : {"label" : "Midnight" , "dark" : True , "icon" : "bi-moon-stars-fill" ,
10291036 "bg-void" : "#050810" , "bg-dark" : "#080c18" , "bg-panel" : "#0d1225" ,
1037+ "bg-surface" : "#141a2e" ,
10301038 "bg-card" : "rgba(255,255,255,0.028)" , "bg-hover" : "rgba(255,255,255,0.055)" ,
10311039 "bg-active" : "rgba(0,212,255,0.09)" , "border" : "rgba(255,255,255,0.07)" ,
10321040 "border-hi" : "rgba(0,212,255,0.45)" , "text-hi" : "#f8fafc" ,
10331041 "text-1" : "#e2e8f0" , "text-2" : "#94a3b8" , "text-3" : "#4b5563" ,
10341042 "accent" : "#00d4ff" , "card-bg" : "#1a1d23" },
10351043 "obsidian" : {"label" : "Obsidian" , "dark" : True , "icon" : "bi-gem" ,
10361044 "bg-void" : "#0a0a0a" , "bg-dark" : "#111111" , "bg-panel" : "#181818" ,
1045+ "bg-surface" : "#222222" ,
10371046 "bg-card" : "rgba(255,255,255,0.035)" , "bg-hover" : "rgba(255,255,255,0.06)" ,
10381047 "bg-active" : "rgba(168,85,247,0.1)" , "border" : "rgba(255,255,255,0.08)" ,
10391048 "border-hi" : "rgba(168,85,247,0.5)" , "text-hi" : "#fafafa" ,
10401049 "text-1" : "#e0e0e0" , "text-2" : "#9e9e9e" , "text-3" : "#555555" ,
10411050 "accent" : "#a855f7" , "card-bg" : "#1e1e1e" },
10421051 "deep-ocean" : {"label" : "Deep Ocean" , "dark" : True , "icon" : "bi-water" ,
10431052 "bg-void" : "#020617" , "bg-dark" : "#0f172a" , "bg-panel" : "#1e293b" ,
1053+ "bg-surface" : "#263448" ,
10441054 "bg-card" : "rgba(255,255,255,0.03)" , "bg-hover" : "rgba(255,255,255,0.05)" ,
10451055 "bg-active" : "rgba(56,189,248,0.1)" , "border" : "rgba(255,255,255,0.06)" ,
10461056 "border-hi" : "rgba(56,189,248,0.5)" , "text-hi" : "#f8fafc" ,
10471057 "text-1" : "#cbd5e1" , "text-2" : "#64748b" , "text-3" : "#475569" ,
10481058 "accent" : "#38bdf8" , "card-bg" : "#1e293b" },
10491059 "aurora" : {"label" : "Aurora" , "dark" : True , "icon" : "bi-stars" ,
10501060 "bg-void" : "#030712" , "bg-dark" : "#0c1427" , "bg-panel" : "#162032" ,
1061+ "bg-surface" : "#1e2a3e" ,
10511062 "bg-card" : "rgba(255,255,255,0.03)" , "bg-hover" : "rgba(255,255,255,0.055)" ,
10521063 "bg-active" : "rgba(16,185,129,0.1)" , "border" : "rgba(255,255,255,0.07)" ,
10531064 "border-hi" : "rgba(16,185,129,0.5)" , "text-hi" : "#ecfdf5" ,
10541065 "text-1" : "#d1fae5" , "text-2" : "#6ee7b7" , "text-3" : "#34d399" ,
10551066 "accent" : "#10b981" , "card-bg" : "#1a2332" },
10561067 "snowlight" : {"label" : "Snowlight" , "dark" : False , "icon" : "bi-sun-fill" ,
10571068 "bg-void" : "#f8fafc" , "bg-dark" : "#f1f5f9" , "bg-panel" : "#ffffff" ,
1069+ "bg-surface" : "#eef2f7" ,
10581070 "bg-card" : "rgba(0,0,0,0.03)" , "bg-hover" : "rgba(0,0,0,0.05)" ,
10591071 "bg-active" : "rgba(99,102,241,0.08)" , "border" : "rgba(0,0,0,0.1)" ,
10601072 "border-hi" : "rgba(99,102,241,0.5)" , "text-hi" : "#0f172a" ,
10611073 "text-1" : "#1e293b" , "text-2" : "#64748b" , "text-3" : "#94a3b8" ,
10621074 "accent" : "#6366f1" , "card-bg" : "#ffffff" },
10631075 "paper" : {"label" : "Paper" , "dark" : False , "icon" : "bi-file-earmark-text" ,
10641076 "bg-void" : "#fafaf9" , "bg-dark" : "#f5f5f4" , "bg-panel" : "#ffffff" ,
1077+ "bg-surface" : "#edeceb" ,
10651078 "bg-card" : "rgba(0,0,0,0.025)" , "bg-hover" : "rgba(0,0,0,0.04)" ,
10661079 "bg-active" : "rgba(234,88,12,0.08)" , "border" : "rgba(0,0,0,0.08)" ,
10671080 "border-hi" : "rgba(234,88,12,0.45)" , "text-hi" : "#1c1917" ,
10681081 "text-1" : "#292524" , "text-2" : "#78716c" , "text-3" : "#a8a29e" ,
10691082 "accent" : "#ea580c" , "card-bg" : "#ffffff" },
10701083 "cloud" : {"label" : "Cloud" , "dark" : False , "icon" : "bi-cloud-sun-fill" ,
10711084 "bg-void" : "#f0f9ff" , "bg-dark" : "#e0f2fe" , "bg-panel" : "#ffffff" ,
1085+ "bg-surface" : "#daeaf8" ,
10721086 "bg-card" : "rgba(0,0,0,0.02)" , "bg-hover" : "rgba(0,0,0,0.04)" ,
10731087 "bg-active" : "rgba(14,165,233,0.08)" , "border" : "rgba(0,0,0,0.08)" ,
10741088 "border-hi" : "rgba(14,165,233,0.45)" , "text-hi" : "#0c4a6e" ,
@@ -1094,12 +1108,42 @@ def build_sidebar() -> html.Div:
10941108_light_themes = [t for t in _THEMES .values () if not t ["dark" ]]
10951109
10961110def _theme_card (tid : str , t : dict ) -> html .Div :
1097- """Build a clickable theme preview card."""
1111+ """Build a clickable theme preview card with a mini UI mockup."""
1112+ bg = t ["bg-void" ]
1113+ panel = t ["bg-panel" ]
1114+ accent = t ["accent" ]
1115+ text1 = t ["text-1" ]
1116+ text3 = t ["text-3" ]
1117+ border = t ["border" ]
10981118 return html .Button ([
1119+ # Mini UI preview
10991120 html .Div ([
1100- html .Div (className = "theme-swatch-bar" , style = {"background" : t ["accent" ]}),
1101- html .Div (className = "theme-swatch-bg" , style = {"background" : t ["bg-void" ]}),
1102- ], className = "theme-swatch" ),
1121+ # Topbar
1122+ html .Div ([
1123+ html .Div (className = "tm-logo" , style = {"background" : accent }),
1124+ html .Div (className = "tm-topbar-spacer" ),
1125+ html .Div (className = "tm-avatar" , style = {"background" : text3 }),
1126+ ], className = "tm-topbar" , style = {"background" : panel , "borderBottom" : f"1px solid { border } " }),
1127+ # Body
1128+ html .Div ([
1129+ # Sidebar
1130+ html .Div ([
1131+ html .Div (className = "tm-nav-item" , style = {"background" : accent , "opacity" : "0.7" }),
1132+ html .Div (className = "tm-nav-item" , style = {"background" : text3 , "opacity" : "0.4" }),
1133+ html .Div (className = "tm-nav-item" , style = {"background" : text3 , "opacity" : "0.4" }),
1134+ html .Div (className = "tm-nav-item" , style = {"background" : text3 , "opacity" : "0.3" }),
1135+ ], className = "tm-sidebar" , style = {"background" : panel , "borderRight" : f"1px solid { border } " }),
1136+ # Content
1137+ html .Div ([
1138+ html .Div (className = "tm-line tm-line-title" , style = {"background" : text1 , "opacity" : "0.6" }),
1139+ html .Div (className = "tm-line" , style = {"background" : text3 , "opacity" : "0.3" }),
1140+ html .Div (className = "tm-line tm-line-short" , style = {"background" : text3 , "opacity" : "0.2" }),
1141+ html .Div (className = "tm-btn" , style = {"background" : accent , "opacity" : "0.5" }),
1142+ html .Div (className = "tm-code-block" , style = {"background" : panel , "border" : f"1px solid { border } " }),
1143+ ], className = "tm-content" ),
1144+ ], className = "tm-body" ),
1145+ ], className = "tm-preview" , style = {"background" : bg }),
1146+ # Label
11031147 html .Div ([
11041148 html .I (className = f"bi { t ['icon' ]} me-1" ),
11051149 t ["label" ],
@@ -1375,12 +1419,6 @@ def _profile_section() -> html.Div:
13751419 ),
13761420 ], className = "profile-select-row" ),
13771421 html .Div (id = "profile-auth-type" , className = "conn-hint mt-1" ),
1378- html .Button (
1379- [html .I (className = "bi bi-arrow-repeat me-2" ), "Re-authenticate with SSO" ],
1380- id = "reauth-btn" ,
1381- n_clicks = 0 ,
1382- className = "reauth-btn mt-2" ,
1383- ),
13841422 html .Div (id = "reauth-status" , className = "mt-2 small" ),
13851423 ], id = "profile-section" )
13861424
@@ -1453,12 +1491,20 @@ def _custom_section() -> html.Div:
14531491 _profile_section (),
14541492 _sso_section (),
14551493 _custom_section (),
1456- html .Button (
1457- [html .I (className = "bi bi-plug-fill me-2" ), "Connect" ],
1458- id = "apply-conn-btn" ,
1459- n_clicks = 0 ,
1460- className = "apply-btn mt-3" ,
1461- ),
1494+ html .Div ([
1495+ html .Button (
1496+ [html .I (className = "bi bi-arrow-repeat me-2" ), "Re-auth SSO" ],
1497+ id = "reauth-btn" ,
1498+ n_clicks = 0 ,
1499+ className = "reauth-btn" ,
1500+ ),
1501+ html .Button (
1502+ [html .I (className = "bi bi-plug-fill me-2" ), "Connect" ],
1503+ id = "apply-conn-btn" ,
1504+ n_clicks = 0 ,
1505+ className = "apply-btn" ,
1506+ ),
1507+ ], className = "conn-btn-row mt-3" ),
14621508 html .Div (id = "conn-status" , className = "mt-2 small" ),
14631509 ], className = "px-4 pb-3" ),
14641510
@@ -1741,12 +1787,14 @@ def update_settings(tz, lang, theme_clicks, current):
17411787 function(settings) {
17421788 if (!settings) return window.dash_clientside.no_update;
17431789
1744- var themes = """ + json .dumps ({k : {kk : vv for kk , vv in v .items () if kk not in ("label" , "icon" , "dark" )} for k , v in _THEMES .items ()}) + """;
1790+ var themes = """ + json .dumps ({k : {kk : vv for kk , vv in v .items () if kk not in ("label" , "icon" )} for k , v in _THEMES .items ()}) + """;
17451791 var theme = themes[settings.theme || "midnight"] || themes["midnight"];
1792+ var isDark = theme["dark"];
17461793 var root = document.documentElement;
17471794 root.style.setProperty('--bg-void', theme['bg-void']);
17481795 root.style.setProperty('--bg-dark', theme['bg-dark']);
17491796 root.style.setProperty('--bg-panel', theme['bg-panel']);
1797+ root.style.setProperty('--bg-surface', theme['bg-surface']);
17501798 root.style.setProperty('--bg-card', theme['bg-card']);
17511799 root.style.setProperty('--bg-hover', theme['bg-hover']);
17521800 root.style.setProperty('--bg-active', theme['bg-active']);
@@ -1768,6 +1816,68 @@ def update_settings(tz, lang, theme_clicks, current):
17681816 }
17691817 });
17701818
1819+ // Push theme into JSON tree iframes
1820+ var iframeVars = isDark ? {
1821+ '--t-bg': theme['bg-void'], '--t-text': theme['text-2'], '--t-text-hi': theme['text-1'],
1822+ '--t-muted': theme['text-3'], '--t-border': theme['border'], '--t-accent': theme['accent'],
1823+ '--t-key': '#60a5fa', '--t-str': '#86efac', '--t-num': '#fbbf24',
1824+ '--t-bool': '#c084fc', '--t-null': theme['text-2'], '--t-punc': theme['text-3'],
1825+ '--t-btn-bg': 'rgba(0,212,255,.07)', '--t-btn-border': 'rgba(0,212,255,.2)',
1826+ '--t-input-bg': 'rgba(255,255,255,.06)', '--t-input-border': 'rgba(255,255,255,.12)',
1827+ '--t-scroll': 'rgba(255,255,255,.12)', '--t-tip-bg': theme['bg-panel'],
1828+ '--t-mark': '#7c3aed', '--t-mark-cur': '#f59e0b'
1829+ } : {
1830+ '--t-bg': theme['bg-void'], '--t-text': '#374151', '--t-text-hi': '#111827',
1831+ '--t-muted': '#9ca3af', '--t-border': theme['border'], '--t-accent': theme['accent'],
1832+ '--t-key': '#2563eb', '--t-str': '#059669', '--t-num': '#d97706',
1833+ '--t-bool': '#7c3aed', '--t-null': '#9ca3af', '--t-punc': '#6b7280',
1834+ '--t-btn-bg': 'rgba(99,102,241,.08)', '--t-btn-border': 'rgba(99,102,241,.25)',
1835+ '--t-input-bg': 'rgba(0,0,0,.04)', '--t-input-border': 'rgba(0,0,0,.12)',
1836+ '--t-scroll': 'rgba(0,0,0,.15)', '--t-tip-bg': '#ffffff',
1837+ '--t-mark': '#7c3aed', '--t-mark-cur': '#f59e0b'
1838+ };
1839+ // Store current iframe vars globally so new iframes can pick them up
1840+ window.__iframeThemeVars = iframeVars;
1841+
1842+ // Apply to all existing iframes
1843+ function applyIframeTheme(iframe) {
1844+ try {
1845+ var iDoc = iframe.contentDocument || (iframe.contentWindow && iframe.contentWindow.document);
1846+ if (iDoc && iDoc.documentElement) {
1847+ var r = iDoc.documentElement;
1848+ var vars = window.__iframeThemeVars;
1849+ if (vars) { for (var k in vars) { r.style.setProperty(k, vars[k]); } }
1850+ }
1851+ } catch(e) {}
1852+ }
1853+ document.querySelectorAll('iframe').forEach(function(iframe) {
1854+ applyIframeTheme(iframe);
1855+ // Also apply when iframe finishes loading (for newly created ones)
1856+ iframe.addEventListener('load', function() { applyIframeTheme(iframe); });
1857+ });
1858+
1859+ // Watch for new iframes added to the DOM and theme them automatically
1860+ if (!window.__iframeThemeObserver) {
1861+ window.__iframeThemeObserver = new MutationObserver(function(mutations) {
1862+ for (var i = 0; i < mutations.length; i++) {
1863+ var nodes = mutations[i].addedNodes;
1864+ for (var j = 0; j < nodes.length; j++) {
1865+ var nd = nodes[j];
1866+ if (nd.tagName === 'IFRAME') {
1867+ nd.addEventListener('load', function() { applyIframeTheme(nd); });
1868+ applyIframeTheme(nd);
1869+ } else if (nd.querySelectorAll) {
1870+ nd.querySelectorAll('iframe').forEach(function(f) {
1871+ f.addEventListener('load', function() { applyIframeTheme(f); });
1872+ applyIframeTheme(f);
1873+ });
1874+ }
1875+ }
1876+ }
1877+ });
1878+ window.__iframeThemeObserver.observe(document.body, { childList: true, subtree: true });
1879+ }
1880+
17711881 return window.dash_clientside.no_update;
17721882 }
17731883 """ ,
0 commit comments