Add support for dark and light theme.
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
// bind to the html
|
// bind to the html
|
||||||
|
const uiBody = document.body;
|
||||||
|
const uiToggleThemeBtn = document.getElementById('theme-toggle');
|
||||||
|
|
||||||
const uiConnectWebUsbSerialBtn = document.getElementById('connect_webusb_serial_btn');
|
const uiConnectWebUsbSerialBtn = document.getElementById('connect_webusb_serial_btn');
|
||||||
const uiConnectSerialBtn = document.getElementById('connect_serial_btn');
|
const uiConnectSerialBtn = document.getElementById('connect_serial_btn');
|
||||||
const uiDisconnectBtn = document.getElementById('disconnect_btn');
|
const uiDisconnectBtn = document.getElementById('disconnect_btn');
|
||||||
@@ -27,7 +30,9 @@
|
|||||||
const uiNearTheBottomThreshold = 100; // pixels from the bottom to trigger scroll
|
const uiNearTheBottomThreshold = 100; // pixels from the bottom to trigger scroll
|
||||||
|
|
||||||
const maxCommandHistoryLength = 123; // max number of command history entries
|
const maxCommandHistoryLength = 123; // max number of command history entries
|
||||||
const maxReceivedDataLength = 8192/8; // max number of received data entries
|
const maxReceivedDataLength = 8192 / 8; // max number of received data entries
|
||||||
|
|
||||||
|
const THEME_STATES = ['auto', 'light', 'dark'];
|
||||||
|
|
||||||
class CommandHistoryEntry {
|
class CommandHistoryEntry {
|
||||||
constructor(text) {
|
constructor(text) {
|
||||||
@@ -59,6 +64,16 @@
|
|||||||
this.receivedData = [];
|
this.receivedData = [];
|
||||||
|
|
||||||
// bind the UI elements
|
// bind the UI elements
|
||||||
|
uiToggleThemeBtn.addEventListener('click', () => this.toggleTheme());
|
||||||
|
// Listener for OS Theme Changes
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
||||||
|
const currentPreference = localStorage.getItem('theme') || 'auto';
|
||||||
|
// Only act if the user is in automatic mode
|
||||||
|
if (currentPreference === 'auto') {
|
||||||
|
this.setTheme('auto');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
uiConnectWebUsbSerialBtn.addEventListener('click', () => this.connectWebUsbSerialPort());
|
uiConnectWebUsbSerialBtn.addEventListener('click', () => this.connectWebUsbSerialPort());
|
||||||
uiConnectSerialBtn.addEventListener('click', () => this.connectSerialPort());
|
uiConnectSerialBtn.addEventListener('click', () => this.connectSerialPort());
|
||||||
uiDisconnectBtn.addEventListener('click', () => this.disconnectPort());
|
uiDisconnectBtn.addEventListener('click', () => this.disconnectPort());
|
||||||
@@ -88,6 +103,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
restoreState() {
|
restoreState() {
|
||||||
|
// Restore theme choice
|
||||||
|
const savedTheme = localStorage.getItem('theme');
|
||||||
|
if (savedTheme) {
|
||||||
|
this.setTheme(savedTheme);
|
||||||
|
}
|
||||||
|
|
||||||
// Restore command history
|
// Restore command history
|
||||||
let savedCommandHistory = JSON.parse(localStorage.getItem('commandHistory') || '[]');
|
let savedCommandHistory = JSON.parse(localStorage.getItem('commandHistory') || '[]');
|
||||||
for (const cmd of savedCommandHistory) {
|
for (const cmd of savedCommandHistory) {
|
||||||
@@ -112,6 +133,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTheme(theme) {
|
||||||
|
const modeName = theme.charAt(0).toUpperCase() + theme.slice(1);
|
||||||
|
uiToggleThemeBtn.textContent = `Theme: ${modeName}`;
|
||||||
|
|
||||||
|
if (theme === 'auto') {
|
||||||
|
// In auto mode, we rely on the OS preference.
|
||||||
|
// We check the media query and add/remove the class accordingly.
|
||||||
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
if (prefersDark) {
|
||||||
|
uiBody.classList.add('dark-mode');
|
||||||
|
} else {
|
||||||
|
uiBody.classList.remove('dark-mode');
|
||||||
|
}
|
||||||
|
} else if (theme === 'light') {
|
||||||
|
// Force light mode by removing the class.
|
||||||
|
uiBody.classList.remove('dark-mode');
|
||||||
|
} else if (theme === 'dark') {
|
||||||
|
// Force dark mode by adding the class.
|
||||||
|
uiBody.classList.add('dark-mode');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the theme to localStorage
|
||||||
|
localStorage.setItem('theme', theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTheme() {
|
||||||
|
const currentTheme = localStorage.getItem('theme') || 'auto';
|
||||||
|
const nextThemeIndex = (THEME_STATES.indexOf(currentTheme) + 1) % THEME_STATES.length;
|
||||||
|
const nextTheme = THEME_STATES[nextThemeIndex];
|
||||||
|
this.setTheme(nextTheme);
|
||||||
|
}
|
||||||
|
|
||||||
appendCommandToHistory(commandHistoryEntry) {
|
appendCommandToHistory(commandHistoryEntry) {
|
||||||
const wasNearBottom = uiCommandHistoryScrollbox.scrollHeight - uiCommandHistoryScrollbox.scrollTop <= uiCommandHistoryScrollbox.clientHeight + uiNearTheBottomThreshold;
|
const wasNearBottom = uiCommandHistoryScrollbox.scrollHeight - uiCommandHistoryScrollbox.scrollTop <= uiCommandHistoryScrollbox.clientHeight + uiNearTheBottomThreshold;
|
||||||
|
|
||||||
|
@@ -13,7 +13,8 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<h1 class="title">TinyUSB - WebUSB Serial</h1>
|
<h1 class="app-title">TinyUSB - WebUSB Serial</h1>
|
||||||
|
<button id="theme-toggle" class="btn btn-theme">Theme: Auto</button>
|
||||||
<a class="github-link" href="https://github.com/hathach/tinyusb/tree/master/examples/device/webusb_serial/website"
|
<a class="github-link" href="https://github.com/hathach/tinyusb/tree/master/examples/device/webusb_serial/website"
|
||||||
target="_blank">
|
target="_blank">
|
||||||
Find my source on GitHub
|
Find my source on GitHub
|
||||||
|
@@ -25,6 +25,7 @@ body {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0.5em 1em;
|
padding: 0.5em 1em;
|
||||||
|
gap: 1em;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +34,15 @@ h2 {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-title {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-theme {
|
||||||
|
background-color: #6b6b6b;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
.github-link {
|
.github-link {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
@@ -198,3 +208,65 @@ main {
|
|||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================================
|
||||||
|
Togglable Dark Mode
|
||||||
|
================================
|
||||||
|
*/
|
||||||
|
/* This class will be added to the body element by JavaScript */
|
||||||
|
body.dark-mode {
|
||||||
|
/* Invert base background and text colors */
|
||||||
|
background: #1e1e1e;
|
||||||
|
color: #d4d4d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .btn-theme {
|
||||||
|
background-color: #b0b0b0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .github-link {
|
||||||
|
color: #58a6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .resizer {
|
||||||
|
background-color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .input {
|
||||||
|
background-color: #3c3c3c;
|
||||||
|
color: #f0f0f0;
|
||||||
|
border: 2px solid #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .input::placeholder {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .input:focus {
|
||||||
|
background-color: #2a2d2e;
|
||||||
|
border-color: #0078d7;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .scrollbox {
|
||||||
|
background-color: #252526;
|
||||||
|
border: 1px solid #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .monospaced {
|
||||||
|
color: #d4d4d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .command-history-entry {
|
||||||
|
border-bottom: 1px solid #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .command-history-entry:hover {
|
||||||
|
background-color: #3c3c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .send-mode-command {
|
||||||
|
background-color: #555;
|
||||||
|
color: #f5f5f5;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user