// Clock Class class Clock { constructor(clockElement, greetingElement) { this.clockElement = clockElement; this.greetingElement = greetingElement; this.interval = null; } start() { this.update(); this.interval = setInterval(() => this.update(), 1000); } stop() { if (this.interval) clearInterval(this.interval); } update() { const now = new Date(); this.clockElement.textContent = now.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit' }); this.updateGreeting(); } updateGreeting() { this.greetingElement.textContent = this.getGreeting(); } getGreeting() { const hour = new Date().getHours(); let greeting = ''; if (hour >= 5 && hour < 12) greeting = 'Good morning'; else if (hour >= 12 && hour < 18) greeting = 'Good afternoon'; else if (hour >= 18 && hour < 22) greeting = 'Good evening'; else greeting = 'Good night'; const name = localStorage.getItem('username'); return name ? `${greeting}, ${name}` : greeting; } } // Make LinksManager available globally window.linksManager = null; class LinksManager { } class SearchEngineManager { constructor() { this.engines = JSON.parse(localStorage.getItem('searchEngines')) || [ { name: 'SearXNG', url: 'https://search.ploszukiwacz.pl/search?q=%s', default: true } ]; this.searchForm = document.getElementById('search-form'); this.enginesContainer = document.getElementById('search-engines'); this.init(); } init() { this.renderEngines(); this.attachEventListeners(); this.setDefaultEngine(); } renderEngines() { this.enginesContainer.innerHTML = this.engines.map((engine, index) => `
`).join(''); } attachEventListeners() { document.getElementById('addSearchEngine').addEventListener('click', () => { this.addEngine({ name: 'New Engine', url: 'https://', default: false }); }); } addEngine(engine) { this.engines.push(engine); this.save(); this.renderEngines(); } updateEngine(index, field, value) { if (this.engines[index]) { this.engines[index][field] = value; this.save(); this.renderEngines(); } } removeEngine(index) { if (this.engines[index].default && this.engines.length > 1) { this.engines[0].default = true; } this.engines.splice(index, 1); this.save(); this.renderEngines(); } setDefault(index) { this.engines.forEach((engine, i) => { engine.default = i === index; }); this.save(); this.setDefaultEngine(); } setDefaultEngine() { const defaultEngine = this.engines.find(e => e.default) || this.engines[0]; if (defaultEngine) { this.searchForm.action = defaultEngine.url.replace('%s', ''); this.searchForm.querySelector('input').placeholder = `Search with ${defaultEngine.name}...`; } } save() { localStorage.setItem('searchEngines', JSON.stringify(this.engines)); } } class ShortcutManager { constructor() { this.shortcuts = JSON.parse(localStorage.getItem('shortcuts')) || { focusSearch: 's', openSettings: ',', switchLayout: 'l' }; this.init(); } init() { this.renderShortcuts(); this.attachGlobalListeners(); } renderShortcuts() { const container = document.getElementById('shortcuts-editor'); if (!container) return; container.innerHTML = Object.entries(this.shortcuts) .map(([action, key]) => `
${this.formatActionName(action)}
`).join(''); } formatActionName(action) { return action .replace(/([A-Z])/g, ' $1') .replace(/^./, str => str.toUpperCase()); } attachGlobalListeners() { document.addEventListener('keydown', (e) => { // Ignore if target is an input or textarea if (e.target.matches('input, textarea')) return; if (e.key === this.shortcuts.focusSearch) { e.preventDefault(); document.getElementById('search-input').focus(); } else if (e.key === this.shortcuts.openSettings) { e.preventDefault(); document.querySelector('.settings-button').click(); } else if (e.key === this.shortcuts.switchLayout) { e.preventDefault(); const layoutSelect = document.getElementById('layoutSelect'); layoutSelect.value = layoutSelect.value === 'grid' ? 'list' : 'grid'; layoutSelect.dispatchEvent(new Event('change')); } }); } updateShortcut(action, key) { if (key && key !== 'Escape' && key !== 'Tab') { this.shortcuts[action] = key.toLowerCase(); this.save(); this.renderShortcuts(); } } save() { localStorage.setItem('shortcuts', JSON.stringify(this.shortcuts)); } } // Make ShortcutManager available globally window.shortcutManager = null; // Settings Manager Class class SettingsManager { // ...existing SettingsManager code... } // Main initialization document.addEventListener('DOMContentLoaded', () => { // Initialize clock const clock = new Clock( document.getElementById('clock'), document.getElementById('greeting') ); clock.start(); // Initialize settings const settings = new SettingsManager(); // Focus search on load document.getElementById('search-input').focus(); // Name handling const nameInput = document.getElementById('nameInput'); const saveNameBtn = document.getElementById('saveName'); // Load saved name const savedName = localStorage.getItem('username'); if (savedName) { nameInput.value = savedName; } // Save name saveNameBtn.addEventListener('click', () => { const name = nameInput.value.trim(); if (name) { localStorage.setItem('username', name); } else { localStorage.removeItem('username'); nameInput.value = ''; // Clear input if empty } clock.updateGreeting(); }); // Also handle Enter key in name input nameInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { e.preventDefault(); saveNameBtn.click(); } }); // Background handling const fileInput = document.getElementById('bgImage'); const removeButton = document.getElementById('removeButton'); const presetOptions = document.querySelectorAll('.preset-bg-option'); function setBackground(url) { document.body.style.backgroundImage = url ? `url(${url})` : 'none'; localStorage.setItem('background', url || ''); // Update active state of preset options presetOptions.forEach(option => { const optionBg = option.dataset.bg; option.classList.toggle('active', optionBg === (url || 'none')); }); } // Load saved background const savedBg = localStorage.getItem('background'); if (savedBg) { setBackground(savedBg); } // Handle preset backgrounds presetOptions.forEach(option => { const bgUrl = option.dataset.bg; // Add none class for the no-background option if (bgUrl === 'none') { option.classList.add('none'); } else { // Set preview image option.style.backgroundImage = `url(${bgUrl})`; // Preload image const img = new Image(); img.src = bgUrl; } option.addEventListener('click', () => { setBackground(bgUrl === 'none' ? '' : bgUrl); }); }); // Handle custom upload fileInput.addEventListener('change', (e) => { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = (e) => { setBackground(e.target.result); }; reader.readAsDataURL(file); } }); removeButton.addEventListener('click', () => { setBackground(''); fileInput.value = ''; }); // Settings popup handling const settingsButton = document.querySelector('.settings-button'); const settingsPopup = document.getElementById('settingsPopup'); const closeSettings = document.querySelector('.close-settings'); settingsButton.addEventListener('click', () => { settingsPopup.classList.add('show'); }); closeSettings.addEventListener('click', () => { settingsPopup.classList.remove('show'); }); // Close popup when clicking outside settingsPopup.addEventListener('click', (e) => { if (e.target === settingsPopup) { settingsPopup.classList.remove('show'); } }); // Theme handling const themeSelect = document.getElementById('themeSelect'); function 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); } // Load saved theme const savedTheme = localStorage.getItem('theme') || 'mocha'; themeSelect.value = savedTheme; setTheme(savedTheme); // Handle theme changes themeSelect.addEventListener('change', (e) => { setTheme(e.target.value); }); // Initialize managers globally window.linksManager = new LinksManager(); window.searchManager = new SearchEngineManager(); window.shortcutManager = new ShortcutManager(); const shortcutManager = new ShortcutManager(); // Layout handling const layoutSelect = document.getElementById('layoutSelect'); layoutSelect.addEventListener('change', (e) => { document.body.setAttribute('data-layout', e.target.value); localStorage.setItem('layout', e.target.value); }); // Load saved layout const savedLayout = localStorage.getItem('layout') || 'grid'; layoutSelect.value = savedLayout; document.body.setAttribute('data-layout', savedLayout); // Custom CSS handling const customCSSEditor = document.getElementById('customCSS'); customCSSEditor.value = localStorage.getItem('customCSS') || ''; customCSSEditor.addEventListener('change', () => { localStorage.setItem('customCSS', customCSSEditor.value); applyCustomCSS(); }); function applyCustomCSS() { let customStyle = document.getElementById('custom-css') || document.createElement('style'); customStyle.id = 'custom-css'; customStyle.textContent = customCSSEditor.value; document.head.appendChild(customStyle); } // Apply custom CSS on load applyCustomCSS(); // Font handling const fontSelect = document.getElementById('fontSelect'); fontSelect.addEventListener('change', (e) => { document.documentElement.style.setProperty('--font-family', e.target.value); if (e.target.value === 'MapleMono') { document.documentElement.style.setProperty('--font-mono', 'MapleMono'); } localStorage.setItem('font', e.target.value); }); // Load saved font const savedFont = localStorage.getItem('font'); if (savedFont) { fontSelect.value = savedFont; document.documentElement.style.setProperty('--font-family', savedFont); if (savedFont === 'MapleMono') { document.documentElement.style.setProperty('--font-mono', 'MapleMono'); } } // Event delegation for settings actions document.addEventListener('click', (e) => { const action = e.target.dataset.action; if (action) { switch (action) { case 'openSettings': settingsPopup.classList.add('show'); break; case 'closeSettings': settingsPopup.classList.remove('show'); break; case 'removeBackground': setBackground(''); fileInput.value = ''; break; case 'saveName': const name = nameInput.value.trim(); if (name) { localStorage.setItem('username', name); } else { localStorage.removeItem('username'); nameInput.value = ''; // Clear input if empty } clock.updateGreeting(); break; case 'addCategory': const categoryName = prompt('Enter category name:'); if (categoryName) linksManager.addCategory(categoryName); break; case 'addLink': const category = prompt('Enter category:'); if (category && linksManager.links[category]) { linksManager.addLink(category, { name: 'New Link', url: 'https://', icon: 'fas fa-link' }); } break; case 'exportLinks': linksManager.export(); break; case 'importLinks': document.getElementById('importLinks').click(); break; default: break; } } }); document.getElementById('importLinks').addEventListener('change', (e) => { if (e.target.files[0]) linksManager.import(e.target.files[0]); }); });