diff --git a/static/app.js b/static/app.js
index 240d41c..2c999cf 100644
--- a/static/app.js
+++ b/static/app.js
@@ -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");
diff --git a/static/index.html b/static/index.html
index d3fe8cd..1742882 100644
--- a/static/index.html
+++ b/static/index.html
@@ -13,6 +13,7 @@
This Little Corner — Elastic Search
+
diff --git a/static/style.css b/static/style.css
index 08ddc4e..526f992 100644
--- a/static/style.css
+++ b/static/style.css
@@ -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;
}