Spaces:
Running on Zero
Running on Zero
Force dark mode by pinning Gradio's .dark class
Browse filesThe ?__theme=dark redirect didn't stick — HF Spaces controls the embedded
iframe's theme and overrides the URL param. Instead, pin Gradio's `.dark`
class on <html>, <body>, and <gradio-app> via a <head> script, and re-add
it with a MutationObserver whenever HF's theme toggle strips it. This makes
the app render identically to dark mode regardless of OS or HF theme.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
app.py
CHANGED
|
@@ -1425,17 +1425,45 @@ footer { display: none !important; }
|
|
| 1425 |
"""
|
| 1426 |
|
| 1427 |
|
| 1428 |
-
|
| 1429 |
-
|
| 1430 |
-
|
| 1431 |
-
|
| 1432 |
-
|
| 1433 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1434 |
}
|
| 1435 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1436 |
"""
|
| 1437 |
|
| 1438 |
-
FORCE_DARK_HEAD =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1439 |
|
| 1440 |
|
| 1441 |
def build_app() -> gr.Blocks:
|
|
|
|
| 1425 |
"""
|
| 1426 |
|
| 1427 |
|
| 1428 |
+
# The UI is dark-mode-native (navy "MAISI Console" aesthetic, no light variant).
|
| 1429 |
+
# Gradio drives light/dark by toggling a `.dark` class on the DOM; HF Spaces'
|
| 1430 |
+
# own theme switch can remove it. We pin the class on every plausible host
|
| 1431 |
+
# element and re-add it via MutationObserver whenever it's stripped, so the app
|
| 1432 |
+
# always renders dark regardless of OS preference or the HF theme toggle.
|
| 1433 |
+
_FORCE_DARK_BODY = """
|
| 1434 |
+
function force() {
|
| 1435 |
+
document.documentElement.classList.add('dark');
|
| 1436 |
+
if (document.body) document.body.classList.add('dark');
|
| 1437 |
+
document.querySelectorAll('gradio-app').forEach(function (el) {
|
| 1438 |
+
el.classList.add('dark');
|
| 1439 |
+
});
|
| 1440 |
+
}
|
| 1441 |
+
force();
|
| 1442 |
+
new MutationObserver(force).observe(document.documentElement, {
|
| 1443 |
+
attributes: true, attributeFilter: ['class']
|
| 1444 |
+
});
|
| 1445 |
+
function watchBody() {
|
| 1446 |
+
force();
|
| 1447 |
+
if (document.body) {
|
| 1448 |
+
new MutationObserver(force).observe(document.body, {
|
| 1449 |
+
attributes: true, attributeFilter: ['class']
|
| 1450 |
+
});
|
| 1451 |
}
|
| 1452 |
}
|
| 1453 |
+
if (document.readyState === 'loading') {
|
| 1454 |
+
document.addEventListener('DOMContentLoaded', watchBody);
|
| 1455 |
+
} else {
|
| 1456 |
+
watchBody();
|
| 1457 |
+
}
|
| 1458 |
"""
|
| 1459 |
|
| 1460 |
+
FORCE_DARK_HEAD = (
|
| 1461 |
+
'<meta name="color-scheme" content="dark">'
|
| 1462 |
+
"<script>(function () {" + _FORCE_DARK_BODY + "})();</script>"
|
| 1463 |
+
)
|
| 1464 |
+
|
| 1465 |
+
# Re-assert once more after the Gradio app finishes loading (belt-and-suspenders).
|
| 1466 |
+
FORCE_DARK_JS = "() => {" + _FORCE_DARK_BODY + "}"
|
| 1467 |
|
| 1468 |
|
| 1469 |
def build_app() -> gr.Blocks:
|