Skip to content

Commit 607341a

Browse files
authored
Merge pull request #77 from C-Lodder/switcher
Add system preference to theme switcher
2 parents 922dce8 + c000d18 commit 607341a

File tree

9 files changed

+164
-114
lines changed

9 files changed

+164
-114
lines changed

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# Changelog
22

3-
## 0.0.12
3+
## WIP
44
- Add support for automatic intro/full text image resizing (Thanks @nikosdion)
5-
- Use OS prefered colour scheme if theme hasn't been set
5+
- Add system preference to theme switcher
66
- Fix "show theme switcher" parameter not working (Thanks @nikosdion)
7+
8+
## 0.0.12
9+
- Use OS prefered colour scheme if theme hasn't been set
710
- Fix CSS not being loaded if theme switcher was disabled
811
- Fix styling for invalid field feedback
912

component.php

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
Joomla\CMS\HTML\HTMLHelper::_('stylesheet',
1919
Joomla\CMS\Uri\Uri::root() . 'templates/lightning/css/modal.css', ['version' => 'auto']);
2020
}
21+
HTMLHelper::_('script', 'switch.min.js', ['version' => 'auto', 'relative' => true], ['type' => 'module']);
22+
2123
?>
2224
<!DOCTYPE html>
2325
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
@@ -29,14 +31,5 @@
2931
<body>
3032
<jdoc:include type="message" />
3133
<jdoc:include type="component" />
32-
33-
<script>
34-
(() => {
35-
const prefersColourScheme = window.matchMedia('(prefers-color-scheme:light)')
36-
const colourScheme = prefersColourScheme.matches ? 'is-light' : 'is-dark'
37-
const theme = localStorage.getItem('theme') ?? colourScheme
38-
document.documentElement.classList.add(theme)
39-
})()
40-
</script>
4134
</body>
4235
</html>

error.php

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
if ($themeSwitcher)
2626
{
2727
HTMLHelper::_('stylesheet', 'switch.css', ['version' => 'auto', 'relative' => true]);
28-
HTMLHelper::_('script', 'switch.min.js', ['version' => 'auto', 'relative' => true], ['type' => 'module']);
2928
}
29+
HTMLHelper::_('script', 'switch.min.js', ['version' => 'auto', 'relative' => true], ['type' => 'module']);
3030

3131
// Fetch CSS
3232
$css = file_get_contents(__DIR__ . '/css/template.css');
@@ -66,8 +66,10 @@
6666
<?php endif; ?>
6767
</div>
6868
<?php if ($themeSwitcher) : ?>
69-
<div class="color-scheme-switch">
70-
<input type="checkbox" name="color-scheme-switch" class="color-scheme-switch-checkbox" id="color-scheme-switch">
69+
<div class="color-scheme-switch" id="color-scheme-switch">
70+
<input type="radio" name="color-scheme-switch" value="is-light" class="color-scheme-switch-radio" aria-label="Light color scheme">
71+
<input type="radio" name="color-scheme-switch" value="is-system" class="color-scheme-switch-radio" aria-label="System color scheme">
72+
<input type="radio" name="color-scheme-switch" value="is-dark" class="color-scheme-switch-radio" aria-label="Dark color scheme">
7173
<label class="color-scheme-switch-label" for="color-scheme-switch"></label>
7274
</div>
7375
<?php endif; ?>
@@ -128,16 +130,5 @@
128130

129131
<jdoc:include type="styles" />
130132
<jdoc:include type="scripts" />
131-
132-
<?php if ($themeSwitcher) : ?>
133-
<script>
134-
(() => {
135-
const prefersColourScheme = window.matchMedia('(prefers-color-scheme:light)')
136-
const colourScheme = prefersColourScheme.matches ? 'is-light' : 'is-dark'
137-
const theme = localStorage.getItem('theme') ?? colourScheme
138-
document.documentElement.classList.add(theme)
139-
})()
140-
</script>
141-
<?php endif; ?>
142133
</body>
143134
</html>

index.php

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
if ($themeSwitcher)
2929
{
3030
HTMLHelper::_('stylesheet', 'switch.css', ['version' => 'auto', 'relative' => true]);
31-
HTMLHelper::_('script', 'switch.min.js', ['version' => 'auto', 'relative' => true], ['type' => 'module']);
3231
}
32+
HTMLHelper::_('script', 'switch.min.js', ['version' => 'auto', 'relative' => true], ['type' => 'module']);
3333

