diff --git a/www/index.html b/www/index.html index 3bf5884b..a008f845 100644 --- a/www/index.html +++ b/www/index.html @@ -483,10 +483,14 @@ -

* Implements workarounds specific to Wikimedia ZIMs. Try generic option if there are display errors with recent ZIMs.

+

 (Auto themes match the dark/light mode of your device.)

+

* Implements workarounds specific to Wikimedia ZIMs. Try generic option if there are display errors with recent ZIMs.

[ Show article with applied theme ] diff --git a/www/js/app.js b/www/js/app.js index 95832549..a78eb38e 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -87,7 +87,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // Turns caching of the PWA's code on or off and deletes the cache (it defaults to true unless the bypass option is set in Expert Settings) params['appCache'] = settingsStore.getItem('appCache') !== 'false'; // A parameter to set the app theme and, if necessary, the CSS theme for article content (defaults to 'light') - params['appTheme'] = settingsStore.getItem('appTheme') || 'light'; // Currently implemented: light|dark|dark_invert|dark_mwInvert + params['appTheme'] = settingsStore.getItem('appTheme') || 'light'; // Currently implemented: light|dark|dark_invert|dark_mwInvert|auto|auto_invert|auto_mwInvert| // A global parameter to turn on/off the use of Keyboard HOME Key to focus search bar params['useHomeKeyToFocusSearchBar'] = settingsStore.getItem('useHomeKeyToFocusSearchBar') === 'true'; // A parameter to access the URL of any extension that this app was launched from @@ -158,7 +158,6 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys document.getElementById('titleSearchRange').value = params.maxSearchResultsSize; document.getElementById('titleSearchRangeVal').textContent = params.maxSearchResultsSize; document.getElementById('appThemeSelect').value = params.appTheme; - uiUtil.applyAppTheme(params.appTheme); document.getElementById('useHomeKeyToFocusSearchBarCheck').checked = params.useHomeKeyToFocusSearchBar; switchHomeKeyToFocusSearchBar(); document.getElementById('bypassAppCacheCheck').checked = !params.appCache; @@ -171,6 +170,23 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // Unique identifier of the article expected to be displayed var expectedArticleURLToBeDisplayed = ""; + + // define and store dark preference for matchMedia + var darkPreference = window.matchMedia('(prefers-color-scheme:dark)'); + // if 'prefers-color-scheme' is not supported in the browser, then the "auto" options are not displayed to the user + if (window.matchMedia('(prefers-color-scheme)').media === 'not all') { + var optionsToBeRemoved = document.getElementById("appThemeSelect").querySelectorAll('.auto'); + for (var i = 0; i < optionsToBeRemoved.length; i++) { + optionsToBeRemoved[i].parentNode.removeChild(optionsToBeRemoved[i]); + } + } + // Apply previously stored appTheme + uiUtil.applyAppTheme(params.appTheme); + + // Whenever the system theme changes, call applyAppTheme function + darkPreference.onchange = function() { + uiUtil.applyAppTheme(params.appTheme); + } /** * Resize the IFrame height, so that it fills the whole available height in the window diff --git a/www/js/lib/uiUtil.js b/www/js/lib/uiUtil.js index 9e5b3ede..9b147de1 100644 --- a/www/js/lib/uiUtil.js +++ b/www/js/lib/uiUtil.js @@ -431,17 +431,20 @@ define(rqDef, function(settingsStore) { * For each contentTheme, a stylesheet must be provided in www/css that is named 'kiwixJS' + contentTheme * A rule may additionally be needed in app.css for full implementation of contentTheme * - * @param {String} theme The theme to apply (light|dark[_invert|_mwInvert]) + * @param {String} theme The theme to apply (light|dark[_invert|_mwInvert]|auto[_invert|_mwInvert]) */ function applyAppTheme(theme) { + var darkPreference = window.matchMedia('(prefers-color-scheme:dark)'); + // Resolve the app theme from the matchMedia preference (for auto themes) or from the theme string + var appTheme = /^auto/.test(theme) ? darkPreference.matches ? 'dark' : 'light' : theme.replace(/_.*$/, ''); + // Get contentTheme from chosen theme + var contentTheme = theme.replace(/^[^_]*/, ''); var htmlEl = document.querySelector('html'); var footer = document.querySelector('footer'); var oldTheme = htmlEl.dataset.theme || ''; var iframe = document.getElementById('articleContent'); var doc = iframe.contentDocument; var kiwixJSSheet = doc ? doc.getElementById('kiwixJSTheme') || null : null; - var appTheme = theme.replace(/_.*$/, ''); - var contentTheme = theme.replace(/^[^_]*/, ''); var oldAppTheme = oldTheme.replace(/_.*$/, ''); var oldContentTheme = oldTheme.replace(/^[^_]*/, ''); // Remove oldAppTheme and oldContentTheme @@ -454,14 +457,21 @@ define(rqDef, function(settingsStore) { // is not dark (but we want it applied when the content is dark or inverted) footer.classList.add(contentTheme || '_light'); // Embed a reference to applied theme, so we can remove it generically in the future - htmlEl.dataset.theme = theme; + htmlEl.dataset.theme = appTheme + contentTheme; // Hide any previously displayed help - var oldHelp = document.getElementById(oldTheme + '-help'); + var oldHelp = document.getElementById(oldContentTheme.replace(/_/, '') + '-help'); if (oldHelp) oldHelp.style.display = 'none'; // Show any specific help for selected contentTheme - var help = document.getElementById(theme + '-help'); + var help = document.getElementById(contentTheme.replace(/_/, '') + '-help'); if (help) help.style.display = 'block'; - + // Remove the contentTheme for auto themes whenever system is in light mode + if (/^auto/.test(theme) && appTheme === 'light') contentTheme = null; + // Hide any previously displayed description for auto themes + var oldDescription = document.getElementById('kiwix-auto-description'); + if (oldDescription) oldDescription.style.display = 'none'; + // Show description for auto themes + var description = document.getElementById('kiwix-' + theme.replace(/_.*$/, '') + '-description'); + if (description) description.style.display = 'block'; // If there is no ContentTheme or we are applying a different ContentTheme, remove any previously applied ContentTheme if (oldContentTheme && oldContentTheme !== contentTheme) { iframe.classList.remove(oldContentTheme);