You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by ka...@apache.org on 2025/11/07 02:32:47 UTC

(airflow-site) branch feat-modernize-theme-5qPcf created (now 9559cc99cc)

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

kaxilnaik pushed a change to branch feat-modernize-theme-5qPcf
in repository https://gitbox.apache.org/repos/asf/airflow-site.git


      at 9559cc99cc Add dark mode support to Airflow documentation site

This branch includes the following new commits:

     new b53c62f3e0 Upgrade Docsy theme from v0.2.0-pre to v0.12.0 and enable dark mode
     new 9559cc99cc Add dark mode support to Airflow documentation site

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(airflow-site) 01/02: Upgrade Docsy theme from v0.2.0-pre to v0.12.0 and enable dark mode

Posted by ka...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kaxilnaik pushed a commit to branch feat-modernize-theme-5qPcf
in repository https://gitbox.apache.org/repos/asf/airflow-site.git

commit b53c62f3e08216ab537929e76a5773598c3d1e61
Author: Kaxil Naik <ka...@gmail.com>
AuthorDate: Thu Nov 6 01:10:52 2025 +0000

    Upgrade Docsy theme from v0.2.0-pre to v0.12.0 and enable dark mode
    
    - Fixed corrupted Docsy submodule by removing and re-adding
    - Upgraded through major versions: v0.2.0 -> v0.6.0 -> v0.10.0 -> v0.12.0
    - Added missing SCSS variables for compatibility:
      * $td-sidebar-tree-root-color
      * $font-awesome-font-name
      * .-bg-orange utility class
    - Removed Bootstrap 4 dependencies (switched to Bootstrap 5.3.3)
    - Removed custom scripts.html override (conflicts with Bootstrap 5)
    - Enabled dark mode via showLightDarkModeMenu = true
    
    Dark mode is now available via the light/dark toggle in the UI.
---
 landing-pages/site/assets/scss/_colors.scss                          | 5 +++++
 landing-pages/site/assets/scss/_variables.scss                       | 2 ++
 landing-pages/site/config.toml                                       | 2 ++
 .../site/layouts/partials/{scripts.html => scripts.html.backup}      | 0
 landing-pages/site/themes/docsy                                      | 2 +-
 5 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/landing-pages/site/assets/scss/_colors.scss b/landing-pages/site/assets/scss/_colors.scss
index f0ae3f4e25..4eee5b3f3e 100644
--- a/landing-pages/site/assets/scss/_colors.scss
+++ b/landing-pages/site/assets/scss/_colors.scss
@@ -32,3 +32,8 @@ $colors: (
         slate-grey: #636365,
         greyish-brown: #51504f
 );
+
+// Background color utility class for Docsy theme compatibility
+.-bg-orange {
+  background-color: #FFA630; // Using $secondary color
+}
diff --git a/landing-pages/site/assets/scss/_variables.scss b/landing-pages/site/assets/scss/_variables.scss
index bfba27f0cd..1ba7fe4335 100644
--- a/landing-pages/site/assets/scss/_variables.scss
+++ b/landing-pages/site/assets/scss/_variables.scss
@@ -59,6 +59,7 @@ $code-color: darken($secondary, 20%) !default;
 // UI element colors
 
 $border-color: $gray-300 !default;
+$td-sidebar-tree-root-color: $primary !default;
 $td-sidebar-bg-color: rgba($primary, 0.03) !default;
 $td-sidebar-border-color: $border-color !default;
 
@@ -77,6 +78,7 @@ $link-hover-decoration: none !default;
 $google_font_name: "Open Sans" !default;
 $google_font_family: "Open+Sans:300,300i,400,400i,700,700i" !default;
 $web-font-path: "/external/css/OpenSans.css";
+$font-awesome-font-name: "Font Awesome 6 Free" !default;
 
 $td-fonts-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
 
diff --git a/landing-pages/site/config.toml b/landing-pages/site/config.toml
index 5473d5e3a6..84004f225c 100644
--- a/landing-pages/site/config.toml
+++ b/landing-pages/site/config.toml
@@ -103,6 +103,8 @@ sidebar_search_disable = false
 navbar_logo = true
 # Set to true to disable the About link in the site footer
 footer_about_disable = false
+# Enable dark mode toggle
+showLightDarkModeMenu = true
 
 # Adds a H2 section titled "Feedback" to the bottom of each doc. The responses are sent to Google Analytics as events.
 # This feature depends on [services.googleAnalytics] and will be disabled if "services.googleAnalytics.id" is not set.
diff --git a/landing-pages/site/layouts/partials/scripts.html b/landing-pages/site/layouts/partials/scripts.html.backup
similarity index 100%
rename from landing-pages/site/layouts/partials/scripts.html
rename to landing-pages/site/layouts/partials/scripts.html.backup
diff --git a/landing-pages/site/themes/docsy b/landing-pages/site/themes/docsy
index 8d2b933154..ace4e37cee 160000
--- a/landing-pages/site/themes/docsy
+++ b/landing-pages/site/themes/docsy
@@ -1 +1 @@
-Subproject commit 8d2b933154ac99fe997a727efb4ba8a47cf5001b
+Subproject commit ace4e37ceedcec9c48d329adb1128201061ef23d


(airflow-site) 02/02: Add dark mode support to Airflow documentation site

Posted by ka...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kaxilnaik pushed a commit to branch feat-modernize-theme-5qPcf
in repository https://gitbox.apache.org/repos/asf/airflow-site.git

commit 9559cc99cc8e2b6cc2d392e8c8ffc70528c28d0e
Author: Kaxil Naik <ka...@gmail.com>
AuthorDate: Fri Nov 7 01:40:07 2025 +0000

    Add dark mode support to Airflow documentation site
    
    Upgrade Docsy theme from v0.2.0 to v0.12.0 and implement Bootstrap 5 dark mode.
    
    Core Changes:
    - Enable showLightDarkModeMenu in config.toml
    - Add theme toggle component to navbar (light/dark/auto modes)
    - Store user preference in localStorage
    - Respect prefers-color-scheme media query
    
    Styling Implementation:
    - Use Bootstrap 5 CSS variables (--bs-body-color, --bs-secondary-bg, etc.) for all UI elements
    - Style navbar, header, sidebar, tables, admonitions, and forms for dark mode
    - Add Pygments-generated GitHub Dark theme for code syntax highlighting in Sphinx docs
    - Adapt confetti animation to dynamically set background based on theme
    - Ensure proper semantic colors for all admonition types (note, warning, error, hint, etc.)
    
    Technical Details:
    - Added $td-sidebar-tree-root-color variable (required by Docsy v0.2.0+)
    - Added $font-awesome-font-name variable (required by Docsy v0.6.0+)
    - Added .-bg-orange utility class (required by Docsy v0.6.0+)
    - Created pygments/_dark.scss (generated via: pygmentize -S github-dark)
    - Use hooks/body-end.html for webpack scripts (proper Docsy pattern)
    - Add dark mode support to Sphinx theme (header.html, layout.html)
    - Update .gitignore to exclude site/public/ directory
    
    Fixed Issues:
    - Confetti animation now visible with transparent header background
    - Sidebar links readable in dark mode (increased contrast)
    - All admonition types (including seealso) properly colored
    - Logo text white in dark mode
    - Navbar and header backgrounds adapt to theme
    
    Architecture:
    - Removed baseof.html override, use Docsy hooks instead
    - Follow Docsy best practices for customization
    - Use CSS variables for maintainability
    
    Testing:
    - Verified dark mode toggle works on all pages
    - Confirmed confetti animation adapts to theme changes
    - Tested all admonition types in light and dark modes
    - Verified code syntax highlighting in Sphinx documentation
