zephyrie Claude Opus 4.7 commited on
Commit
89c8f24
·
1 Parent(s): d2fed28

Force dark mode by pinning Gradio's .dark class

Browse files

The ?__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>

Files changed (1) hide show
  1. app.py +35 -7
app.py CHANGED
@@ -1425,17 +1425,45 @@ footer { display: none !important; }
1425
  """
1426
 
1427
 
1428
- FORCE_DARK_JS = """
1429
- () => {
1430
- const url = new URL(window.location);
1431
- if (url.searchParams.get('__theme') !== 'dark') {
1432
- url.searchParams.set('__theme', 'dark');
1433
- window.location.replace(url.href);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1434
  }
1435
  }
 
 
 
 
 
1436
  """
1437
 
1438
- FORCE_DARK_HEAD = '<meta name="color-scheme" content="dark">'
 
 
 
 
 
 
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: