Redesign settings UI and update Electron to v40

Revamps the settings page with improved layout, modernized CSS, and enhanced accessibility, including new layout helpers, better grouping, and consistent styling. Updates Electron from v39.2.7 to v40.0.0 in dependencies. Adds dynamic theme application to the settings page, ensuring user-selected themes are reflected immediately.
This commit is contained in:
2026-01-18 13:22:46 +13:00
parent bb4cbabb76
commit 0eb9ec0c9a
5 changed files with 502 additions and 265 deletions
+22 -5
View File
@@ -16,7 +16,7 @@
"steamworks.js": "^0.3.2" "steamworks.js": "^0.3.2"
}, },
"devDependencies": { "devDependencies": {
"electron": "^39.2.7", "electron": "^40.0.0",
"electron-builder": "^23.0.0", "electron-builder": "^23.0.0",
"electron-nightly": "^39.0.0-nightly.20250811" "electron-nightly": "^39.0.0-nightly.20250811"
} }
@@ -1407,15 +1407,15 @@
} }
}, },
"node_modules/electron": { "node_modules/electron": {
"version": "39.2.7", "version": "40.0.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-39.2.7.tgz", "resolved": "https://registry.npmjs.org/electron/-/electron-40.0.0.tgz",
"integrity": "sha512-KU0uFS6LSTh4aOIC3miolcbizOFP7N1M46VTYVfqIgFiuA2ilfNaOHLDS9tCMvwwHRowAsvqBrh9NgMXcTOHCQ==", "integrity": "sha512-UyBy5yJ0/wm4gNugCtNPjvddjAknMTuXR2aCHioXicH7aKRKGDBPp4xqTEi/doVcB3R+MN3wfU9o8d/9pwgK2A==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@electron/get": "^2.0.0", "@electron/get": "^2.0.0",
"@types/node": "^22.7.7", "@types/node": "^24.9.0",
"extract-zip": "^2.0.1" "extract-zip": "^2.0.1"
}, },
"bin": { "bin": {
@@ -1693,6 +1693,23 @@
"node": ">= 10.0.0" "node": ">= 10.0.0"
} }
}, },
"node_modules/electron/node_modules/@types/node": {
"version": "24.10.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz",
"integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"node_modules/electron/node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+1 -1
View File
@@ -22,7 +22,7 @@
"steamworks.js": "^0.3.2" "steamworks.js": "^0.3.2"
}, },
"devDependencies": { "devDependencies": {
"electron": "^39.2.7", "electron": "^40.0.0",
"electron-builder": "^23.0.0", "electron-builder": "^23.0.0",
"electron-nightly": "^39.0.0-nightly.20250811" "electron-nightly": "^39.0.0-nightly.20250811"
}, },
+396 -232
View File
@@ -14,16 +14,19 @@
.plugin-authors .muted { opacity:.7; margin-right: 6px; } .plugin-authors .muted { opacity:.7; margin-right: 6px; }
:root { :root {
--bg: #121418; --bg: #121418;
--dark-blue: #0B1C2B; --gradient-end: #1B1035;
--dark-purple: #1B1035; --surface: rgba(255, 255, 255, 0.06);
--surface-hover: rgba(255, 255, 255, 0.10);
--primary: #7B2EFF; --primary: #7B2EFF;
--primary-hover: #9654FF;
--accent: #00C6FF; --accent: #00C6FF;
--text: #E0E0E0; --text: #E0E0E0;
--surface-1: rgba(255, 255, 255, 0.04); --text-secondary: #B8B8C0;
--surface-2: rgba(255, 255, 255, 0.06); --text-muted: #8f8f9d;
--card-border: rgba(255, 255, 255, 0.10); --border: rgba(255, 255, 255, 0.12);
--ring: 0 0 0 3px rgba(123, 46, 255, 0.35); --border-subtle: rgba(255, 255, 255, 0.06);
--glow: 0 8px 30px rgba(123, 46, 255, 0.25), 0 2px 10px rgba(0, 198, 255, 0.15); --ring: 0 0 0 2px rgba(123, 46, 255, 0.4);
--glow-subtle: 0 4px 20px rgba(123, 46, 255, 0.15);
} }
/* Load InterVariable */ /* Load InterVariable */
@@ -35,15 +38,14 @@
} }
body { body {
/* Nebula gradient background with subtle radial glow */
background: background:
radial-gradient(1200px 600px at 10% -10%, rgba(0, 198, 255, 0.15), transparent 60%), radial-gradient(800px 400px at 10% 0%, rgba(123, 46, 255, 0.08), transparent 60%),
radial-gradient(1000px 500px at 110% 10%, rgba(123, 46, 255, 0.2), transparent 60%), radial-gradient(800px 400px at 100% 20%, rgba(0, 198, 255, 0.06), transparent 60%),
linear-gradient(145deg, var(--bg) 0%, var(--dark-purple) 100%); linear-gradient(180deg, var(--bg), var(--gradient-end));
color: var(--text); color: var(--text);
font-family: 'InterVariable', system-ui, -apple-system, Segoe UI, Roboto, sans-serif; font-family: 'InterVariable', system-ui, -apple-system, 'Segoe UI', 'Roboto', sans-serif;
margin: 0; margin: 0;
padding: 2rem; padding: 0;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: flex-start; align-items: flex-start;
@@ -53,47 +55,39 @@ body {
.container { .container {
position: relative; position: relative;
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%)); background: var(--bg);
backdrop-filter: blur(14px) saturate(120%);
-webkit-backdrop-filter: blur(14px) saturate(120%);
padding: 0; padding: 0;
border-radius: 18px; border-radius: 0;
border: 1px solid var(--card-border); border: none;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45); box-shadow: none;
max-width: 1200px; max-width: 100vw;
width: 100%; width: 100%;
display: flex; display: flex;
overflow: hidden; overflow: hidden;
max-height: calc(100vh - 4rem); height: 100vh;
} }
/* Subtle animated sheen around the container */ /* Subtle animated sheen around the container */
.container::before {
content: '';
position: absolute;
inset: -1px;
border-radius: inherit;
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);
z-index: 0;
pointer-events: none;
}
/* Sidebar + content layout */ /* Sidebar + content layout */
.sidebar { .sidebar {
width: 280px; width: 260px;
background: linear-gradient(180deg, color-mix(in srgb, var(--text) 6%, transparent), color-mix(in srgb, var(--text) 4%, transparent)); background: linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.02));
border-right: 1px solid rgba(255,255,255,0.08); border-right: 1px solid var(--border);
padding: 1.25rem 1rem; padding: 1.5rem 0;
position: relative; position: relative;
z-index: 1; z-index: 1;
overflow-y: auto;
} }
.sidebar h1 { .sidebar h1 {
font-size: 1.1rem; font-size: 1.35rem;
margin: 0 0 1rem 0; font-weight: 300;
margin: 0 0 1.5rem 0;
padding: 0 1rem;
color: var(--primary); color: var(--primary);
letter-spacing: 0.4px; letter-spacing: -0.01em;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
@@ -102,58 +96,50 @@ body {
.tabs { .tabs {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 4px; gap: 2px;
} }
.tab-link { .tab-link {
text-align: left; text-align: left;
background: linear-gradient(180deg, transparent, transparent); background: transparent;
color: var(--text); color: var(--text-secondary);
border: 1px solid transparent; border: none;
border-radius: 10px; border-radius: 4px;
padding: 10px 12px 10px 14px; padding: 10px 1rem;
margin: 0;
cursor: pointer; cursor: pointer;
transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease, transform 0.1s ease; transition: background 0.15s ease, color 0.15s ease;
font-size: 14px; font-size: 15px;
font-weight: 400;
font-family: inherit; font-family: inherit;
width: 100%; width: 100%;
position: relative; position: relative;
z-index: 1; z-index: 1;
border-left: 3px solid transparent;
} }
.tab-link:hover { .tab-link:hover {
background: rgba(255,255,255,0.06); background: var(--surface);
border-color: rgba(255,255,255,0.08); color: var(--text);
} }
.tab-link.active { .tab-link.active {
background: linear-gradient(180deg, color-mix(in srgb, var(--primary) 22%, transparent), color-mix(in srgb, var(--accent) 14%, transparent)); background: linear-gradient(90deg, rgba(123, 46, 255, 0.12), rgba(0, 198, 255, 0.08));
color: var(--text); color: var(--text);
border: 1px solid color-mix(in srgb, var(--primary) 35%, transparent); border-left-color: var(--primary);
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text) 8%, transparent); font-weight: 500;
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
} }
/* Left accent bar */
.tab-link.active::before {
content: '';
position: absolute;
left: -1px;
top: 8px;
bottom: 8px;
width: 3px;
border-radius: 2px;
background: linear-gradient(180deg, var(--accent), var(--primary));
}
.content { .content {
flex: 1; flex: 1;
padding: 1.25rem 1.5rem 2rem 1.5rem; padding: 2rem 3rem;
overflow: auto; overflow: auto;
position: relative; position: relative;
z-index: 1; z-index: 1;
background: background: var(--bg);
radial-gradient(800px 300px at 60% -10%, rgba(0, 198, 255, 0.10), transparent 50%),
radial-gradient(700px 260px at 20% -20%, rgba(123, 46, 255, 0.18), transparent 50%);
} }
.tab-panel { .tab-panel {
@@ -164,92 +150,112 @@ body {
display: block; display: block;
} }
h1 {
font-size: 1.5rem;
margin-bottom: 1.5rem;
color: var(--primary);
}
.setting-group { .setting-group {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.6rem; gap: 0.75rem;
margin-bottom: 1rem; margin-bottom: 1.5rem;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1rem 1.25rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
} }
label { label {
font-weight: bold; font-weight: 400;
margin-bottom: 0.5rem; margin-bottom: 0.35rem;
color: var(--text);
font-size: 15px;
} }
input { input[type="text"],
padding: 0.6rem; input[type="file"] {
font-size: 1rem; padding: 0.5rem 0.65rem;
border: 1px solid color-mix(in srgb, var(--text) 12%, transparent); font-size: 14px;
border-radius: 10px; border: 1px solid var(--border);
margin-bottom: 0.75rem; border-radius: 6px;
background-color: color-mix(in srgb, var(--bg) 82%, #000 18%); margin-bottom: 0.5rem;
background-color: var(--surface);
color: var(--text); color: var(--text);
outline: none; outline: none;
transition: all 0.15s ease;
} }
input:focus { input[type="text"]:focus,
input[type="file"]:focus {
box-shadow: var(--ring); box-shadow: var(--ring);
border-color: color-mix(in srgb, var(--primary) 50%, transparent); border-color: var(--primary);
background-color: var(--surface-hover);
}
select {
padding: 0.5rem 0.65rem;
font-size: 14px;
border: 1px solid var(--border);
border-radius: 6px;
background-color: var(--surface);
color: var(--text);
outline: none;
transition: all 0.15s ease;
}
select:focus {
box-shadow: var(--ring);
border-color: var(--primary);
background-color: var(--surface-hover);
} }
button { button {
padding: 0.65rem 0.9rem; padding: 0.5rem 1rem;
font-size: 0.95rem; font-size: 14px;
background: linear-gradient(180deg, color-mix(in srgb, var(--primary) 90%, var(--accent) 10%), color-mix(in srgb, var(--primary) 80%, #000 20%)); background: var(--surface);
color: var(--text); color: var(--text);
border: 1px solid color-mix(in srgb, var(--primary) 18%, transparent); border: 1px solid var(--border);
border-radius: 10px; border-radius: 6px;
cursor: pointer; cursor: pointer;
transition: transform 0.08s ease, box-shadow 0.2s ease, background 0.2s ease, filter 0.2s ease; font-weight: 400;
transition: all 0.15s ease;
} }
button:hover { button:hover {
filter: brightness(1.03) saturate(1.05); background: var(--surface-hover);
box-shadow: var(--glow); box-shadow: var(--glow-subtle);
} }
button:active {
transform: translateY(1px);
}
/* Primary button style (e.g., Big Picture Mode) */ /* Primary button style (e.g., Big Picture Mode) */
.primary-btn { .primary-btn {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
padding: 12px 24px; padding: 0.5rem 1rem;
font-size: 1rem; font-size: 14px;
font-weight: 600; font-weight: 500;
background: linear-gradient(135deg, var(--primary) 0%, color-mix(in srgb, var(--primary) 60%, #000 40%) 50%, var(--accent) 100%); background: linear-gradient(135deg, var(--primary), var(--accent));
background-size: 200% 100%;
color: var(--text); color: var(--text);
border: 1px solid rgba(255,255,255,0.15); border: 1px solid var(--primary);
border-radius: 12px; border-radius: 6px;
cursor: pointer; cursor: pointer;
transition: all 0.3s ease; transition: all 0.15s ease;
box-shadow: 0 4px 20px color-mix(in srgb, var(--primary) 30%, transparent); box-shadow: var(--glow-subtle);
} }
.primary-btn:hover { .primary-btn:hover {
background-position: 100% 0; background: linear-gradient(135deg, var(--primary-hover), var(--accent));
box-shadow: 0 6px 30px color-mix(in srgb, var(--primary) 45%, transparent), 0 0 20px color-mix(in srgb, var(--accent) 20%, transparent); box-shadow: 0 4px 24px rgba(123, 46, 255, 0.25);
transform: translateY(-2px); transform: translateY(-1px);
} }
.primary-btn:active {
transform: translateY(0);
box-shadow: 0 2px 10px color-mix(in srgb, var(--primary) 30%, transparent);
}
.note { .note {
font-size: 0.8rem; font-size: 13px;
color: color-mix(in srgb, var(--text) 70%, transparent); color: var(--text-muted);
margin-top: 1rem; margin-top: 0.35rem;
line-height: 1.5;
} }
.status { .status {
@@ -259,14 +265,14 @@ button:active {
transform: translateX(-50%); transform: translateX(-50%);
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.75rem;
background-color: color-mix(in srgb, var(--bg) 82%, #000 18%); background-color: var(--surface);
color: var(--text); color: var(--text);
padding: 0.8rem 1.2rem; padding: 0.75rem 1.25rem;
border-radius: 12px; border-radius: 6px;
border: 1px solid color-mix(in srgb, var(--text) 8%, transparent); border: 1px solid var(--border);
box-shadow: 0 8px 30px rgba(0,0,0,0.5); box-shadow: 0 4px 12px rgba(0,0,0,0.4);
font-size: 1rem; font-size: 14px;
z-index: 1000; z-index: 1000;
} }
@@ -298,95 +304,187 @@ button:active {
box-sizing: border-box; box-sizing: border-box;
} }
.setting-group .setting-row button,
.setting-group .setting-row input,
.setting-group .setting-row select {
width: auto;
}
/* Inline layout helpers (Firefox-like settings rows) */
.setting-row {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.setting-row label {
margin-bottom: 0;
}
.setting-row .note {
margin: 0;
}
.label-min {
min-width: 100px;
}
.setting-row button,
.setting-row input,
.setting-row select {
width: auto;
min-width: 160px;
}
.setting-row select {
flex: 1 1 220px;
}
.button-row {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
}
.stack {
display: flex;
flex-direction: column;
gap: 10px;
}
.range-row {
display: flex;
align-items: center;
gap: 12px;
}
.range-row input[type="range"] {
flex: 1 1 auto;
min-width: 160px;
}
.range-row .range-value {
min-width: 56px;
text-align: right;
font-weight: 600;
color: color-mix(in srgb, var(--text) 85%, transparent);
}
.settings-fieldset {
border: 1px solid var(--border);
border-radius: 6px;
padding: 1rem;
background: rgba(123, 46, 255, 0.03);
}
.settings-fieldset legend {
padding: 0 0.5rem;
font-size: 14px;
font-weight: 500;
color: var(--primary);
}
/* Cards (customization groups) */ /* Cards (customization groups) */
.customization-group { .customization-group {
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%))); background: var(--surface);
border: 1px solid var(--card-border); border: 1px solid var(--border);
border-radius: 14px; border-radius: 8px;
padding: 14px 16px 16px 16px; padding: 1rem 1.25rem;
box-shadow: 0 6px 24px rgba(0,0,0,0.25); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
margin-bottom: 20px; margin-bottom: 1.5rem;
} }
.customization-group > h3 { .customization-group > h3 {
margin: 0 0 10px 0; margin: 0 0 0.75rem 0;
position: relative; position: relative;
padding-left: 10px; padding-left: 0;
font-size: 1.1rem;
font-weight: 600;
color: var(--primary);
} }
.customization-group > h3::before {
content: '';
position: absolute; .setting-group > h3 {
left: 0; margin: 0 0 0.75rem 0;
top: 50%; font-size: 1.1rem;
transform: translateY(-50%); font-weight: 600;
width: 4px; position: relative;
height: 18px; padding-left: 0;
border-radius: 2px; color: var(--primary);
background: linear-gradient(180deg, var(--accent), var(--primary));
} }
/* Section titles */ /* Section titles */
h2 { h2 {
display: inline-flex; display: block;
align-items: center; font-size: 1.5rem;
gap: 10px; font-weight: 300;
font-size: 1.2rem; margin: 0 0 1.5rem 0;
margin: 0 0 12px 0; color: var(--text);
letter-spacing: -0.01em;
position: relative;
padding-bottom: 0.75rem;
} }
h2::after { h2::after {
content: ''; content: '';
flex: 1 1 auto; position: absolute;
height: 1px; bottom: 0;
background: linear-gradient(90deg, rgba(255,255,255,0.15), transparent); left: 0;
width: 60px;
height: 3px;
background: linear-gradient(90deg, var(--primary), var(--accent));
border-radius: 2px;
} }
/* Theming: theme selector buttons override */ /* Theming: theme selector buttons override */
.theme-selector { .theme-selector {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
gap: 16px; gap: 12px;
padding: 10px 0; padding: 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%))); background: transparent;
border: 1px solid var(--card-border); border: none;
border-radius: 12px; border-radius: 0;
padding: 12px;
} }
.theme-btn { .theme-btn {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
padding: 12px 8px; padding: 10px 8px;
border: 1px solid rgba(255,255,255,0.10) !important; border: 2px solid var(--border) !important;
border-radius: 12px !important; border-radius: 8px !important;
background: linear-gradient(180deg, rgba(255,255,255,0.03), rgba(255,255,255,0.02)) !important; background: var(--surface) !important;
color: var(--text); color: var(--text);
text-align: center; text-align: center;
font-size: 0.85rem; font-size: 13px;
min-height: 90px; min-height: 90px;
font-weight: 400;
}
.theme-btn:hover {
background: var(--surface-hover) !important;
border-color: var(--text-muted) !important;
} }
.theme-btn:hover { box-shadow: 0 8px 24px rgba(0,0,0,0.25); }
.theme-btn.active { .theme-btn.active {
box-shadow: inset 0 0 0 1px rgba(255,255,255,0.06), var(--glow); border-color: var(--primary) !important;
box-shadow: 0 0 0 2px var(--primary), var(--glow-subtle);
background: linear-gradient(180deg, rgba(123, 46, 255, 0.08), rgba(0, 198, 255, 0.05)) !important;
} }
.theme-preview { .theme-preview {
width: 60px; width: 64px;
height: 40px; height: 42px;
border-radius: 6px !important; border-radius: 4px !important;
border: 1px solid rgba(255, 255, 255, 0.2); border: 1px solid var(--border);
position: relative; position: relative;
overflow: hidden; overflow: hidden;
} }
.theme-preview::after {
content: '';
position: absolute;
inset: 0;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 6px;
pointer-events: none;
}
.custom-theme-btn { border-style: dashed !important; opacity: 0.95; } .custom-theme-btn { border-style: dashed !important; opacity: 0.95; }
.custom-theme-btn:hover { opacity: 1; } .custom-theme-btn:hover { opacity: 1; }
@@ -394,66 +492,86 @@ h2::after {
input[type="range"] { input[type="range"] {
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
height: 6px; height: 4px;
background: linear-gradient(90deg, rgba(123,46,255,0.6), rgba(0,198,255,0.6)); background: linear-gradient(90deg, var(--primary), var(--accent));
border-radius: 999px; border-radius: 2px;
outline: none; outline: none;
border: 1px solid rgba(255,255,255,0.15); border: none;
cursor: pointer;
opacity: 0.8;
}
input[type="range"]:hover {
opacity: 1;
} }
input[type="range"]::-webkit-slider-thumb { input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
width: 18px; width: 16px;
height: 18px; height: 16px;
border-radius: 50%; border-radius: 50%;
background: #fff; background: var(--primary);
border: 2px solid rgba(123,46,255,0.9); border: 2px solid #fff;
box-shadow: 0 2px 10px rgba(123,46,255,0.35); box-shadow: 0 1px 3px rgba(0,0,0,0.3);
cursor: pointer;
} }
input[type="range"]::-moz-range-thumb { input[type="range"]::-moz-range-thumb {
width: 18px; width: 16px;
height: 18px; height: 16px;
border-radius: 50%; border-radius: 50%;
background: #fff; background: var(--primary);
border: 2px solid rgba(123,46,255,0.9); border: 2px solid #fff;
box-shadow: 0 2px 10px rgba(123,46,255,0.35); box-shadow: 0 1px 3px rgba(0,0,0,0.3);
cursor: pointer;
} }
/* Checkboxes/radios */ /* Checkboxes/radios */
input[type="checkbox"], input[type="radio"] { input[type="checkbox"], input[type="radio"] {
accent-color: #8a4dff; accent-color: var(--primary);
width: 16px;
height: 16px;
margin-right: 8px;
} }
/* Layout & logo options */ /* Layout & logo options */
.layout-options { display: flex; flex-direction: column; gap: 10px; } .layout-options { display: flex; flex-direction: column; gap: 10px; }
.layout-options label { display: flex; align-items: center; gap: 8px; cursor: pointer; padding: 8px; border-radius: 6px; transition: background 0.2s ease; } .layout-options label {
.layout-options label:hover { background: rgba(255,255,255,0.05); } display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
padding: 8px;
border-radius: 4px;
transition: background 0.15s ease;
}
.layout-options label:hover { background: var(--surface); }
.logo-options { display: flex; flex-direction: column; gap: 12px; } .logo-options { display: flex; flex-direction: column; gap: 12px; }
.logo-options label { display: flex; align-items: center; gap: 8px; } .logo-options label { display: flex; align-items: center; gap: 8px; }
.logo-options input[type="text"] { flex: 1; } .logo-options input[type="text"] { flex: 1; }
/* Color customization controls */ /* Color customization controls */
.color-controls { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; } .color-controls { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; }
.color-group { display: flex; flex-direction: column; gap: 5px; } .color-group { display: flex; flex-direction: column; gap: 8px; }
.color-group label { font-size: 0.9rem; color: var(--text); opacity: 0.9; } .color-group label { font-size: 14px; color: var(--text-secondary); font-weight: 500; }
input[type="color"] { input[type="color"] {
width: 100%; width: 100%;
height: 40px; height: 40px;
padding: 0; padding: 0;
border: 1px solid rgba(255,255,255,0.2); border: 1px solid var(--border);
border-radius: 8px; border-radius: 4px;
background: transparent; background: transparent;
cursor: pointer; cursor: pointer;
} }
/* Preview area */ /* Preview area */
.preview-container { .preview-container {
background: linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.03)) !important; background: var(--surface) !important;
border-radius: 14px !important; border-radius: 8px !important;
border: 1px solid var(--card-border) !important; border: 1px solid var(--border) !important;
box-shadow: 0 10px 30px rgba(0,0,0,0.3); box-shadow: none;
overflow: hidden;
} }
.preview-home { .preview-home {
display: flex; display: flex;
@@ -462,9 +580,9 @@ input[type="color"] {
gap: 15px; gap: 15px;
padding: 20px; padding: 20px;
background: var(--bg); background: var(--bg);
border-radius: 8px; border-radius: 4px;
min-height: 200px; min-height: 200px;
border: 1px dashed rgba(255,255,255,0.12); border: 1px dashed var(--border);
} }
.preview-text { letter-spacing: 0.3px; } .preview-text { letter-spacing: 0.3px; }
.preview-logo { font-size: 1.5rem; font-weight: 700; color: var(--primary); } .preview-logo { font-size: 1.5rem; font-weight: 700; color: var(--primary); }
@@ -481,76 +599,122 @@ input[type="color"] {
} }
#search-history-list li, #site-history-list li { #search-history-list li, #site-history-list li {
list-style: none; list-style: none;
padding: 8px 10px; padding: 10px 12px;
background: rgba(255,255,255,0.03); background: var(--surface);
border: 1px solid rgba(255,255,255,0.08); border: 1px solid var(--border);
border-radius: 10px; border-radius: 4px;
font-size: 14px;
} }
#site-history-list a { #site-history-list a {
color: var(--accent); color: var(--primary);
text-decoration: none; text-decoration: none;
} }
#site-history-list a:hover { text-decoration: underline; } #site-history-list a:hover {
text-decoration: underline;
color: var(--primary-hover);
}
/* About buttons */ /* About buttons */
.github-btn, .help-btn { .github-btn, .help-btn {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
padding: 8px 12px; padding: 0.5rem 1rem;
background: var(--accent); background: var(--surface);
color: var(--text); color: var(--text);
border: 1px solid rgba(255,255,255,0.08) !important; border: 1px solid var(--border) !important;
border-radius: 10px !important; border-radius: 4px !important;
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
transition: transform 0.08s ease, box-shadow 0.2s ease, filter 0.2s ease; transition: background 0.15s ease;
box-shadow: 0 6px 18px rgba(0,0,0,0.25); font-size: 14px;
}
.github-btn:hover, .help-btn:hover {
background: var(--surface-hover);
}
.github-btn svg, .help-btn svg {
width: 16px;
height: 16px;
fill: currentColor;
} }
.github-btn:hover, .help-btn:hover { filter: brightness(1.03) saturate(1.05); box-shadow: var(--glow); }
.github-btn:active, .help-btn:active { transform: translateY(1px); }
.about-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; } .about-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
/* Debug info */ /* Debug info */
.debug-info { .debug-info {
background: rgba(0,0,0,0.35) !important; background: var(--surface);
border: 1px solid rgba(255,255,255,0.1); border: 1px solid var(--border);
border-radius: 10px; border-radius: 4px;
padding: 12px;
font-size: 13px;
line-height: 1.6;
color: var(--text-secondary);
font-family: 'Consolas', 'Monaco', monospace;
} }
/* General lists inside cards */ /* General lists inside cards */
.customization-group ul { list-style: none; padding: 0; margin: 0; } .customization-group ul { list-style: none; padding: 0; margin: 0; }
.customization-group ul li { padding: 6px 0; border-bottom: 1px solid rgba(255,255,255,0.06); } .customization-group ul li {
padding: 10px 0;
border-bottom: 1px solid var(--border-subtle);
font-size: 14px;
line-height: 1.5;
}
.customization-group ul li:last-child { border-bottom: none; } .customization-group ul li:last-child { border-bottom: none; }
/* Theme management buttons */ /* Theme management buttons */
.theme-management { display: flex; flex-wrap: wrap; gap: 10px; } .theme-management { display: flex; flex-wrap: wrap; gap: 10px; }
#reset-to-default { background: linear-gradient(180deg, #e53e3e, #c53030); } #reset-to-default {
background: #d41b2c;
border-color: #d41b2c;
color: white;
}
#reset-to-default:hover {
background: #a4161a;
border-color: #a4161a;
}
/* Scrollbar styling (Chromium) */ /* Scrollbar styling (Chromium) */
*::-webkit-scrollbar { height: 10px; width: 10px; } *::-webkit-scrollbar { height: 12px; width: 12px; }
*::-webkit-scrollbar-track { background: rgba(255,255,255,0.04); border-radius: 999px; } *::-webkit-scrollbar-track { background: var(--bg); }
*::-webkit-scrollbar-thumb { background: linear-gradient(180deg, rgba(123,46,255,0.7), rgba(0,198,255,0.7)); border-radius: 999px; } *::-webkit-scrollbar-thumb {
*::-webkit-scrollbar-thumb:hover { background: linear-gradient(180deg, rgba(123,46,255,0.9), rgba(0,198,255,0.9)); } background: linear-gradient(180deg, var(--primary), var(--accent));
border-radius: 6px;
border: 2px solid var(--bg);
}
*::-webkit-scrollbar-thumb:hover {
background: linear-gradient(180deg, var(--primary-hover), var(--accent));
}
/* small-screen adjustments */ /* small-screen adjustments */
@media (max-width: 480px) { @media (max-width: 768px) {
.container { body {
padding: 0; padding: 0;
border-radius: 12px; }
box-shadow: 0 0 8px rgba(0,0,0,0.35); .container {
flex-direction: column; flex-direction: column;
max-width: 100%; max-width: 100%;
height: 100vh;
border-radius: 0;
} }
.sidebar { .sidebar {
width: 100%; width: 100%;
border-right: none; border-right: none;
border-bottom: 1px solid rgba(255,255,255,0.08); border-bottom: 1px solid var(--border);
padding-bottom: 0.5rem; padding: 1rem;
} }
.tabs { flex-direction: row; flex-wrap: wrap; gap: 6px; } .tabs {
.tab-link { flex: 1 1 auto; } flex-direction: row;
h1 { flex-wrap: wrap;
gap: 6px;
}
.tab-link {
flex: 1 1 auto;
min-width: 120px;
}
.content {
padding: 1.5rem 1rem;
}
h2 {
font-size: 1.25rem; font-size: 1.25rem;
} }
} }
+31 -26
View File
@@ -24,17 +24,20 @@
<!-- General Panel --> <!-- General Panel -->
<section class="tab-panel active" id="panel-general" role="tabpanel" aria-labelledby="tab-general"> <section class="tab-panel active" id="panel-general" role="tabpanel" aria-labelledby="tab-general">
<h2>General</h2> <h2>General</h2>
<div class="setting-group"> <div class="setting-group">
<label for="clear-data-btn">Clear All Cookies &amp; Data</label> <h3>Data Management</h3>
<button id="clear-data-btn">Clear Data</button> <p class="note">Clear all cookies, cache, and browsing data stored locally on this device.</p>
<div class="setting-row">
<button id="clear-data-btn">Clear All Data</button>
</div>
</div> </div>
<p class="note">Settings are stored locally on this device.</p>
<!-- Big Picture Mode --> <!-- Big Picture Mode -->
<div class="setting-group"> <div class="setting-group">
<h3>🎮 Big Picture Mode</h3> <h3>Big Picture Mode</h3>
<p class="note">A controller-friendly UI designed for Steam Deck and handheld devices.</p> <p class="note">A controller-friendly UI designed for Steam Deck and handheld devices.</p>
<div style="display: flex; align-items: center; gap: 12px; margin-top: 10px;"> <div class="setting-row">
<button id="launch-bigpicture-btn" class="primary-btn"> <button id="launch-bigpicture-btn" class="primary-btn">
<span style="font-size: 18px;">🎮</span> Launch Big Picture Mode <span style="font-size: 18px;">🎮</span> Launch Big Picture Mode
</button> </button>
@@ -43,21 +46,25 @@
</div> </div>
<div class="setting-group"> <div class="setting-group">
<h3>Weather</h3> <h3>Weather Display</h3>
<fieldset class="weather-units" style="display:flex; flex-direction:column; gap:8px; border:1px solid rgba(255,255,255,0.15); padding:10px; border-radius:8px;"> <p class="note">Choose how temperature is displayed on the Home page weather card.</p>
<legend style="padding:0 6px; opacity:.85;">Temperature units</legend> <fieldset class="weather-units settings-fieldset">
<label><input type="radio" name="weather-unit" id="weather-unit-auto" value="auto" checked> Auto (based on locale)</label> <legend>Temperature units</legend>
<label><input type="radio" name="weather-unit" id="weather-unit-c" value="c"> Celsius (°C)</label> <label style="display: block; margin-bottom: 8px;"><input type="radio" name="weather-unit" id="weather-unit-auto" value="auto" checked> Auto (based on locale)</label>
<label><input type="radio" name="weather-unit" id="weather-unit-f" value="f"> FahrenheitF)</label> <label style="display: block; margin-bottom: 8px;"><input type="radio" name="weather-unit" id="weather-unit-c" value="c"> CelsiusC)</label>
<label style="display: block; margin-bottom: 8px;"><input type="radio" name="weather-unit" id="weather-unit-f" value="f"> Fahrenheit (°F)</label>
</fieldset> </fieldset>
<p class="note">Affects the weather card on the Home page.</p>
</div> </div>
<div class="debug-info" id="debug-info">Loading debug info...</div>
<div class="setting-group">
<h3>System Information</h3>
<div class="debug-info" id="debug-info">Loading debug info...</div>
</div>
</section> </section>
<!-- Appearance Panel --> <!-- Appearance Panel -->
<section class="tab-panel" id="panel-appearance" role="tabpanel" aria-labelledby="tab-appearance"> <section class="tab-panel" id="panel-appearance" role="tabpanel" aria-labelledby="tab-appearance">
<h2>🎨 Appearance</h2> <h2>Appearance</h2>
<!-- Theme Selection --> <!-- Theme Selection -->
<div class="customization-group"> <div class="customization-group">
<h3>Theme Presets</h3> <h3>Theme Presets</h3>
@@ -120,12 +127,10 @@
<!-- Display Scale --> <!-- Display Scale -->
<div class="customization-group"> <div class="customization-group">
<h3>Display Scale</h3> <h3>Display Scale</h3>
<div style="display: flex; flex-direction: column; gap: 12px;"> <p class="note">Adjust the default zoom level when opening the browser. Changes require a reload to take effect.</p>
<div style="display: flex; align-items: center; gap: 12px;"> <div class="range-row">
<input type="range" id="display-scale-slider" min="50" max="300" value="100" step="10" style="flex: 1; cursor: pointer;"> <input type="range" id="display-scale-slider" min="50" max="300" value="100" step="10">
<span id="display-scale-value" style="min-width: 50px; text-align: right; font-weight: bold;">100%</span> <span id="display-scale-value" class="range-value">100%</span>
</div>
<p class="note">Adjust the default display scale (zoom) when opening the browser. Requires reload to take effect.</p>
</div> </div>
</div> </div>
@@ -214,7 +219,7 @@
<div class="customization-group"> <div class="customization-group">
<h3>Site History</h3> <h3>Site History</h3>
<ul id="site-history-list"></ul> <ul id="site-history-list"></ul>
<div style="display:flex; gap:10px; margin-top:10px; flex-wrap:wrap;"> <div class="button-row" style="margin-top:10px;">
<button id="clear-site-history-btn">Clear Site History</button> <button id="clear-site-history-btn">Clear Site History</button>
<button id="add-test-history-btn">Add Test History</button> <button id="add-test-history-btn">Add Test History</button>
</div> </div>
@@ -225,7 +230,7 @@
<section class="tab-panel" id="panel-plugins" role="tabpanel" aria-labelledby="tab-plugins"> <section class="tab-panel" id="panel-plugins" role="tabpanel" aria-labelledby="tab-plugins">
<h2>Plugins</h2> <h2>Plugins</h2>
<div class="customization-group"> <div class="customization-group">
<div style="display:flex; gap:8px; flex-wrap:wrap; align-items:center;"> <div class="button-row">
<button id="plugins-reload-all">Reload Plugins</button> <button id="plugins-reload-all">Reload Plugins</button>
<span class="note">Changes to renderer preloads may require app restart.</span> <span class="note">Changes to renderer preloads may require app restart.</span>
</div> </div>
@@ -273,7 +278,7 @@
<h3>Security Updates</h3> <h3>Security Updates</h3>
<p class="note" style="margin-bottom: 12px;">Nebula Browser is distributed via Steam, but the Electron runtime can be updated separately for security patches and performance improvements.</p> <p class="note" style="margin-bottom: 12px;">Nebula Browser is distributed via Steam, but the Electron runtime can be updated separately for security patches and performance improvements.</p>
<div style="display: flex; flex-direction: column; gap: 12px;"> <div class="stack">
<!-- Update Status Banner --> <!-- Update Status Banner -->
<div id="electron-update-banner" style="display: none; padding: 12px; border-radius: 8px; background: rgba(123, 46, 255, 0.1); border: 1px solid rgba(123, 46, 255, 0.3);"> <div id="electron-update-banner" style="display: none; padding: 12px; border-radius: 8px; background: rgba(123, 46, 255, 0.1); border: 1px solid rgba(123, 46, 255, 0.3);">
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px;"> <div style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px;">
@@ -297,9 +302,9 @@
<!-- Version Info --> <!-- Version Info -->
<div style="font-size: 0.9em; opacity: 0.8;"> <div style="font-size: 0.9em; opacity: 0.8;">
<div style="display: flex; gap: 8px; align-items: center; margin-bottom: 8px;"> <div class="setting-row" style="margin-bottom: 8px;">
<label for="electron-version-select" style="min-width: 100px;">Update Channel:</label> <label for="electron-version-select" class="label-min">Update Channel:</label>
<select id="electron-version-select" style="flex: 1; padding: 8px; border-radius: 4px; background-color: var(--secondary, #00C6FF); color: var(--bg, #121418); border: none; cursor: pointer;"> <select id="electron-version-select">
<option value="stable">Stable (Recommended)</option> <option value="stable">Stable (Recommended)</option>
<option value="nightly">Nightly (Latest Features)</option> <option value="nightly">Nightly (Latest Features)</option>
</select> </select>
+51
View File
@@ -300,6 +300,56 @@ window.addEventListener('DOMContentLoaded', () => {
initTabs(); initTabs();
}); });
// Apply current theme to settings page
function applyCurrentThemeToSettings() {
if (!window.BrowserCustomizer) return;
const savedTheme = localStorage.getItem('nebula-theme');
let theme = null;
if (savedTheme) {
try {
theme = JSON.parse(savedTheme);
} catch (e) {
console.warn('Failed to parse saved theme', e);
}
}
if (!theme || !theme.colors) return;
// Apply theme colors to CSS variables
const root = document.documentElement;
root.style.setProperty('--bg', theme.colors.bg || '#121418');
root.style.setProperty('--gradient-end', theme.colors.darkPurple || '#1B1035');
root.style.setProperty('--primary', theme.colors.primary || '#7B2EFF');
root.style.setProperty('--accent', theme.colors.accent || '#00C6FF');
root.style.setProperty('--text', theme.colors.text || '#E0E0E0');
// Update glow colors based on theme
const primaryRgb = hexToRgb(theme.colors.primary || '#7B2EFF');
if (primaryRgb) {
root.style.setProperty('--ring', `0 0 0 2px rgba(${primaryRgb.r}, ${primaryRgb.g}, ${primaryRgb.b}, 0.4)`);
root.style.setProperty('--glow-subtle', `0 4px 20px rgba(${primaryRgb.r}, ${primaryRgb.g}, ${primaryRgb.b}, 0.15)`);
}
}
// Helper to convert hex to RGB
function hexToRgb(hex) {
const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
// Listen for theme changes
window.addEventListener('storage', (e) => {
if (e.key === 'nebula-theme') {
applyCurrentThemeToSettings();
}
});
// About tab population // About tab population
async function populateAbout() { async function populateAbout() {
try { try {
@@ -356,6 +406,7 @@ async function populateAbout() {
window.addEventListener('DOMContentLoaded', () => { window.addEventListener('DOMContentLoaded', () => {
populateAbout(); populateAbout();
setupElectronUpdater(); setupElectronUpdater();
applyCurrentThemeToSettings();
// Refresh about info when About tab is clicked // Refresh about info when About tab is clicked
const aboutTabBtn = document.getElementById('tab-about'); const aboutTabBtn = document.getElementById('tab-about');