---
 landing-pages/.gitignore                           |   1 +
 landing-pages/site/assets/scss/_colors.scss        |   4 +-
 landing-pages/site/assets/scss/_header.scss        |  21 +
 landing-pages/site/assets/scss/_navbar.scss        |  67 ++++
 landing-pages/site/assets/scss/_rating.scss        |  32 +-
 landing-pages/site/assets/scss/_roadmap.scss       |   5 +
 landing-pages/site/assets/scss/_rst-content.scss   | 427 ++++++++++++++++-----
 landing-pages/site/assets/scss/_variables.scss     |   4 +-
 landing-pages/site/assets/scss/main-custom.scss    |   2 +-
 landing-pages/site/assets/scss/pygments/_dark.scss | 121 ++++++
 .../layouts/{partials => _partials}/navbar.html    |  10 +
 .../baseof.html => partials/hooks/body-end.html}   |  24 +-
 landing-pages/site/layouts/partials/navbar.html    |  10 +
 .../site/layouts/partials/scripts.html.backup      |  14 -
 landing-pages/src/js/headerAnimation.js            |  10 +-
 .../sphinx_airflow_theme/globaltoc.html            |  20 +
 .../sphinx_airflow_theme/header.html               |  34 ++
 .../sphinx_airflow_theme/layout.html               | 103 ++++-
 18 files changed, 772 insertions(+), 137 deletions(-)

diff --git a/landing-pages/.gitignore b/landing-pages/.gitignore
index 4aa6c9e0db..7b46e9dd7f 100644
--- a/landing-pages/.gitignore
+++ b/landing-pages/.gitignore
@@ -3,3 +3,4 @@ dist/
 site/data/webpack.json
 resources/
 site/static/_gen/
+site/public/
diff --git a/landing-pages/site/assets/scss/_colors.scss b/landing-pages/site/assets/scss/_colors.scss
index 4eee5b3f3e..948b34cc78 100644
--- a/landing-pages/site/assets/scss/_colors.scss
+++ b/landing-pages/site/assets/scss/_colors.scss
@@ -33,7 +33,7 @@ $colors: (
         greyish-brown: #51504f
 );
 
-// Background color utility class for Docsy theme compatibility
+// Background color utility class required by Docsy v0.6.0+ theme
 .-bg-orange {
-  background-color: #FFA630; // Using $secondary color
+  background-color: #FFA630; // Using $secondary color value
 }
diff --git a/landing-pages/site/assets/scss/_header.scss b/landing-pages/site/assets/scss/_header.scss
index 324623886d..7e0b7a37ac 100644
--- a/landing-pages/site/assets/scss/_header.scss
+++ b/landing-pages/site/assets/scss/_header.scss
@@ -22,6 +22,8 @@
   position: relative;
   margin: 123px -20px 0;
   min-height: calc(100vh - 123px);
+  // background-color is handled by the canvas animation which draws white/dark background
+  transition: background-color 0.3s ease;
 }
 
 #header-canvas {
@@ -119,3 +121,22 @@
     }
   }
 }
+
+// Dark mode styles
+[data-bs-theme="dark"] {
+  #header {
+    // background-color handled by canvas animation
+  }
+
+  #header-canvas {
+    .text-area {
+      &--header {
+        color: rgba(255, 255, 255, 0.95);
+      }
+
+      &--subheader {
+        color: rgba(255, 255, 255, 0.75);
+      }
+    }
+  }
+}
diff --git a/landing-pages/site/assets/scss/_navbar.scss b/landing-pages/site/assets/scss/_navbar.scss
index 64b88e2a90..96b8c664ac 100644
--- a/landing-pages/site/assets/scss/_navbar.scss
+++ b/landing-pages/site/assets/scss/_navbar.scss
@@ -28,6 +28,7 @@
   border-bottom: solid 1px map-get($colors, very-light-pink);
   z-index: 32;
   padding: 30px 60px;
+  transition: background-color 0.3s ease, border-color 0.3s ease;
 
   &__menu-container {
     flex-grow: 1;
@@ -50,6 +51,7 @@
     margin-right: 30px;
     position: relative;
     width: fit-content;
+    transition: color 0.3s ease;
 
     &::before, &::after {
       content: "";
@@ -74,6 +76,43 @@
   &--box-shadow {
     box-shadow: 0 2px 6px 0 rgba(0, 0, 0, .12);
   }
+
+  // Theme toggle styling
+  &__theme-toggle {
+    display: inline-flex;
+    align-items: center;
+    position: relative;
+
+    .btn {
+      padding: 0.25rem 0.5rem;
+      font-size: 0.875rem;
+      border: none;
+      background: none;
+
+      svg {
+        width: 1rem;
+        height: 1rem;
+      }
+    }
+
+    .dropdown-menu {
+      font-size: 0.8125rem;
+      min-width: 7rem;
+      padding: 0.25rem 0;
+      left: 0 !important;
+      right: auto !important;
+
+      .dropdown-item {
+        padding: 0.375rem 0.75rem;
+        font-size: 0.8125rem;
+
+        svg {
+          width: 0.875rem;
+          height: 0.875rem;
+        }
+      }
+    }
+  }
 }
 
 @media (max-width: $tablet) {
@@ -154,3 +193,31 @@
     }
   }
 }
+
+// Dark mode styles
+[data-bs-theme="dark"] {
+  .navbar {
+    background-color: #1a1a1a;
+    border-bottom-color: #333;
+
+    &__text-link {
+      color: rgba(255, 255, 255, 0.85);
+
+      &:hover, &.active {
+        color: rgba(255, 255, 255, 1);
+      }
+    }
+
+    // Make logo text (Apache Airflow) white in dark mode
+    &__icon-container {
+      svg path[fill="#51504f"] {
+        fill: rgba(255, 255, 255, 0.95);
+      }
+    }
+
+    // Also handle mobile drawer background
+    &__drawer {
+      background-color: #1a1a1a;
+    }
+  }
+}
diff --git a/landing-pages/site/assets/scss/_rating.scss b/landing-pages/site/assets/scss/_rating.scss
index afaf719fc9..5e6b8348aa 100644
--- a/landing-pages/site/assets/scss/_rating.scss
+++ b/landing-pages/site/assets/scss/_rating.scss
@@ -31,18 +31,44 @@
   cursor: pointer;
   margin-right: 13px;
 
