Skip to content

Commit 364be3b

Browse files
authored
Merge pull request freeCodeCamp#1086 from simon04/prefers-color-scheme
Add support for prefers-color-scheme media query
2 parents af8576f + cc406a8 commit 364be3b

File tree

5 files changed

+62
-16
lines changed

5 files changed

+62
-16
lines changed

assets/javascripts/app/settings.coffee

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ class app.Settings
77
'arrowScroll'
88
'analyticsConsent'
99
'docs'
10-
'dark'
10+
'dark' # legacy
11+
'theme'
1112
'layout'
1213
'size'
1314
'tips'
@@ -31,10 +32,16 @@ class app.Settings
3132
manualUpdate: false
3233
schema: 1
3334
analyticsConsent: false
35+
theme: 'auto'
3436

3537
constructor: ->
3638
@store = new CookiesStore
3739
@cache = {}
40+
@autoSupported = window.matchMedia('(prefers-color-scheme)').media != 'not all'
41+
if @autoSupported
42+
@darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)')
43+
@darkModeQuery.addListener => @setTheme(@get('theme'))
44+
3845

3946
get: (key) ->
4047
return @cache[key] if @cache.hasOwnProperty(key)
@@ -43,7 +50,7 @@ class app.Settings
4350
set: (key, value) ->
4451
@store.set(key, value)
4552
delete @cache[key]
46-
@toggleDark(value) if key == 'dark'
53+
@setTheme(value) if key == 'theme'
4754
return
4855

4956
del: (key) ->
@@ -114,15 +121,24 @@ class app.Settings
114121
return
115122

116123
initLayout: ->
117-
@toggleDark(@get('dark') is 1)
124+
if @get('dark') is 1
125+
@set('theme', 'dark')
126+
@del 'dark'
127+
@setTheme(@get('theme'))
118128
@toggleLayout(layout, @hasLayout(layout)) for layout in @LAYOUTS
119129
@initSidebarWidth()
120130
return
121131

122-
toggleDark: (enable) ->
132+
setTheme: (theme) ->
133+
if theme is 'auto'
134+
theme = if @darkModeQuery.matches then 'dark' else 'default'
123135
classList = document.documentElement.classList
124-
classList.toggle('_theme-default', !enable)
125-
classList.toggle('_theme-dark', enable)
136+
classList.remove('_theme-default', '_theme-dark')
137+
classList.add('_theme-' + theme)
138+
@updateColorMeta()
139+
return
140+
141+
updateColorMeta: ->
126142
color = getComputedStyle(document.documentElement).getPropertyValue('--headerBackground').trim()
127143
$('meta[name=theme-color]').setAttribute('content', color)
128144
return

assets/javascripts/templates/pages/settings_tmpl.coffee

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
1+
themeOption = ({ label, value }, settings) -> """
2+
<label class="_settings-label _theme-label">
3+
<input type="radio" name="theme" value="#{value}"#{if settings.theme == value then ' checked' else ''}>
4+
#{label}
5+
</label>
6+
"""
7+
18
app.templates.settingsPage = (settings) -> """
29
<h1 class="_lined-heading">Preferences</h1>
310
11+
<div class="_settings-fieldset">
12+
<h2 class="_settings-legend">Theme:</h2>
13+
<div class="_settings-inputs">
14+
#{if settings.autoSupported
15+
themeOption label: "Automatic <small>Matches system setting</small>", value: "auto", settings
16+
else
17+
""}
18+
#{themeOption label: "Light", value: "default", settings}
19+
#{themeOption label: "Dark", value: "dark", settings}
20+
</div>
21+
</div>
22+
423
<div class="_settings-fieldset">
524
<h2 class="_settings-legend">General:</h2>
625
726
<div class="_settings-inputs">
8-
<label class="_settings-label">
9-
<input type="checkbox" form="settings" name="dark" value="1"#{if settings.dark then ' checked' else ''}>Enable dark theme
10-
</label>
1127
<label class="_settings-label _setting-max-width">
1228
<input type="checkbox" form="settings" name="layout" value="_max-width"#{if settings['_max-width'] then ' checked' else ''}>Enable fixed-width layout
1329
</label>

assets/javascripts/views/content/settings_page.coffee

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,20 @@ class app.views.SettingsPage extends app.View
1111

1212
currentSettings: ->
1313
settings = {}
14-
settings.dark = app.settings.get('dark')
14+
settings.theme = app.settings.get('theme')
1515
settings.smoothScroll = !app.settings.get('fastScroll')
1616
settings.arrowScroll = app.settings.get('arrowScroll')
1717
settings.autoInstall = app.settings.get('autoInstall')
1818
settings.analyticsConsent = app.settings.get('analyticsConsent')
19+
settings.autoSupported = app.settings.autoSupported
1920
settings[layout] = app.settings.hasLayout(layout) for layout in app.settings.LAYOUTS
2021
settings
2122

2223
getTitle: ->
2324
'Preferences'
2425

25-
toggleDark: (enable) ->
26-
app.settings.set('dark', !!enable)
26+
setTheme: (value) ->
27+
app.settings.set('theme', value)
2728
return
2829

2930
toggleLayout: (layout, enable) ->
@@ -74,8 +75,8 @@ class app.views.SettingsPage extends app.View
7475
onChange: (event) =>
7576
input = event.target
7677
switch input.name
77-
when 'dark'
78-
@toggleDark input.checked
78+
when 'theme'
79+
@setTheme input.value
7980
when 'layout'
8081
@toggleLayout input.value, input.checked
8182
when 'smoothScroll'

assets/stylesheets/components/_settings.scss

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,21 @@
4848
}
4949

5050
._settings-label {
51-
margin: 0 0 .375rem;
51+
&:not(._theme-label) {
52+
margin: 0 0 .375rem;
53+
}
5254

5355
> small {
5456
display: block;
5557
color: var(--textColorLight);
5658
margin-left: 1.75rem;
5759
}
60+
&._theme-label > small {
61+
display: inline-block;
62+
margin-left: 0.75rem;
63+
}
5864

59-
input[type=checkbox] {
65+
input[type=checkbox], input[type=radio] {
6066
vertical-align: top;
6167
margin: .25rem .375rem;
6268
}

assets/stylesheets/global/_base.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ html {
1010
@import 'global/print';
1111
}
1212

13+
html._theme-default {
14+
color-scheme: light only;
15+
}
16+
html._theme-dark {
17+
color-scheme: dark only;
18+
}
19+
1320
body {
1421
height: 100%;
1522
margin: 0;

0 commit comments

Comments
 (0)