11// Theme toggle functionality
2- const themeToggle = document . querySelector ( '.theme-toggle' ) ;
3- const themeIcon = themeToggle . querySelector ( 'i' ) ;
2+ let themeToggle ;
3+ let themeIcon ;
44const htmlElement = document . documentElement ;
55
66// Available themes
@@ -24,20 +24,21 @@ function getSystemTheme() {
2424 return window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ? 'dark' : 'light' ;
2525}
2626
27+ // Update theme icon based on current theme
28+ function updateThemeIcon ( preference ) {
29+ const { cfg } = themes [ preference ] ;
30+ if ( ! cfg || ! themeIcon ) return ;
31+ const { icon } = cfg ;
32+ themeIcon . className = `bi ${ icon } ` ;
33+ }
34+
2735// Function to update theme based on preference
2836function updateTheme ( preference ) {
2937 const theme = preference === 'system' ? getSystemTheme ( ) : preference ;
3038 htmlElement . setAttribute ( 'data-bs-theme' , theme ) ;
3139 updateThemeIcon ( preference ) ;
3240}
3341
34- // Update theme when system preference changes
35- window . matchMedia ( '(prefers-color-scheme: dark)' ) . addEventListener ( 'change' , e => {
36- if ( localStorage . getItem ( 'theme' ) === 'system' ) {
37- updateTheme ( 'system' ) ;
38- }
39- } ) ;
40-
4142// Function to create theme dropdown menu
4243function createThemeMenu ( ) {
4344 const menu = document . createElement ( 'div' ) ;
@@ -61,59 +62,67 @@ function createThemeMenu() {
6162 return menu ;
6263}
6364
64- // Initialize theme
65- const savedTheme = localStorage . getItem ( ' theme' ) || 'system' ;
66- updateTheme ( savedTheme ) ;
65+ document . addEventListener ( 'DOMContentLoaded' , ( ) => {
66+ themeToggle = document . querySelector ( '. theme-toggle' ) ;
67+ themeIcon = themeToggle . querySelector ( 'i' ) ;
6768
68- // Toggle theme menu on click
69- let activeMenu = null ;
70- themeToggle . addEventListener ( 'click' , ( e ) => {
71- e . stopPropagation ( ) ;
69+ // Update theme when system preference changes
70+ window . matchMedia ( '(prefers-color-scheme: dark)' ) . addEventListener ( 'change' , e => {
71+ if ( localStorage . getItem ( 'theme' ) === 'system' ) {
72+ updateTheme ( 'system' ) ;
73+ }
74+ } ) ;
7275
73- if ( activeMenu ) {
74- activeMenu . remove ( ) ;
75- activeMenu = null ;
76- return ;
77- }
76+ // Initialize theme
77+ const savedTheme = localStorage . getItem ( 'theme' ) || 'system' ;
78+ updateTheme ( savedTheme ) ;
7879
79- const menu = createThemeMenu ( ) ;
80- document . body . appendChild ( menu ) ;
80+ // Toggle theme menu on click
81+ let activeMenu = null ;
82+ themeToggle . addEventListener ( 'click' , ( e ) => {
83+ e . stopPropagation ( ) ;
8184
82- // Position menu below button
83- const buttonRect = themeToggle . getBoundingClientRect ( ) ;
84- menu . style . position = 'fixed' ;
85- menu . style . top = `${ buttonRect . bottom + 5 } px` ;
85+ if ( activeMenu ) {
86+ activeMenu . remove ( ) ;
87+ activeMenu = null ;
88+ return ;
89+ }
8690
87- const isRTL = document . dir === 'rtl' ;
88- const horizontalPosition = isRTL ? buttonRect . left : ( window . innerWidth - buttonRect . right ) ;
91+ const menu = createThemeMenu ( ) ;
92+ document . body . appendChild ( menu ) ;
8993
90- // Ensure menu stays within viewport
91- const menuWidth = 150 ; // matches min-width from CSS
92- const safeOffset = 5 ;
93- const maxRight = window . innerWidth - menuWidth - safeOffset ;
94- const right = Math . min ( horizontalPosition - safeOffset , maxRight ) ;
94+ // Position menu below button
95+ const buttonRect = themeToggle . getBoundingClientRect ( ) ;
96+ menu . style . position = 'fixed' ;
97+ menu . style . top = `${ buttonRect . bottom + 5 } px` ;
9598
96- menu . style [ isRTL ? 'left' : 'right' ] = `${ right } px` ;
97- activeMenu = menu ;
98- } ) ;
99+ const isRTL = document . dir === 'rtl' ;
100+ const horizontalPosition = isRTL ? buttonRect . left : ( window . innerWidth - buttonRect . right ) ;
99101
100- // Close menu when clicking outside
101- document . addEventListener ( 'click' , ( event ) => {
102- if ( activeMenu ) {
103- activeMenu . remove ( ) ;
104- activeMenu = null ;
105- }
106- } ) ;
102+ // Ensure menu stays within viewport
103+ const menuWidth = 150 ; // matches min-width from CSS
104+ const safeOffset = 5 ;
105+ const maxRight = window . innerWidth - menuWidth - safeOffset ;
106+ const right = Math . min ( horizontalPosition - safeOffset , maxRight ) ;
107107
108- // Add keyboard navigation
109- document . addEventListener ( 'keydown' , ( event ) => {
110- if ( event . key === 'Escape' && activeMenu ) {
111- activeMenu . remove ( ) ;
112- activeMenu = null ;
113- }
114- } ) ;
115- // Update theme icon based on current theme
116- function updateThemeIcon ( preference ) {
117- const { icon } = themes [ preference ] ;
118- themeIcon . className = `bi ${ icon } ` ;
119- }
108+ menu . style [ isRTL ? 'left' : 'right' ] = `${ right } px` ;
109+ activeMenu = menu ;
110+ } ) ;
111+
112+ // Close menu when clicking outside
113+ document . addEventListener ( 'click' , ( event ) => {
114+ if ( activeMenu ) {
115+ activeMenu . remove ( ) ;
116+ activeMenu = null ;
117+ }
118+ } ) ;
119+
120+ // Add keyboard navigation
121+ document . addEventListener ( 'keydown' , ( event ) => {
122+ if ( event . key === 'Escape' && activeMenu ) {
123+ activeMenu . remove ( ) ;
124+ activeMenu = null ;
125+ }
126+ } ) ;
127+
128+ } )
0 commit comments