+  &:hover, &:hover ~ & {
+    svg {
+      path {
+        fill: #017cee;
+        stroke: none;
+      }
+    }
+  }
+
   svg {
     path {
       fill: none;
       stroke: #51504f;
     }
   }
+}
+
+// Dark mode styles
+[data-bs-theme="dark"] {
+  .rating-container {
+    p {
+      color: rgba(255, 255, 255, 0.85);
+    }
+  }
+
+  .rate-star {
+    &:hover, &:hover ~ & {
+      svg {
+        path {
+          fill: #68d2fe;
+          stroke: none;
+        }
+      }
+    }
 
-  &:hover, &:hover ~ & {
     svg {
       path {
-        fill: #017cee;
-        stroke: none;
+        stroke: rgba(255, 255, 255, 0.75);
       }
     }
   }
diff --git a/landing-pages/site/assets/scss/_roadmap.scss b/landing-pages/site/assets/scss/_roadmap.scss
index 599523671a..3b5b4bf99b 100644
--- a/landing-pages/site/assets/scss/_roadmap.scss
+++ b/landing-pages/site/assets/scss/_roadmap.scss
@@ -288,3 +288,8 @@
     }
   }
 }
+
+// Dark mode styles for roadmap page
+[data-bs-theme="dark"] .roadmap .td-sidebar {
+  background-color: #2d2d2d !important;
+}
diff --git a/landing-pages/site/assets/scss/_rst-content.scss b/landing-pages/site/assets/scss/_rst-content.scss
index 1fdd833c3a..6bc5cc11c0 100644
--- a/landing-pages/site/assets/scss/_rst-content.scss
+++ b/landing-pages/site/assets/scss/_rst-content.scss
@@ -17,21 +17,28 @@
  * under the License.
  */
 
