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
+7 -2
View File
@@ -539,9 +539,11 @@ function createWindow(startUrl, bigPictureMode = false) {
transparent: true, transparent: true,
}); });
} else if (process.platform === 'win32') { } else if (process.platform === 'win32') {
// Use frameless window on Windows with custom title bar controls
// rendered in the tab strip area (Firefox-style).
Object.assign(windowOptions, { Object.assign(windowOptions, {
frame: true, // Use default Windows title bar. frame: false,
// removed titleBarOverlay to restore native Windows controls. backgroundColor: '#0b0d10',
}); });
} else { } else {
windowOptions.frame = true; windowOptions.frame = true;
@@ -932,6 +934,9 @@ ipcMain.handle('window-maximize', event => {
ipcMain.handle('window-close', event => { ipcMain.handle('window-close', event => {
BrowserWindow.fromWebContents(event.sender).close(); BrowserWindow.fromWebContents(event.sender).close();
}); });
ipcMain.handle('window-is-maximized', event => {
return BrowserWindow.fromWebContents(event.sender).isMaximized();
});
// Add site and search history IPC handlers // Add site and search history IPC handlers
// Site history is now handled via localStorage in the renderer // Site history is now handled via localStorage in the renderer
+46 -50
View File
@@ -49,14 +49,14 @@ body, html {
padding: 4rem 2rem 2rem; padding: 4rem 2rem 2rem;
} }
.edit-btn { position: fixed; top: 16px; right: 16px; z-index: 5; background: rgba(255,255,255,0.1); color:#fff; border:1px solid rgba(255,255,255,0.2); border-radius:8px; padding:6px 10px; cursor:pointer; backdrop-filter: blur(6px); } .edit-btn { position: fixed; top: 16px; right: 16px; z-index: 5; background: color-mix(in srgb, var(--text) 10%, transparent); color: var(--text); border:1px solid color-mix(in srgb, var(--text) 20%, transparent); border-radius:8px; padding:6px 10px; cursor:pointer; backdrop-filter: blur(6px); }
.edit-btn[aria-pressed="true"] { background: rgba(255,255,255,0.22); } .edit-btn[aria-pressed="true"] { background: color-mix(in srgb, var(--text) 22%, transparent); }
.edit-mode .edit-btn { display:none; } .edit-mode .edit-btn { display:none; }
.edit-mode .greeting-title, .edit-mode .search-container, .edit-mode .top-sites-card, .edit-mode .glance { outline: 2px dashed rgba(255,255,255,0.35); outline-offset: 4px; cursor: grab; } .edit-mode .greeting-title, .edit-mode .search-container, .edit-mode .top-sites-card, .edit-mode .glance { outline: 2px dashed color-mix(in srgb, var(--text) 35%, transparent); outline-offset: 4px; cursor: grab; }
.edit-mode .glance.dragging { cursor: grabbing; } .edit-mode .glance.dragging { cursor: grabbing; }
/* Edit toolbar */ /* Edit toolbar */
.edit-toolbar { position: fixed; top: 16px; right: 16px; display:none; gap:10px; z-index:6; backdrop-filter: blur(8px); background: rgba(8,10,16,0.5); border:1px solid rgba(255,255,255,0.15); padding:8px 10px; border-radius:12px; box-shadow: 0 12px 30px -14px rgba(0,0,0,.7); } .edit-toolbar { position: fixed; top: 16px; right: 16px; display:none; gap:10px; z-index:6; backdrop-filter: blur(8px); background: color-mix(in srgb, var(--bg) 50%, transparent); border:1px solid color-mix(in srgb, var(--text) 15%, transparent); padding:8px 10px; border-radius:12px; box-shadow: 0 12px 30px -14px color-mix(in srgb, var(--bg) 70%, transparent); }
.edit-mode .edit-toolbar { display:flex; } .edit-mode .edit-toolbar { display:flex; }
.edit-toolbar[hidden] { display: none !important; } .edit-toolbar[hidden] { display: none !important; }
@@ -65,17 +65,17 @@ body, html {
.edit-btn.pos-bl, .edit-toolbar.pos-bl { left:16px; bottom:16px; right:auto; top:auto; } .edit-btn.pos-bl, .edit-toolbar.pos-bl { left:16px; bottom:16px; right:auto; top:auto; }
.edit-btn.pos-tr, .edit-toolbar.pos-tr { right:16px; top:16px; left:auto; bottom:auto; } .edit-btn.pos-tr, .edit-toolbar.pos-tr { right:16px; top:16px; left:auto; bottom:auto; }
.edit-btn.pos-tl, .edit-toolbar.pos-tl { left:16px; top:16px; right:auto; bottom:auto; } .edit-btn.pos-tl, .edit-toolbar.pos-tl { left:16px; top:16px; right:auto; bottom:auto; }
.edit-toolbar .btn { min-width:90px; padding:8px 12px; border-radius:8px; border:1px solid transparent; color:#fff; cursor:pointer; } .edit-toolbar .btn { min-width:90px; padding:8px 12px; border-radius:8px; border:1px solid transparent; color: var(--text); cursor:pointer; }
.edit-toolbar .btn.primary { background: linear-gradient(135deg, var(--accent), var(--primary)); } .edit-toolbar .btn.primary { background: linear-gradient(135deg, var(--accent), var(--primary)); }
.edit-toolbar .btn.secondary { background: rgba(255,255,255,0.14); border-color: rgba(255,255,255,0.2); } .edit-toolbar .btn.secondary { background: color-mix(in srgb, var(--text) 14%, transparent); border-color: color-mix(in srgb, var(--text) 20%, transparent); }
/* Greeting hero title */ /* Greeting hero title */
.greeting-title { .greeting-title {
font-size: clamp(2rem, 5vw, 3.5rem); font-size: clamp(2rem, 5vw, 3.5rem);
font-weight: 700; font-weight: 700;
letter-spacing: 0.3px; letter-spacing: 0.3px;
color: #cfd4ff; color: var(--text);
text-shadow: 0 4px 22px rgba(0,0,0,0.6); text-shadow: 0 4px 22px color-mix(in srgb, var(--bg) 60%, transparent);
margin-bottom: 1.25rem; margin-bottom: 1.25rem;
position: relative; position: relative;
top: var(--home-greeting-y); top: var(--home-greeting-y);
@@ -119,14 +119,10 @@ body, html {
z-index: 300; /* ensure dropdown overlays bookmarks/top-sites stacking contexts */ z-index: 300; /* ensure dropdown overlays bookmarks/top-sites stacking contexts */
top: var(--home-search-y); top: var(--home-search-y);
/* Unified glassy pill */ /* Unified glassy pill */
background: linear-gradient( background: color-mix(in srgb, var(--text) 12%, transparent);
180deg, border: 1px solid color-mix(in srgb, var(--text) 20%, transparent);
rgba(255,255,255,0.14),
rgba(255,255,255,0.10)
);
border: 1px solid rgba(255,255,255,0.20);
border-radius: 9999px; border-radius: 9999px;
box-shadow: 0 18px 50px -22px rgba(0,0,0,0.8), inset 0 1px 0 rgba(255,255,255,0.12); box-shadow: 0 18px 50px -22px color-mix(in srgb, var(--bg) 80%, transparent), inset 0 1px 0 color-mix(in srgb, var(--text) 12%, transparent);
backdrop-filter: blur(10px) saturate(140%); backdrop-filter: blur(10px) saturate(140%);
-webkit-backdrop-filter: blur(10px) saturate(140%); -webkit-backdrop-filter: blur(10px) saturate(140%);
padding: 6px 8px; padding: 6px 8px;
@@ -134,13 +130,13 @@ body, html {
} }
.search-container:hover { .search-container:hover {
background: linear-gradient(180deg, rgba(255,255,255,0.18), rgba(255,255,255,0.12)); background: color-mix(in srgb, var(--text) 16%, transparent);
border-color: rgba(255,255,255,0.28); border-color: color-mix(in srgb, var(--text) 28%, transparent);
} }
.search-container:focus-within { .search-container:focus-within {
box-shadow: 0 22px 60px -24px rgba(0,0,0,0.9), 0 0 0 2px rgba(123,46,255,0.45), inset 0 1px 0 rgba(255,255,255,0.16); box-shadow: 0 22px 60px -24px color-mix(in srgb, var(--bg) 90%, transparent), 0 0 0 2px color-mix(in srgb, var(--primary) 45%, transparent), inset 0 1px 0 color-mix(in srgb, var(--text) 16%, transparent);
border-color: rgba(123,46,255,0.55); border-color: color-mix(in srgb, var(--primary) 55%, transparent);
} }
/* Search bar */ /* Search bar */
@@ -161,18 +157,18 @@ body, html {
padding: 0 10px 0 8px; padding: 0 10px 0 8px;
font-size: 1.05rem; font-size: 1.05rem;
line-height: 1; line-height: 1;
color: #ffffff; color: var(--text);
caret-color: var(--accent); caret-color: var(--accent);
} }
.search-bar input.search-input::placeholder { .search-bar input.search-input::placeholder {
color: rgba(255,255,255,0.55); color: color-mix(in srgb, var(--text) 55%, transparent);
} }
.search-bar button.search-btn { .search-bar button.search-btn {
border: 1px solid rgba(255,255,255,0.14); border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
background: rgba(12,14,20,0.45); background: color-mix(in srgb, var(--bg) 45%, transparent);
color: white; color: var(--text);
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 9999px; border-radius: 9999px;
@@ -184,7 +180,7 @@ body, html {
transition: transform 120ms ease, background 160ms ease, border-color 160ms ease; transition: transform 120ms ease, background 160ms ease, border-color 160ms ease;
} }
.search-bar button.search-btn:hover { transform: scale(1.02); background: rgba(24,26,34,0.55); border-color: rgba(255,255,255,0.24); } .search-bar button.search-btn:hover { transform: scale(1.02); background: color-mix(in srgb, var(--bg) 55%, transparent); border-color: color-mix(in srgb, var(--text) 24%, transparent); }
.search-bar button.search-btn:active { transform: scale(0.98); } .search-bar button.search-btn:active { transform: scale(0.98); }
.search-bar button.search-btn .material-symbols-outlined { .search-bar button.search-btn .material-symbols-outlined {
@@ -194,8 +190,8 @@ body, html {
/* Search engine trigger unified look */ /* Search engine trigger unified look */
.search-engine-selector { position: relative; display: flex; align-items: center; } .search-engine-selector { position: relative; display: flex; align-items: center; }
.search-engine-btn { .search-engine-btn {
background: rgba(12,14,20,0.45); background: color-mix(in srgb, var(--bg) 45%, transparent);
border: 1px solid rgba(255,255,255,0.14); border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
border-radius: 9999px; border-radius: 9999px;
padding: 8px 10px 8px 12px; padding: 8px 10px 8px 12px;
cursor: pointer; cursor: pointer;
@@ -207,7 +203,7 @@ body, html {
box-shadow: none; box-shadow: none;
transition: background 160ms ease, border-color 160ms ease, transform 120ms ease; transition: background 160ms ease, border-color 160ms ease, transform 120ms ease;
} }
.search-engine-btn:hover { background: rgba(24,26,34,0.55); border-color: rgba(255,255,255,0.24); } .search-engine-btn:hover { background: color-mix(in srgb, var(--bg) 55%, transparent); border-color: color-mix(in srgb, var(--text) 24%, transparent); }
.search-engine-btn:active { transform: scale(0.98); } .search-engine-btn:active { transform: scale(0.98); }
.search-engine-btn img { width: 22px; height: 22px; filter: none; } .search-engine-btn img { width: 22px; height: 22px; filter: none; }
@@ -220,7 +216,7 @@ body, html {
top: 8px; top: 8px;
bottom: 8px; bottom: 8px;
width: 1px; width: 1px;
background: linear-gradient(to bottom, rgba(255,255,255,0.06), rgba(255,255,255,0.24), rgba(255,255,255,0.06)); background: linear-gradient(to bottom, color-mix(in srgb, var(--text) 6%, transparent), color-mix(in srgb, var(--text) 24%, transparent), color-mix(in srgb, var(--text) 6%, transparent));
pointer-events: none; pointer-events: none;
} }
@@ -244,10 +240,10 @@ body, html {
position: absolute; position: absolute;
top: 110%; top: 110%;
left: 0; left: 0;
background: linear-gradient(180deg, rgba(18,20,24,0.96), rgba(18,20,24,0.9)); background: color-mix(in srgb, var(--bg) 94%, #000 6%);
border-radius: 10px; border-radius: 10px;
border: 1px solid rgba(255,255,255,0.12); border: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
box-shadow: 0 18px 50px -22px rgba(0,0,0,0.8), inset 0 1px 0 rgba(255,255,255,0.06); box-shadow: 0 18px 50px -22px color-mix(in srgb, var(--bg) 80%, transparent), inset 0 1px 0 color-mix(in srgb, var(--text) 6%, transparent);
z-index: 100; z-index: 100;
padding: 0.5rem; padding: 0.5rem;
display: flex; display: flex;
@@ -310,9 +306,9 @@ body, html {
margin-top: 1.25rem; margin-top: 1.25rem;
padding: 1rem 1rem 1.25rem; padding: 1rem 1rem 1.25rem;
border-radius: 16px; border-radius: 16px;
background: radial-gradient(120% 140% at 0% 0%, rgba(255,255,255,0.06), rgba(255,255,255,0.03) 45%, rgba(255,255,255,0.02)); background: color-mix(in srgb, var(--text) 6%, transparent);
border: 1px solid rgba(255,255,255,0.12); border: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
box-shadow: 0 18px 50px -20px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.06); box-shadow: 0 18px 50px -20px color-mix(in srgb, var(--bg) 60%, transparent), inset 0 1px 0 color-mix(in srgb, var(--text) 6%, transparent);
backdrop-filter: blur(6px); backdrop-filter: blur(6px);
position: relative; position: relative;
top: var(--home-bookmarks-y); top: var(--home-bookmarks-y);
@@ -321,18 +317,18 @@ body, html {
display:flex; align-items:center; justify-content:space-between; display:flex; align-items:center; justify-content:space-between;
margin-bottom: 0.75rem; padding: 0 0.25rem; margin-bottom: 0.75rem; padding: 0 0.25rem;
} }
.top-sites-header h2 { font-size: 1rem; font-weight: 700; color: #dfe3ff; opacity: .9; } .top-sites-header h2 { font-size: 1rem; font-weight: 700; color: var(--text); opacity: .9; }
.link-btn { .link-btn {
background: none; border: none; color: #9aa8ff; cursor: pointer; font-size: .9rem; background: none; border: none; color: var(--accent); cursor: pointer; font-size: .9rem;
} }
.link-btn:hover { color: #c7d0ff; text-decoration: underline; } .link-btn:hover { color: var(--primary); text-decoration: underline; }
/* Individual bookmark tile */ /* Individual bookmark tile */
.bookmark { .bookmark {
background: rgba(255,255,255,0.05); background: color-mix(in srgb, var(--text) 5%, transparent);
border: 1px solid rgba(255,255,255,0.1); border: 1px solid color-mix(in srgb, var(--text) 10%, transparent);
backdrop-filter: blur(6px); backdrop-filter: blur(6px);
box-shadow: 0 4px 16px rgba(0,0,0,0.3); box-shadow: 0 4px 16px color-mix(in srgb, var(--bg) 30%, transparent);
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
color: var(--text); color: var(--text);
width: 100px; width: 100px;
@@ -349,7 +345,7 @@ body, html {
.bookmark:hover { .bookmark:hover {
transform: translateY(-4px) scale(1.1); transform: translateY(-4px) scale(1.1);
box-shadow: 0 8px 24px rgba(0,0,0,0.5); box-shadow: 0 8px 24px color-mix(in srgb, var(--bg) 50%, transparent);
} }
.bookmark-icon { .bookmark-icon {
@@ -462,7 +458,7 @@ body[data-theme="dark"] .bookmark .material-symbols-outlined,
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background: rgba(18,20,24,0.8); background: color-mix(in srgb, var(--bg) 80%, transparent);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -563,18 +559,18 @@ body[data-theme="dark"] .bookmark .material-symbols-outlined,
.glance.pos-tr { right:22px; top:22px; left:auto; bottom:auto; } .glance.pos-tr { right:22px; top:22px; left:auto; bottom:auto; }
.glance.pos-tl { left:22px; top:22px; right:auto; bottom:auto; } .glance.pos-tl { left:22px; top:22px; right:auto; bottom:auto; }
.glance-card { .glance-card {
min-width: 280px; background: rgba(12,16,26,0.55); border: 1px solid rgba(255,255,255,0.1); min-width: 280px; background: color-mix(in srgb, var(--bg) 55%, transparent); border: 1px solid color-mix(in srgb, var(--text) 10%, transparent);
border-radius: 16px; padding: 1rem; box-shadow: 0 14px 40px -18px rgba(0,0,0,.8), inset 0 1px 0 rgba(255,255,255,0.05); border-radius: 16px; padding: 1rem; box-shadow: 0 14px 40px -18px color-mix(in srgb, var(--bg) 80%, transparent), inset 0 1px 0 color-mix(in srgb, var(--text) 5%, transparent);
backdrop-filter: blur(8px); backdrop-filter: blur(8px);
} }
.glance { transition: transform 0.06s linear; will-change: transform; } .glance { transition: transform 0.06s linear; will-change: transform; }
.glance.dragging { transform: translate3d(var(--drag-x, 0px), var(--drag-y, 0px), 0) scale(1.02); } .glance.dragging { transform: translate3d(var(--drag-x, 0px), var(--drag-y, 0px), 0) scale(1.02); }
.glance.dragging .glance-card { box-shadow: 0 24px 60px -24px rgba(0,0,0,.9), 0 0 0 2px rgba(255,255,255,.12) inset; } .glance.dragging .glance-card { box-shadow: 0 24px 60px -24px color-mix(in srgb, var(--bg) 90%, transparent), 0 0 0 2px color-mix(in srgb, var(--text) 12%, transparent) inset; }
.glance-title { font-size: .95rem; color: #dfe3ff; opacity: .9; margin-bottom: .65rem; } .glance-title { font-size: .95rem; color: var(--text); opacity: .9; margin-bottom: .65rem; }
.glance-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; } .glance-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.glance-tile { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); border-radius: 12px; padding: .6rem .75rem; text-align:left; } .glance-tile { background: color-mix(in srgb, var(--text) 5%, transparent); border: 1px solid color-mix(in srgb, var(--text) 10%, transparent); border-radius: 12px; padding: .6rem .75rem; text-align:left; }
.glance-label { font-size: .7rem; color: #b8c1ff; opacity: .85; margin-bottom: .25rem; } .glance-label { font-size: .7rem; color: var(--accent); opacity: .85; margin-bottom: .25rem; }
.glance-value { font-size: 1.05rem; letter-spacing: .3px; color:#fff; } .glance-value { font-size: 1.05rem; letter-spacing: .3px; color: var(--text); }
@media (max-width: 700px) { @media (max-width: 700px) {
.glance { position: static; margin-top: 1rem; } .glance { position: static; margin-top: 1rem; }
+23
View File
@@ -25,7 +25,30 @@
</style> </style>
</head> </head>
<body> <body>
<!-- Windows title bar controls wrapper - sits above tab bar -->
<div id="titlebar-container">
<div id="tab-bar"></div> <div id="tab-bar"></div>
<div id="window-controls">
<button id="min-btn" title="Minimize" aria-label="Minimize">
<svg width="10" height="10" viewBox="0 0 10 10">
<path d="M0 5h10" stroke="currentColor" stroke-width="1" fill="none"/>
</svg>
</button>
<button id="max-btn" title="Maximize" aria-label="Maximize">
<svg width="10" height="10" viewBox="0 0 10 10" class="maximize-icon">
<rect x="0.5" y="0.5" width="9" height="9" stroke="currentColor" stroke-width="1" fill="none"/>
</svg>
<svg width="10" height="10" viewBox="0 0 10 10" class="restore-icon" style="display:none">
<path d="M2.5 0.5h7v7M0.5 2.5h7v7h-7z" stroke="currentColor" stroke-width="1" fill="none"/>
</svg>
</button>
<button id="close-btn" title="Close" aria-label="Close">
<svg width="10" height="10" viewBox="0 0 10 10">
<path d="M0 0l10 10M10 0l-10 10" stroke="currentColor" stroke-width="1" fill="none"/>
</svg>
</button>
</div>
</div>
<div id="nav"> <div id="nav">
<div class="nav-left"> <div class="nav-left">
+185 -19
View File
@@ -128,24 +128,110 @@ function addToSiteHistory(url) {
} }
} }
// Store current theme colors globally for use by renderTabs
let currentThemeColors = null;
// Apply theme colors to the main UI (URL bar and tabs) // Apply theme colors to the main UI (URL bar and tabs)
function applyThemeToMainUI(theme) { function applyThemeToMainUI(theme) {
if (!theme || !theme.colors) return; if (!theme || !theme.colors) return;
const root = document.documentElement; const root = document.documentElement;
const colors = theme.colors;
// Apply URL bar and tab colors // Store colors globally for renderTabs to use
if (theme.colors.urlBarBg) root.style.setProperty('--url-bar-bg', theme.colors.urlBarBg); currentThemeColors = colors;
if (theme.colors.urlBarText) root.style.setProperty('--url-bar-text', theme.colors.urlBarText);
if (theme.colors.urlBarBorder) root.style.setProperty('--url-bar-border', theme.colors.urlBarBorder);
if (theme.colors.tabBg) root.style.setProperty('--tab-bg', theme.colors.tabBg);
if (theme.colors.tabText) root.style.setProperty('--tab-text', theme.colors.tabText);
if (theme.colors.tabActive) root.style.setProperty('--tab-active', theme.colors.tabActive);
if (theme.colors.tabActiveText) root.style.setProperty('--tab-active-text', theme.colors.tabActiveText);
if (theme.colors.tabBorder) root.style.setProperty('--tab-border', theme.colors.tabBorder);
console.log('[THEME] Applied theme colors to main UI'); // Set CSS variables on root for elements using var()
const setVar = (cssVar, value, fallback) => {
const val = value || fallback;
if (val) root.style.setProperty(cssVar, val);
};
// Core palette so popups/menus and the address bar stay in sync
setVar('--bg', colors.bg, '#0b0d10');
setVar('--dark-blue', colors.darkBlue, '#0b1c2b');
setVar('--dark-purple', colors.darkPurple, '#1b1035');
setVar('--primary', colors.primary, '#7b2eff');
setVar('--accent', colors.accent, '#00c6ff');
setVar('--text', colors.text, '#e0e0e0');
// URL bar + tab strip styling
setVar('--url-bar-bg', colors.urlBarBg, '#1c2030');
setVar('--url-bar-text', colors.urlBarText, '#e0e0e0');
setVar('--url-bar-border', colors.urlBarBorder, '#3e4652');
setVar('--tab-bg', colors.tabBg, '#161925');
setVar('--tab-text', colors.tabText, '#a4a7b3');
setVar('--tab-active', colors.tabActive, '#1c2030');
setVar('--tab-active-text', colors.tabActiveText, '#e0e0e0');
setVar('--tab-border', colors.tabBorder, '#2b3040');
// Also directly apply to key elements to ensure styles take effect
const nav = document.getElementById('nav');
const titlebarContainer = document.getElementById('titlebar-container');
const tabBar = document.getElementById('tab-bar');
const urlBox = document.getElementById('url');
const navCenter = document.querySelector('.nav-center');
if (nav) {
nav.style.setProperty('background', colors.urlBarBg || '#1c2030', 'important');
nav.style.setProperty('border-bottom-color', colors.urlBarBorder || '#3e4652', 'important');
} }
if (navCenter) {
navCenter.style.setProperty('background', colors.urlBarBg || '#1c2030', 'important');
navCenter.style.setProperty('border-color', colors.urlBarBorder || '#3e4652', 'important');
}
if (titlebarContainer) {
titlebarContainer.style.setProperty('background', colors.tabBg || '#161925', 'important');
}
if (tabBar) {
tabBar.style.setProperty('background', colors.tabBg || '#161925', 'important');
tabBar.style.setProperty('border-bottom-color', colors.tabBorder || '#2b3040', 'important');
}
if (urlBox) {
urlBox.style.setProperty('color', colors.urlBarText || '#e0e0e0', 'important');
}
// Update existing tab elements to reflect new theme colors
document.querySelectorAll('.tab').forEach(tab => {
const isActive = tab.classList.contains('active');
tab.style.setProperty('background', isActive
? (colors.tabActive || '#1c2030')
: (colors.tabBg || '#161925'), 'important');
tab.style.setProperty('color', isActive
? (colors.tabActiveText || '#e0e0e0')
: (colors.tabText || '#a4a7b3'), 'important');
tab.style.setProperty('border-color', colors.tabBorder || '#2b3040', 'important');
});
// Align the chrome background with the theme gradient or fallback
if (theme.gradient) {
document.body.style.background = theme.gradient;
} else if (colors.bg) {
document.body.style.background = colors.bg;
}
// Persist so other pages (home/settings) can pull the latest palette
try { localStorage.setItem('currentTheme', JSON.stringify(theme)); } catch {}
console.log('[THEME] Applied theme to main UI:', {
urlBarBg: colors.urlBarBg,
tabBg: colors.tabBg,
navFound: !!nav,
titlebarFound: !!titlebarContainer,
tabBarFound: !!tabBar
});
}
// Detect platform and add class to body for CSS platform-specific styling
(function detectPlatform() {
const platform = navigator.platform.toLowerCase();
if (platform.includes('mac')) {
document.body.classList.add('platform-darwin');
} else if (platform.includes('win')) {
document.body.classList.add('platform-win32');
} else {
document.body.classList.add('platform-linux');
}
})();
// 1) cache hot DOM references // 1) cache hot DOM references
const urlBox = document.getElementById('url'); const urlBox = document.getElementById('url');
@@ -729,6 +815,8 @@ function convertHomeTabToWebview(tabId, inputUrl, resolvedUrl) {
// After creating dynamic webview: // After creating dynamic webview:
webview.addEventListener('ipc-message', e => { webview.addEventListener('ipc-message', e => {
if (e.channel === 'theme-update') { if (e.channel === 'theme-update') {
const theme = e.args && e.args[0];
if (theme) applyThemeToMainUI(theme);
const home = document.getElementById('home-webview'); const home = document.getElementById('home-webview');
if (home) home.send('theme-update', ...e.args); if (home) home.send('theme-update', ...e.args);
} else if (e.channel === 'navigate' && e.args[0]) { } else if (e.channel === 'navigate' && e.args[0]) {
@@ -908,6 +996,18 @@ function renderTabs() {
el.dataset.tabId = tab.id; el.dataset.tabId = tab.id;
currentOrder.push(tab.id); currentOrder.push(tab.id);
// Apply theme colors to new tab element
if (currentThemeColors) {
const isActive = tab.id === activeTabId;
el.style.setProperty('background', isActive
? (currentThemeColors.tabActive || '#1c2030')
: (currentThemeColors.tabBg || '#161925'), 'important');
el.style.setProperty('color', isActive
? (currentThemeColors.tabActiveText || '#e0e0e0')
: (currentThemeColors.tabText || '#a4a7b3'), 'important');
el.style.setProperty('border-color', currentThemeColors.tabBorder || '#2b3040', 'important');
}
if (!lastTabOrder.includes(tab.id)) { if (!lastTabOrder.includes(tab.id)) {
// New tab enters with animation // New tab enters with animation
el.classList.add('tab--enter'); el.classList.add('tab--enter');
@@ -1215,6 +1315,18 @@ window.addEventListener('DOMContentLoaded', () => {
try { try {
const theme = JSON.parse(savedTheme); const theme = JSON.parse(savedTheme);
applyThemeToMainUI(theme); applyThemeToMainUI(theme);
// Also send to home-webview once it's ready
const homeWebview = document.getElementById('home-webview');
if (homeWebview) {
const sendThemeToHome = () => {
try { homeWebview.send('theme-update', theme); } catch {}
};
// If already loaded, send immediately; otherwise wait for dom-ready
if (homeWebview.getWebContentsId) {
sendThemeToHome();
}
homeWebview.addEventListener('dom-ready', sendThemeToHome, { once: true });
}
} catch (err) { } catch (err) {
console.error('Error applying saved theme:', err); console.error('Error applying saved theme:', err);
} }
@@ -1371,17 +1483,71 @@ window.addEventListener('DOMContentLoaded', () => {
window.downloadsAPI?.onDone(()=> { refreshDownloadsMini(); }); window.downloadsAPI?.onDone(()=> { refreshDownloadsMini(); });
window.downloadsAPI?.onCleared(()=> { refreshDownloadsMini(); }); window.downloadsAPI?.onCleared(()=> { refreshDownloadsMini(); });
// window control bindings // window control bindings (Windows frameless window)
const minBtn = document.getElementById('min-btn'); const minBtn = document.getElementById('min-btn');
const maxBtn = document.getElementById('max-btn'); const maxBtn = document.getElementById('max-btn');
const closeBtn = document.getElementById('close-btn'); const closeBtn = document.getElementById('close-btn');
if (minBtn && maxBtn && closeBtn) { const windowControls = document.getElementById('window-controls');
if (process.platform !== 'darwin') {
minBtn.addEventListener('click', () => ipcRenderer.invoke('window-minimize')); console.log('[WindowControls] Elements found:', { minBtn: !!minBtn, maxBtn: !!maxBtn, closeBtn: !!closeBtn, windowControls: !!windowControls });
maxBtn.addEventListener('click', () => ipcRenderer.invoke('window-maximize'));
closeBtn.addEventListener('click', () => ipcRenderer.invoke('window-close')); // Detect platform - hide controls on macOS (uses native traffic lights)
} else { const isMacOS = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
document.getElementById('window-controls').style.display = 'none'; console.log('[WindowControls] Platform:', navigator.platform, 'isMacOS:', isMacOS);
if (windowControls) {
if (isMacOS) {
// Hide window controls on macOS
windowControls.style.display = 'none';
// Remove right padding for window controls
document.getElementById('tab-bar').style.paddingRight = '10px';
} else if (minBtn && maxBtn && closeBtn) {
// Windows/Linux: Set up custom title bar controls
console.log('[WindowControls] Setting up event listeners for Windows/Linux');
minBtn.addEventListener('click', (e) => {
console.log('[WindowControls] Minimize clicked');
e.stopPropagation();
ipcRenderer.invoke('window-minimize');
});
maxBtn.addEventListener('click', async (e) => {
console.log('[WindowControls] Maximize clicked');
e.stopPropagation();
await ipcRenderer.invoke('window-maximize');
updateMaximizeIcon();
});
closeBtn.addEventListener('click', (e) => {
console.log('[WindowControls] Close clicked');
e.stopPropagation();
ipcRenderer.invoke('window-close');
});
// Update maximize icon based on window state
async function updateMaximizeIcon() {
try {
const isMaximized = await ipcRenderer.invoke('window-is-maximized');
const maximizeIcon = maxBtn.querySelector('.maximize-icon');
const restoreIcon = maxBtn.querySelector('.restore-icon');
if (maximizeIcon && restoreIcon) {
maximizeIcon.style.display = isMaximized ? 'none' : 'block';
restoreIcon.style.display = isMaximized ? 'block' : 'none';
maxBtn.title = isMaximized ? 'Restore' : 'Maximize';
maxBtn.setAttribute('aria-label', isMaximized ? 'Restore' : 'Maximize');
}
} catch (e) {
// Ignore errors during state check
}
}
// Initial state check
updateMaximizeIcon();
// Listen for window resize to update maximize icon
window.addEventListener('resize', () => {
// Debounce resize events
clearTimeout(window._maximizeIconTimeout);
window._maximizeIconTimeout = setTimeout(updateMaximizeIcon, 100);
});
} }
} }
+29 -25
View File
@@ -53,7 +53,7 @@ body {
.container { .container {
position: relative; position: relative;
background: linear-gradient(180deg, rgba(20, 14, 40, 0.6), rgba(16, 10, 28, 0.6)); background: linear-gradient(180deg, color-mix(in srgb, var(--bg) 85%, #000 15%), color-mix(in srgb, var(--dark-purple, var(--bg)) 80%, #000 20%));
backdrop-filter: blur(14px) saturate(120%); backdrop-filter: blur(14px) saturate(120%);
-webkit-backdrop-filter: blur(14px) saturate(120%); -webkit-backdrop-filter: blur(14px) saturate(120%);
padding: 0; padding: 0;
@@ -73,7 +73,7 @@ body {
position: absolute; position: absolute;
inset: -1px; inset: -1px;
border-radius: inherit; border-radius: inherit;
background: linear-gradient(135deg, rgba(123,46,255,0.25), rgba(0,198,255,0.15) 40%, transparent 60%); background: linear-gradient(135deg, color-mix(in srgb, var(--primary) 25%, transparent), color-mix(in srgb, var(--accent) 18%, transparent) 40%, transparent 60%);
filter: blur(20px); filter: blur(20px);
z-index: 0; z-index: 0;
pointer-events: none; pointer-events: none;
@@ -82,7 +82,7 @@ body {
/* Sidebar + content layout */ /* Sidebar + content layout */
.sidebar { .sidebar {
width: 280px; width: 280px;
background: linear-gradient(180deg, rgba(255,255,255,0.03), rgba(255,255,255,0.02)); background: linear-gradient(180deg, color-mix(in srgb, var(--text) 6%, transparent), color-mix(in srgb, var(--text) 4%, transparent));
border-right: 1px solid rgba(255,255,255,0.08); border-right: 1px solid rgba(255,255,255,0.08);
padding: 1.25rem 1rem; padding: 1.25rem 1rem;
position: relative; position: relative;
@@ -127,10 +127,10 @@ body {
} }
.tab-link.active { .tab-link.active {
background: linear-gradient(180deg, rgba(123, 46, 255, 0.18), rgba(0, 198, 255, 0.10)); background: linear-gradient(180deg, color-mix(in srgb, var(--primary) 22%, transparent), color-mix(in srgb, var(--accent) 14%, transparent));
color: #fff; color: var(--text);
border: 1px solid rgba(123,46,255,0.35); border: 1px solid color-mix(in srgb, var(--primary) 35%, transparent);
box-shadow: inset 0 0 0 1px rgba(255,255,255,0.06); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text) 8%, transparent);
} }
/* Left accent bar */ /* Left accent bar */
@@ -185,24 +185,24 @@ label {
input { input {
padding: 0.6rem; padding: 0.6rem;
font-size: 1rem; font-size: 1rem;
border: 1px solid rgba(255,255,255,0.12); border: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
border-radius: 10px; border-radius: 10px;
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
background-color: rgba(11, 28, 43, 0.6); background-color: color-mix(in srgb, var(--bg) 82%, #000 18%);
color: var(--text); color: var(--text);
outline: none; outline: none;
} }
input:focus { input:focus {
box-shadow: var(--ring); box-shadow: var(--ring);
border-color: rgba(123,46,255,0.5); border-color: color-mix(in srgb, var(--primary) 50%, transparent);
} }
button { button {
padding: 0.65rem 0.9rem; padding: 0.65rem 0.9rem;
font-size: 0.95rem; font-size: 0.95rem;
background: linear-gradient(180deg, rgba(123,46,255,0.95), rgba(90, 20, 220, 0.95)); background: linear-gradient(180deg, color-mix(in srgb, var(--primary) 90%, var(--accent) 10%), color-mix(in srgb, var(--primary) 80%, #000 20%));
color: #fff; color: var(--text);
border: 1px solid rgba(255,255,255,0.08); border: 1px solid color-mix(in srgb, var(--primary) 18%, transparent);
border-radius: 10px; border-radius: 10px;
cursor: pointer; cursor: pointer;
transition: transform 0.08s ease, box-shadow 0.2s ease, background 0.2s ease, filter 0.2s ease; transition: transform 0.08s ease, box-shadow 0.2s ease, background 0.2s ease, filter 0.2s ease;
@@ -225,30 +225,30 @@ button:active {
padding: 12px 24px; padding: 12px 24px;
font-size: 1rem; font-size: 1rem;
font-weight: 600; font-weight: 600;
background: linear-gradient(135deg, #7B2EFF 0%, #5a1fd4 50%, #00C6FF 100%); background: linear-gradient(135deg, var(--primary) 0%, color-mix(in srgb, var(--primary) 60%, #000 40%) 50%, var(--accent) 100%);
background-size: 200% 100%; background-size: 200% 100%;
color: #fff; color: var(--text);
border: 1px solid rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.15);
border-radius: 12px; border-radius: 12px;
cursor: pointer; cursor: pointer;
transition: all 0.3s ease; transition: all 0.3s ease;
box-shadow: 0 4px 20px rgba(123, 46, 255, 0.3); box-shadow: 0 4px 20px color-mix(in srgb, var(--primary) 30%, transparent);
} }
.primary-btn:hover { .primary-btn:hover {
background-position: 100% 0; background-position: 100% 0;
box-shadow: 0 6px 30px rgba(123, 46, 255, 0.45), 0 0 20px rgba(0, 198, 255, 0.2); box-shadow: 0 6px 30px color-mix(in srgb, var(--primary) 45%, transparent), 0 0 20px color-mix(in srgb, var(--accent) 20%, transparent);
transform: translateY(-2px); transform: translateY(-2px);
} }
.primary-btn:active { .primary-btn:active {
transform: translateY(0); transform: translateY(0);
box-shadow: 0 2px 10px rgba(123, 46, 255, 0.3); box-shadow: 0 2px 10px color-mix(in srgb, var(--primary) 30%, transparent);
} }
.note { .note {
font-size: 0.8rem; font-size: 0.8rem;
color: #aaa; color: color-mix(in srgb, var(--text) 70%, transparent);
margin-top: 1rem; margin-top: 1rem;
} }
@@ -260,11 +260,11 @@ button:active {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
background-color: rgba(18,20,24,0.8); background-color: color-mix(in srgb, var(--bg) 82%, #000 18%);
color: white; color: var(--text);
padding: 0.8rem 1.2rem; padding: 0.8rem 1.2rem;
border-radius: 12px; border-radius: 12px;
border: 1px solid rgba(255,255,255,0.08); border: 1px solid color-mix(in srgb, var(--text) 8%, transparent);
box-shadow: 0 8px 30px rgba(0,0,0,0.5); box-shadow: 0 8px 30px rgba(0,0,0,0.5);
font-size: 1rem; font-size: 1rem;
z-index: 1000; z-index: 1000;
@@ -300,7 +300,7 @@ button:active {
/* Cards (customization groups) */ /* Cards (customization groups) */
.customization-group { .customization-group {
background: linear-gradient(180deg, var(--surface-1), var(--surface-2)); background: linear-gradient(180deg, var(--surface-1, color-mix(in srgb, var(--bg) 85%, #000 15%)), var(--surface-2, color-mix(in srgb, var(--bg) 78%, #000 22%)));
border: 1px solid var(--card-border); border: 1px solid var(--card-border);
border-radius: 14px; border-radius: 14px;
padding: 14px 16px 16px 16px; padding: 14px 16px 16px 16px;
@@ -348,6 +348,10 @@ h2::after {
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 16px; gap: 16px;
padding: 10px 0; padding: 10px 0;
background: linear-gradient(180deg, var(--surface-1, color-mix(in srgb, var(--bg) 85%, #000 15%)), var(--surface-2, color-mix(in srgb, var(--bg) 78%, #000 22%)));
border: 1px solid var(--card-border);
border-radius: 12px;
padding: 12px;
} }
.theme-btn { .theme-btn {
display: flex; display: flex;
@@ -494,8 +498,8 @@ input[type="color"] {
align-items: center; align-items: center;
gap: 8px; gap: 8px;
padding: 8px 12px; padding: 8px 12px;
background: linear-gradient(180deg, rgba(123,46,255,0.95), rgba(90, 20, 220, 0.95)); background: var(--accent);
color: #fff; color: var(--text);
border: 1px solid rgba(255,255,255,0.08) !important; border: 1px solid rgba(255,255,255,0.08) !important;
border-radius: 10px !important; border-radius: 10px !important;
text-decoration: none; text-decoration: none;
+107 -91
View File
@@ -2,12 +2,9 @@ html, body {
height: 100%; height: 100%;
margin: 0; margin: 0;
padding: 0; padding: 0;
/* Subtle aurora background that peeks through glassy chrome */ /* Background now driven by theme */
background: background: var(--bg, #0b0d10);
radial-gradient(1200px 600px at 10% -10%, rgba(62, 33, 110, 0.18), transparent 45%), color: var(--text, white);
radial-gradient(1000px 500px at 90% -20%, rgba(18, 124, 201, 0.16), transparent 40%),
#0b0d10;
color: white;
font-family: 'Segoe UI', system-ui, -apple-system, Ubuntu, Roboto, sans-serif; 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). /* Space reserved on the left for system window controls (traffic lights on macOS).
Applied cross-platform per request to keep a consistent layout. */ Applied cross-platform per request to keep a consistent layout. */
--window-controls-offset: 80px; /* adjust if needed */ --window-controls-offset: 80px; /* adjust if needed */
/* Space reserved on the right for Windows title bar controls */
--window-controls-width: 138px;
/* Design tokens */ /* Design tokens */
--bg: #0b0d10; --bg: #0b0d10;
@@ -50,22 +49,30 @@ html, body {
--tab-border: #2B3040; --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 STRIP */
#tab-bar { #tab-bar {
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
gap: 2px; gap: 2px;
/* Increase left padding to avoid overlap with OS window controls area */ flex: 1;
padding: 6px 10px 0 var(--window-controls-offset); /* Default: small left padding for Windows/Linux (no traffic lights) */
padding: 6px 10px 0 10px;
background: var(--tab-bg); background: var(--tab-bg);
border-bottom: 1px solid var(--tab-border); border-bottom: 1px solid var(--tab-border);
overflow-x: auto; /* scroll when many tabs */ overflow-x: auto; /* scroll when many tabs */
scrollbar-color: #444 #2a2a3c; /* thumb and track for Firefox */ scrollbar-color: #444 #2a2a3c; /* thumb and track for Firefox */
scrollbar-width: thin; /* slimmer track */ scrollbar-width: thin; /* slimmer track */
-webkit-backdrop-filter: blur(var(--blur)); /* Inherit drag from container */
backdrop-filter: blur(var(--blur));
/* Only the background areas are draggable. Individual tabs opt-out via no-drag. */
-webkit-app-region: drag; -webkit-app-region: drag;
min-height: 38px;
} }
/* NAVBAR LAYOUT */ /* NAVBAR LAYOUT */
@@ -153,13 +160,9 @@ html, body {
.nav-right > button, .nav-right > button,
#reload-btn, #reload-btn,
#menu-btn { #menu-btn {
background: background: color-mix(in srgb, var(--url-bar-bg) 90%, var(--text) 10%);
/* 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;
color: var(--text); color: var(--text);
border: 1px solid transparent; border: 1px solid color-mix(in srgb, var(--text) 15%, transparent);
width: 34px; width: 34px;
height: 34px; height: 34px;
display: inline-grid; display: inline-grid;
@@ -167,7 +170,7 @@ html, body {
border-radius: 50%; border-radius: 50%;
cursor: pointer; cursor: pointer;
/* subtle inner highlight adds edge definition */ /* 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; transition: transform 120ms ease, box-shadow 120ms ease, filter 120ms ease;
line-height: 0; /* avoid vertical misalignment for glyphs */ line-height: 0; /* avoid vertical misalignment for glyphs */
padding: 0; padding: 0;
@@ -177,24 +180,21 @@ html, body {
/* Downloads button chrome to match other nav buttons */ /* Downloads button chrome to match other nav buttons */
#downloads-btn { #downloads-btn {
background: background: color-mix(in srgb, var(--url-bar-bg) 90%, var(--text) 10%);
linear-gradient(180deg, rgba(50,54,74,0.96), rgba(38,42,60,0.96)) padding-box, color: var(--text);
linear-gradient(180deg, rgba(255,255,255,0.18), rgba(0,0,0,0.45)) border-box; border: 1px solid color-mix(in srgb, var(--text) 15%, transparent);
color: var(--muted);
border: 1px solid transparent;
width: 34px; width: 34px;
height: 34px; height: 34px;
display: inline-grid; display: inline-grid;
place-items: center; place-items: center;
border-radius: 50%; border-radius: 50%;
cursor: pointer; 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; transition: transform 120ms ease, box-shadow 120ms ease, filter 120ms ease, color 120ms ease;
line-height: 0; line-height: 0;
padding: 0; padding: 0;
-webkit-appearance: none; -webkit-appearance: none;
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: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); } #downloads-btn:active { transform: translateY(1px) scale(0.98); }
@@ -203,10 +203,8 @@ html, body {
/* Match home-active chrome variant */ /* Match home-active chrome variant */
body:has(#home-container.active) #downloads-btn { body:has(#home-container.active) #downloads-btn {
background: background: color-mix(in srgb, var(--url-bar-bg) 85%, var(--text) 15%);
linear-gradient(180deg, rgba(60,66,90,0.98), rgba(44,48,68,0.98)) padding-box, box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 10%, transparent);
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);
} }
.nav-left button:hover, .nav-left button:hover,
@@ -214,7 +212,7 @@ body:has(#home-container.active) #downloads-btn {
#reload-btn:hover, #reload-btn:hover,
#menu-btn:hover { #menu-btn:hover {
filter: brightness(1.05); 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, .nav-left button:active,
@@ -227,9 +225,8 @@ body:has(#home-container.active) #downloads-btn {
/* Primary action (Go button) keeps rectangular look but modernized */ /* Primary action (Go button) keeps rectangular look but modernized */
.nav-center + button, .nav-center + button,
.nav-center button { .nav-center button {
background: background: var(--accent);
linear-gradient(180deg, var(--accent), var(--accent-700)); color: var(--text);
color: white !important;
border: 1px solid transparent; border: 1px solid transparent;
padding: 8px 14px; padding: 8px 14px;
border-radius: 10px; 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; transition: transform 120ms ease, box-shadow 120ms ease, filter 120ms ease;
} }
.nav-center + button:hover, .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,
.nav-center button:active { transform: translateY(1px) scale(0.98); } .nav-center button:active { transform: translateY(1px) scale(0.98); }
@@ -252,9 +249,8 @@ body:has(#home-container.active) #downloads-btn {
position: absolute; position: absolute;
top: 30px; top: 30px;
right: 0; right: 0;
background: background: color-mix(in srgb, var(--url-bar-bg) 92%, var(--text) 8%);
linear-gradient(180deg, rgba(30,34,50,0.92), rgba(25,28,42,0.92)) padding-box, border: 1px solid color-mix(in srgb, var(--primary) 25%, color-mix(in srgb, var(--accent) 18%, transparent));
linear-gradient(135deg, rgba(140, 86, 255, 0.25), rgba(62, 149, 255, 0.18)) border-box;
border-radius: 14px; border-radius: 14px;
padding: 8px; padding: 8px;
display: flex; display: flex;
@@ -288,13 +284,13 @@ body:has(#home-container.active) #downloads-btn {
} }
#menu-popup button:hover { #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 */ /* Big Picture Mode button special style */
#bigpicture-btn { #bigpicture-btn {
background: linear-gradient(135deg, rgba(123, 46, 255, 0.15) 0%, rgba(0, 198, 255, 0.1) 100%) !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 rgba(123, 46, 255, 0.3) !important; border: 1px solid color-mix(in srgb, var(--primary) 30%, transparent) !important;
margin: 4px 0; margin: 4px 0;
} }
@@ -322,10 +318,8 @@ body:has(#home-container.active) #downloads-btn {
position: absolute; position: absolute;
top: 34px; top: 34px;
right: 0; right: 0;
background: background: color-mix(in srgb, var(--url-bar-bg) 95%, var(--text) 5%);
linear-gradient(180deg, rgba(30,34,50,0.95), rgba(25,28,42,0.95)) padding-box, border: 1px solid color-mix(in srgb, var(--primary) 18%, color-mix(in srgb, var(--accent) 14%, transparent));
linear-gradient(135deg, rgba(140, 86, 255, 0.18), rgba(62, 149, 255, 0.14)) border-box;
border: 1px solid transparent;
border-radius: 12px; border-radius: 12px;
min-width: 280px; min-width: 280px;
box-shadow: var(--shadow-1); 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 > span { font-weight: 600; color: var(--text); }
.downloads-pop-header > button { background: transparent; border: none; color: var(--accent); cursor: pointer; } .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-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; } .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: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.06); border-radius: 10px; padding: 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: #eee; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } .dl-file { font-size: 12px; color: var(--text); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }
.dl-meta { font-size: 11px; color: #bbb; } .dl-meta { font-size: 11px; color: var(--tab-text); }
.dl-actions { display:flex; gap:6px; } .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-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: rgba(255,255,255,0.08); border-radius: 3px; overflow: hidden; grid-column: 1 / -1; } .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: #3b82f6; width: 0%; transition: width .12s linear; } .dl-bar { height: 100%; background: var(--accent); width: 0%; transition: width .12s linear; }
/* Circular progress ring around downloads button */ /* Circular progress ring around downloads button */
#downloads-btn { position: relative; } #downloads-btn { position: relative; }
@@ -361,8 +355,8 @@ body:has(#home-container.active) #downloads-btn {
pointer-events: none; pointer-events: none;
} }
#downloads-btn .ring svg { width: 100%; height: 100%; transform: rotate(-90deg); } #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.bg { stroke: color-mix(in srgb, var(--text) 15%, transparent); 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.fg { stroke: var(--accent); stroke-width: 3; fill: none; stroke-linecap: round; transition: stroke-dashoffset .12s linear, opacity .12s ease; }
/* WEBVIEWS */ /* WEBVIEWS */
#webviews { #webviews {
@@ -452,7 +446,7 @@ body:has(#home-container.active) #downloads-btn {
.tab.active { .tab.active {
color: var(--tab-active-text); color: var(--tab-active-text);
background: var(--tab-active); 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 { .tab.active::after {
@@ -462,7 +456,7 @@ body:has(#home-container.active) #downloads-btn {
right: 0; right: 0;
top: 0; top: 0;
height: 2px; height: 2px;
background: linear-gradient(90deg, var(--accent), var(--accent-600)); background: var(--accent);
} }
.tab .tab-favicon { .tab .tab-favicon {
@@ -489,15 +483,15 @@ body:has(#home-container.active) #downloads-btn {
border: none; border: none;
border-radius: 11px; border-radius: 11px;
background: transparent; background: transparent;
color: #b5b5b5; color: var(--tab-text);
opacity: 0; /* hidden by default */ opacity: 0; /* hidden by default */
transition: background 120ms ease, color 120ms ease, opacity 120ms ease; transition: background 120ms ease, color 120ms ease, opacity 120ms ease;
} }
.tab:hover .tab-close, .tab:hover .tab-close,
.tab.active .tab-close { opacity: 1; } .tab.active .tab-close { opacity: 1; }
.tab .tab-close:hover { background: #3b3e47; color: #fff; } .tab .tab-close:hover { background: color-mix(in srgb, var(--text) 20%, transparent); color: var(--text); }
.tab .tab-close:active { background: #2e3139; } .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 aligned to the right end of the strip */
.new-tab-button { .new-tab-button {
@@ -508,15 +502,13 @@ body:has(#home-container.active) #downloads-btn {
display: grid; display: grid;
place-items: center; place-items: center;
border-radius: 13px; border-radius: 13px;
border: 1px solid transparent; border: 1px solid color-mix(in srgb, var(--text) 18%, transparent);
background: background: color-mix(in srgb, var(--tab-bg) 90%, var(--text) 10%);
linear-gradient(180deg, rgba(50,54,74,0.98), rgba(38,42,60,0.98)) padding-box, color: var(--text);
linear-gradient(180deg, rgba(255,255,255,0.18), rgba(0,0,0,0.45)) border-box;
color: #f0f0f6;
cursor: pointer; cursor: pointer;
transition: transform 120ms ease, background 120ms ease, color 120ms ease, border-color 120ms ease, box-shadow 120ms ease; 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); } .new-tab-button:active { transform: translateY(1px) scale(0.98); }
/* ZOOM CONTROLS */ /* ZOOM CONTROLS */
@@ -525,8 +517,8 @@ body:has(#home-container.active) #downloads-btn {
align-items: center; align-items: center;
gap: 6px; gap: 6px;
padding: 6px 8px; padding: 6px 8px;
background: rgba(255,255,255,0.04); background: color-mix(in srgb, var(--text) 4%, transparent);
border: 1px solid rgba(255,255,255,0.07); border: 1px solid color-mix(in srgb, var(--text) 7%, transparent);
border-radius: 10px; border-radius: 10px;
} }
.zoom-controls .zoom-label { .zoom-controls .zoom-label {
@@ -556,31 +548,58 @@ body:has(#home-container.active) #downloads-btn {
color: var(--muted); color: var(--muted);
} }
/* window controls (Windows only) */ /* window controls (Windows/Linux only) - Firefox-style next to tabs */
#window-controls { #window-controls {
position: absolute;
top: 0;
right: 0;
display: flex; display: flex;
gap: 2px; align-items: stretch;
padding: 4px; align-self: stretch;
z-index: 200; -webkit-app-region: no-drag;
background: transparent;
border-bottom: 1px solid var(--tab-border);
} }
#window-controls button { #window-controls button {
width: 46px; width: 46px;
height: 28px;
background: transparent; background: transparent;
border: none; border: none;
color: white; color: var(--text);
font-size: 12px;
cursor: pointer; 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 { #window-controls button:hover {
background: rgba(255,255,255,0.1); background: rgba(255,255,255,0.1);
color: var(--text);
} }
#window-controls #close-btn:hover { #window-controls #close-btn:hover {
background: #e81123; 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 { #tab-bar::-webkit-scrollbar {
@@ -709,35 +728,32 @@ body:has(#home-container.active) #downloads-btn {
box-shadow: none; 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 { body:has(#home-container.active) #tab-bar {
background: linear-gradient(180deg, rgba(12,14,20,0.88), rgba(12,14,20,0.82)); background: color-mix(in srgb, var(--tab-bg) 92%, black);
border-bottom-color: rgba(255,255,255,0.08); border-bottom-color: color-mix(in srgb, var(--tab-border) 80%, transparent);
box-shadow: 0 10px 24px -12px rgba(0,0,0,0.6); box-shadow: 0 10px 24px -12px rgba(0,0,0,0.6);
} }
body:has(#home-container.active) #nav { body:has(#home-container.active) #nav {
background: linear-gradient(180deg, rgba(14,16,22,0.9), rgba(14,16,22,0.84)); background: color-mix(in srgb, var(--url-bar-bg) 92%, black);
border-bottom: 1px solid rgba(255,255,255,0.08); 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); box-shadow: 0 14px 36px -16px rgba(0,0,0,0.7);
} }
body:has(#home-container.active) .nav-center { body:has(#home-container.active) .nav-center {
background: background: color-mix(in srgb, var(--url-bar-bg) 96%, black);
linear-gradient(180deg, rgba(24,26,36,0.96), rgba(20,22,32,0.96)) padding-box, border: 1px solid color-mix(in srgb, var(--primary, var(--accent)) 45%, transparent);
linear-gradient(135deg, rgba(140, 86, 255, 0.45), rgba(62, 149, 255, 0.32)) border-box;
border: 1px solid transparent;
} }
body:has(#home-container.active) .nav-left button, body:has(#home-container.active) .nav-left button,
body:has(#home-container.active) .nav-right > button, body:has(#home-container.active) .nav-right > button,
body:has(#home-container.active) #reload-btn, body:has(#home-container.active) #reload-btn,
body:has(#home-container.active) #menu-btn { body:has(#home-container.active) #menu-btn {
/* slightly lighter than nav to pop over Home */ /* slightly lighter than nav to pop over Home - uses theme colors */
background: background: color-mix(in srgb, var(--url-bar-bg) 85%, var(--text) 15%);
linear-gradient(180deg, rgba(60,66,90,0.98), rgba(44,48,68,0.98)) padding-box, border: 1px solid color-mix(in srgb, var(--text) 20%, transparent);
linear-gradient(180deg, rgba(255,255,255,0.22), rgba(0,0,0,0.5)) border-box; box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 10%, transparent);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
} }
/* Elevate active tab a touch more over home */ /* Elevate active tab a touch more over home */