|
2 | 2 |
|
3 | 3 | (async () => { |
4 | 4 | // bind to the html |
| 5 | + const uiBody = document.body; |
| 6 | + const uiToggleThemeBtn = document.getElementById('theme-toggle'); |
| 7 | + |
5 | 8 | const uiConnectWebUsbSerialBtn = document.getElementById('connect_webusb_serial_btn'); |
6 | 9 | const uiConnectSerialBtn = document.getElementById('connect_serial_btn'); |
7 | 10 | const uiDisconnectBtn = document.getElementById('disconnect_btn'); |
|
27 | 30 | const uiNearTheBottomThreshold = 100; // pixels from the bottom to trigger scroll |
28 | 31 |
|
29 | 32 | const maxCommandHistoryLength = 123; // max number of command history entries |
30 | | - const maxReceivedDataLength = 8192/8; // max number of received data entries |
| 33 | + const maxReceivedDataLength = 8192 / 8; // max number of received data entries |
| 34 | + |
| 35 | + const THEME_STATES = ['auto', 'light', 'dark']; |
31 | 36 |
|
32 | 37 | class CommandHistoryEntry { |
33 | 38 | constructor(text) { |
|
59 | 64 | this.receivedData = []; |
60 | 65 |
|
61 | 66 | // bind the UI elements |
| 67 | + uiToggleThemeBtn.addEventListener('click', () => this.toggleTheme()); |
| 68 | + // Listener for OS Theme Changes |
| 69 | + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { |
| 70 | + const currentPreference = localStorage.getItem('theme') || 'auto'; |
| 71 | + // Only act if the user is in automatic mode |
| 72 | + if (currentPreference === 'auto') { |
| 73 | + this.setTheme('auto'); |
| 74 | + } |
| 75 | + }); |
| 76 | + |
62 | 77 | uiConnectWebUsbSerialBtn.addEventListener('click', () => this.connectWebUsbSerialPort()); |
63 | 78 | uiConnectSerialBtn.addEventListener('click', () => this.connectSerialPort()); |
64 | 79 | uiDisconnectBtn.addEventListener('click', () => this.disconnectPort()); |
|
88 | 103 | } |
89 | 104 |
|
90 | 105 | restoreState() { |
| 106 | + // Restore theme choice |
| 107 | + const savedTheme = localStorage.getItem('theme'); |
| 108 | + if (savedTheme) { |
| 109 | + this.setTheme(savedTheme); |
| 110 | + } |
| 111 | + |
91 | 112 | // Restore command history |
92 | 113 | let savedCommandHistory = JSON.parse(localStorage.getItem('commandHistory') || '[]'); |
93 | 114 | for (const cmd of savedCommandHistory) { |
|
112 | 133 | } |
113 | 134 | } |
114 | 135 |
|
| 136 | + setTheme(theme) { |
| 137 | + const modeName = theme.charAt(0).toUpperCase() + theme.slice(1); |
| 138 | + uiToggleThemeBtn.textContent = `Theme: ${modeName}`; |
| 139 | + |
| 140 | + if (theme === 'auto') { |
| 141 | + // In auto mode, we rely on the OS preference. |
| 142 | + // We check the media query and add/remove the class accordingly. |
| 143 | + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; |
| 144 | + if (prefersDark) { |
| 145 | + uiBody.classList.add('dark-mode'); |
| 146 | + } else { |
| 147 | + uiBody.classList.remove('dark-mode'); |
| 148 | + } |
| 149 | + } else if (theme === 'light') { |
| 150 | + // Force light mode by removing the class. |
| 151 | + uiBody.classList.remove('dark-mode'); |
| 152 | + } else if (theme === 'dark') { |
| 153 | + // Force dark mode by adding the class. |
| 154 | + uiBody.classList.add('dark-mode'); |
| 155 | + } |
| 156 | + |
| 157 | + // Save the theme to localStorage |
| 158 | + localStorage.setItem('theme', theme); |
| 159 | + } |
| 160 | + |
| 161 | + toggleTheme() { |
| 162 | + const currentTheme = localStorage.getItem('theme') || 'auto'; |
| 163 | + const nextThemeIndex = (THEME_STATES.indexOf(currentTheme) + 1) % THEME_STATES.length; |
| 164 | + const nextTheme = THEME_STATES[nextThemeIndex]; |
| 165 | + this.setTheme(nextTheme); |
| 166 | + } |
| 167 | + |
115 | 168 | appendCommandToHistory(commandHistoryEntry) { |
116 | 169 | const wasNearBottom = uiCommandHistoryScrollbox.scrollHeight - uiCommandHistoryScrollbox.scrollTop <= uiCommandHistoryScrollbox.clientHeight + uiNearTheBottomThreshold; |
117 | 170 |
|
|
0 commit comments