diff --git a/package.json b/package.json index 62a9d57..8cf96b3 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "node-sass": "^8.0.0", "prettier": "^2.8.1", "riot": "^7.1.0", - "riot-mui": "github:joxit/riot-5-mui#a9b0ce4", + "riot-mui": "github:joxit/riot-5-mui#a97f2d3", "rollup": "^3.9.0", "rollup-plugin-app-utils": "^1.0.6", "rollup-plugin-copy": "^3.4.0", diff --git a/src/components/docker-registry-ui.riot b/src/components/docker-registry-ui.riot index d7c065d..c051977 100644 --- a/src/components/docker-registry-ui.riot +++ b/src/components/docker-registry-ui.riot @@ -101,6 +101,19 @@ along with this program. If not, see .
  • License AGPL-3.0
  • +
  • + + wb_sunny + + brightness_2 + + +
  • @@ -156,7 +169,8 @@ along with this program. If not, see . this.state.catalogElementsLimit = props.catalogElementsLimit || 100000; this.state.pullUrl = this.pullUrl(this.state.registryUrl, props.pullUrl); this.state.useControlCacheHeader = props.useControlCacheHeader; - loadTheme(props, this.root.parentNode.style); + const theme = loadTheme(props, this.root.parentNode.style); + this.state.themeSwitch = theme === 'dark'; }, onServerChange(registryUrl) { this.update({ @@ -216,6 +230,11 @@ along with this program. If not, see . filter: value, }); }, + onThemeChange(e) { + const theme = e.target.checked ? 'dark' : 'light'; + loadTheme({ ...this.props, theme }, this.root.parentNode.style); + this.update({ themeSwitch: e.target.checked }); + }, baseRoute: '([^#]*?)/(\\?[^#]*?)?(#!)?(/?)', router, version, @@ -245,5 +264,9 @@ along with this program. If not, see . material-footer .material-footer-logo { color: var(--footer-text); } + + material-switch i { + user-select: none; + } diff --git a/src/index.js b/src/index.js index 60ac3ac..a76338c 100644 --- a/src/index.js +++ b/src/index.js @@ -13,6 +13,7 @@ import { MaterialDropdown, MaterialPopup, MaterialInput, + MaterialSwitch, } from 'riot-mui'; import DockerRegistryUI from './components/docker-registry-ui.riot'; @@ -31,6 +32,7 @@ register('material-tabs', MaterialTabs); register('material-dropdown', MaterialDropdown); register('material-popup', MaterialPopup); register('material-input', MaterialInput); +register('material-switch', MaterialSwitch); const createApp = component(DockerRegistryUI); const tags = document.getElementsByTagName('docker-registry-ui'); diff --git a/src/scripts/theme.js b/src/scripts/theme.js index b919c74..d1be707 100644 --- a/src/scripts/theme.js +++ b/src/scripts/theme.js @@ -23,6 +23,8 @@ const DARK_THEME = { 'footer-background': '#555', }; +const LOCAL_STORAGE_THEME = 'registryUiTheme'; + let THEME; const normalizeKey = (k) => @@ -33,19 +35,30 @@ const normalizeKey = (k) => const preferDarkMode = ({ theme }) => { if (theme === 'auto') { - if (typeof window.matchMedia === 'function') { - const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)'); - return prefersDarkScheme && prefersDarkScheme.matches; + switch (localStorage.getItem(LOCAL_STORAGE_THEME)) { + case 'dark': + return true; + case 'light': + return false; + default: + if (typeof window.matchMedia === 'function') { + const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)'); + return prefersDarkScheme && prefersDarkScheme.matches; + } } } return theme === 'dark'; }; export const loadTheme = (props, style) => { - THEME = preferDarkMode(props) ? DARK_THEME : LIGHT_THEME; + const isDarkMode = preferDarkMode(props); + THEME = isDarkMode ? { ...DARK_THEME } : { ...LIGHT_THEME }; Object.entries(props) .filter(([k, v]) => v && /^theme[A-Z]/.test(k)) .map(([k, v]) => [normalizeKey(k), v]) .forEach(([k, v]) => (THEME[k] = v)); Object.entries(THEME).forEach(([k, v]) => style.setProperty(`--${k}`, v)); + const theme = isDarkMode ? 'dark' : 'light'; + localStorage.setItem(LOCAL_STORAGE_THEME, theme); + return theme; }; diff --git a/src/style.scss b/src/style.scss index 3c7631c..aa49909 100644 --- a/src/style.scss +++ b/src/style.scss @@ -26,6 +26,7 @@ @import 'riot-mui/src/material-elements/material-dropdown/material-dropdown.scss'; @import 'riot-mui/src/material-elements/material-popup/material-popup.scss'; @import 'riot-mui/src/material-elements/material-input/material-input.scss'; +@import 'riot-mui/src/material-elements/material-switch/material-switch.scss'; @import './roboto.scss'; @import './material-icons.scss'; @@ -340,6 +341,9 @@ main { material-footer { padding: 0.5em 1em; + li { + align-self: center; + } } .copy-to-clipboard {