diff --git a/assets/javascripts/app/settings.coffee b/assets/javascripts/app/settings.coffee index 8a4c2b72..eb1c9289 100644 --- a/assets/javascripts/app/settings.coffee +++ b/assets/javascripts/app/settings.coffee @@ -7,7 +7,8 @@ class app.Settings 'arrowScroll' 'analyticsConsent' 'docs' - 'dark' + 'dark' # legacy + 'theme' 'layout' 'size' 'tips' @@ -31,10 +32,16 @@ class app.Settings manualUpdate: false schema: 1 analyticsConsent: false + theme: 'auto' constructor: -> @store = new CookiesStore @cache = {} + @autoSupported = window.matchMedia('(prefers-color-scheme)').media != 'not all' + if @autoSupported + @darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)') + @darkModeQuery.addListener => @setTheme(@get('theme')) + get: (key) -> return @cache[key] if @cache.hasOwnProperty(key) @@ -43,7 +50,7 @@ class app.Settings set: (key, value) -> @store.set(key, value) delete @cache[key] - @toggleDark(value) if key == 'dark' + @setTheme(value) if key == 'theme' return del: (key) -> @@ -114,15 +121,24 @@ class app.Settings return initLayout: -> - @toggleDark(@get('dark') is 1) + if @get('dark') is 1 + @set('theme', 'dark') + @del 'dark' + @setTheme(@get('theme')) @toggleLayout(layout, @hasLayout(layout)) for layout in @LAYOUTS @initSidebarWidth() return - toggleDark: (enable) -> + setTheme: (theme) -> + if theme is 'auto' + theme = if @darkModeQuery.matches then 'dark' else 'default' classList = document.documentElement.classList - classList.toggle('_theme-default', !enable) - classList.toggle('_theme-dark', enable) + classList.remove('_theme-default', '_theme-dark') + classList.add('_theme-' + theme) + @updateColorMeta() + return + + updateColorMeta: -> color = getComputedStyle(document.documentElement).getPropertyValue('--headerBackground').trim() $('meta[name=theme-color]').setAttribute('content', color) return diff --git a/assets/javascripts/templates/pages/settings_tmpl.coffee b/assets/javascripts/templates/pages/settings_tmpl.coffee index d5cb0985..6d227069 100644 --- a/assets/javascripts/templates/pages/settings_tmpl.coffee +++ b/assets/javascripts/templates/pages/settings_tmpl.coffee @@ -1,13 +1,29 @@ +themeOption = ({ label, value }, settings) -> """ + +""" + app.templates.settingsPage = (settings) -> """

Preferences

+
+

Theme:

+
+ #{if settings.autoSupported + themeOption label: "Automatic Matches system setting", value: "auto", settings + else + ""} + #{themeOption label: "Light", value: "default", settings} + #{themeOption label: "Dark", value: "dark", settings} +
+
+

General:

- diff --git a/assets/javascripts/views/content/settings_page.coffee b/assets/javascripts/views/content/settings_page.coffee index 9ca606c6..2db7c6bc 100644 --- a/assets/javascripts/views/content/settings_page.coffee +++ b/assets/javascripts/views/content/settings_page.coffee @@ -11,19 +11,20 @@ class app.views.SettingsPage extends app.View currentSettings: -> settings = {} - settings.dark = app.settings.get('dark') + settings.theme = app.settings.get('theme') settings.smoothScroll = !app.settings.get('fastScroll') settings.arrowScroll = app.settings.get('arrowScroll') settings.autoInstall = app.settings.get('autoInstall') settings.analyticsConsent = app.settings.get('analyticsConsent') + settings.autoSupported = app.settings.autoSupported settings[layout] = app.settings.hasLayout(layout) for layout in app.settings.LAYOUTS settings getTitle: -> 'Preferences' - toggleDark: (enable) -> - app.settings.set('dark', !!enable) + setTheme: (value) -> + app.settings.set('theme', value) return toggleLayout: (layout, enable) -> @@ -74,8 +75,8 @@ class app.views.SettingsPage extends app.View onChange: (event) => input = event.target switch input.name - when 'dark' - @toggleDark input.checked + when 'theme' + @setTheme input.value when 'layout' @toggleLayout input.value, input.checked when 'smoothScroll' diff --git a/assets/stylesheets/components/_settings.scss b/assets/stylesheets/components/_settings.scss index 86bbf005..807f5500 100644 --- a/assets/stylesheets/components/_settings.scss +++ b/assets/stylesheets/components/_settings.scss @@ -48,15 +48,21 @@ } ._settings-label { - margin: 0 0 .375rem; + &:not(._theme-label) { + margin: 0 0 .375rem; + } > small { display: block; color: var(--textColorLight); margin-left: 1.75rem; } + &._theme-label > small { + display: inline-block; + margin-left: 0.75rem; + } - input[type=checkbox] { + input[type=checkbox], input[type=radio] { vertical-align: top; margin: .25rem .375rem; } diff --git a/assets/stylesheets/global/_base.scss b/assets/stylesheets/global/_base.scss index b81d5a93..ec7be4f2 100644 --- a/assets/stylesheets/global/_base.scss +++ b/assets/stylesheets/global/_base.scss @@ -10,6 +10,13 @@ html { @import 'global/print'; } +html._theme-default { + color-scheme: light only; +} +html._theme-dark { + color-scheme: dark only; +} + body { height: 100%; margin: 0;