1- const themeWatcher = watchColorSchemeChange ( ( colorScheme ) => {
2- if ( ! hasLocalStorage ( ) ) {
3- document ?. addEventListener ( 'DOMContentLoaded' , ( ) => {
4- // remove icon - toggle not supported
5- document . querySelector ( '#theme-toggle' ) . remove ( )
1+ document . addEventListener ( "DOMContentLoaded" , ( ) => {
2+ const themeBtn = document . querySelector ( '#theme-toggle' ) ;
3+ const root = document ?. documentElement ;
4+
5+ const themeWatcher = watchColorSchemeChange ( ( colorScheme ) => {
6+ if ( ! hasLocalStorage ( ) ) {
7+ // If localStorage is not supported, use system preference
68 setTheme ( colorScheme ) ;
7- } )
8- } else {
9- // user's PS system theme settings
10- const systemTheme = localStorage . getItem ( 'system-theme' )
11- // setting stored in local storage
12- const localTheme = localStorage . getItem ( 'local-theme' )
13- // // if no local theme set - system is default
14- if ( localTheme === null ) {
15- setTheme ( colorScheme )
16- localStorage . setItem ( 'system-theme' , colorScheme || 'light' )
17- // page load - load any stored themes or set theme
9+ themeBtn . remove ( ) ; // Hide toggle
1810 } else {
19- // listen for system changes, update if any
20- if ( colorScheme != systemTheme ) {
21- setTheme ( colorScheme )
22- localStorage . setItem ( 'system-theme' , colorScheme || 'light' )
23- // override local theme
24- localStorage . removeItem ( 'local-theme' )
11+ const localTheme = localStorage . getItem ( 'local-theme' ) ;
12+ if ( localTheme === null ) {
13+ localStorage . setItem ( 'local-theme' , colorScheme ) ; // store system theme as local theme
14+ setTheme ( colorScheme ) ; // use system theme
2515 } else {
26- // else load local theme
27- if ( localTheme === 'light' ) {
28- lightModeOn ( )
29- } else if ( localTheme === 'dark' ) {
30- darkModeOn ( )
31- }
16+ setTheme ( localTheme ) ; // use previous theme
3217 }
18+
19+ // add click event on theme loggle btn
20+ themeBtn . addEventListener ( 'click' , toggleLocalStorageTheme ) ;
21+ // set accessibility on page load
22+ themeBtn . setAttribute ( 'aria-label' , colorScheme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode' ) ;
3323 }
34- // wait for load then and add listner on button
35- document . addEventListener ( 'DOMContentLoaded' , ( ) => {
24+ } ) ;
3625
37- document
38- . querySelector ( '#theme-toggle' )
39- . addEventListener ( 'click' , toggleLocalStorageTheme )
40- } )
41- }
42- } )
43- // set the theme to given value
44- function setTheme ( theme ) {
45- // only support dark else any other defaults to light
46- if ( theme === 'dark' ) {
47- darkModeOn ( )
48- } else {
49- lightModeOn ( )
50- }
51- }
52- // toggle btwn themes or set a theme if none set
53- function toggleLocalStorageTheme ( e ) {
54- const localTheme = localStorage . getItem ( 'local-theme' )
55- if ( localTheme === 'light' ) {
56- localStorage . setItem ( 'local-theme' , 'dark' )
57- darkModeOn ( )
58- } else if ( localTheme === 'dark' ) {
59- localStorage . setItem ( 'local-theme' , 'light' )
60- lightModeOn ( )
61- // localTheme still null
62- } else {
63- // need to check page state then set
64- if ( darkModeState ( ) ) {
65- localStorage . setItem ( 'local-theme' , 'light' )
26+ // apply given theme
27+ function setTheme ( theme ) {
28+ if ( theme === 'dark' ) {
29+ darkModeOn ( )
30+ } else {
6631 lightModeOn ( )
32+ }
33+ }
34+ // toggle theme btn or set a theme if none set
35+ function toggleLocalStorageTheme ( ) {
36+ let nextTheme ;
37+ const localTheme = localStorage . getItem ( 'local-theme' ) ;
38+
39+ if ( localTheme === 'light' ) {
40+ nextTheme = 'dark' ;
41+ } else if ( localTheme === 'dark' ) {
42+ nextTheme = 'light' ;
6743 } else {
68- localStorage . setItem ( 'local-theme' , 'dark' )
69- darkModeOn ( )
44+ nextTheme = darkModeState ( ) ? 'light' : 'dark' ;
7045 }
46+
47+ localStorage . setItem ( 'local-theme' , nextTheme ) ;
48+ setTheme ( nextTheme ) ;
49+ }
50+ function darkModeOn ( ) {
51+ root . classList . remove ( 'light-mode' )
52+ root . classList . add ( 'dark-mode' )
53+ updateThemeIcon ( 'dark' ) ;
7154 }
72- }
73- function darkModeOn ( ) {
74- document ?. documentElement ?. classList ?. remove ( 'light-mode' )
75- document ?. documentElement ?. classList ?. add ( 'dark-mode' )
76- updateThemeIcon ( 'dark' ) ;
77- }
78- function lightModeOn ( ) {
79- document ?. documentElement ?. classList . remove ( 'dark-mode' )
80- document ?. documentElement ?. classList ?. add ( 'light-mode' )
81- updateThemeIcon ( 'light' ) ;
82- }
83- function darkModeState ( ) {
84- return document ?. documentElement ?. classList . contains ( 'dark-mode' )
85- }
86- function hasLocalStorage ( ) {
87- return typeof Storage !== 'undefined'
88- }
89- function watchColorSchemeChange ( callback ) {
90- // query user's machine for system setting & use that
91- const darkMediaQuery = window ?. matchMedia ( '(prefers-color-scheme: dark)' )
55+ function lightModeOn ( ) {
56+ root . classList . remove ( 'dark-mode' )
57+ root . classList . add ( 'light-mode' )
58+ updateThemeIcon ( 'light' ) ;
59+ }
60+ function darkModeState ( ) {
61+ return root . classList . contains ( 'dark-mode' )
62+ }
63+ function hasLocalStorage ( ) {
64+ return typeof Storage !== 'undefined'
65+ }
66+ function watchColorSchemeChange ( callback ) {
67+ // get system theme preference
68+ const darkMediaQuery = window ?. matchMedia ( '(prefers-color-scheme: dark)' )
9269
93- const handleChange = ( event ) => {
94- const newColorScheme = event ?. matches ? 'dark' : 'light'
95- callback ( newColorScheme )
70+ const handleChange = ( event ) => {
71+ const newColorScheme = event ?. matches ? 'dark' : 'light'
72+ callback ( newColorScheme )
73+ }
74+ darkMediaQuery . addEventListener ( 'change' , handleChange )
75+ // initial call : if system theme is not dark then light mode is choosen
76+ callback ( darkMediaQuery . matches ? 'dark' : 'light' )
77+ // remove event from window
78+ return ( ) => darkMediaQuery . removeEventListener ( 'change' , handleChange )
9679 }
97- darkMediaQuery . addEventListener ( 'change' , handleChange )
98- // handle init load value
99- callback ( darkMediaQuery . matches ? 'dark' : 'light' )
100- // Return a function to remove the event listener
101- return ( ) => darkMediaQuery . removeEventListener ( 'change' , handleChange )
102- }
10380
104- function updateThemeIcon ( theme ) {
105- const sun = document . getElementById ( 'icon-sun' ) ;
106- const moon = document . getElementById ( 'icon-moon' ) ;
107- if ( ! sun || ! moon ) return ;
108-
109- const isDark = theme === 'dark' ;
81+ function updateThemeIcon ( theme ) {
82+ const sun = document . getElementById ( 'icon-sun' ) ;
83+ const moon = document . getElementById ( 'icon-moon' ) ;
84+ if ( ! sun || ! moon ) return ;
85+
86+ const isDark = theme === 'dark' ;
11087
111- // Show the icon representing the *next* theme
112- sun . style . display = isDark ? 'block' : 'none' ; // Show sun in dark mode
113- moon . style . display = isDark ? 'none' : 'block' ; // Show moon in light mode
114- // improve accessibility for screen readers
115- sun . setAttribute ( 'aria-hidden' , isDark ? 'false' : 'true' ) ;
116- moon . setAttribute ( 'aria-hidden' , isDark ? 'true' : 'false' ) ;
117- } ;
88+ // hide or show icon
89+ sun . hidden = ! isDark ;
90+ moon . hidden = isDark ;
91+ // improve accessibility for screen readers
92+ sun . setAttribute ( 'aria-hidden' , isDark ? 'false' : 'true' ) ;
93+ moon . setAttribute ( 'aria-hidden' , isDark ? 'true' : 'false' ) ;
94+ // change label on btn click
95+ themeBtn . setAttribute ( 'aria-label' , isDark ? 'Switch to light mode' : 'Switch to dark mode' ) ;
96+ } ;
97+ } ) ;
0 commit comments