+// Set Open Sans as the default body font to match production behavior
+// This ensures both Hugo pages and Sphinx docs use the same font stack
+body {
+  font-family: "Open Sans", -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+}
+
 .rst-content {
-  color: #707070;
+  // Use Bootstrap CSS variables for automatic light/dark mode support
+  color: var(--bs-body-color);
 
   h1 {
     margin-top: 0;
     margin-bottom: 30px;
     font-weight: 500;
     font-family: "Rubik", sans-serif;
-    color: #51504f;
+    color: var(--bs-emphasis-color);
     font-size: 225%;
   }
 
   h2, h3, h4, h5, h6, p {
     font-family: 'Roboto', sans-serif;
-    color: #707070;
+    color: var(--bs-body-color);
   }
 
   h2, h3, h4, h5, h6 {
@@ -69,17 +76,21 @@
 
   code {
     max-width: 100%;
-    color: #51504f;
+    color: var(--bs-code-color);
+    background-color: var(--bs-secondary-bg);
     padding: 0 5px;
     font-family: 'Roboto Mono', monospace;
     overflow-x: auto;
   }
 
-  .note, .attention, .caution, .danger, .error, .hint, .important, .tip, .warning, .admonition-todo, .admonition {
+  // Admonitions using Bootstrap contextual colors
+  .note, .seealso, .attention, .caution, .danger, .error, .hint, .important, .tip, .warning, .admonition-todo, .admonition {
     padding: 9px 10px;
     line-height: 24px;
     margin-bottom: 24px;
-    background: #e7f2fa;
+    background: var(--bs-info-bg-subtle);
+    border-left: 4px solid var(--bs-info-border-subtle);
+    color: var(--bs-body-color);
   }
 
   @media (max-width: 768px) {
@@ -91,110 +102,87 @@
 
   .admonition-title:before {
     content: "!";
-    background-color: white;
+    background-color: var(--bs-body-bg);
     border-radius: 50%;
     padding: 0 4px;
     margin-right: 5px;
   }
 
   .admonition-title {
-    color: #fff;
+    color: var(--bs-emphasis-color);
     font-weight: 500;
     font-size: 10px;
     line-height: 2.1;
     display: block;
-    background: #68d1ff;
+    background: var(--bs-info-bg-subtle);
     margin: -10px;
     padding: 0 12px;
     margin-bottom: 9px;
   }
 
+  // Danger/Error admonitions
   .danger, .error {
-    background: #fdece9;
-
-    &::before {
-      color: #fdece9;
-    }
+    background: var(--bs-danger-bg-subtle);
+    border-left-color: var(--bs-danger-border-subtle);
   }
 
   .danger .admonition-title, .error .admonition-title {
-    background: #ee8170;
-
-    &::before {
-      color: #ee8170;
-    }
+    background: var(--bs-danger-bg-subtle);
+    color: var(--bs-danger-text-emphasis);
   }
 
+  // Warning/Caution/Attention admonitions
   .attention, .caution {
-    background: #fff8f6;
+    background: var(--bs-warning-bg-subtle);
+    border-left-color: var(--bs-warning-border-subtle);
   }
 
   .warning {
-    background: #f8f8f8;
+    background: var(--bs-secondary-bg);
+    border-left-color: var(--bs-border-color);
   }
 
   .attention .admonition-title, .caution .admonition-title {
-    background: #ffa996;
-
-    &::before {
-      color: #ffa996;
-    }
+    background: var(--bs-warning-bg-subtle);
+    color: var(--bs-warning-text-emphasis);
   }
 
   .warning .admonition-title {
-    background: #a6a6a6;
-
-    &::before {
-      color: #a6a6a6;
-    }
+    background: var(--bs-secondary-bg);
+    color: var(--bs-emphasis-color);
   }
 
+  // Note/Seealso - info colored
   .note, .seealso {
-    background: #f3fbff;
+    background: var(--bs-info-bg-subtle);
+    border-left-color: var(--bs-info-border-subtle);
   }
 
   .note .admonition-title, .seealso .admonition-title {
-    background: #68d2fe;
-
-    &::before {
-      color: #68d2fe;
-    }
-  }
-
-  .hint {
-    background: #f2fef6;
+    background: var(--bs-info-bg-subtle);
+    color: var(--bs-info-text-emphasis);
   }
 
-  .important {
-    background: #e6f9fc;
+  // Hint/Tip - success colored
+  .hint, .tip {
+    background: var(--bs-success-bg-subtle);
+    border-left-color: var(--bs-success-border-subtle);
   }
 
-  .tip {
-    background: #e5f7ec;
+  .hint .admonition-title, .tip .admonition-title {
+    background: var(--bs-success-bg-subtle);
+    color: var(--bs-success-text-emphasis);
   }
 
-  .hint .admonition-title {
-    background: #63e598;
-
-    &::before {
-      color: #63e598;
-    }
+  // Important - info colored
+  .important {
+    background: var(--bs-info-bg-subtle);
+    border-left-color: var(--bs-info-border-subtle);
   }
 
   .important .admonition-title {
-    background: #5bdae3;
-
-    &::before {
-      color: #5bdae3;
-    }
-  }
-
-  .tip .admonition-title {
-    background: #5bcb88;
-
-    &::before {
-      color: #5bcb88;
-    }
+    background: var(--bs-info-bg-subtle);
+    color: var(--bs-info-text-emphasis);
   }
 
   .note p:last-child, .attention p:last-child, .caution p:last-child, .danger p:last-child, .error p:last-child, .hint p:last-child, .important p:last-child, .tip p:last-child, .warning p:last-child, .seealso p:last-child, .admonition p:last-child {
@@ -237,7 +225,7 @@
   }
 
   pre {
-    background-color: #f2f8fe;
+    background-color: var(--bs-secondary-bg);
   }
 
   pre.literal-block, .linenodiv pre {
@@ -345,14 +333,14 @@
   }
 
   table.docutils thead th, table.field-list thead th {
-    border-bottom: solid 1px rgba(81, 80, 79, 0.3);
-    border-left: solid 1px rgba(81, 80, 79, 0.3);
+    border-bottom: solid 1px var(--bs-border-color);
+    border-left: solid 1px var(--bs-border-color);
   }
 
   table.docutils thead th p, table.field-list thead th p {
     font-weight: bold;
     font-size: 18px;
-    color: #51504f;
+    color: var(--bs-emphasis-color);
     line-height: 1.33;
     margin-bottom: 0;
   }
@@ -367,16 +355,16 @@
   }
 
   table.docutils:not(.field-list) tr:nth-child(2n-1) td {
-    background-color: rgba(112, 112, 112, 0.05);
+    background-color: var(--bs-secondary-bg);
   }
 
   table.docutils {
-    border: 1px solid rgba(81, 80, 79, 0.3);
+    border: 1px solid var(--bs-border-color);
   }
 
   table.docutils td {
-    border-bottom: 1px solid rgba(81, 80, 79, 0.3);
-    border-left: 1px solid rgba(81, 80, 79, 0.3);
+    border-bottom: 1px solid var(--bs-border-color);
+    border-left: 1px solid var(--bs-border-color);
   }
 
   table.docutils tbody > tr:last-child td {
@@ -403,12 +391,12 @@
   }
 
   code.literal {
-    color: #E74C3C
+    color: var(--bs-danger-text-emphasis);
   }
 
   code.xref, a code {
     font-weight: bold;
-    color: #707070;
+    color: var(--bs-body-color);
   }
 
   pre, kbd {
@@ -424,7 +412,7 @@
   }
 
   a code {
-    color: #2980B9
+    color: var(--bs-link-color);
   }
 
   dl {
@@ -456,9 +444,9 @@
     margin: 6px 0;
     font-size: 100%;
     line-height: 1.63;
-    background: #f3fbff;
-    color: #51504f;
-    border-top: solid 4px #68d1ff;
+    background: var(--bs-info-bg-subtle);
+    color: var(--bs-emphasis-color);
+    border-top: solid 4px var(--bs-info-border-subtle);
     padding: 8px 10px;
     position: relative;
 
@@ -468,28 +456,28 @@
   }
 
   dl:not(.docutils) dt:before {
-    color: #68d1ff
+    color: var(--bs-info-text-emphasis);
   }
 
   dl:not(.docutils) dt .headerlink {
-    color: #707070;
+    color: var(--bs-body-color);
     font-size: 100% !important
   }
 
   dl:not(.docutils) dt .fn-backref {
-    color: #0cb6ff;
+    color: var(--bs-link-color);
   }
 
   dl:not(.docutils) dl dt {
     margin-bottom: 6px;
     border: none;
-    border-left: solid 8px #a6a6a6;
-    background: #f8f8f8;
-    color: #707070
+    border-left: solid 8px var(--bs-border-color);
+    background: var(--bs-secondary-bg);
+    color: var(--bs-body-color);
   }
 
   dl:not(.docutils) dl dt .headerlink {
-    color: #707070;
+    color: var(--bs-body-color);
     font-size: 100% !important
   }
 
@@ -515,7 +503,7 @@
   dl:not(.docutils) .optional {
     display: inline-block;
     padding: 0 4px;
-    color: #51504f;
+    color: var(--bs-emphasis-color);
     font-weight: bold
   }
 
@@ -535,7 +523,7 @@
 
   .example-header {
     position: relative;
-    background: #017cee;
+    background: var(--bs-primary);
     padding: 8px 16px;
     margin-bottom: 0;
   }
@@ -605,11 +593,11 @@
   }
 
   .viewcode-button:visited {
-    color: #404040;
+    color: var(--bs-body-color);
   }
 
   .viewcode-button:hover, .viewcode-button:focus {
-    color: #404040;
+    color: var(--bs-emphasis-color);
   }
 
   .section {
@@ -624,3 +612,264 @@
     }
   }
 }
+
+// Dark mode styles using Bootstrap 5's CSS variables
+// This ensures consistency with Bootstrap's design system
+[data-bs-theme="dark"] {
+  .rst-content {
+    color: var(--bs-body-color);
+
+    h1, h2, h3, h4, h5, h6 {
+      color: var(--bs-emphasis-color);
+    }
+
+    p {
+      color: var(--bs-body-color);
+    }
+
+    // Make rubric headings more visible
+    p.rubric {
+      color: var(--bs-emphasis-color);
+      font-weight: bold;
+    }
+
+    a {
+      color: var(--bs-link-color);
+
+      &:hover {
+        color: var(--bs-link-hover-color);
+      }
+    }
+
+    code {
+      background-color: var(--bs-secondary-bg);
+      color: var(--bs-code-color);
+    }
+
+            // Syntax highlighting for code blocks in dark mode
+            // Generated via: cd sphinx_airflow_theme/demo && uv run pygmentize -S github-dark -f html -a ".highlight" > ../../landing-pages/site/assets/scss/pygments/_dark.scss
+            // To change theme: replace "github-dark" with another Pygments style (run: uv run pygmentize -L styles)
+            @import "pygments/dark";
+
+    // Override background to use Bootstrap variables for consistency
+    .highlight {
+      background: var(--bs-secondary-bg) !important;
+
+      pre {
+        background: var(--bs-secondary-bg) !important;
+      }
+    }
+
+    pre {
+      background: var(--bs-secondary-bg) !important;
+      border-color: var(--bs-border-color);
+      color: var(--bs-body-color);
+    }
+
+    // Doc test blocks
+    .doctest {
+      background: var(--bs-secondary-bg) !important;
+
+      .gp, .go {
+        color: var(--bs-body-color) !important;
+      }
+    }
+
+    table {
+      border-color: var(--bs-border-color);
+
+      th {
+        background: var(--bs-tertiary-bg) !important;
+        color: var(--bs-emphasis-color) !important;
+        border-color: var(--bs-border-color) !important;
+      }
+
+      td {
+        border-color: var(--bs-border-color);
+        color: var(--bs-body-color);
+        background-color: var(--bs-body-bg);
+      }
+
+      // Alternating row colors for better readability
+      &.docutils:not(.field-list) tr:nth-child(2n-1) td {
+        background-color: var(--bs-secondary-bg) !important;
+      }
+    }
+
+    .admonition {
+      background-color: var(--bs-secondary-bg);
+      border-color: var(--bs-border-color);
+
+      .admonition-title {
+        background-color: var(--bs-tertiary-bg);
+        color: var(--bs-emphasis-color);
+      }
+    }
+
+    // Info-type admonitions (blue/teal)
+    .note, .seealso, .important {
+      background: var(--bs-info-bg-subtle);
+      border-color: var(--bs-info-border-subtle);
+    }
+
+    // Success-type admonitions (green/blue)
+    .hint, .tip {
+      background: var(--bs-success-bg-subtle);
+      border-color: var(--bs-success-border-subtle);
+    }
+
+    // Danger-type admonitions (red)
+    .error, .danger {
+      background: var(--bs-danger-bg-subtle);
+      border-color: var(--bs-danger-border-subtle);
+    }
+
+    // Warning-type admonitions (orange/yellow)
+    .warning, .attention, .caution {
+      background: var(--bs-warning-bg-subtle);
+      border-color: var(--bs-warning-border-subtle);
+    }
+
+    .viewcode-button {
+      color: var(--bs-body-color);
+
+      &:visited, &:hover, &:focus {
+        color: var(--bs-emphasis-color);
+      }
+    }
+
+    dt {
+      color: var(--bs-emphasis-color);
+    }
+
+    dd {
+      color: var(--bs-secondary-color);
+    }
+  }
+
+  // Main layout
+  .base-layout {
+    background-color: var(--bs-body-bg);
+  }
+
+  .roadmap {
+    background-color: var(--bs-body-bg);
+  }
+
+  // Sidebar navigation
+  .wy-nav-side-toc {
+    background-color: var(--bs-secondary-bg) !important;
+    border-color: var(--bs-border-color);
+
+    a {
+      color: var(--bs-emphasis-color) !important; // Changed from secondary-color for better readability, !important to override .roadmap specificity
+
+      &:hover {
+        color: var(--bs-link-color) !important; // Use link color for interactivity
+      }
+    }
+
+    .caption {
+      color: var(--bs-emphasis-color);
+      font-weight: 600;
+    }
+  }
+
+  // Also handle roadmap-specific selectors
+  .roadmap .wy-nav-side-toc .wy-menu-vertical a {
+    color: var(--bs-emphasis-color) !important;
+
+    &:hover {
+      color: var(--bs-link-color) !important;
+    }
+  }
+
+  .td-sidebar {
+    background-color: var(--bs-secondary-bg) !important;
+    border-color: var(--bs-border-color);
+
+    a {
+      color: var(--bs-emphasis-color); // Changed from body-color for better visibility
+
+      &:hover, &.active {
+        color: var(--bs-link-color); // Use link color for interactivity
+      }
+    }
+
+    h2, h3, h4 {
+      color: var(--bs-emphasis-color);
+    }
+
+    // Make section headings like "REFERENCES" more visible
+    .td-sidebar-nav__section-title,
+    .caption {
+      color: var(--bs-emphasis-color) !important; // Changed from secondary-color
+      font-weight: 700; // Increased from 600
+      text-transform: uppercase;
+      letter-spacing: 0.5px;
+      font-size: 0.75rem;
+    }
+
+    .form-control {
+      background-color: var(--bs-tertiary-bg);
+      border-color: var(--bs-border-color);
+      color: var(--bs-body-color);
+
+      &::placeholder {
+        color: var(--bs-secondary-color);
+      }
+
+      &:focus {
+        background-color: var(--bs-body-bg);
+        border-color: var(--bs-link-color);
+        color: var(--bs-emphasis-color);
+      }
+    }
+
+    button {
+      background-color: var(--bs-secondary-bg);
+      border-color: var(--bs-border-color);
+      color: var(--bs-body-color);
+
+      &:hover {
+        background-color: var(--bs-tertiary-bg);
+        color: var(--bs-emphasis-color);
+      }
+    }
+  }
+
+  // Version selector and dropdowns
+  .docs-version-selector,
+  .sidebar__version-selector {
+    background-color: var(--bs-secondary-bg);
+    border-color: var(--bs-border-color);
+    color: var(--bs-body-color);
+
+    button {
+      background-color: var(--bs-secondary-bg);
+      border-color: var(--bs-border-color);
+      color: var(--bs-body-color);
+
+      &:hover {
+        background-color: var(--bs-tertiary-bg);
+      }
+    }
+  }
+
+  // Breadcrumbs
+  .breadcrumb {
+    background-color: transparent;
+
+    a {
+      color: var(--bs-link-color);
+    }
+
+    .breadcrumb-item {
+      color: var(--bs-secondary-color);
+
+      &::before {
+        color: var(--bs-border-color);
+      }
+    }
+  }
+}
diff --git a/landing-pages/site/assets/scss/_variables.scss b/landing-pages/site/assets/scss/_variables.scss
index 1ba7fe4335..93e12503ca 100644
--- a/landing-pages/site/assets/scss/_variables.scss
+++ b/landing-pages/site/assets/scss/_variables.scss
@@ -59,7 +59,7 @@ $code-color: darken($secondary, 20%) !default;
 // UI element colors
 
 $border-color: $gray-300 !default;
-$td-sidebar-tree-root-color: $primary !default;
+$td-sidebar-tree-root-color: $primary !default; // Required by Docsy v0.2.0+ for sidebar tree styling
 $td-sidebar-bg-color: rgba($primary, 0.03) !default;
 $td-sidebar-border-color: $border-color !default;
 
@@ -78,7 +78,7 @@ $link-hover-decoration: none !default;
 $google_font_name: "Open Sans" !default;
 $google_font_family: "Open+Sans:300,300i,400,400i,700,700i" !default;
 $web-font-path: "/external/css/OpenSans.css";
-$font-awesome-font-name: "Font Awesome 6 Free" !default;
+$font-awesome-font-name: "Font Awesome 6 Free" !default; // Required by Docsy v0.6.0+ for Font Awesome 6 compatibility
 
 $td-fonts-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
 
diff --git a/landing-pages/site/assets/scss/main-custom.scss b/landing-pages/site/assets/scss/main-custom.scss
index fb5887e204..ed49f47c28 100644
--- a/landing-pages/site/assets/scss/main-custom.scss
+++ b/landing-pages/site/assets/scss/main-custom.scss
@@ -17,10 +17,10 @@
  * under the License.
  */
 
+@import url('/external/css/OpenSans.css');
 @import url('/external/css/Rubik.css');
 @import url('/external/css/Roboto.css');
 @import url('/external/css/RobotoMono.css');
-
 @import "typography";
 @import "accordion";
 @import "buttons";
diff --git a/landing-pages/site/assets/scss/pygments/_dark.scss b/landing-pages/site/assets/scss/pygments/_dark.scss
new file mode 100644
index 0000000000..8c42469020
--- /dev/null
+++ b/landing-pages/site/assets/scss/pygments/_dark.scss
@@ -0,0 +1,121 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Generated using: pygmentize -S github-dark -f html -a '.highlight'
+
+/*
+ * Pygments Syntax Highlighting - GitHub Dark Theme
+ *
+ * DO NOT EDIT THIS FILE MANUALLY - IT IS GENERATED
+ *
+ * To regenerate:
+ *   cd sphinx_airflow_theme/demo
+ *   uv run pygmentize -S github-dark -f html -a ".highlight" > ../../landing-pages/site/assets/scss/pygments/_dark.scss
+ *
+ * To list available themes: uv run pygmentize -L styles
+ *
+ * Generated: 2025-11-07
+ */
+
+pre { line-height: 125%; }
+td.linenos .normal { color: #6e7681; background-color: #0d1117; padding-left: 5px; padding-right: 5px; }
+span.linenos { color: #6e7681; background-color: #0d1117; padding-left: 5px; padding-right: 5px; }
+td.linenos .special { color: #e6edf3; background-color: #6e7681; padding-left: 5px; padding-right: 5px; }
+span.linenos.special { color: #e6edf3; background-color: #6e7681; padding-left: 5px; padding-right: 5px; }
+.highlight .hll { background-color: #6e7681 }
+.highlight { background: #0d1117; color: #E6EDF3 }
+.highlight .c { color: #8B949E; font-style: italic } /* Comment */
+.highlight .err { color: #F85149 } /* Error */
+.highlight .esc { color: #E6EDF3 } /* Escape */
+.highlight .g { color: #E6EDF3 } /* Generic */
+.highlight .k { color: #FF7B72 } /* Keyword */
+.highlight .l { color: #A5D6FF } /* Literal */
+.highlight .n { color: #E6EDF3 } /* Name */
+.highlight .o { color: #FF7B72; font-weight: bold } /* Operator */
+.highlight .x { color: #E6EDF3 } /* Other */
+.highlight .p { color: #E6EDF3 } /* Punctuation */
+.highlight .ch { color: #8B949E; font-style: italic } /* Comment.Hashbang */
+.highlight .cm { color: #8B949E; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #8B949E; font-weight: bold; font-style: italic } /* Comment.Preproc */
+.highlight .cpf { color: #8B949E; font-style: italic } /* Comment.PreprocFile */
+.highlight .c1 { color: #8B949E; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #8B949E; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #FFA198; background-color: #490202 } /* Generic.Deleted */
+.highlight .ge { color: #E6EDF3; font-style: italic } /* Generic.Emph */
+.highlight .ges { color: #E6EDF3; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
+.highlight .gr { color: #FFA198 } /* Generic.Error */
+.highlight .gh { color: #79C0FF; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #56D364; background-color: #0F5323 } /* Generic.Inserted */
+.highlight .go { color: #8B949E } /* Generic.Output */
+.highlight .gp { color: #8B949E } /* Generic.Prompt */
+.highlight .gs { color: #E6EDF3; font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #79C0FF } /* Generic.Subheading */
+.highlight .gt { color: #FF7B72 } /* Generic.Traceback */
+.highlight .g-Underline { color: #E6EDF3; text-decoration: underline } /* Generic.Underline */
+.highlight .kc { color: #79C0FF } /* Keyword.Constant */
+.highlight .kd { color: #FF7B72 } /* Keyword.Declaration */
+.highlight .kn { color: #FF7B72 } /* Keyword.Namespace */
+.highlight .kp { color: #79C0FF } /* Keyword.Pseudo */
+.highlight .kr { color: #FF7B72 } /* Keyword.Reserved */
+.highlight .kt { color: #FF7B72 } /* Keyword.Type */
+.highlight .ld { color: #79C0FF } /* Literal.Date */
+.highlight .m { color: #A5D6FF } /* Literal.Number */
+.highlight .s { color: #A5D6FF } /* Literal.String */
+.highlight .na { color: #E6EDF3 } /* Name.Attribute */
+.highlight .nb { color: #E6EDF3 } /* Name.Builtin */
+.highlight .nc { color: #F0883E; font-weight: bold } /* Name.Class */
+.highlight .no { color: #79C0FF; font-weight: bold } /* Name.Constant */
+.highlight .nd { color: #D2A8FF; font-weight: bold } /* Name.Decorator */
+.highlight .ni { color: #FFA657 } /* Name.Entity */
+.highlight .ne { color: #F0883E; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #D2A8FF; font-weight: bold } /* Name.Function */
+.highlight .nl { color: #79C0FF; font-weight: bold } /* Name.Label */
+.highlight .nn { color: #FF7B72 } /* Name.Namespace */
+.highlight .nx { color: #E6EDF3 } /* Name.Other */
+.highlight .py { color: #79C0FF } /* Name.Property */
+.highlight .nt { color: #7EE787 } /* Name.Tag */
+.highlight .nv { color: #79C0FF } /* Name.Variable */
+.highlight .ow { color: #FF7B72; font-weight: bold } /* Operator.Word */
+.highlight .pm { color: #E6EDF3 } /* Punctuation.Marker */
+.highlight .w { color: #6E7681 } /* Text.Whitespace */
+.highlight .mb { color: #A5D6FF } /* Literal.Number.Bin */
+.highlight .mf { color: #A5D6FF } /* Literal.Number.Float */
+.highlight .mh { color: #A5D6FF } /* Literal.Number.Hex */
+.highlight .mi { color: #A5D6FF } /* Literal.Number.Integer */
+.highlight .mo { color: #A5D6FF } /* Literal.Number.Oct */
+.highlight .sa { color: #79C0FF } /* Literal.String.Affix */
+.highlight .sb { color: #A5D6FF } /* Literal.String.Backtick */
+.highlight .sc { color: #A5D6FF } /* Literal.String.Char */
+.highlight .dl { color: #79C0FF } /* Literal.String.Delimiter */
+.highlight .sd { color: #A5D6FF } /* Literal.String.Doc */
+.highlight .s2 { color: #A5D6FF } /* Literal.String.Double */
+.highlight .se { color: #79C0FF } /* Literal.String.Escape */
+.highlight .sh { color: #79C0FF } /* Literal.String.Heredoc */
+.highlight .si { color: #A5D6FF } /* Literal.String.Interpol */
+.highlight .sx { color: #A5D6FF } /* Literal.String.Other */
+.highlight .sr { color: #79C0FF } /* Literal.String.Regex */
+.highlight .s1 { color: #A5D6FF } /* Literal.String.Single */
+.highlight .ss { color: #A5D6FF } /* Literal.String.Symbol */
+.highlight .bp { color: #E6EDF3 } /* Name.Builtin.Pseudo */
+.highlight .fm { color: #D2A8FF; font-weight: bold } /* Name.Function.Magic */
+.highlight .vc { color: #79C0FF } /* Name.Variable.Class */
+.highlight .vg { color: #79C0FF } /* Name.Variable.Global */
+.highlight .vi { color: #79C0FF } /* Name.Variable.Instance */
+.highlight .vm { color: #79C0FF } /* Name.Variable.Magic */
+.highlight .il { color: #A5D6FF } /* Literal.Number.Integer.Long */
diff --git a/landing-pages/site/layouts/partials/navbar.html b/landing-pages/site/layouts/_partials/navbar.html
similarity index 88%
copy from landing-pages/site/layouts/partials/navbar.html
copy to landing-pages/site/layouts/_partials/navbar.html
index 858d9dcbac..882374cb8c 100644
--- a/landing-pages/site/layouts/partials/navbar.html
+++ b/landing-pages/site/layouts/_partials/navbar.html
@@ -29,6 +29,11 @@
         {{ template "menu-content" . }}
     </div>
     <div class="no-desktop navbar__drawer-container">
+        {{ if .Site.Params.ui.showLightDarkModeMenu -}}
+        <div class="navbar__theme-toggle">
+            {{ partial "theme-toggler" . }}
+        </div>
+        {{ end -}}
         <button class="navbar__toggle-button" id="navbar-toggle-button">
             {{ with resources.Get "icons/hamburger-icon.svg" }}
                 <div id="hamburger-icon" class="navbar__toggle-button--icon visible">
@@ -63,6 +68,11 @@
                     {{ $el.Name }}
                 </a>
             {{ end }}
+            {{ if .Site.Params.ui.showLightDarkModeMenu -}}
+            <div class="navbar__theme-toggle">
+                {{ partial "theme-toggler" . }}
+            </div>
+            {{ end -}}
         </div>
     </div>
 {{ end }}
diff --git a/landing-pages/site/layouts/_default/baseof.html b/landing-pages/site/layouts/partials/hooks/body-end.html
similarity index 59%
rename from landing-pages/site/layouts/_default/baseof.html
rename to landing-pages/site/layouts/partials/hooks/body-end.html
index 8858e75f7c..0d005ba75f 100644
--- a/landing-pages/site/layouts/_default/baseof.html
+++ b/landing-pages/site/layouts/partials/hooks/body-end.html
@@ -17,28 +17,8 @@
  under the License.
 */}}
 
-<!doctype html>
-<html lang="{{ .Site.Language.Lang }}" class="no-js">
-<head>
-    {{ partial "head.html" . }}
-</head>
-<body class="td-{{ .Kind }}">
-<header>
-    {{ partial "navbar.html" . }}
-</header>
-<div class="container-fluid td-default">
-    {{ block "animation-header" . }}{{ end }}
-    <div class="home-page-layout base-layout">
-        <main role="main" class="td-main container">
-            {{ block "main" . }}{{ end }}
-        </main>
-        {{ partial "suggest-change" . }}
-    </div>
-</div>
-{{ partialCached "footer.html" . }}
-{{ partial "scripts.html" . }}
-</body>
+{{/* Include webpack-generated main.js for confetti animation and other features */}}
 {{ with .Site.Data.webpack }}
     <script src="{{ relURL .main.js }}"></script>
 {{ end }}
-</html>
+
diff --git a/landing-pages/site/layouts/partials/navbar.html b/landing-pages/site/layouts/partials/navbar.html
index 858d9dcbac..84e037a310 100644
--- a/landing-pages/site/layouts/partials/navbar.html
+++ b/landing-pages/site/layouts/partials/navbar.html
@@ -27,8 +27,18 @@
     </div>
     <div class="desktop-only navbar__menu-container">
         {{ template "menu-content" . }}
+        {{ if .Site.Params.ui.showLightDarkModeMenu -}}
+        <div class="navbar__theme-toggle">
+            {{ partial "theme-toggler" . }}
+        </div>
+        {{ end -}}
     </div>
     <div class="no-desktop navbar__drawer-container">
+        {{ if .Site.Params.ui.showLightDarkModeMenu -}}
+        <div class="navbar__theme-toggle">
+            {{ partial "theme-toggler" . }}
+        </div>
+        {{ end -}}
         <button class="navbar__toggle-button" id="navbar-toggle-button">
             {{ with resources.Get "icons/hamburger-icon.svg" }}
                 <div id="hamburger-icon" class="navbar__toggle-button--icon visible">
diff --git a/landing-pages/site/layouts/partials/scripts.html.backup b/landing-pages/site/layouts/partials/scripts.html.backup
deleted file mode 100644
index b6be1b26d4..0000000000
--- a/landing-pages/site/layouts/partials/scripts.html.backup
+++ /dev/null
@@ -1,14 +0,0 @@
-
-<script src="/external/js/cdnjs.cloudflare.com-1.14.3-popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
-<script src="/external/js/stackpath.bootstrapcdn.com-4.1.3-bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
-{{ $jsBase := resources.Get "js/base.js" }}
-{{ $jsAnchor := resources.Get "js/anchor.js" }}
-{{ $jsSearch := resources.Get "js/search.js" | resources.ExecuteAsTemplate "js/search.js" .Site.Home }}
-{{ $js := (slice $jsBase $jsAnchor $jsSearch) | resources.Concat "js/main.js" }}
-{{ if hugo.IsServer }}
-<script src="{{ $js.RelPermalink }}"></script>
-{{ else }}
-{{ $js := $js | minify | fingerprint }}
-<script src="{{ $js.RelPermalink }}" integrity="{{ $js.Data.Integrity }}" crossorigin="anonymous"></script>
-{{ end }}
-{{ partial "hooks/body-end.html" . }}
diff --git a/landing-pages/src/js/headerAnimation.js b/landing-pages/src/js/headerAnimation.js
index 55c11f65c1..9b77f3a49d 100644
--- a/landing-pages/src/js/headerAnimation.js
+++ b/landing-pages/src/js/headerAnimation.js
@@ -210,7 +210,6 @@ export function initHeaderAnimation() {
   const button = document.querySelector("#header-button");
 
   documentReady(function() {
-
     new p5((sketch) => {
 
       let colors = [];
@@ -237,7 +236,14 @@ export function initHeaderAnimation() {
       };
 
       sketch.draw = () => {
-        sketch.background(255, 255, 255);
+        // Dark mode support: dynamically set canvas background based on theme
+        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);
+        }
+
         if (DRAW_SAFE_AREA) {
           logoArea.draw(sketch);
         }
diff --git a/sphinx_airflow_theme/sphinx_airflow_theme/globaltoc.html b/sphinx_airflow_theme/sphinx_airflow_theme/globaltoc.html
index c5d5951628..11c277fb67 100644
--- a/sphinx_airflow_theme/sphinx_airflow_theme/globaltoc.html
+++ b/sphinx_airflow_theme/sphinx_airflow_theme/globaltoc.html
@@ -87,4 +87,24 @@
         color: #707070;
     }
 
+    /* Dark mode support */
+    [data-bs-theme="dark"] .toctree .caption {
+        color: rgba(255, 255, 255, 0.95);
+    }
+    [data-bs-theme="dark"] .toctree li {
+        color: rgba(255, 255, 255, 0.85);
+    }
+    [data-bs-theme="dark"] .toctree a {
+        color: rgba(255, 255, 255, 0.85);
+    }
+    [data-bs-theme="dark"] .toctree a:hover {
+        color: rgba(255, 255, 255, 1);
+    }
+    [data-bs-theme="dark"] .toctree .current > a:not([href="#"]) {
+        color: #68d2fe;
+    }
+    [data-bs-theme="dark"] .toctree .current {
+        color: #68d2fe;
+    }
+
 </style>
diff --git a/sphinx_airflow_theme/sphinx_airflow_theme/header.html b/sphinx_airflow_theme/sphinx_airflow_theme/header.html
index f8f1d64554..9bdc02163f 100644
--- a/sphinx_airflow_theme/sphinx_airflow_theme/header.html
+++ b/sphinx_airflow_theme/sphinx_airflow_theme/header.html
@@ -59,6 +59,40 @@
                             {{ link.text }}
                         </a>
                     {% endfor %}
+                    <div class="navbar__theme-toggle">
+                        <button class="btn btn-link nav-link dropdown-toggle d-flex align-items-center"
+                                id="bd-theme"
+                                type="button"
+                                aria-expanded="false"
+                                data-bs-toggle="dropdown"
+                                data-bs-display="static"
+                                aria-label="Toggle theme (auto)">
+                            <svg class="bi my-1 theme-icon-active"><use href="#circle-half"></use></svg>
+                        </button>
+                        <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bd-theme-text">
+                            <li>
+                                <button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="false">
+                                    <svg class="bi me-2 opacity-50"><use href="#sun-fill"></use></svg>
+                                    Light
+                                    <svg class="bi ms-auto d-none"><use href="#check2"></use></svg>
+                                </button>
+                            </li>
+                            <li>
+                                <button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="false">
+                                    <svg class="bi me-2 opacity-50"><use href="#moon-stars-fill"></use></svg>
+                                    Dark
+                                    <svg class="bi ms-auto d-none"><use href="#check2"></use></svg>
+                                </button>
+                            </li>
+                            <li>
+                                <button type="button" class="dropdown-item d-flex align-items-center active" data-bs-theme-value="auto" aria-pressed="true">
+                                    <svg class="bi me-2 opacity-50"><use href="#circle-half"></use></svg>
+                                    Auto
+                                    <svg class="bi ms-auto d-none"><use href="#check2"></use></svg>
+                                </button>
+                            </li>
+                        </ul>
+                    </div>
                 </div>
 
                 {% if not theme_hide_website_buttons %}
diff --git a/sphinx_airflow_theme/sphinx_airflow_theme/layout.html b/sphinx_airflow_theme/sphinx_airflow_theme/layout.html
index 09a7566fe4..c518458ff9 100644
--- a/sphinx_airflow_theme/sphinx_airflow_theme/layout.html
+++ b/sphinx_airflow_theme/sphinx_airflow_theme/layout.html
@@ -215,8 +215,8 @@
     <script type="text/javascript" src="{{ pathto('_static/_gen/js/docs.js', 1) }}"></script>
     <script type="text/javascript" id="documentation_options" data-url_root="{{ pathto('', 1) }}" src="{{ pathto('_static/documentation_options.js', 1) }}"></script>
     <script src="/external/js/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
-    <script src="/external/js/cdnjs.cloudflare.com-1.14.3-popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
-    <script src="/external/js/stackpath.bootstrapcdn.com-4.1.3-bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
+    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
+    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script>
     {%- for js in script_files %}
         {{ js_tag(js) }}
     {%- endfor %}
@@ -324,6 +324,105 @@
 
 {%- block body_tag %}<body class="td-section">{% endblock %}
 
+<svg xmlns="http://www.w3.org/2000/svg" class="d-none">
+  <symbol id="check2" viewBox="0 0 16 16">
+    <path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/>
+  </symbol>
+  <symbol id="circle-half" viewBox="0 0 16 16">
+    <path d="M8 15A7 7 0 1 0 8 1v14zm0 1A8 8 0 1 1 8 0a8 8 0 0 1 0 16z"/>
+  </symbol>
+  <symbol id="moon-stars-fill" viewBox="0 0 16 16">
+    <path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z"/>
+    <path d="M10.794 3.148a.217.217 0 0 1 .412 0l.387 1.162c.173.518.579.924 1.097 1.097l1.162.387a.217.217 0 0 1 0 .412l-1.162.387a1.734 1.734 0 0 0-1.097 1.097l-.387 1.162a.217.217 0 0 1-.412 0l-.387-1.162A1.734 1.734 0 0 0 9.31 6.593l-1.162-.387a.217.217 0 0 1 0-.412l1.162-.387a1.734 1.734 0 0 0 1.097-1.097l.387-1.162zM13.863.099a.145.145 0 0 1 .274 0l.258.774c.115.346.386.617.732.732l.774.258a.145.145 0 0 1 0 .274l-.774.258a1.156 1.156 0 0 0-.732.732l-.258.774a.145.145 0 0 1-.274 0l- [...]
+  </symbol>
+  <symbol id="sun-fill" viewBox="0 0 16 16">
+    <path d="M8 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.70 [...]
+  </symbol>
+</svg>
+
+<script>
+  /*!
+   * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
+   * Copyright 2011-2024 The Bootstrap Authors
+   * Licensed under Creative Commons Attribution 3.0 Unported License.
+   */
+
+  (() => {
+    'use strict'
+
+    const getStoredTheme = () => localStorage.getItem('theme')
+    const setStoredTheme = theme => localStorage.setItem('theme', theme)
+
+    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())
+
+    const showActiveTheme = (theme, focus = false) => {
+      const themeSwitcher = document.querySelector('#bd-theme')
+
+      if (!themeSwitcher) {
+        return
+      }
+
+      const themeSwitcherText = document.querySelector('#bd-theme-text')
+      const activeThemeIcon = document.querySelector('.theme-icon-active use')
+      const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
+      const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')
+
+      document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
+        element.classList.remove('active')
+        element.setAttribute('aria-pressed', 'false')
+      })
+
+      btnToActive.classList.add('active')
+      btnToActive.setAttribute('aria-pressed', 'true')
+      activeThemeIcon.setAttribute('href', svgOfActiveBtn)
+      const themeSwitcherLabel = `${themeSwitcherText ? themeSwitcherText.textContent : ''} (${btnToActive.dataset.bsThemeValue})`
+      themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
+
+      if (focus) {
+        themeSwitcher.focus()
+      }
+    }
+
+    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
+      const storedTheme = getStoredTheme()
+      if (storedTheme !== 'light' && storedTheme !== 'dark') {
+        setTheme(getPreferredTheme())
+      }
+    })
+
+    window.addEventListener('DOMContentLoaded', () => {
+      showActiveTheme(getPreferredTheme())
+
+      document.querySelectorAll('[data-bs-theme-value]')
+        .forEach(toggle => {
+          toggle.addEventListener('click', () => {
+            const theme = toggle.getAttribute('data-bs-theme-value')
+            setStoredTheme(theme)
+            setTheme(theme)
+            showActiveTheme(theme, true)
+          })
+        })
+    })
+  })()
+</script>
+
 {%- block header %}
     {% include "header.html" %}
 {% endblock %}