3434
// Font Awesome
3535
HTMLHelper::_('stylesheet', 'media/vendor/fontawesome-free/css/fontawesome.min.css', ['version' => 'auto']);
@@ -130,8 +130,10 @@
130130
<span id="navbar-menu-toggle" class="navbar-menu-toggle"><span></span></span>
131131
<?php endif; ?>
132132
<?php if ($themeSwitcher) : ?>
133-
<div class="color-scheme-switch">
134-
<input type="checkbox" name="color-scheme-switch" class="color-scheme-switch-checkbox" id="color-scheme-switch">
133+
<div class="color-scheme-switch" id="color-scheme-switch">
134+
<input type="radio" name="color-scheme-switch" value="is-light" class="color-scheme-switch-radio" aria-label="Light color scheme">
135+
<input type="radio" name="color-scheme-switch" value="is-system" class="color-scheme-switch-radio" aria-label="System color scheme">
136+
<input type="radio" name="color-scheme-switch" value="is-dark" class="color-scheme-switch-radio" aria-label="Dark color scheme">
135137
<label class="color-scheme-switch-label" for="color-scheme-switch"></label>
136138
</div>
137139
<?php endif; ?>
@@ -200,13 +202,6 @@
200202

201203
<script>
202204
(() => {
203-
<?php if ($themeSwitcher) : ?>
204-
const prefersColourScheme = window.matchMedia('(prefers-color-scheme:light)')
205-
const colourScheme = prefersColourScheme.matches ? 'is-light' : 'is-dark'
206-
const theme = localStorage.getItem('theme') ?? colourScheme
207-
document.documentElement.classList.add(theme)
208-
<?php endif; ?>
209-
210205
const styles = <?php echo $cachesStyleSheets; ?>;
211206
styles.forEach(item => {
212207
document.body.insertAdjacentHTML('beforeend', item);

js/switch.js

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,62 @@
44
*/
55

66
(() => {
7+
// Theme states
8+
const THEME = {
9+
dark: 'is-dark',
10+
light: 'is-light',
11+
system: 'is-system',
12+
}
13+
14+
// Method to change the class on the <html> element
15+
const applyClass = (value) => {
16+
html.classList.remove(THEME.dark, THEME.light, THEME.system)
17+
html.classList.add(value)
18+
}
719

8-
// Switcher toggle
20+
// Variables
21+
const html = document.documentElement
22+
const matchMedia = window.matchMedia('(prefers-color-scheme:dark)')
923
const switcher = document.getElementById('color-scheme-switch')
24+
1025
if (switcher) {
11-
const html = document.documentElement
12-
const theme = localStorage.getItem('theme') !== undefined ? localStorage.getItem('theme') : 'is-light'
13-
14-
switcher.checked = theme === 'is-dark' ? true : false
15-
16-
switcher.addEventListener('change', () => {
17-
if (switcher.checked) {
18-
localStorage.setItem('theme', 'is-dark')
19-
html.classList.add('is-dark')
20-
} else {
21-
localStorage.setItem('theme', 'is-light')
22-
html.classList.remove('is-dark')
23-
}
26+
const colourScheme = matchMedia.matches ? THEME.dark : THEME.light
27+
const storedTheme = localStorage.getItem('theme') !== null ? localStorage.getItem('theme') : THEME.system
28+
29+
// Set the default input to be checked
30+
if (storedTheme !== THEME.system) {
31+
switcher.querySelector(`input[value="${storedTheme}"]`).checked = true
32+
applyClass(storedTheme)
33+
} else {
34+
// Set default theme
35+
switcher.querySelector(`input[value="${THEME.system}"]`).checked = true
36+
matchMedia.matches ? applyClass(THEME.dark) : applyClass(THEME.light)
37+
}
38+
39+
// Loop through all switcher inputs
40+
switcher.querySelectorAll('input').forEach((input) => {
41+
input.addEventListener('change', ({ target }) => {
42+
if (target.value === THEME.dark || target.value === THEME.light) {
43+
localStorage.setItem('theme', target.value)
44+
applyClass(target.value)
45+
} else {
46+
localStorage.setItem('theme', THEME.system)
47+
applyClass(colourScheme)
48+
}
49+
})
2450
})
51+
} else {
52+
// Set default theme
53+
matchMedia.matches ? applyClass(THEME.dark) : applyClass(THEME.light)
2554
}
2655

56+
// Listen for changes made to the system
57+
matchMedia.addListener((event) => {
58+
// If the switcher is disabled or enabled BUT set to the system preference, change the theme
59+
// The theme will not change if it has manually been set by the switcher
60+
if (!switcher || (switcher && switcher.querySelector(`input[value="${THEME.system}"]`).checked)) {
61+
return event.matches ? applyClass(THEME.dark) : applyClass(THEME.light)
62+
}
63+
})
64+
2765
})()

js/switch.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

offline.php

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
if ($themeSwitcher)
2626
{
2727
HTMLHelper::_('stylesheet', 'switch.css', ['version' => 'auto', 'relative' => true]);
28-
HTMLHelper::_('script', 'switch.min.js', ['version' => 'auto', 'relative' => true]);
2928
}
29+
HTMLHelper::_('script', 'switch.min.js', ['version' => 'auto', 'relative' => true], ['type' => 'module']);
3030

3131
// Fetch CSS
3232
$css = file_get_contents(__DIR__ . '/css/template.css');
@@ -67,11 +67,13 @@
6767
<?php endif; ?>
6868
</div>
6969
<?php if ($themeSwitcher) : ?>
70-
<div class="color-scheme-switch">
71-
<input type="checkbox" name="color-scheme-switch" class="color-scheme-switch-checkbox" id="color-scheme-switch">
72-
<label class="color-scheme-switch-label" for="color-scheme-switch"></label>
73-
</div>
74-
<?php endif; ?>
70+
<div class="color-scheme-switch" id="color-scheme-switch">
71+
<input type="radio" name="color-scheme-switch" value="is-light" class="color-scheme-switch-radio" aria-label="Light color scheme">
72+
<input type="radio" name="color-scheme-switch" value="is-system" class="color-scheme-switch-radio" aria-label="System color scheme">
73+
<input type="radio" name="color-scheme-switch" value="is-dark" class="color-scheme-switch-radio" aria-label="Dark color scheme">
74+
<label class="color-scheme-switch-label" for="color-scheme-switch"></label>
75+
</div>
76+
<?php endif; ?>
7577
</nav>
7678
</header>
7779
<div class="grid-child container-component">
@@ -121,17 +123,6 @@
121123
</div>
122124
</div>
123125

124-
<?php if ($themeSwitcher) : ?>
125-
<script>
126-
(() => {
127-
const prefersColourScheme = window.matchMedia('(prefers-color-scheme:light)')
128-
const colourScheme = prefersColourScheme.matches ? 'is-light' : 'is-dark'
129-
const theme = localStorage.getItem('theme') ?? colourScheme
130-
document.documentElement.classList.add(theme)
131-
})()
132-
</script>
133-
<?php endif; ?>
134-
135126
<jdoc:include type="styles" />
136127
<jdoc:include type="scripts" />
137128
</body>

src/css/switch.css

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,53 @@
11
/* Switcher */
22

33
.color-scheme-switch {
4+
--switcher-width: 75px;
5+
--switcher-height: 36px;
6+
--switcher-toggle-bg-color: hsl(216, 10%, 10%);
7+
--switcher-bg-color: #fff;
8+
--switcher-border-color: hsl(0, 0%, 89%);
9+
410
position: relative;
5-
width: 70px;
6-
flex: 0 0 70px;
11+
display: flex;
12+
height: var(--switcher-height);
13+
flex: 0 0 var(--switcher-width);
14+
flex-wrap: nowrap;
715
user-select: none;
8-
}
9-
10-
.color-scheme-switch-checkbox {
11-
display: none;
12-
}
16+
border: 2px solid var(--switcher-border-color);
17+
border-radius: var(--switcher-height);
18+
background-color: var(--switcher-bg-color);
19+
box-sizing: content-box;
1320

14-
.color-scheme-switch-label {
15-
display: block;
16-
overflow: hidden;
17-
cursor: pointer;
18-
height: 36px;
19-
padding: 0;
20-
line-height: 36px;
21-
border: 2px solid #e3e3e3;
22-
border-radius: 36px;
23-
background-color: #fff;
24-
transition: background-color .3s ease-in-out;
25-
margin-bottom: 0;
21+
input {
22+
height: var(--switcher-height);
23+
margin: 0;
24+
flex: 1 1 33%;
25+
opacity: 0;
26+
appearance: none;
27+
}
2628

27-
&::before {
29+
label {
2830
position: absolute;
2931
top: 0;
3032
bottom: 0;
3133
left: 0;
3234
display: block;
33-
width: 36px;
35+
width: var(--switcher-height);
36+
height: var(--switcher-height);
3437
margin: 0;
3538
content: "";
36-
background: var(--hiq-body-background-color);
37-
border: inherit;
38-
border-radius: inherit;
39-
transform: translateX(0);
39+
background: var(--switcher-toggle-bg-color);
40+
border-radius: var(--switcher-height);
4041
transition: transform .3s ease-in-out;
4142
}
42-
}
43-
44-
.color-scheme-switch-checkbox:checked + .color-scheme-switch-label {
45-
background-color: var(--hiq-header-background-color);
46-
border-color: var(--hiq-body-background-color);
4743

48-
&::before {
49-
transform: translateX(33px);
50-
transition: transform .3s ease-in-out;
44+
input:first-child:checked ~ label {
45+
transform: translateX(0);
46+
}
47+
input:nth-child(2):checked ~ label {
48+
transform: translateX(calc(calc(var(--switcher-width) / 2) - 50%));
49+
}
50+
input:nth-child(3):checked ~ label {
51+
transform: translateX(calc(var(--switcher-width) - 100%));
5152
}
5253
}

0 commit comments

Comments
 (0)