Add pseudo-dark mode while maintaining XP aesthetic

- Create CSS variables for theme customization
- Define light and dark XP color schemes
- Dark mode uses darker backgrounds, lighter text
- Maintain classic XP beveled borders and shadows
- Add moon/sun toggle button in title bar
- Implement theme switching with localStorage
- Support system color scheme preference
- Smooth transitions between themes

The dark mode keeps the Windows XP look with:
- Dark teal/navy desktop background
- Dark gray window and button faces
- Lighter text colors
- Darker gradient title bars
- All original XP styling preserved

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
knight 2025-11-04 23:49:38 -05:00
parent 60e2c49811
commit c4e9e952a5
3 changed files with 174 additions and 24 deletions

View File

@ -1,4 +1,45 @@
(() => {
// Theme management
const themeToggle = document.getElementById("themeToggle");
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
function getTheme() {
const saved = localStorage.getItem("xp-theme");
if (saved) return saved;
return prefersDark.matches ? "dark" : "light";
}
function setTheme(theme) {
if (theme === "dark") {
document.documentElement.setAttribute("data-theme", "dark");
if (themeToggle) themeToggle.textContent = "☀️";
} else {
document.documentElement.removeAttribute("data-theme");
if (themeToggle) themeToggle.textContent = "🌙";
}
localStorage.setItem("xp-theme", theme);
}
function toggleTheme() {
const current = document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light";
setTheme(current === "dark" ? "light" : "dark");
}
// Initialize theme
setTheme(getTheme());
// Listen for theme toggle
if (themeToggle) {
themeToggle.addEventListener("click", toggleTheme);
}
// Listen for system theme changes
prefersDark.addEventListener("change", (e) => {
if (!localStorage.getItem("xp-theme")) {
setTheme(e.matches ? "dark" : "light");
}
});
let qs = new URLSearchParams(window.location.search);
const qInput = document.getElementById("q");
const channelDropdown = document.getElementById("channelDropdown");

View File

@ -13,6 +13,7 @@
<div class="title-bar">
<div class="title-bar-text">This Little Corner — Elastic Search</div>
<div class="title-bar-controls">
<button id="themeToggle" aria-label="Toggle theme" title="Toggle dark mode" style="margin-right: 4px; min-width: 24px; font-size: 14px;">🌙</button>
<button aria-label="Minimize"></button>
<button aria-label="Maximize"></button>
<button aria-label="Close"></button>

View File

@ -1,5 +1,101 @@
/* Custom styles for XP.css integration */
/* Theme variables - Light mode (default) */
:root {
--xp-bg-desktop: teal;
--xp-bg-window: #ece9d8;
--xp-bg-white: white;
--xp-text-primary: black;
--xp-text-secondary: #666;
--xp-border-light: white;
--xp-border-dark: #0a0a0a;
--xp-border-shadow: grey;
--xp-border-highlight: #dfdfdf;
--xp-button-face: #ece9d8;
--xp-titlebar-bg: linear-gradient(to right, #0054e3, #1591e6);
--xp-titlebar-text: white;
--xp-selection-bg: #0a246a;
--xp-selection-text: white;
--xp-field-bg: white;
--xp-field-border: #7f9db9;
}
/* Dark mode theme */
[data-theme="dark"] {
--xp-bg-desktop: #1a1a2e;
--xp-bg-window: #2d2d44;
--xp-bg-white: #1e1e2e;
--xp-text-primary: #e0e0e0;
--xp-text-secondary: #a0a0a0;
--xp-border-light: #4a4a5e;
--xp-border-dark: #0a0a0a;
--xp-border-shadow: #1a1a1a;
--xp-border-highlight: #3a3a4e;
--xp-button-face: #2d2d44;
--xp-titlebar-bg: linear-gradient(to right, #1a3a5e, #2a4a6e);
--xp-titlebar-text: #e0e0e0;
--xp-selection-bg: #2a4a7e;
--xp-selection-text: white;
--xp-field-bg: #1e1e2e;
--xp-field-border: #4a5a6e;
}
/* Apply theme variables */
body {
background: var(--xp-bg-desktop);
color: var(--xp-text-primary);
}
.window {
background: var(--xp-bg-window);
}
.window-body {
background: var(--xp-bg-window);
color: var(--xp-text-primary);
}
.title-bar {
background: var(--xp-titlebar-bg);
color: var(--xp-titlebar-text);
}
button {
background: var(--xp-button-face);
color: var(--xp-text-primary);
box-shadow: inset -1px -1px var(--xp-border-dark),
inset 1px 1px var(--xp-border-light),
inset -2px -2px var(--xp-border-shadow),
inset 2px 2px var(--xp-border-highlight);
}
button:active {
box-shadow: inset -1px -1px var(--xp-border-light),
inset 1px 1px var(--xp-border-dark),
inset -2px -2px var(--xp-border-highlight),
inset 2px 2px var(--xp-border-shadow);
}
input[type="text"],
textarea,
select {
background: var(--xp-field-bg);
color: var(--xp-text-primary);
border-color: var(--xp-field-border);
}
fieldset {
border-color: var(--xp-border-shadow) var(--xp-border-light) var(--xp-border-light) var(--xp-border-shadow);
}
.status-bar {
background: var(--xp-bg-window);
}
.status-bar-field {
color: var(--xp-text-primary);
}
/* Fix blurry text rendering - override XP.css font smoothing */
.window,
.window *,
@ -33,10 +129,18 @@ label {
font-size: 11px;
}
body {
background: teal;
padding: 0;
margin: 0;
/* Smooth theme transitions */
body,
.window,
.window-body,
button,
input,
select,
textarea,
.status-bar,
.channel-dropdown summary,
.channel-options {
transition: background 0.3s ease, color 0.3s ease, border-color 0.3s ease;
}
/* Channel dropdown custom styling */
@ -49,9 +153,10 @@ body {
list-style: none;
cursor: pointer;
padding: 3px 4px;
background: ButtonFace;
background: var(--xp-button-face);
color: var(--xp-text-primary);
border: 1px solid;
border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;
border-color: var(--xp-border-light) var(--xp-border-shadow) var(--xp-border-shadow) var(--xp-border-light);
min-width: 180px;
text-align: left;
}
@ -74,12 +179,13 @@ body {
position: absolute;
margin-top: 2px;
padding: 4px;
background: ButtonFace;
background: var(--xp-bg-window);
color: var(--xp-text-primary);
border: 1px solid;
border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;
border-color: var(--xp-border-light) var(--xp-border-shadow) var(--xp-border-shadow) var(--xp-border-light);
max-height: 300px;
overflow-y: auto;
box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.2);
box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3);
z-index: 100;
min-width: 220px;
}
@ -116,7 +222,7 @@ body {
/* Results styling */
#results .item {
border-bottom: 1px solid ButtonShadow;
border-bottom: 1px solid var(--xp-border-shadow);
padding: 12px 0;
margin-bottom: 8px;
}
@ -144,9 +250,10 @@ body {
/* Transcript and highlights */
.transcript {
background: Window;
background: var(--xp-field-bg);
color: var(--xp-text-primary);
border: 1px solid;
border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;
border-color: var(--xp-border-shadow) var(--xp-border-light) var(--xp-border-light) var(--xp-border-shadow);
padding: 8px;
margin-top: 6px;
max-height: 200px;
@ -169,9 +276,9 @@ body {
}
.highlight-row:hover {
background: Highlight;
color: HighlightText;
border: 1px dotted WindowText;
background: var(--xp-selection-bg);
color: var(--xp-selection-text);
border: 1px dotted var(--xp-text-primary);
}
mark {
@ -187,9 +294,10 @@ mark {
.full-transcript {
margin-top: 12px;
padding: 8px;
background: Window;
background: var(--xp-field-bg);
color: var(--xp-text-primary);
border: 2px solid;
border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;
border-color: var(--xp-border-shadow) var(--xp-border-light) var(--xp-border-light) var(--xp-border-shadow);
max-height: 400px;
overflow-y: auto;
font-size: 11px;
@ -198,7 +306,7 @@ mark {
.transcript-segment {
margin-bottom: 10px;
padding-bottom: 6px;
border-bottom: 1px solid ButtonShadow;
border-bottom: 1px solid var(--xp-border-shadow);
}
.transcript-segment:last-child {
@ -241,7 +349,7 @@ mark {
}
.transcript-text {
color: WindowText;
color: var(--xp-text-primary);
line-height: 1.4;
}
@ -251,8 +359,8 @@ mark {
display: flex;
align-items: center;
justify-content: space-between;
background: ActiveCaption;
color: CaptionText;
background: var(--xp-titlebar-bg);
color: var(--xp-titlebar-text);
padding: 2px 4px;
}
@ -264,8 +372,8 @@ mark {
}
.transcript-close:hover {
background: Highlight;
color: HighlightText;
background: var(--xp-selection-bg);
color: var(--xp-selection-text);
}
/* Chart styling */
@ -283,7 +391,7 @@ mark {
}
#frequencyChart .axis text {
fill: WindowText;
fill: var(--xp-text-primary);
font-size: 10px;
}