This is an automated email from the ASF dual-hosted git repository.
kaxilnaik pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow-site.git
The following commit(s) were added to refs/heads/main by this push:
new 66043cc438 Upgrade ancient Docsy theme and implement dark mode (#1270)
66043cc438 is described below
commit 66043cc4380b50800a569c755d83fe23899f1997
Author: Kaxil Naik <[email protected]>
AuthorDate: Wed Dec 17 02:22:40 2025 +0000
Upgrade ancient Docsy theme and implement dark mode (#1270)
* 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.
* 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
Fix CSS lint errors and add dark mode support for blog page
- Replace hardcoded colors in blog page with Bootstrap CSS variables
- Fix CSS specificity linting errors in rating component
- Add stylelint disable for dark mode block where linter doesn't understand
theme context
* Upgrade Hugo to 0.146.0 and install Docsy NPM dependencies
The Docsy v0.12.0 theme requires Hugo 0.146.0+ and uses
Bootstrap/FontAwesome
as NPM dependencies rather than Hugo modules.
Changes:
- Upgraded Hugo from 0.135.0 to 0.146.0 (minimum required by Docsy v0.12.0)
- Added npm install step in Docsy theme directory to install Bootstrap 5.3.6
and FontAwesome 6.7.2 from theme's package.json
The theme's hugo.yaml mounts these from node_modules/ directories. No Go
installation or Hugo module commands needed.
Tested with act - build completes successfully.
* Fix CSS generation for Docsy v0.12.0 upgrade
Custom CSS (main-custom.scss) was not being generated after upgrading
Docsy from v0.2.0-pre to v0.12.0.
Root cause:
Docsy v0.12.0 has layouts/_partials/head.html which Hugo prioritizes
over our layouts/partials/head.html, so our CSS processing wasn't called.
Fix:
- Add layouts/_partials/head.html to override Docsy's template
- Add layouts/_partials/head-css.html (must exist in same directory)
- Remove CSS processing from head-end.html hook (moved to head-css.html)
* Vendor external JS
* docs(theme): improve dark-mode docs sidebar contrast
- Add dark-mode overrides for Docsy/Sphinx left sidebar (CONTENT) toctree
links
---
.github/workflows/build.yml | 5 +-
landing-pages/.gitignore | 1 +
landing-pages/site/assets/scss/_blog-page.scss | 33 ++
landing-pages/site/assets/scss/_colors.scss | 5 +
landing-pages/site/assets/scss/_header.scss | 21 +
landing-pages/site/assets/scss/_navbar.scss | 67 ++++
landing-pages/site/assets/scss/_rating.scss | 28 ++
landing-pages/site/assets/scss/_roadmap.scss | 5 +
landing-pages/site/assets/scss/_rst-content.scss | 445 ++++++++++++++++-----
landing-pages/site/assets/scss/_variables.scss | 2 +
landing-pages/site/assets/scss/main-custom.scss | 2 +-
landing-pages/site/assets/scss/pygments/_dark.scss | 121 ++++++
landing-pages/site/config.toml | 2 +
landing-pages/site/layouts/_default/baseof.html | 4 +-
landing-pages/site/layouts/_partials/head-css.html | 41 ++
landing-pages/site/layouts/_partials/head.html | 42 ++
.../layouts/{partials => _partials}/navbar.html | 10 +
.../baseof.html => partials/hooks/body-end.html} | 30 +-
.../site/layouts/partials/hooks/head-end.html | 10 -
landing-pages/site/layouts/partials/navbar.html | 10 +
landing-pages/site/layouts/partials/scripts.html | 14 -
.../site/static/external/js/bootstrap-5.3.3.min.js | 7 +
.../site/static/external/js/popper-2.11.8.min.js | 6 +
landing-pages/site/themes/docsy | 2 +-
landing-pages/src/js/headerAnimation.js | 10 +-
.../sphinx_airflow_theme/__init__.py | 2 +-
.../sphinx_airflow_theme/globaltoc.html | 20 +
.../sphinx_airflow_theme/header.html | 34 ++
.../sphinx_airflow_theme/layout.html | 103 ++++-
29 files changed, 929 insertions(+), 153 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b7bcd1f015..25e2685bf3 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -84,8 +84,11 @@ jobs:
- name: 📚 Install Hugo
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f
# v3.0.0
with:
- hugo-version: '0.135.0'
+ hugo-version: '0.146.0'
extended: true
+ - name: 📦 Install Docsy theme dependencies (Bootstrap & FontAwesome)
+ working-directory: /mnt/airflow-site/landing-pages/site/themes/docsy
+ run: npm install
- name: 🟢 Install node dependencies
run: |
/mnt/airflow-site/site.sh install-node-deps
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/_blog-page.scss
b/landing-pages/site/assets/scss/_blog-page.scss
index baf27066e8..53296f0e27 100644
--- a/landing-pages/site/assets/scss/_blog-page.scss
+++ b/landing-pages/site/assets/scss/_blog-page.scss
@@ -163,3 +163,36 @@
justify-content: center
}
}
+
+// Dark mode support using Bootstrap CSS variables
+[data-bs-theme="dark"] {
+ .blogpost-content {
+ &__metadata {
+ &--title {
+ color: var(--bs-emphasis-color);
+ }
+
+ &--description {
+ color: var(--bs-body-color);
+ }
+
+ &--date {
+ color: var(--bs-secondary-color);
+ }
+ }
+ }
+
+ .tag {
+ color: var(--bs-link-color);
+ background-color: var(--bs-link-color-rgb, 104, 210, 254, 0.15);
+
+ &.active, &:hover {
+ background-color: var(--bs-link-color);
+ color: var(--bs-body-bg);
+ }
+ }
+
+ .new-entry--link {
+ color: var(--bs-link-color);
+ }
+}
diff --git a/landing-pages/site/assets/scss/_colors.scss
b/landing-pages/site/assets/scss/_colors.scss
index f0ae3f4e25..948b34cc78 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 required by Docsy v0.6.0+ theme
+.-bg-orange {
+ 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..83594416a4 100644
--- a/landing-pages/site/assets/scss/_rating.scss
+++ b/landing-pages/site/assets/scss/_rating.scss
@@ -47,3 +47,31 @@
}
}
}
+
+// Dark mode styles
+// stylelint-disable no-descending-specificity
+[data-bs-theme="dark"] {
+ .rating-container {
+ p {
+ color: rgba(255, 255, 255, 0.85);
+ }
+ }
+
+ .rate-star {
+ svg {
+ path {
+ stroke: rgba(255, 255, 255, 0.75);
+ }
+ }
+
+ &:hover, &:hover ~ & {
+ svg {
+ path {
+ fill: #68d2fe;
+ stroke: none;
+ }
+ }
+ }
+ }
+}
+// stylelint-enable no-descending-specificity
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 404c584dc0..d07ec6c41f 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 {
scroll-margin-top: 130px;
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,282 @@
}
}
}
+
+// 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);
+ }
+ }
+ }
+}
+
+/* Dark-mode readability: left sidebar ("CONTENT") contrast */
+[data-bs-theme="dark"] .td-sidebar .toctree a,
+[data-bs-theme="dark"] .td-sidebar .toctree a.reference.internal,
+[data-bs-theme="dark"] .td-sidebar .toctree a.reference.internal:visited {
+ color: rgba(255, 255, 255, 0.78);
+}
+
+[data-bs-theme="dark"] .td-sidebar .toctree a:hover,
+[data-bs-theme="dark"] .td-sidebar .toctree a:focus {
+ color: rgba(255, 255, 255, 0.95);
+}
+
+[data-bs-theme="dark"] .td-sidebar .toctree li.current > a,
+[data-bs-theme="dark"] .td-sidebar .toctree li.current > a:not([href="#"]) {
+ color: #68d2fe;
+ font-weight: 600;
+}
diff --git a/landing-pages/site/assets/scss/_variables.scss
b/landing-pages/site/assets/scss/_variables.scss
index bfba27f0cd..93e12503ca 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; // 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;
@@ -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; // 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 60cb3e2ef3..c486fa2f8d 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/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/_default/baseof.html
b/landing-pages/site/layouts/_default/baseof.html
index afbac71e21..0ab0ab5673 100644
--- a/landing-pages/site/layouts/_default/baseof.html
+++ b/landing-pages/site/layouts/_default/baseof.html
@@ -44,8 +44,6 @@
</div>
{{ partialCached "footer.html" . }}
{{ partial "scripts.html" . }}
+{{ partial "hooks/body-end.html" . }}
</body>
-{{ with .Site.Data.webpack }}
- <script src="{{ relURL .main.js }}"></script>
-{{ end }}
</html>
diff --git a/landing-pages/site/layouts/_partials/head-css.html
b/landing-pages/site/layouts/_partials/head-css.html
new file mode 100644
index 0000000000..499c6e962b
--- /dev/null
+++ b/landing-pages/site/layouts/_partials/head-css.html
@@ -0,0 +1,41 @@
+{{/*
+ 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.
+*/}}
+{{/* Process Docsy's main stylesheet */}}
+{{ $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. */}}
+{{ $css := resources.Get $scssMain | toCSS (dict "enableSourceMap" true) }}
+<link href="{{ $css.RelPermalink }}" rel="stylesheet">
+{{ else }}
+{{ $css := resources.Get $scssMain | toCSS (dict "enableSourceMap" false) |
postCSS | minify | fingerprint }}
+<link rel="preload" href="{{ $css.RelPermalink }}" as="style">
+<link href="{{ $css.RelPermalink }}" rel="stylesheet" integrity="{{
$css.Data.integrity }}">
+{{ end }}
+
+{{/* Process our custom stylesheet for landing pages */}}
+{{ $scssCustom := "scss/main-custom.scss"}}
+{{ $customScssResource := resources.Get $scssCustom }}
+{{ if hugo.IsServer }}
+{{ $cssCustom := $customScssResource | toCSS (dict "enableSourceMap" true) |
postCSS }}
+<link href="{{ $cssCustom.RelPermalink }}" rel="stylesheet">
+{{ else }}
+{{ $cssCustom := $customScssResource | toCSS (dict "enableSourceMap" false) |
postCSS | minify | fingerprint }}
+<link rel="preload" href="{{ $cssCustom.RelPermalink }}" as="style">
+<link href="{{ $cssCustom.RelPermalink }}" rel="stylesheet" integrity="{{
$cssCustom.Data.integrity }}">
+{{ end }}
diff --git a/landing-pages/site/layouts/_partials/head.html
b/landing-pages/site/layouts/_partials/head.html
new file mode 100644
index 0000000000..9fc5a3b070
--- /dev/null
+++ b/landing-pages/site/layouts/_partials/head.html
@@ -0,0 +1,42 @@
+{{/*
+ 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.
+*/}}
+<meta charset="{{ .Site.Params.charset }}">
+<meta name="viewport" content="width=device-width, initial-scale=1,
shrink-to-fit=no">
+{{ hugo.Generator }}
+{{ if eq (getenv "HUGO_ENV") "production" }}
+<META NAME="ROBOTS" CONTENT="INDEX, FOLLOW">
+{{ else }}
+<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
+{{ end }}
+{{ range .AlternativeOutputFormats -}}
+<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink |
safeURL }}">
+{{ end -}}
+{{ partialCached "favicons.html" . }}
+<title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{ . }} |
{{ end }}{{ .Site.Title }}{{ end }}</title>
+{{- template "_internal/opengraph.html" . -}}
+{{- template "_internal/schema.html" . -}}
+{{ if eq (getenv "HUGO_ENV") "production" }}
+{{ template "_internal/google_analytics.html" . }}
+{{ end }}
+{{ partial "head-css.html" . }}
+<script
+ src="/external/js/jquery-3.3.1.min.js"
+ integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
+ crossorigin="anonymous"></script>
+{{ partial "hooks/head-end.html" . }}
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 50%
copy from landing-pages/site/layouts/_default/baseof.html
copy to landing-pages/site/layouts/partials/hooks/body-end.html
index afbac71e21..e783767480 100644
--- a/landing-pages/site/layouts/_default/baseof.html
+++ b/landing-pages/site/layouts/partials/hooks/body-end.html
@@ -17,35 +17,7 @@
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>
- <div class="base-layout--button">
- <div class="base-layout--scrollButton">
- {{ partial "scroll-to-top" . }}
- </div>
- <div class="base-layout--suggestButton">
- {{ partial "suggest-change" . }}
- </div>
- </div>
- </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/hooks/head-end.html
b/landing-pages/site/layouts/partials/hooks/head-end.html
index 16d8edb652..dec8657f52 100644
--- a/landing-pages/site/layouts/partials/hooks/head-end.html
+++ b/landing-pages/site/layouts/partials/hooks/head-end.html
@@ -19,16 +19,6 @@
<meta name="description" content="{{ .Description | default
$.Site.Params.description }}" />
-{{ $scssMain := "scss/main-custom.scss"}}
-{{ if hugo.IsServer }}
- {{ $css := resources.Get $scssMain | toCSS (dict "enableSourceMap" true) |
postCSS }}
- <link href="{{ $css.RelPermalink }}" rel="stylesheet">
-{{ else }}
- {{ $css := resources.Get $scssMain | toCSS (dict "enableSourceMap" false)
| postCSS | minify | fingerprint }}
- <link rel="preload" href="{{ $css.RelPermalink }}" as="style">
- <link href="{{ $css.RelPermalink }}" rel="stylesheet" integrity="{{
$css.Data.integrity }}">
-{{ end }}
-
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
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
b/landing-pages/site/layouts/partials/scripts.html
deleted file mode 100644
index b6be1b26d4..0000000000
--- a/landing-pages/site/layouts/partials/scripts.html
+++ /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/site/static/external/js/bootstrap-5.3.3.min.js
b/landing-pages/site/static/external/js/bootstrap-5.3.3.min.js
new file mode 100644
index 0000000000..d5dc5ea1f6
--- /dev/null
+++ b/landing-pages/site/static/external/js/bootstrap-5.3.3.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v5.3.3 (https://getbootstrap.com/)
+ * Copyright 2011-2024 The Bootstrap Authors
(https://github.com/twbs/bootstrap/graphs/contributors)
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ */
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof
module?module.exports=e(require("@popperjs/core")):"function"==typeof
define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof
globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,(function(t){"use
strict";function e(t){const
e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t)for(const i
in t)if("default"!==i){const
s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enu
[...]
+//# sourceMappingURL=bootstrap.min.js.map
\ No newline at end of file
diff --git a/landing-pages/site/static/external/js/popper-2.11.8.min.js
b/landing-pages/site/static/external/js/popper-2.11.8.min.js
new file mode 100644
index 0000000000..393856474d
--- /dev/null
+++ b/landing-pages/site/static/external/js/popper-2.11.8.min.js
@@ -0,0 +1,6 @@
+/**
+ * @popperjs/core v2.11.8 - MIT License
+ */
+
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof
module?t(exports):"function"==typeof
define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof
globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use
strict";function t(e){if(null==e)return window;if("[object
Window]"!==e.toString()){var t=e.ownerDocument;return
t&&t.defaultView||window}return e}function n(e){return e instanceof
t(e).Element||e instanceof Element}function r(e){return e instanceof
t(e).HTMLEle [...]
+//# sourceMappingURL=popper.min.js.map
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
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/__init__.py
b/sphinx_airflow_theme/sphinx_airflow_theme/__init__.py
index 3ca55c2761..b9a320e5d3 100644
--- a/sphinx_airflow_theme/sphinx_airflow_theme/__init__.py
+++ b/sphinx_airflow_theme/sphinx_airflow_theme/__init__.py
@@ -18,7 +18,7 @@
from os import path
from sphinx.application import Sphinx
-__version__ = '0.2.3'
+__version__ = '0.3.0'
__version_full__ = __version__
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..e9ab2f8464 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="/external/js/popper-2.11.8.min.js"></script>
+ <script src="/external/js/bootstrap-5.3.3.min.js"></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 %}