Implement custom Windows title bar and theme refactor

Adds a frameless window with custom title bar controls for Windows, including minimize, maximize/restore, and close buttons. Refactors theme color application to use CSS variables and color-mix for improved consistency and dynamic theming across home, settings, and main UI. Updates renderer and styles to support the new title bar, platform detection, and improved color handling. No changes to lock files.
This commit is contained in:
2026-01-01 15:25:45 +13:00
parent 1b71a4001d
commit 26126982e2
6 changed files with 398 additions and 188 deletions
+107 -91
View File
@@ -2,12 +2,9 @@ html, body {
height: 100%;
margin: 0;
padding: 0;
/* Subtle aurora background that peeks through glassy chrome */
background:
radial-gradient(1200px 600px at 10% -10%, rgba(62, 33, 110, 0.18), transparent 45%),
radial-gradient(1000px 500px at 90% -20%, rgba(18, 124, 201, 0.16), transparent 40%),
#0b0d10;
color: white;
/* Background now driven by theme */
background: var(--bg, #0b0d10);
color: var(--text, white);
font-family: 'Segoe UI', system-ui, -apple-system, Ubuntu, Roboto, sans-serif;
}
@@ -16,6 +13,8 @@ html, body {
/* Space reserved on the left for system window controls (traffic lights on macOS).
Applied cross-platform per request to keep a consistent layout. */
--window-controls-offset: 80px; /* adjust if needed */
/* Space reserved on the right for Windows title bar controls */
--window-controls-width: 138px;
/* Design tokens */
--bg: #0b0d10;
@@ -50,22 +49,30 @@ html, body {
--tab-border: #2B3040;
}
/* TITLEBAR CONTAINER - holds tab bar and window controls */
#titlebar-container {
display: flex;
position: relative;
background: var(--tab-bg);
-webkit-app-region: drag;
}
/* TAB STRIP */
#tab-bar {
display: flex;
align-items: flex-end;
gap: 2px;
/* Increase left padding to avoid overlap with OS window controls area */
padding: 6px 10px 0 var(--window-controls-offset);
flex: 1;
/* Default: small left padding for Windows/Linux (no traffic lights) */
padding: 6px 10px 0 10px;
background: var(--tab-bg);
border-bottom: 1px solid var(--tab-border);
overflow-x: auto; /* scroll when many tabs */
scrollbar-color: #444 #2a2a3c; /* thumb and track for Firefox */
scrollbar-width: thin; /* slimmer track */
-webkit-backdrop-filter: blur(var(--blur));
backdrop-filter: blur(var(--blur));
/* Only the background areas are draggable. Individual tabs opt-out via no-drag. */
/* Inherit drag from container */
-webkit-app-region: drag;
min-height: 38px;
}
/* NAVBAR LAYOUT */
@@ -153,13 +160,9 @@ html, body {
.nav-right > button,
#reload-btn,
#menu-btn {
background:
/* brighter, more opaque fill for contrast */
linear-gradient(180deg, rgba(50,54,74,0.96), rgba(38,42,60,0.96)) padding-box,
/* stronger border highlight */
linear-gradient(180deg, rgba(255,255,255,0.18), rgba(0,0,0,0.45)) border-box;
background: color-mix(in srgb, var(--url-bar-bg) 90%, var(--text) 10%);
color: var(--text);
border: 1px solid transparent;
border: 1px solid color-mix(in srgb, var(--text) 15%, transparent);
width: 34px;
height: 34px;
display: inline-grid;
@@ -167,7 +170,7 @@ html, body {
border-radius: 50%;
cursor: pointer;
/* subtle inner highlight adds edge definition */
box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 8%, transparent);
transition: transform 120ms ease, box-shadow 120ms ease, filter 120ms ease;
line-height: 0; /* avoid vertical misalignment for glyphs */
padding: 0;
@@ -177,24 +180,21 @@ html, body {
/* Downloads button chrome to match other nav buttons */
#downloads-btn {
background:
linear-gradient(180deg, rgba(50,54,74,0.96), rgba(38,42,60,0.96)) padding-box,
linear-gradient(180deg, rgba(255,255,255,0.18), rgba(0,0,0,0.45)) border-box;
color: var(--muted);
border: 1px solid transparent;
background: color-mix(in srgb, var(--url-bar-bg) 90%, var(--text) 10%);
color: var(--text);
border: 1px solid color-mix(in srgb, var(--text) 15%, transparent);
width: 34px;
height: 34px;
display: inline-grid;
place-items: center;
border-radius: 50%;
cursor: pointer;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 8%, transparent);
transition: transform 120ms ease, box-shadow 120ms ease, filter 120ms ease, color 120ms ease;
line-height: 0;
padding: 0;
-webkit-appearance: none;
appearance: none;
background-color: transparent;
}
#downloads-btn:hover { filter: brightness(1.05); box-shadow: 0 4px 14px rgba(0,0,0,0.35); color: var(--text); }
#downloads-btn:active { transform: translateY(1px) scale(0.98); }
@@ -203,10 +203,8 @@ html, body {
/* Match home-active chrome variant */
body:has(#home-container.active) #downloads-btn {
background:
linear-gradient(180deg, rgba(60,66,90,0.98), rgba(44,48,68,0.98)) padding-box,
linear-gradient(180deg, rgba(255,255,255,0.22), rgba(0,0,0,0.5)) border-box;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
background: color-mix(in srgb, var(--url-bar-bg) 85%, var(--text) 15%);
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 10%, transparent);
}
.nav-left button:hover,
@@ -214,7 +212,7 @@ body:has(#home-container.active) #downloads-btn {
#reload-btn:hover,
#menu-btn:hover {
filter: brightness(1.05);
box-shadow: 0 4px 14px rgba(0,0,0,0.35);
box-shadow: 0 4px 14px color-mix(in srgb, var(--bg) 50%, transparent);
}
.nav-left button:active,
@@ -227,9 +225,8 @@ body:has(#home-container.active) #downloads-btn {
/* Primary action (Go button) keeps rectangular look but modernized */
.nav-center + button,
.nav-center button {
background:
linear-gradient(180deg, var(--accent), var(--accent-700));
color: white !important;
background: var(--accent);
color: var(--text);
border: 1px solid transparent;
padding: 8px 14px;
border-radius: 10px;
@@ -237,7 +234,7 @@ body:has(#home-container.active) #downloads-btn {
transition: transform 120ms ease, box-shadow 120ms ease, filter 120ms ease;
}
.nav-center + button:hover,
.nav-center button:hover { box-shadow: 0 8px 20px rgba(111, 76, 255, 0.35); }
.nav-center button:hover { box-shadow: 0 8px 20px color-mix(in srgb, var(--primary) 35%, transparent); }
.nav-center + button:active,
.nav-center button:active { transform: translateY(1px) scale(0.98); }
@@ -252,9 +249,8 @@ body:has(#home-container.active) #downloads-btn {
position: absolute;
top: 30px;
right: 0;
background:
linear-gradient(180deg, rgba(30,34,50,0.92), rgba(25,28,42,0.92)) padding-box,
linear-gradient(135deg, rgba(140, 86, 255, 0.25), rgba(62, 149, 255, 0.18)) border-box;
background: color-mix(in srgb, var(--url-bar-bg) 92%, var(--text) 8%);
border: 1px solid color-mix(in srgb, var(--primary) 25%, color-mix(in srgb, var(--accent) 18%, transparent));
border-radius: 14px;
padding: 8px;
display: flex;
@@ -288,13 +284,13 @@ body:has(#home-container.active) #downloads-btn {
}
#menu-popup button:hover {
background: rgba(255,255,255,0.06);
background: color-mix(in srgb, var(--text) 8%, transparent);
}
/* Big Picture Mode button special style */
#bigpicture-btn {
background: linear-gradient(135deg, rgba(123, 46, 255, 0.15) 0%, rgba(0, 198, 255, 0.1) 100%) !important;
border: 1px solid rgba(123, 46, 255, 0.3) !important;
background: linear-gradient(135deg, color-mix(in srgb, var(--primary) 15%, transparent) 0%, color-mix(in srgb, var(--accent) 10%, transparent) 100%) !important;
border: 1px solid color-mix(in srgb, var(--primary) 30%, transparent) !important;
margin: 4px 0;
}
@@ -322,10 +318,8 @@ body:has(#home-container.active) #downloads-btn {
position: absolute;
top: 34px;
right: 0;
background:
linear-gradient(180deg, rgba(30,34,50,0.95), rgba(25,28,42,0.95)) padding-box,
linear-gradient(135deg, rgba(140, 86, 255, 0.18), rgba(62, 149, 255, 0.14)) border-box;
border: 1px solid transparent;
background: color-mix(in srgb, var(--url-bar-bg) 95%, var(--text) 5%);
border: 1px solid color-mix(in srgb, var(--primary) 18%, color-mix(in srgb, var(--accent) 14%, transparent));
border-radius: 12px;
min-width: 280px;
box-shadow: var(--shadow-1);
@@ -339,14 +333,14 @@ body:has(#home-container.active) #downloads-btn {
.downloads-pop-header > span { font-weight: 600; color: var(--text); }
.downloads-pop-header > button { background: transparent; border: none; color: var(--accent); cursor: pointer; }
.downloads-pop-list { display:flex; flex-direction: column; gap: 8px; max-height: 280px; overflow: auto; }
.downloads-empty { color: #aaa; font-size: 12px; text-align: center; padding: 16px 8px; }
.dl-item { display:grid; grid-template-columns: 1fr auto; gap: 6px 8px; background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.06); border-radius: 10px; padding: 8px; }
.dl-file { font-size: 12px; color: #eee; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }
.dl-meta { font-size: 11px; color: #bbb; }
.downloads-empty { color: var(--tab-text); font-size: 12px; text-align: center; padding: 16px 8px; }
.dl-item { display:grid; grid-template-columns: 1fr auto; gap: 6px 8px; background: color-mix(in srgb, var(--text) 3%, transparent); border: 1px solid color-mix(in srgb, var(--text) 6%, transparent); border-radius: 10px; padding: 8px; }
.dl-file { font-size: 12px; color: var(--text); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }
.dl-meta { font-size: 11px; color: var(--tab-text); }
.dl-actions { display:flex; gap:6px; }
.dl-actions button { background: transparent; color: #ddd; border: 1px solid rgba(255,255,255,0.12); border-radius: 8px; padding: 4px 8px; cursor: pointer; }
.dl-progress { height: 4px; background: rgba(255,255,255,0.08); border-radius: 3px; overflow: hidden; grid-column: 1 / -1; }
.dl-bar { height: 100%; background: #3b82f6; width: 0%; transition: width .12s linear; }
.dl-actions button { background: transparent; color: var(--text); border: 1px solid color-mix(in srgb, var(--text) 12%, transparent); border-radius: 8px; padding: 4px 8px; cursor: pointer; }
.dl-progress { height: 4px; background: color-mix(in srgb, var(--text) 8%, transparent); border-radius: 3px; overflow: hidden; grid-column: 1 / -1; }
.dl-bar { height: 100%; background: var(--accent); width: 0%; transition: width .12s linear; }
/* Circular progress ring around downloads button */
#downloads-btn { position: relative; }
@@ -361,8 +355,8 @@ body:has(#home-container.active) #downloads-btn {
pointer-events: none;
}
#downloads-btn .ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
#downloads-btn .ring circle.bg { stroke: rgba(255,255,255,0.15); stroke-width: 3; fill: none; }
#downloads-btn .ring circle.fg { stroke: #3b82f6; stroke-width: 3; fill: none; stroke-linecap: round; transition: stroke-dashoffset .12s linear, opacity .12s ease; }
#downloads-btn .ring circle.bg { stroke: color-mix(in srgb, var(--text) 15%, transparent); stroke-width: 3; fill: none; }
#downloads-btn .ring circle.fg { stroke: var(--accent); stroke-width: 3; fill: none; stroke-linecap: round; transition: stroke-dashoffset .12s linear, opacity .12s ease; }
/* WEBVIEWS */
#webviews {
@@ -452,7 +446,7 @@ body:has(#home-container.active) #downloads-btn {
.tab.active {
color: var(--tab-active-text);
background: var(--tab-active);
box-shadow: 0 8px 22px rgba(0,0,0,0.35);
box-shadow: 0 8px 22px color-mix(in srgb, var(--bg) 35%, transparent);
}
.tab.active::after {
@@ -462,7 +456,7 @@ body:has(#home-container.active) #downloads-btn {
right: 0;
top: 0;
height: 2px;
background: linear-gradient(90deg, var(--accent), var(--accent-600));
background: var(--accent);
}
.tab .tab-favicon {
@@ -489,15 +483,15 @@ body:has(#home-container.active) #downloads-btn {
border: none;
border-radius: 11px;
background: transparent;
color: #b5b5b5;
color: var(--tab-text);
opacity: 0; /* hidden by default */
transition: background 120ms ease, color 120ms ease, opacity 120ms ease;
}
.tab:hover .tab-close,
.tab.active .tab-close { opacity: 1; }
.tab .tab-close:hover { background: #3b3e47; color: #fff; }
.tab .tab-close:active { background: #2e3139; }
.tab .tab-close:hover { background: color-mix(in srgb, var(--text) 20%, transparent); color: var(--text); }
.tab .tab-close:active { background: color-mix(in srgb, var(--text) 15%, transparent); }
/* New tab (+) button aligned to the right end of the strip */
.new-tab-button {
@@ -508,15 +502,13 @@ body:has(#home-container.active) #downloads-btn {
display: grid;
place-items: center;
border-radius: 13px;
border: 1px solid transparent;
background:
linear-gradient(180deg, rgba(50,54,74,0.98), rgba(38,42,60,0.98)) padding-box,
linear-gradient(180deg, rgba(255,255,255,0.18), rgba(0,0,0,0.45)) border-box;
color: #f0f0f6;
border: 1px solid color-mix(in srgb, var(--text) 18%, transparent);
background: color-mix(in srgb, var(--tab-bg) 90%, var(--text) 10%);
color: var(--text);
cursor: pointer;
transition: transform 120ms ease, background 120ms ease, color 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
}
.new-tab-button:hover { filter: brightness(1.06); box-shadow: 0 6px 16px rgba(0,0,0,0.35); }
.new-tab-button:hover { filter: brightness(1.06); box-shadow: 0 6px 16px color-mix(in srgb, var(--bg) 35%, transparent); }
.new-tab-button:active { transform: translateY(1px) scale(0.98); }
/* ZOOM CONTROLS */
@@ -525,8 +517,8 @@ body:has(#home-container.active) #downloads-btn {
align-items: center;
gap: 6px;
padding: 6px 8px;
background: rgba(255,255,255,0.04);
border: 1px solid rgba(255,255,255,0.07);
background: color-mix(in srgb, var(--text) 4%, transparent);
border: 1px solid color-mix(in srgb, var(--text) 7%, transparent);
border-radius: 10px;
}
.zoom-controls .zoom-label {
@@ -556,31 +548,58 @@ body:has(#home-container.active) #downloads-btn {
color: var(--muted);
}
/* window controls (Windows only) */
/* window controls (Windows/Linux only) - Firefox-style next to tabs */
#window-controls {
position: absolute;
top: 0;
right: 0;
display: flex;
gap: 2px;
padding: 4px;
z-index: 200;
align-items: stretch;
align-self: stretch;
-webkit-app-region: no-drag;
background: transparent;
border-bottom: 1px solid var(--tab-border);
}
#window-controls button {
width: 46px;
height: 28px;
background: transparent;
border: none;
color: white;
font-size: 12px;
color: var(--text);
cursor: pointer;
transition: background 120ms ease;
transition: background 120ms ease, color 120ms ease;
display: flex;
align-items: center;
justify-content: center;
-webkit-app-region: no-drag;
padding: 0;
}
#window-controls button svg {
width: 12px;
height: 12px;
pointer-events: none;
}
#window-controls button:hover {
background: rgba(255,255,255,0.1);
color: var(--text);
}
#window-controls #close-btn:hover {
background: #e81123;
color: white;
}
#window-controls #close-btn:hover svg path {
stroke: white;
}
/* Hide window controls on macOS via body class set by JS */
body.platform-darwin #window-controls {
display: none !important;
}
/* macOS: add left padding for traffic lights */
body.platform-darwin #tab-bar {
padding-left: var(--window-controls-offset);
}
#tab-bar::-webkit-scrollbar {
@@ -709,35 +728,32 @@ body:has(#home-container.active) #downloads-btn {
box-shadow: none;
}
/* Stronger chrome contrast when Home is visible */
/* Stronger chrome contrast when Home is visible - uses theme variables */
body:has(#home-container.active) #tab-bar {
background: linear-gradient(180deg, rgba(12,14,20,0.88), rgba(12,14,20,0.82));
border-bottom-color: rgba(255,255,255,0.08);
background: color-mix(in srgb, var(--tab-bg) 92%, black);
border-bottom-color: color-mix(in srgb, var(--tab-border) 80%, transparent);
box-shadow: 0 10px 24px -12px rgba(0,0,0,0.6);
}
body:has(#home-container.active) #nav {
background: linear-gradient(180deg, rgba(14,16,22,0.9), rgba(14,16,22,0.84));
border-bottom: 1px solid rgba(255,255,255,0.08);
background: color-mix(in srgb, var(--url-bar-bg) 92%, black);
border-bottom: 1px solid color-mix(in srgb, var(--url-bar-border) 80%, transparent);
box-shadow: 0 14px 36px -16px rgba(0,0,0,0.7);
}
body:has(#home-container.active) .nav-center {
background:
linear-gradient(180deg, rgba(24,26,36,0.96), rgba(20,22,32,0.96)) padding-box,
linear-gradient(135deg, rgba(140, 86, 255, 0.45), rgba(62, 149, 255, 0.32)) border-box;
border: 1px solid transparent;
background: color-mix(in srgb, var(--url-bar-bg) 96%, black);
border: 1px solid color-mix(in srgb, var(--primary, var(--accent)) 45%, transparent);
}
body:has(#home-container.active) .nav-left button,
body:has(#home-container.active) .nav-right > button,
body:has(#home-container.active) #reload-btn,
body:has(#home-container.active) #menu-btn {
/* slightly lighter than nav to pop over Home */
background:
linear-gradient(180deg, rgba(60,66,90,0.98), rgba(44,48,68,0.98)) padding-box,
linear-gradient(180deg, rgba(255,255,255,0.22), rgba(0,0,0,0.5)) border-box;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
/* slightly lighter than nav to pop over Home - uses theme colors */
background: color-mix(in srgb, var(--url-bar-bg) 85%, var(--text) 15%);
border: 1px solid color-mix(in srgb, var(--text) 20%, transparent);
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 10%, transparent);
}
/* Elevate active tab a touch more over home */