This is an automated email from the ASF dual-hosted git repository.

shahar pushed a commit to branch fix-ui-fouc
in repository https://gitbox.apache.org/repos/asf/airflow-site.git

commit 5ad553f40b816f9619e79605a30ee5ee7bbb9a1a
Author: Shahar Epstein <[email protected]>
AuthorDate: Sat Jan 3 18:25:58 2026 +0200

    Fix FOUC issues and dark mode button
---
 landing-pages/site/assets/js/dark-mode-init.js     | 35 ++++++++++++++++++++++
 landing-pages/site/assets/js/dark-mode.js          |  4 +--
 landing-pages/site/assets/scss/_base-layout.scss   |  4 +++
 landing-pages/site/assets/scss/_header.scss        |  3 +-
 landing-pages/site/layouts/partials/head-css.html  |  5 ++++
 .../site/layouts/partials/hooks/head-end.html      | 18 +++++++++++
 landing-pages/src/js/headerAnimation.js            |  7 +++++
 7 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/landing-pages/site/assets/js/dark-mode-init.js 
b/landing-pages/site/assets/js/dark-mode-init.js
new file mode 100644
index 0000000000..3b21b7fe91
--- /dev/null
+++ b/landing-pages/site/assets/js/dark-mode-init.js
@@ -0,0 +1,35 @@
+(() => {
+  'use strict'
+
+  const style = document.createElement('style')
+  style.innerHTML = '* { -webkit-transition: none !important; -moz-transition: 
none !important; -ms-transition: none !important; -o-transition: none 
!important; transition: none !important; }'
+  document.head.appendChild(style)
+
+  window.addEventListener('DOMContentLoaded', () => {
+    setTimeout(() => {
+      style.remove()
+    }, 0)
+  })
+
+  const themeKey = 'td-color-theme'
+  const getStoredTheme = () => localStorage.getItem(themeKey)
+
+  const getPreferredTheme = () => {
+    const storedTheme = getStoredTheme()
+    if (storedTheme) {
+      return storedTheme
+    }
+
+    return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' 
: 'light'
+  }
+
+  const setTheme = theme => {
+    if (theme === 'auto') {
+      document.documentElement.setAttribute('data-bs-theme', 
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'))
+    } else {
+      document.documentElement.setAttribute('data-bs-theme', theme)
+    }
+  }
+
+  setTheme(getPreferredTheme())
+})()
diff --git a/landing-pages/site/assets/js/dark-mode.js 
b/landing-pages/site/assets/js/dark-mode.js
index 856cb6ff0b..b5d7f04b8f 100644
--- a/landing-pages/site/assets/js/dark-mode.js
+++ b/landing-pages/site/assets/js/dark-mode.js
@@ -27,7 +27,7 @@
  * Licensed under the Creative Commons Attribution 3.0 Unported License.
  */
 
-(() => {
+;(() => {
   'use strict'
 
   const themeKey = 'td-color-theme'
@@ -104,7 +104,7 @@
   })
 
   window.addEventListener('DOMContentLoaded', () => {
-    showActiveTheme(getPreferredTheme())
+    showActiveTheme(getStoredTheme() || 'auto')
 
     document.querySelectorAll('[data-bs-theme-value]')
       .forEach(toggle => {
diff --git a/landing-pages/site/assets/scss/_base-layout.scss 
b/landing-pages/site/assets/scss/_base-layout.scss
index 69241171c8..98d25d08a3 100644
--- a/landing-pages/site/assets/scss/_base-layout.scss
+++ b/landing-pages/site/assets/scss/_base-layout.scss
@@ -19,6 +19,10 @@
 @import "media";
 @import "fonts";
 
+html {
+  overflow-y: scroll;
+}
+
 .base-layout {
   // padding: 123px 0 40px;
   padding: 163px 0 40px; // TEMP - accommodate Airflow Summit banner (123 + 40)
diff --git a/landing-pages/site/assets/scss/_header.scss 
b/landing-pages/site/assets/scss/_header.scss
index 7e0b7a37ac..bbb354fa5a 100644
--- a/landing-pages/site/assets/scss/_header.scss
+++ b/landing-pages/site/assets/scss/_header.scss
@@ -125,7 +125,8 @@
 // Dark mode styles
 [data-bs-theme="dark"] {
   #header {
-    // background-color handled by canvas animation
+    background-color: #1a1a1a;
+    isolation: isolate;
   }
 
   #header-canvas {
diff --git a/landing-pages/site/layouts/partials/head-css.html 
b/landing-pages/site/layouts/partials/head-css.html
index 738714bdc7..313c1475ce 100644
--- a/landing-pages/site/layouts/partials/head-css.html
+++ b/landing-pages/site/layouts/partials/head-css.html
@@ -16,6 +16,11 @@
  specific language governing permissions and limitations
  under the License.
 */}}
+<link rel="preload" href="/external/css/OpenSans.css" as="style">
+<link rel="preload" href="/external/css/Rubik.css" as="style">
+<link rel="preload" href="/external/css/Roboto.css" as="style">
+<link rel="preload" href="/external/css/RobotoMono.css" as="style">
+
 {{ $scssMain := "scss/main.scss"}}
 {{ if hugo.IsServer }}
 {{/* Note the missing postCSS. This makes it snappier to develop in Chrome, 
but makes it look suboptimal in other browsers. */}}
diff --git a/landing-pages/site/layouts/partials/hooks/head-end.html 
b/landing-pages/site/layouts/partials/hooks/head-end.html
new file mode 100644
index 0000000000..c06de4db71
--- /dev/null
+++ b/landing-pages/site/layouts/partials/hooks/head-end.html
@@ -0,0 +1,18 @@
+{{ $darkModeInit := resources.Get "js/dark-mode-init.js" | minify }}
+<script>
+  document.documentElement.classList.add('preload');
+  {{ $darkModeInit.Content | safeJS }}
+  window.addEventListener('DOMContentLoaded', () => {
+      document.documentElement.classList.remove('preload');
+  });
+</script>
+
+<style>
+  .preload * {
+    -webkit-transition: none !important;
+    -moz-transition: none !important;
+    -ms-transition: none !important;
+    -o-transition: none !important;
+    transition: none !important;
+  }
+</style>
diff --git a/landing-pages/src/js/headerAnimation.js 
b/landing-pages/src/js/headerAnimation.js
index 9b77f3a49d..8e7c19f860 100644
--- a/landing-pages/src/js/headerAnimation.js
+++ b/landing-pages/src/js/headerAnimation.js
@@ -233,6 +233,13 @@ export function initHeaderAnimation() {
         logoArea = createLogoArea(sketch, canvas, title, subtitle, button);
         boxes = createBoxes(sketch, vw, vh, logoArea, colors);
         sketch.createCanvas(vw, vh);
+
+        const isDarkMode = 
document.documentElement.getAttribute("data-bs-theme") === "dark";
+        if (isDarkMode) {
+          sketch.background(26, 26, 26); // #1a1a1a to match dark navbar 
background
+        } else {
+          sketch.background(255, 255, 255);
+        }
       };
 
       sketch.draw = () => {

Reply via email to