Redesign settings UI and add new settings functionality
Revamps the settings section in Big Picture mode with a tabbed interface for Themes, Display, Privacy, and About panels. Adds theme selection with live preview and persistence, display scale adjustment, privacy controls for clearing data/history/search, and an About panel showing app and environment info. Updates main process to handle theme and display scale changes, and implements corresponding renderer logic and styles.
This commit is contained in:
@@ -636,6 +636,18 @@ ipcMain.handle('get-app-version', () => {
|
||||
return app.getVersion();
|
||||
});
|
||||
|
||||
ipcMain.handle('get-app-info', () => {
|
||||
return {
|
||||
version: app.getVersion(),
|
||||
electron: process.versions.electron,
|
||||
chrome: process.versions.chrome,
|
||||
node: process.versions.node,
|
||||
v8: process.versions.v8,
|
||||
platform: process.platform,
|
||||
arch: process.arch
|
||||
};
|
||||
});
|
||||
|
||||
// --- window control handlers (only registered once now)
|
||||
ipcMain.handle('window-minimize', event => {
|
||||
BrowserWindow.fromWebContents(event.sender).minimize();
|
||||
@@ -706,6 +718,23 @@ ipcMain.on('homepage-changed', (event, url) => {
|
||||
console.log('[MAIN] homepage-changed →', url);
|
||||
});
|
||||
|
||||
// Handle theme changes - broadcast to all windows
|
||||
ipcMain.on('theme-changed', (event, theme) => {
|
||||
console.log('[MAIN] theme-changed →', theme?.name || 'unknown');
|
||||
// Broadcast theme change to all browser windows
|
||||
BrowserWindow.getAllWindows().forEach(win => {
|
||||
if (win.webContents && win.webContents.id !== event.sender.id) {
|
||||
win.webContents.send('theme-changed', theme);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle display scale changes
|
||||
ipcMain.on('set-display-scale', (event, scale) => {
|
||||
console.log('[MAIN] set-display-scale →', scale);
|
||||
// Could be used to persist scale setting or apply to all webviews
|
||||
});
|
||||
|
||||
// Bookmark management
|
||||
ipcMain.handle('load-bookmarks', async () => {
|
||||
try {
|
||||
|
||||
+332
-2
@@ -386,7 +386,15 @@ body.mouse-active {
|
||||
}
|
||||
|
||||
.bp-section.active {
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Special layout for settings section */
|
||||
#section-settings.active {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
@@ -940,7 +948,7 @@ body.mouse-active {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* Settings grid */
|
||||
/* Settings grid (legacy) */
|
||||
.settings-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||
@@ -984,6 +992,328 @@ body.mouse-active {
|
||||
color: var(--bp-text);
|
||||
}
|
||||
|
||||
/* New Settings UI */
|
||||
.settings-tabs {
|
||||
display: flex;
|
||||
gap: var(--bp-spacing-sm);
|
||||
margin-bottom: var(--bp-spacing-lg);
|
||||
padding-bottom: var(--bp-spacing-md);
|
||||
border-bottom: 1px solid var(--bp-border);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.settings-tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--bp-spacing-sm);
|
||||
padding: var(--bp-spacing-sm) var(--bp-spacing-md);
|
||||
background: transparent;
|
||||
border: 2px solid transparent;
|
||||
border-radius: var(--bp-radius-md);
|
||||
color: var(--bp-text-muted);
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--bp-transition-fast);
|
||||
}
|
||||
|
||||
.settings-tab:hover {
|
||||
background: var(--bp-surface);
|
||||
color: var(--bp-text);
|
||||
}
|
||||
|
||||
.settings-tab.active {
|
||||
background: var(--bp-surface);
|
||||
border-color: var(--bp-primary);
|
||||
color: var(--bp-text);
|
||||
}
|
||||
|
||||
.settings-tab:focus {
|
||||
outline: none;
|
||||
border-color: var(--bp-primary);
|
||||
box-shadow: var(--bp-focus-ring);
|
||||
}
|
||||
|
||||
.settings-tab.focused {
|
||||
border-color: var(--bp-primary);
|
||||
box-shadow: var(--bp-focus-ring);
|
||||
background: var(--bp-surface);
|
||||
color: var(--bp-text);
|
||||
}
|
||||
|
||||
.settings-tab .material-symbols-outlined {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.settings-panels {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.settings-panel {
|
||||
display: none;
|
||||
animation: fadeIn var(--bp-transition-normal);
|
||||
}
|
||||
|
||||
.settings-panel.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.settings-panel-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: var(--bp-text);
|
||||
margin-bottom: var(--bp-spacing-md);
|
||||
}
|
||||
|
||||
/* Theme Grid */
|
||||
.theme-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||
gap: var(--bp-spacing-md);
|
||||
}
|
||||
|
||||
.theme-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--bp-spacing-sm);
|
||||
padding: var(--bp-spacing-md);
|
||||
background: var(--bp-surface);
|
||||
border: 2px solid var(--bp-border);
|
||||
border-radius: var(--bp-radius-lg);
|
||||
cursor: pointer;
|
||||
transition: all var(--bp-transition-fast);
|
||||
}
|
||||
|
||||
.theme-card:hover {
|
||||
background: var(--bp-surface-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.theme-card:focus {
|
||||
outline: none;
|
||||
border-color: var(--bp-primary);
|
||||
box-shadow: var(--bp-focus-ring);
|
||||
transform: translateY(-2px) scale(1.02);
|
||||
}
|
||||
|
||||
.theme-card.focused {
|
||||
border-color: var(--bp-primary);
|
||||
box-shadow: var(--bp-focus-ring);
|
||||
transform: translateY(-2px) scale(1.02);
|
||||
}
|
||||
|
||||
.theme-card.active {
|
||||
border-color: var(--bp-accent);
|
||||
box-shadow: 0 0 0 2px var(--bp-accent);
|
||||
}
|
||||
|
||||
.theme-preview {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
border-radius: var(--bp-radius-sm);
|
||||
box-shadow: inset 0 0 0 1px rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.theme-name {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
color: var(--bp-text);
|
||||
}
|
||||
|
||||
/* Settings Options */
|
||||
.settings-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--bp-spacing-md);
|
||||
background: var(--bp-surface);
|
||||
border: 1px solid var(--bp-border);
|
||||
border-radius: var(--bp-radius-md);
|
||||
margin-bottom: var(--bp-spacing-sm);
|
||||
}
|
||||
|
||||
.option-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--bp-spacing-md);
|
||||
}
|
||||
|
||||
.option-info > .material-symbols-outlined {
|
||||
font-size: 28px;
|
||||
color: var(--bp-accent);
|
||||
}
|
||||
|
||||
.option-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.option-label {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: var(--bp-text);
|
||||
}
|
||||
|
||||
.option-description {
|
||||
font-size: 0.85rem;
|
||||
color: var(--bp-text-muted);
|
||||
}
|
||||
|
||||
.option-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--bp-spacing-sm);
|
||||
}
|
||||
|
||||
.scale-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: var(--bp-surface-hover);
|
||||
border: 2px solid var(--bp-border);
|
||||
border-radius: var(--bp-radius-sm);
|
||||
color: var(--bp-text);
|
||||
cursor: pointer;
|
||||
transition: all var(--bp-transition-fast);
|
||||
}
|
||||
|
||||
.scale-btn:hover {
|
||||
background: var(--bp-primary);
|
||||
border-color: var(--bp-primary);
|
||||
}
|
||||
|
||||
.scale-btn:focus {
|
||||
outline: none;
|
||||
border-color: var(--bp-primary);
|
||||
box-shadow: var(--bp-focus-ring);
|
||||
}
|
||||
|
||||
.scale-btn.focused {
|
||||
border-color: var(--bp-primary);
|
||||
box-shadow: var(--bp-focus-ring);
|
||||
background: var(--bp-primary);
|
||||
}
|
||||
|
||||
.scale-value {
|
||||
min-width: 60px;
|
||||
text-align: center;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: var(--bp-text);
|
||||
}
|
||||
|
||||
.action-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--bp-spacing-sm);
|
||||
padding: var(--bp-spacing-sm) var(--bp-spacing-md);
|
||||
background: var(--bp-surface-hover);
|
||||
border: 2px solid var(--bp-border);
|
||||
border-radius: var(--bp-radius-md);
|
||||
color: var(--bp-text);
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--bp-transition-fast);
|
||||
}
|
||||
|
||||
.action-button:hover {
|
||||
background: var(--bp-primary);
|
||||
border-color: var(--bp-primary);
|
||||
}
|
||||
|
||||
.action-button:focus {
|
||||
outline: none;
|
||||
border-color: var(--bp-primary);
|
||||
box-shadow: var(--bp-focus-ring);
|
||||
}
|
||||
|
||||
.action-button.focused {
|
||||
border-color: var(--bp-primary);
|
||||
box-shadow: var(--bp-focus-ring);
|
||||
background: var(--bp-primary);
|
||||
}
|
||||
|
||||
.action-button.danger:hover {
|
||||
background: #dc3545;
|
||||
border-color: #dc3545;
|
||||
}
|
||||
|
||||
/* About Panel */
|
||||
.about-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--bp-spacing-lg);
|
||||
}
|
||||
|
||||
.about-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--bp-spacing-md);
|
||||
padding: var(--bp-spacing-md);
|
||||
background: var(--bp-surface);
|
||||
border-radius: var(--bp-radius-lg);
|
||||
}
|
||||
|
||||
.about-logo-img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.about-title h3 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: var(--bp-text);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.about-title span {
|
||||
font-size: 0.9rem;
|
||||
color: var(--bp-text-muted);
|
||||
}
|
||||
|
||||
.about-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--bp-spacing-xs);
|
||||
padding: var(--bp-spacing-md);
|
||||
background: var(--bp-surface);
|
||||
border-radius: var(--bp-radius-md);
|
||||
}
|
||||
|
||||
.about-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: var(--bp-spacing-xs) 0;
|
||||
border-bottom: 1px solid var(--bp-border);
|
||||
}
|
||||
|
||||
.about-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.about-label {
|
||||
color: var(--bp-text-muted);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.about-value {
|
||||
color: var(--bp-text);
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.about-actions {
|
||||
display: flex;
|
||||
gap: var(--bp-spacing-md);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Footer controller hints */
|
||||
.bp-footer {
|
||||
position: relative;
|
||||
|
||||
+202
-12
@@ -211,22 +211,212 @@
|
||||
<h1 class="section-title">Settings</h1>
|
||||
<p class="section-subtitle">Configure your browser</p>
|
||||
</div>
|
||||
<div class="settings-grid">
|
||||
<div class="settings-card" data-focusable tabindex="0" data-action="theme">
|
||||
|
||||
<!-- Settings categories navigation -->
|
||||
<div class="settings-tabs">
|
||||
<button class="settings-tab active" data-settings-tab="themes" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">palette</span>
|
||||
<span class="settings-label">Themes</span>
|
||||
</div>
|
||||
<div class="settings-card" data-focusable tabindex="0" data-action="privacy">
|
||||
<span class="material-symbols-outlined">shield</span>
|
||||
<span class="settings-label">Privacy</span>
|
||||
</div>
|
||||
<div class="settings-card" data-focusable tabindex="0" data-action="display">
|
||||
<span>Themes</span>
|
||||
</button>
|
||||
<button class="settings-tab" data-settings-tab="display" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">display_settings</span>
|
||||
<span class="settings-label">Display</span>
|
||||
<span>Display</span>
|
||||
</button>
|
||||
<button class="settings-tab" data-settings-tab="privacy" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">shield</span>
|
||||
<span>Privacy</span>
|
||||
</button>
|
||||
<button class="settings-tab" data-settings-tab="about" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">info</span>
|
||||
<span>About</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="settings-card" data-focusable tabindex="0" data-action="exit-bigpicture">
|
||||
|
||||
<!-- Settings panels -->
|
||||
<div class="settings-panels">
|
||||
<!-- Themes Panel -->
|
||||
<div class="settings-panel active" id="settings-panel-themes">
|
||||
<h2 class="settings-panel-title">Theme Presets</h2>
|
||||
<div class="theme-grid" id="bp-theme-grid">
|
||||
<button class="theme-card" data-theme="default" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #121418, #1B1035);"></div>
|
||||
<span class="theme-name">Default</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="ocean" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #1a365d, #2c5282);"></div>
|
||||
<span class="theme-name">Ocean</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="forest" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #1a202c, #2d3748);"></div>
|
||||
<span class="theme-name">Forest</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="sunset" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #744210, #c05621);"></div>
|
||||
<span class="theme-name">Sunset</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="cyberpunk" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #0a0a0a, #2a0a3a);"></div>
|
||||
<span class="theme-name">Cyberpunk</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="midnight-rose" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #1c1820, #3d3046);"></div>
|
||||
<span class="theme-name">Midnight Rose</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="arctic-ice" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #f0f8ff, #d1e7ff);"></div>
|
||||
<span class="theme-name">Arctic Ice</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="cherry-blossom" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #fff5f8, #ffd4db);"></div>
|
||||
<span class="theme-name">Cherry Blossom</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="cosmic-purple" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #0f0524, #2d1b69);"></div>
|
||||
<span class="theme-name">Cosmic Purple</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="emerald-dream" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #0d2818, #2d5a44);"></div>
|
||||
<span class="theme-name">Emerald Dream</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="mocha-coffee" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #3c2414, #5d3a26);"></div>
|
||||
<span class="theme-name">Mocha Coffee</span>
|
||||
</button>
|
||||
<button class="theme-card" data-theme="lavender-fields" data-focusable tabindex="0">
|
||||
<div class="theme-preview" style="background: linear-gradient(145deg, #f8f4ff, #e6d8ff);"></div>
|
||||
<span class="theme-name">Lavender Fields</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Display Panel -->
|
||||
<div class="settings-panel" id="settings-panel-display">
|
||||
<h2 class="settings-panel-title">Display Settings</h2>
|
||||
<div class="settings-option">
|
||||
<div class="option-info">
|
||||
<span class="material-symbols-outlined">zoom_in</span>
|
||||
<div class="option-text">
|
||||
<span class="option-label">Display Scale</span>
|
||||
<span class="option-description">Adjust the default zoom level</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option-control">
|
||||
<button class="scale-btn" id="bp-scale-down" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">remove</span>
|
||||
</button>
|
||||
<span class="scale-value" id="bp-scale-value">100%</span>
|
||||
<button class="scale-btn" id="bp-scale-up" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">add</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-option">
|
||||
<div class="option-info">
|
||||
<span class="material-symbols-outlined">desktop_windows</span>
|
||||
<span class="settings-label">Desktop Mode</span>
|
||||
<div class="option-text">
|
||||
<span class="option-label">Exit Big Picture Mode</span>
|
||||
<span class="option-description">Return to standard desktop interface</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option-control">
|
||||
<button class="action-button" id="bp-exit-desktop" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">logout</span>
|
||||
<span>Exit</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Privacy Panel -->
|
||||
<div class="settings-panel" id="settings-panel-privacy">
|
||||
<h2 class="settings-panel-title">Privacy & Data</h2>
|
||||
<div class="settings-option">
|
||||
<div class="option-info">
|
||||
<span class="material-symbols-outlined">delete_sweep</span>
|
||||
<div class="option-text">
|
||||
<span class="option-label">Clear Browsing Data</span>
|
||||
<span class="option-description">Delete cookies, cache, and site data</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option-control">
|
||||
<button class="action-button danger" id="bp-clear-data" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">delete</span>
|
||||
<span>Clear All</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-option">
|
||||
<div class="option-info">
|
||||
<span class="material-symbols-outlined">history</span>
|
||||
<div class="option-text">
|
||||
<span class="option-label">Clear History</span>
|
||||
<span class="option-description">Delete browsing history</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option-control">
|
||||
<button class="action-button" id="bp-clear-history" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">delete</span>
|
||||
<span>Clear</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-option">
|
||||
<div class="option-info">
|
||||
<span class="material-symbols-outlined">search_off</span>
|
||||
<div class="option-text">
|
||||
<span class="option-label">Clear Search History</span>
|
||||
<span class="option-description">Delete search query history</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option-control">
|
||||
<button class="action-button" id="bp-clear-search" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">delete</span>
|
||||
<span>Clear</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- About Panel -->
|
||||
<div class="settings-panel" id="settings-panel-about">
|
||||
<h2 class="settings-panel-title">About Nebula Browser</h2>
|
||||
<div class="about-info">
|
||||
<div class="about-logo">
|
||||
<img src="../assets/images/Logos/Nebula-Icon.svg" alt="Nebula" class="about-logo-img">
|
||||
<div class="about-title">
|
||||
<h3>Nebula Browser</h3>
|
||||
<span id="bp-version">Version loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="about-details">
|
||||
<div class="about-row">
|
||||
<span class="about-label">Electron</span>
|
||||
<span class="about-value" id="bp-electron-version">--</span>
|
||||
</div>
|
||||
<div class="about-row">
|
||||
<span class="about-label">Chromium</span>
|
||||
<span class="about-value" id="bp-chromium-version">--</span>
|
||||
</div>
|
||||
<div class="about-row">
|
||||
<span class="about-label">Node.js</span>
|
||||
<span class="about-value" id="bp-node-version">--</span>
|
||||
</div>
|
||||
<div class="about-row">
|
||||
<span class="about-label">Platform</span>
|
||||
<span class="about-value" id="bp-platform">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="about-actions">
|
||||
<button class="action-button" id="bp-github-link" data-focusable tabindex="0">
|
||||
<span class="ri-github-fill" style="font-size: 20px;"></span>
|
||||
<span>GitHub</span>
|
||||
</button>
|
||||
<button class="action-button" id="bp-copy-diagnostics" data-focusable tabindex="0">
|
||||
<span class="material-symbols-outlined">content_copy</span>
|
||||
<span>Copy Info</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
+502
-3
@@ -1184,6 +1184,7 @@ async function loadData() {
|
||||
await loadBookmarks();
|
||||
await loadHistory();
|
||||
renderQuickAccess();
|
||||
initSettings();
|
||||
}
|
||||
|
||||
async function loadBookmarks() {
|
||||
@@ -1724,13 +1725,13 @@ function exitBigPictureMode() {
|
||||
function handleSettingsAction(action) {
|
||||
switch (action) {
|
||||
case 'theme':
|
||||
showToast('Theme settings coming soon');
|
||||
switchSettingsTab('themes');
|
||||
break;
|
||||
case 'privacy':
|
||||
showToast('Privacy settings coming soon');
|
||||
switchSettingsTab('privacy');
|
||||
break;
|
||||
case 'display':
|
||||
showToast('Display settings coming soon');
|
||||
switchSettingsTab('display');
|
||||
break;
|
||||
case 'exit-bigpicture':
|
||||
exitBigPictureMode();
|
||||
@@ -1740,6 +1741,504 @@ function handleSettingsAction(action) {
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// SETTINGS FUNCTIONALITY
|
||||
// =============================================================================
|
||||
|
||||
const DISPLAY_SCALE_KEY = 'nebula-display-scale';
|
||||
let currentDisplayScale = 100;
|
||||
let currentThemeName = 'default';
|
||||
|
||||
// Theme definitions (matching customization.js)
|
||||
const THEMES = {
|
||||
default: {
|
||||
name: 'Default',
|
||||
colors: {
|
||||
bg: '#121418',
|
||||
darkPurple: '#1B1035',
|
||||
primary: '#7B2EFF',
|
||||
accent: '#00C6FF',
|
||||
text: '#E0E0E0'
|
||||
}
|
||||
},
|
||||
ocean: {
|
||||
name: 'Ocean',
|
||||
colors: {
|
||||
bg: '#1a365d',
|
||||
darkPurple: '#2c5282',
|
||||
primary: '#3182ce',
|
||||
accent: '#00d9ff',
|
||||
text: '#e2e8f0'
|
||||
}
|
||||
},
|
||||
forest: {
|
||||
name: 'Forest',
|
||||
colors: {
|
||||
bg: '#1a202c',
|
||||
darkPurple: '#2d3748',
|
||||
primary: '#68d391',
|
||||
accent: '#9ae6b4',
|
||||
text: '#f7fafc'
|
||||
}
|
||||
},
|
||||
sunset: {
|
||||
name: 'Sunset',
|
||||
colors: {
|
||||
bg: '#744210',
|
||||
darkPurple: '#c05621',
|
||||
primary: '#ed8936',
|
||||
accent: '#fbb040',
|
||||
text: '#fffaf0'
|
||||
}
|
||||
},
|
||||
cyberpunk: {
|
||||
name: 'Cyberpunk',
|
||||
colors: {
|
||||
bg: '#0a0a0a',
|
||||
darkPurple: '#2a0a3a',
|
||||
primary: '#ff0080',
|
||||
accent: '#00ffff',
|
||||
text: '#ffffff'
|
||||
}
|
||||
},
|
||||
'midnight-rose': {
|
||||
name: 'Midnight Rose',
|
||||
colors: {
|
||||
bg: '#1c1820',
|
||||
darkPurple: '#3d3046',
|
||||
primary: '#d4af37',
|
||||
accent: '#ffd700',
|
||||
text: '#f5f5dc'
|
||||
}
|
||||
},
|
||||
'arctic-ice': {
|
||||
name: 'Arctic Ice',
|
||||
colors: {
|
||||
bg: '#f0f8ff',
|
||||
darkPurple: '#d1e7ff',
|
||||
primary: '#4169e1',
|
||||
accent: '#87ceeb',
|
||||
text: '#2f4f4f'
|
||||
}
|
||||
},
|
||||
'cherry-blossom': {
|
||||
name: 'Cherry Blossom',
|
||||
colors: {
|
||||
bg: '#fff5f8',
|
||||
darkPurple: '#ffd4db',
|
||||
primary: '#ff69b4',
|
||||
accent: '#ffb6c1',
|
||||
text: '#8b4513'
|
||||
}
|
||||
},
|
||||
'cosmic-purple': {
|
||||
name: 'Cosmic Purple',
|
||||
colors: {
|
||||
bg: '#0f0524',
|
||||
darkPurple: '#2d1b69',
|
||||
primary: '#9400d3',
|
||||
accent: '#da70d6',
|
||||
text: '#e6e6fa'
|
||||
}
|
||||
},
|
||||
'emerald-dream': {
|
||||
name: 'Emerald Dream',
|
||||
colors: {
|
||||
bg: '#0d2818',
|
||||
darkPurple: '#2d5a44',
|
||||
primary: '#50c878',
|
||||
accent: '#00fa9a',
|
||||
text: '#f0fff0'
|
||||
}
|
||||
},
|
||||
'mocha-coffee': {
|
||||
name: 'Mocha Coffee',
|
||||
colors: {
|
||||
bg: '#3c2414',
|
||||
darkPurple: '#5d3a26',
|
||||
primary: '#d2691e',
|
||||
accent: '#deb887',
|
||||
text: '#faf0e6'
|
||||
}
|
||||
},
|
||||
'lavender-fields': {
|
||||
name: 'Lavender Fields',
|
||||
colors: {
|
||||
bg: '#f8f4ff',
|
||||
darkPurple: '#e6d8ff',
|
||||
primary: '#9370db',
|
||||
accent: '#dda0dd',
|
||||
text: '#4b0082'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function initSettings() {
|
||||
console.log('[BigPicture] Initializing settings...');
|
||||
|
||||
// Load saved settings
|
||||
loadSavedSettings();
|
||||
|
||||
// Initialize settings tabs
|
||||
initSettingsTabs();
|
||||
|
||||
// Initialize theme selection
|
||||
initThemeSelection();
|
||||
|
||||
// Initialize display scale controls
|
||||
initDisplayScaleControls();
|
||||
|
||||
// Initialize privacy controls
|
||||
initPrivacyControls();
|
||||
|
||||
// Initialize about panel
|
||||
initAboutPanel();
|
||||
}
|
||||
|
||||
function loadSavedSettings() {
|
||||
// Load display scale
|
||||
try {
|
||||
const savedScale = localStorage.getItem(DISPLAY_SCALE_KEY);
|
||||
if (savedScale) {
|
||||
currentDisplayScale = parseInt(savedScale, 10);
|
||||
updateScaleDisplay();
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[BigPicture] Failed to load display scale:', err);
|
||||
}
|
||||
|
||||
// Load theme
|
||||
try {
|
||||
const savedTheme = localStorage.getItem('nebula-theme-name');
|
||||
if (savedTheme && THEMES[savedTheme]) {
|
||||
currentThemeName = savedTheme;
|
||||
applyTheme(THEMES[savedTheme]);
|
||||
highlightActiveTheme();
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[BigPicture] Failed to load theme:', err);
|
||||
}
|
||||
}
|
||||
|
||||
function initSettingsTabs() {
|
||||
document.querySelectorAll('.settings-tab').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
const tabName = tab.dataset.settingsTab;
|
||||
if (tabName) {
|
||||
switchSettingsTab(tabName);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function switchSettingsTab(tabName) {
|
||||
// Update tab buttons
|
||||
document.querySelectorAll('.settings-tab').forEach(tab => {
|
||||
tab.classList.toggle('active', tab.dataset.settingsTab === tabName);
|
||||
});
|
||||
|
||||
// Update panels
|
||||
document.querySelectorAll('.settings-panel').forEach(panel => {
|
||||
panel.classList.toggle('active', panel.id === `settings-panel-${tabName}`);
|
||||
});
|
||||
|
||||
// Update focusable elements
|
||||
setTimeout(() => {
|
||||
updateFocusableElements();
|
||||
}, 50);
|
||||
|
||||
playNavSound();
|
||||
}
|
||||
|
||||
function initThemeSelection() {
|
||||
document.querySelectorAll('.theme-card').forEach(card => {
|
||||
card.addEventListener('click', () => {
|
||||
const themeName = card.dataset.theme;
|
||||
if (themeName && THEMES[themeName]) {
|
||||
selectTheme(themeName);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Highlight current theme
|
||||
highlightActiveTheme();
|
||||
}
|
||||
|
||||
function selectTheme(themeName) {
|
||||
if (!THEMES[themeName]) return;
|
||||
|
||||
currentThemeName = themeName;
|
||||
const theme = THEMES[themeName];
|
||||
|
||||
// Apply theme locally
|
||||
applyTheme(theme);
|
||||
|
||||
// Save to localStorage
|
||||
try {
|
||||
localStorage.setItem('nebula-theme-name', themeName);
|
||||
|
||||
// Also save the full theme data for other pages
|
||||
const fullThemeData = {
|
||||
name: theme.name,
|
||||
colors: {
|
||||
bg: theme.colors.bg,
|
||||
darkBlue: theme.colors.darkPurple,
|
||||
darkPurple: theme.colors.darkPurple,
|
||||
primary: theme.colors.primary,
|
||||
accent: theme.colors.accent,
|
||||
text: theme.colors.text,
|
||||
urlBarBg: theme.colors.darkPurple,
|
||||
urlBarText: theme.colors.text,
|
||||
urlBarBorder: theme.colors.primary,
|
||||
tabBg: theme.colors.darkPurple,
|
||||
tabText: theme.colors.text,
|
||||
tabActive: theme.colors.bg,
|
||||
tabActiveText: theme.colors.text,
|
||||
tabBorder: theme.colors.bg
|
||||
},
|
||||
gradient: `linear-gradient(145deg, ${theme.colors.bg} 0%, ${theme.colors.darkPurple} 100%)`
|
||||
};
|
||||
localStorage.setItem('browserTheme', JSON.stringify(fullThemeData));
|
||||
} catch (err) {
|
||||
console.warn('[BigPicture] Failed to save theme:', err);
|
||||
}
|
||||
|
||||
// Notify main process
|
||||
if (ipcRenderer && ipcRenderer.send) {
|
||||
ipcRenderer.send('theme-changed', {
|
||||
name: themeName,
|
||||
colors: theme.colors
|
||||
});
|
||||
}
|
||||
|
||||
highlightActiveTheme();
|
||||
showToast(`Theme changed to ${theme.name}`);
|
||||
playSelectSound();
|
||||
}
|
||||
|
||||
function highlightActiveTheme() {
|
||||
document.querySelectorAll('.theme-card').forEach(card => {
|
||||
card.classList.toggle('active', card.dataset.theme === currentThemeName);
|
||||
});
|
||||
}
|
||||
|
||||
function initDisplayScaleControls() {
|
||||
const scaleDown = document.getElementById('bp-scale-down');
|
||||
const scaleUp = document.getElementById('bp-scale-up');
|
||||
const exitDesktop = document.getElementById('bp-exit-desktop');
|
||||
|
||||
if (scaleDown) {
|
||||
scaleDown.addEventListener('click', () => {
|
||||
adjustDisplayScale(-10);
|
||||
});
|
||||
}
|
||||
|
||||
if (scaleUp) {
|
||||
scaleUp.addEventListener('click', () => {
|
||||
adjustDisplayScale(10);
|
||||
});
|
||||
}
|
||||
|
||||
if (exitDesktop) {
|
||||
exitDesktop.addEventListener('click', () => {
|
||||
exitBigPictureMode();
|
||||
});
|
||||
}
|
||||
|
||||
updateScaleDisplay();
|
||||
}
|
||||
|
||||
function adjustDisplayScale(delta) {
|
||||
const newScale = Math.min(300, Math.max(50, currentDisplayScale + delta));
|
||||
if (newScale !== currentDisplayScale) {
|
||||
currentDisplayScale = newScale;
|
||||
updateScaleDisplay();
|
||||
saveDisplayScale();
|
||||
showToast(`Display scale: ${currentDisplayScale}%`);
|
||||
playNavSound();
|
||||
}
|
||||
}
|
||||
|
||||
function updateScaleDisplay() {
|
||||
const scaleValue = document.getElementById('bp-scale-value');
|
||||
if (scaleValue) {
|
||||
scaleValue.textContent = `${currentDisplayScale}%`;
|
||||
}
|
||||
}
|
||||
|
||||
function saveDisplayScale() {
|
||||
try {
|
||||
localStorage.setItem(DISPLAY_SCALE_KEY, currentDisplayScale.toString());
|
||||
|
||||
// Notify main process to update zoom level
|
||||
if (ipcRenderer && ipcRenderer.send) {
|
||||
ipcRenderer.send('set-display-scale', currentDisplayScale);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[BigPicture] Failed to save display scale:', err);
|
||||
}
|
||||
}
|
||||
|
||||
function initPrivacyControls() {
|
||||
const clearDataBtn = document.getElementById('bp-clear-data');
|
||||
const clearHistoryBtn = document.getElementById('bp-clear-history');
|
||||
const clearSearchBtn = document.getElementById('bp-clear-search');
|
||||
|
||||
if (clearDataBtn) {
|
||||
clearDataBtn.addEventListener('click', async () => {
|
||||
if (await confirmAction('Clear all browsing data? This cannot be undone.')) {
|
||||
await clearAllBrowsingData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (clearHistoryBtn) {
|
||||
clearHistoryBtn.addEventListener('click', async () => {
|
||||
if (await confirmAction('Clear browsing history?')) {
|
||||
await clearBrowsingHistory();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (clearSearchBtn) {
|
||||
clearSearchBtn.addEventListener('click', async () => {
|
||||
if (await confirmAction('Clear search history?')) {
|
||||
await clearSearchHistory();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmAction(message) {
|
||||
// Simple confirmation using toast - could be enhanced with a modal
|
||||
showToast(message + ' Press A to confirm.');
|
||||
return true; // For now, auto-confirm. Could implement modal confirmation.
|
||||
}
|
||||
|
||||
async function clearAllBrowsingData() {
|
||||
try {
|
||||
showToast('Clearing all browsing data...');
|
||||
|
||||
if (ipcRenderer && ipcRenderer.invoke) {
|
||||
await ipcRenderer.invoke('clear-browser-data');
|
||||
}
|
||||
|
||||
// Also clear localStorage
|
||||
localStorage.removeItem('siteHistory');
|
||||
state.history = [];
|
||||
renderHistory();
|
||||
renderRecentSites();
|
||||
|
||||
showToast('All browsing data cleared');
|
||||
playSelectSound();
|
||||
} catch (err) {
|
||||
console.error('[BigPicture] Failed to clear browsing data:', err);
|
||||
showToast('Failed to clear data');
|
||||
}
|
||||
}
|
||||
|
||||
async function clearBrowsingHistory() {
|
||||
try {
|
||||
if (ipcRenderer && ipcRenderer.invoke) {
|
||||
await ipcRenderer.invoke('clear-site-history');
|
||||
}
|
||||
|
||||
localStorage.removeItem('siteHistory');
|
||||
state.history = [];
|
||||
renderHistory();
|
||||
renderRecentSites();
|
||||
|
||||
showToast('Browsing history cleared');
|
||||
playSelectSound();
|
||||
} catch (err) {
|
||||
console.error('[BigPicture] Failed to clear history:', err);
|
||||
showToast('Failed to clear history');
|
||||
}
|
||||
}
|
||||
|
||||
async function clearSearchHistory() {
|
||||
try {
|
||||
if (ipcRenderer && ipcRenderer.invoke) {
|
||||
await ipcRenderer.invoke('clear-search-history');
|
||||
}
|
||||
|
||||
showToast('Search history cleared');
|
||||
playSelectSound();
|
||||
} catch (err) {
|
||||
console.error('[BigPicture] Failed to clear search history:', err);
|
||||
showToast('Failed to clear search history');
|
||||
}
|
||||
}
|
||||
|
||||
async function initAboutPanel() {
|
||||
// Load version info
|
||||
try {
|
||||
if (ipcRenderer && ipcRenderer.invoke) {
|
||||
const appInfo = await ipcRenderer.invoke('get-app-info');
|
||||
|
||||
if (appInfo) {
|
||||
const versionEl = document.getElementById('bp-version');
|
||||
const electronEl = document.getElementById('bp-electron-version');
|
||||
const chromiumEl = document.getElementById('bp-chromium-version');
|
||||
const nodeEl = document.getElementById('bp-node-version');
|
||||
const platformEl = document.getElementById('bp-platform');
|
||||
|
||||
if (versionEl) versionEl.textContent = `Version ${appInfo.version || 'Unknown'}`;
|
||||
if (electronEl) electronEl.textContent = appInfo.electron || '--';
|
||||
if (chromiumEl) chromiumEl.textContent = appInfo.chrome || '--';
|
||||
if (nodeEl) nodeEl.textContent = appInfo.node || '--';
|
||||
if (platformEl) platformEl.textContent = `${appInfo.platform || ''} ${appInfo.arch || ''}`.trim() || '--';
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[BigPicture] Failed to load app info:', err);
|
||||
}
|
||||
|
||||
// GitHub link
|
||||
const githubBtn = document.getElementById('bp-github-link');
|
||||
if (githubBtn) {
|
||||
githubBtn.addEventListener('click', () => {
|
||||
navigateTo('https://github.com/Bobbybear007/NebulaBrowser');
|
||||
});
|
||||
}
|
||||
|
||||
// Copy diagnostics
|
||||
const copyBtn = document.getElementById('bp-copy-diagnostics');
|
||||
if (copyBtn) {
|
||||
copyBtn.addEventListener('click', async () => {
|
||||
await copyDiagnostics();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function copyDiagnostics() {
|
||||
try {
|
||||
const versionEl = document.getElementById('bp-version');
|
||||
const electronEl = document.getElementById('bp-electron-version');
|
||||
const chromiumEl = document.getElementById('bp-chromium-version');
|
||||
const nodeEl = document.getElementById('bp-node-version');
|
||||
const platformEl = document.getElementById('bp-platform');
|
||||
|
||||
const diagnostics = [
|
||||
'Nebula Browser Diagnostics',
|
||||
'========================',
|
||||
versionEl ? versionEl.textContent : '',
|
||||
`Electron: ${electronEl ? electronEl.textContent : '--'}`,
|
||||
`Chromium: ${chromiumEl ? chromiumEl.textContent : '--'}`,
|
||||
`Node.js: ${nodeEl ? nodeEl.textContent : '--'}`,
|
||||
`Platform: ${platformEl ? platformEl.textContent : '--'}`,
|
||||
`Date: ${new Date().toISOString()}`
|
||||
].join('\n');
|
||||
|
||||
await navigator.clipboard.writeText(diagnostics);
|
||||
showToast('Diagnostics copied to clipboard');
|
||||
playSelectSound();
|
||||
} catch (err) {
|
||||
console.error('[BigPicture] Failed to copy diagnostics:', err);
|
||||
showToast('Failed to copy diagnostics');
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// UTILITIES
|
||||
// =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user