diff --git a/airflow/www/static/css/bootstrap-theme.css b/airflow/www/static/css/bootstrap-theme.css index 0b1568e8608cf..89133959c4bea 100644 --- a/airflow/www/static/css/bootstrap-theme.css +++ b/airflow/www/static/css/bootstrap-theme.css @@ -36,6 +36,24 @@ html { -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; } +html[data-color-scheme="dark"] { + filter: invert(100%) hue-rotate(180deg); +} +html[data-color-scheme="dark"] #dark_icon { + display: block; +} +html[data-color-scheme="dark"] #light_icon { + display: none; +} +html[data-color-scheme="light"] { + /* not do */ +} +html[data-color-scheme="light"] #dark_icon { + display: none; +} +html[data-color-scheme="light"] #light_icon { + display: block; +} body { margin: 0; } diff --git a/airflow/www/static/js/toggle_theme.js b/airflow/www/static/js/toggle_theme.js new file mode 100644 index 0000000000000..292c4995447c7 --- /dev/null +++ b/airflow/www/static/js/toggle_theme.js @@ -0,0 +1,46 @@ +/*! + * 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. + */ + +/* global document, localStorage */ + +const STORAGE_THEME_KEY = "darkTheme"; +const HTML_THEME_DATASET_KEY = "data-color-scheme"; +const HTML = document.documentElement; +const TOGGLE_BUTTON_ID = "themeToggleButton"; + +const getJsonFromStorage = (key) => JSON.parse(localStorage.getItem(key)); +const updateTheme = (isDark) => { + localStorage.setItem(STORAGE_THEME_KEY, isDark); + HTML.setAttribute(HTML_THEME_DATASET_KEY, isDark ? "dark" : "light"); +}; +const initTheme = () => { + const isDark = getJsonFromStorage(STORAGE_THEME_KEY); + if (isDark !== null) updateTheme(isDark); +}; +const toggleTheme = () => { + const isDark = getJsonFromStorage(STORAGE_THEME_KEY); + updateTheme(!isDark); +}; +document.addEventListener("DOMContentLoaded", () => { + const themeButton = document.getElementById(TOGGLE_BUTTON_ID); + themeButton.addEventListener("click", () => { + toggleTheme(); + }); +}); +initTheme(); diff --git a/airflow/www/templates/airflow/main.html b/airflow/www/templates/airflow/main.html index 69daa701d2651..58383651b7d8a 100644 --- a/airflow/www/templates/airflow/main.html +++ b/airflow/www/templates/airflow/main.html @@ -29,6 +29,7 @@ {% endblock %} {% block head_meta %} + {{ super() }} {% if scheduler_job is defined and (scheduler_job and scheduler_job.is_alive()) %} @@ -114,7 +115,6 @@ {% block tail_js %} {{ super() }} -