2025-01-31 20:35:44 +01:00
|
|
|
export class SettingsManager {
|
|
|
|
constructor() {
|
|
|
|
this.themeManager = new ThemeManager();
|
|
|
|
this.layoutManager = new LayoutManager();
|
|
|
|
this.fontManager = new FontManager();
|
|
|
|
this.settingsButton = document.querySelector('.settings-button');
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
init() {
|
|
|
|
this.attachEventListeners();
|
|
|
|
this.loadSavedSettings();
|
2025-02-01 17:25:09 +01:00
|
|
|
this.setupDataManagement();
|
2025-01-31 20:35:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
attachEventListeners() {
|
|
|
|
const settingsPopup = document.getElementById('settingsPopup');
|
|
|
|
const closeSettings = document.querySelector('.close-settings');
|
|
|
|
|
|
|
|
this.settingsButton.addEventListener('click', () => {
|
|
|
|
settingsPopup.classList.add('show');
|
|
|
|
this.settingsButton.classList.add('disabled');
|
|
|
|
});
|
|
|
|
|
|
|
|
const closeSettingsHandler = () => {
|
|
|
|
settingsPopup.classList.remove('show');
|
|
|
|
this.settingsButton.classList.remove('disabled');
|
|
|
|
};
|
|
|
|
|
|
|
|
closeSettings.addEventListener('click', closeSettingsHandler);
|
|
|
|
|
|
|
|
settingsPopup.addEventListener('click', (e) => {
|
|
|
|
if (e.target === settingsPopup) {
|
|
|
|
closeSettingsHandler();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Add escape key handler
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
|
|
if (e.key === 'Escape' && settingsPopup.classList.contains('show')) {
|
|
|
|
closeSettingsHandler();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
loadSavedSettings() {
|
|
|
|
// Load CSS
|
|
|
|
const customCSSEditor = document.getElementById('customCSS');
|
|
|
|
customCSSEditor.value = localStorage.getItem('customCSS') || '';
|
|
|
|
this.applyCustomCSS();
|
|
|
|
|
|
|
|
// Load theme
|
|
|
|
const savedTheme = localStorage.getItem('theme') || 'mocha';
|
|
|
|
this.themeManager.setTheme(savedTheme);
|
|
|
|
|
|
|
|
// Load layout
|
|
|
|
const savedLayout = localStorage.getItem('layout') || 'grid';
|
|
|
|
this.layoutManager.setLayout(savedLayout);
|
|
|
|
|
|
|
|
// Load font
|
|
|
|
const savedFont = localStorage.getItem('font');
|
|
|
|
if (savedFont) {
|
|
|
|
this.fontManager.setFont(savedFont);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
applyCustomCSS() {
|
|
|
|
const customCSSEditor = document.getElementById('customCSS');
|
|
|
|
let customStyle = document.getElementById('custom-css') || document.createElement('style');
|
|
|
|
customStyle.id = 'custom-css';
|
|
|
|
customStyle.textContent = customCSSEditor.value;
|
|
|
|
document.head.appendChild(customStyle);
|
|
|
|
}
|
2025-02-01 17:25:09 +01:00
|
|
|
|
|
|
|
setupDataManagement() {
|
|
|
|
document.getElementById('exportData').addEventListener('click', () => this.exportAllData());
|
|
|
|
document.getElementById('importData').addEventListener('click', () => {
|
|
|
|
document.getElementById('importDataFile').click();
|
|
|
|
});
|
|
|
|
document.getElementById('importDataFile').addEventListener('change', (e) => {
|
|
|
|
if (e.target.files[0]) this.importAllData(e.target.files[0]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async exportAllData() {
|
|
|
|
const data = {
|
|
|
|
version: '1.0.0',
|
|
|
|
exportDate: new Date().toISOString(),
|
|
|
|
settings: {
|
|
|
|
theme: localStorage.getItem('theme'),
|
|
|
|
layout: localStorage.getItem('layout'),
|
|
|
|
font: localStorage.getItem('font'),
|
|
|
|
linkSize: localStorage.getItem('linkSize'),
|
|
|
|
username: localStorage.getItem('username'),
|
|
|
|
background: localStorage.getItem('background'),
|
|
|
|
customCSS: localStorage.getItem('customCSS')
|
|
|
|
},
|
|
|
|
links: JSON.parse(localStorage.getItem('customLinks') || '{}'),
|
|
|
|
shortcuts: JSON.parse(localStorage.getItem('shortcuts') || '{}'),
|
|
|
|
searchEngines: JSON.parse(localStorage.getItem('searchEngines') || '[]'),
|
|
|
|
customIcons: JSON.parse(localStorage.getItem('customIcons') || '{}')
|
|
|
|
};
|
|
|
|
|
|
|
|
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
const a = document.createElement('a');
|
|
|
|
a.href = url;
|
|
|
|
a.download = `startpage-backup-${new Date().toISOString().split('T')[0]}.json`;
|
|
|
|
a.click();
|
|
|
|
URL.revokeObjectURL(url);
|
|
|
|
}
|
|
|
|
|
|
|
|
async importAllData(file) {
|
|
|
|
try {
|
|
|
|
const text = await file.text();
|
|
|
|
const data = JSON.parse(text);
|
|
|
|
|
|
|
|
if (!data.version) {
|
|
|
|
throw new Error('Invalid backup file format');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Confirm import
|
|
|
|
if (!confirm('This will override all your current settings. Continue?')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Import settings
|
|
|
|
Object.entries(data.settings).forEach(([key, value]) => {
|
|
|
|
if (value !== null) localStorage.setItem(key, value);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Import data
|
|
|
|
localStorage.setItem('customLinks', JSON.stringify(data.links));
|
|
|
|
localStorage.setItem('shortcuts', JSON.stringify(data.shortcuts));
|
|
|
|
localStorage.setItem('searchEngines', JSON.stringify(data.searchEngines));
|
|
|
|
localStorage.setItem('customIcons', JSON.stringify(data.customIcons));
|
|
|
|
|
|
|
|
// Reload page to apply changes
|
|
|
|
alert('Settings imported successfully. The page will now reload.');
|
|
|
|
window.location.reload();
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to import data:', error);
|
|
|
|
alert('Failed to import settings. Make sure the file is a valid backup.');
|
|
|
|
}
|
|
|
|
}
|
2025-01-31 20:35:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class ThemeManager {
|
|
|
|
constructor() {
|
|
|
|
this.themeSelect = document.getElementById('themeSelect');
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
init() {
|
|
|
|
this.themeSelect.addEventListener('change', (e) => {
|
|
|
|
this.setTheme(e.target.value);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
setTheme(theme) {
|
|
|
|
const root = document.documentElement;
|
|
|
|
root.style.setProperty('--base', `var(--${theme}-base)`);
|
|
|
|
root.style.setProperty('--base-rgb', `var(--${theme}-base-rgb)`);
|
|
|
|
root.style.setProperty('--surface0', `var(--${theme}-surface0)`);
|
|
|
|
root.style.setProperty('--surface1', `var(--${theme}-surface1)`);
|
|
|
|
root.style.setProperty('--text', `var(--${theme}-text)`);
|
|
|
|
root.style.setProperty('--blue', `var(--${theme}-blue)`);
|
|
|
|
root.style.setProperty('--pink', `var(--${theme}-pink)`);
|
|
|
|
localStorage.setItem('theme', theme);
|
|
|
|
this.themeSelect.value = theme;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class LayoutManager {
|
|
|
|
constructor() {
|
|
|
|
this.layoutSelect = document.getElementById('layoutSelect');
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
init() {
|
|
|
|
this.layoutSelect.addEventListener('change', (e) => {
|
|
|
|
this.setLayout(e.target.value);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
setLayout(layout) {
|
|
|
|
document.body.setAttribute('data-layout', layout);
|
|
|
|
localStorage.setItem('layout', layout);
|
|
|
|
this.layoutSelect.value = layout;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class FontManager {
|
|
|
|
constructor() {
|
|
|
|
this.fontSelect = document.getElementById('fontSelect');
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
init() {
|
|
|
|
this.fontSelect.addEventListener('change', (e) => {
|
|
|
|
this.setFont(e.target.value);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
setFont(font) {
|
|
|
|
document.documentElement.style.setProperty('--font-family', font);
|
|
|
|
if (font === 'MapleMono') {
|
|
|
|
document.documentElement.style.setProperty('--font-mono', 'MapleMono');
|
|
|
|
}
|
|
|
|
localStorage.setItem('font', font);
|
|
|
|
this.fontSelect.value = font;
|
|
|
|
}
|
|
|
|
}
|