diff --git a/js/main.js b/js/main.js deleted file mode 100644 index 65f7023..0000000 --- a/js/main.js +++ /dev/null @@ -1,98 +0,0 @@ -// Update greeting based on time of day and user settings -function updateGreeting() { - const greeting = document.getElementById('greeting'); - if (!greeting) return; - - const hour = new Date().getHours(); - const isAnonymous = Storage.get('anonymousMode') || false; - const userName = isAnonymous ? - (Storage.get('anonymousName') || anonymousNames.generate()) : - (Storage.get('userName') || 'Friend'); - - let timeGreeting = 'Hello'; - if (hour >= 5 && hour < 12) timeGreeting = 'Good Morning'; - else if (hour >= 12 && hour < 17) timeGreeting = 'Good Afternoon'; - else if (hour >= 17 && hour < 20) timeGreeting = 'Good Evening'; - else timeGreeting = 'Good Night'; - - greeting.textContent = `${timeGreeting}, ${userName}!`; - greeting.style.opacity = '0'; - setTimeout(() => { - greeting.style.opacity = '1'; - }, 100); -} - -// Set up event listeners for modal interactions -function initModalHandlers() { - const modals = document.querySelectorAll('.modal'); - - modals.forEach(modal => { - modal.addEventListener('click', (e) => { - if (e.target === modal) { - closeModal(modal); - } - }); - - const modalContent = modal.querySelector('.modal-content'); - if (modalContent) { - modalContent.addEventListener('click', (e) => { - e.stopPropagation(); - }); - } - }); -} - -// Open modal with animation -function openModal(modal) { - if (!modal) return; - modal.classList.remove('hidden'); - requestAnimationFrame(() => { - modal.classList.add('active'); - }); -} - -// Close modal with animation -function closeModal(modal) { - if (!modal) return; - modal.classList.remove('active'); - setTimeout(() => { - modal.classList.add('hidden'); - }, 300); -} - -// Initialize application -document.addEventListener('DOMContentLoaded', () => { - // Apply visibility settings - ['greeting', 'search', 'shortcuts', 'addShortcut'].forEach(element => { - const isVisible = Storage.get(`show_${element}`); - if (isVisible === false) { - const elementNode = document.getElementById(element === 'search' ? 'search-container' : element); - if (elementNode) elementNode.style.display = 'none'; - } - }); - - // Start onboarding or show main content - if (!Storage.get('onboardingComplete')) { - onboarding.start(); - } else { - document.getElementById('main-content').classList.remove('hidden'); - } - - // Initialize features - search.init(); - shortcuts.init(); - settings.init(); - initModalHandlers(); - - // Set up greeting - updateGreeting(); - setInterval(updateGreeting, 60000); - - // Settings button handler - const settingsButton = document.getElementById('settings-button'); - const settingsModal = document.getElementById('settings-modal'); - - settingsButton.addEventListener('click', () => { - openModal(settingsModal); - }); -}); \ No newline at end of file diff --git a/js/notifications.js b/js/notifications.js deleted file mode 100644 index 0a2b762..0000000 --- a/js/notifications.js +++ /dev/null @@ -1,131 +0,0 @@ -// Notification System Class -class NotificationSystem { - constructor() { - this.container = document.getElementById('notification-container'); - this.notifications = new Map(); - } - - // Display a new notification - show(message, type = 'info', duration = 3000) { - const id = Date.now().toString(); - const notification = document.createElement('div'); - notification.className = `notification notification-${type}`; - - // Create notification elements - const icon = this.createIcon(type); - const content = this.createContent(message); - const closeBtn = this.createCloseButton(id); - const progress = this.createProgressBar(type); - - // Assemble notification - notification.appendChild(icon); - notification.appendChild(content); - notification.appendChild(closeBtn); - notification.appendChild(progress); - - this.container.appendChild(notification); - - // Set removal timer - setTimeout(() => this.remove(id), duration); - - // Store notification reference - this.notifications.set(id, { - element: notification, - duration - }); - - this.updateProgress(id); - - return id; - } - - // Remove a notification - remove(id) { - const notification = this.notifications.get(id); - if (notification) { - notification.element.style.animation = 'slideOutRight 0.3s cubic-bezier(0.16, 1, 0.3, 1)'; - setTimeout(() => { - notification.element.remove(); - this.notifications.delete(id); - }, 300); - } - } - - // Update progress bar - updateProgress(id) { - const notification = this.notifications.get(id); - if (notification) { - const progress = notification.element.querySelector('.notification-progress'); - const startTime = Date.now(); - - const update = () => { - const elapsed = Date.now() - startTime; - const percent = 100 - (elapsed / notification.duration * 100); - - if (percent > 0) { - progress.style.width = `${percent}%`; - requestAnimationFrame(update); - } - }; - - requestAnimationFrame(update); - } - } - - // Helper methods for creating notification elements - createIcon(type) { - const icon = document.createElement('i'); - switch(type) { - case 'success': - icon.className = 'fas fa-check-circle'; - icon.style.color = 'var(--success-color, #4caf50)'; - break; - case 'error': - icon.className = 'fas fa-times-circle'; - icon.style.color = 'var(--error-color, #f44336)'; - break; - case 'info': - default: - icon.className = 'fas fa-info-circle'; - icon.style.color = 'var(--info-color, #2196f3)'; - break; - } - return icon; - } - - createContent(message) { - const content = document.createElement('div'); - content.className = 'notification-content'; - content.textContent = message; - return content; - } - - createCloseButton(id) { - const closeBtn = document.createElement('button'); - closeBtn.className = 'notification-close'; - closeBtn.innerHTML = ''; - closeBtn.onclick = () => this.remove(id); - return closeBtn; - } - - createProgressBar(type) { - const progress = document.createElement('div'); - progress.className = 'notification-progress'; - switch(type) { - case 'success': - progress.style.background = 'var(--success-color, #4caf50)'; - break; - case 'error': - progress.style.background = 'var(--error-color, #f44336)'; - break; - case 'info': - default: - progress.style.background = 'var(--info-color, #2196f3)'; - break; - } - return progress; - } -} - -// Initialize the notification system -const notifications = new NotificationSystem(); \ No newline at end of file diff --git a/js/onboarding.js b/js/onboarding.js deleted file mode 100644 index d9315ea..0000000 --- a/js/onboarding.js +++ /dev/null @@ -1,73 +0,0 @@ -// Onboarding module -const onboarding = { - // Check if onboarding is complete - isComplete: () => { - return Storage.get('onboardingComplete') === true; - }, - - // Start the onboarding process - start: () => { - const modal = document.getElementById('onboarding-modal'); - const mainContent = document.getElementById('main-content'); - - if (!onboarding.isComplete()) { - modal.classList.remove('hidden'); - modal.classList.add('active'); - mainContent.classList.add('hidden'); - - document.getElementById('next-step-btn').addEventListener('click', () => onboarding.nextStep(1)); - document.getElementById('complete-setup-btn').addEventListener('click', onboarding.complete); - - // Set up search engine selection - const engines = document.querySelectorAll('.search-engine-option'); - engines.forEach(engine => { - engine.addEventListener('click', () => { - engines.forEach(e => e.classList.remove('selected')); - engine.classList.add('selected'); - }); - }); - } else { - modal.classList.add('hidden'); - mainContent.classList.remove('hidden'); - } - }, - - // Move to the next step in onboarding - nextStep: (currentStep) => { - const currentStepEl = document.querySelector(`[data-step="${currentStep}"]`); - const nextStepEl = document.querySelector(`[data-step="${currentStep + 1}"]`); - const name = document.getElementById('user-name').value.trim(); - - if (!name) { - notifications.show('Please enter your name!', 'error'); - return; - } - - Storage.set('userName', name); - - currentStepEl.classList.add('hidden'); - nextStepEl.classList.remove('hidden'); - nextStepEl.classList.add('visible'); - }, - - // Complete the onboarding process - complete: () => { - const selectedEngine = document.querySelector('.search-engine-option.selected'); - if (!selectedEngine) { - notifications.show('Please select a search engine!', 'error'); - return; - } - - const searchEngine = selectedEngine.dataset.engine; - Storage.set('searchEngine', searchEngine); - Storage.set('onboardingComplete', true); - - const modal = document.getElementById('onboarding-modal'); - const mainContent = document.getElementById('main-content'); - - modal.classList.add('hidden'); - mainContent.classList.remove('hidden'); - notifications.show('Welcome to your new tab! 👋', 'success'); - updateGreeting(); - } -}; \ No newline at end of file diff --git a/js/search.js b/js/search.js deleted file mode 100644 index 7998479..0000000 --- a/js/search.js +++ /dev/null @@ -1,47 +0,0 @@ -const search = { - // Supported search engines and their URLs - engines: { - google: 'https://www.google.com/search?q=', - bing: 'https://www.bing.com/search?q=', - duckduckgo: 'https://duckduckgo.com/?q=', - brave: 'https://search.brave.com/search?q=', - qwant: 'https://www.qwant.com/?q=', - searxng: 'https://searx.org/search?q=' - }, - - // Perform search using selected engine - perform: () => { - const searchBar = document.getElementById('search-bar'); - const query = searchBar.value.trim(); - const engine = Storage.get('searchEngine') || 'google'; - - if (query) { - const searchUrl = search.engines[engine] + encodeURIComponent(query); - window.location.href = searchUrl; - } - }, - - // Initialize search functionality - init: () => { - const searchBar = document.getElementById('search-bar'); - const searchButton = document.getElementById('search-button'); - - searchBar.addEventListener('keypress', (e) => { - if (e.key === 'Enter') { - search.perform(); - } - }); - - searchButton.addEventListener('click', search.perform); - - // Global keyboard shortcut to focus search bar - document.addEventListener('keydown', (e) => { - if (e.key === '/' && - !['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName) && - window.getSelection().toString() === '') { - e.preventDefault(); - searchBar.focus(); - } - }); - } -}; \ No newline at end of file diff --git a/js/settings.js b/js/settings.js deleted file mode 100644 index ea0ab68..0000000 --- a/js/settings.js +++ /dev/null @@ -1,336 +0,0 @@ -// Anonymous name generator -const anonymousNames = { - adjectives: ['Hidden', 'Secret', 'Mystery', 'Shadow', 'Unknown', 'Silent', 'Stealth', 'Phantom', 'Ghost', 'Anon'], - nouns: [' User', ' Visitor', ' Guest', ' Agent', ' Entity', ' Person', ' Browser', ' Explorer', ' Wanderer', ' Navigator'], - - generate: function() { - const adjective = this.adjectives[Math.floor(Math.random() * this.adjectives.length)]; - const noun = this.nouns[Math.floor(Math.random() * this.nouns.length)]; - return `${adjective}${noun}`; - } -}; - -// Main settings object -const settings = { - // Toggle between light and dark themes - toggleTheme: () => { - const currentTheme = document.body.getAttribute('data-theme'); - const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; - document.body.setAttribute('data-theme', newTheme); - Storage.set('theme', newTheme); - - const themeIcon = document.querySelector('#toggle-theme i'); - themeIcon.className = `fas fa-${newTheme === 'dark' ? 'sun' : 'moon'}`; - }, - - // Toggle anonymous mode - toggleAnonymousMode: () => { - const isAnonymous = Storage.get('anonymousMode') || false; - Storage.set('anonymousMode', !isAnonymous); - - if (!isAnonymous) { - const randomName = anonymousNames.generate(); - Storage.set('anonymousName', randomName); - notifications.show('Anonymous mode enabled!', 'info'); - } else { - Storage.remove('anonymousName'); - notifications.show('Anonymous mode disabled!', 'info'); - } - - shortcuts.render(); - updateGreeting(); - }, - - // Update the search engine - updateSearchEngine: (engine) => { - Storage.set('searchEngine', engine); - notifications.show('Search engine updated successfully!', 'success'); - }, - - // Update visibility of UI elements - updateVisibility: () => { - const elements = { - greeting: { - id: 'greeting', - toggle: 'toggle-greeting', - functions: ['updateGreeting'], - name: 'Greeting' - }, - search: { - id: 'search-container', - toggle: 'toggle-search', - functions: ['search.init', 'search.perform'], - name: 'Search bar' - }, - shortcuts: { - id: 'shortcuts-grid', - toggle: 'toggle-shortcuts', - functions: ['shortcuts.init', 'shortcuts.render'], - name: 'Shortcuts' - }, - addShortcut: { - id: 'add-shortcut', - toggle: 'toggle-add-shortcut', - functions: [], - name: 'Add shortcut button' - } - }; - - Object.entries(elements).forEach(([key, element]) => { - const isVisible = Storage.get(`show_${key}`); - if (isVisible === null) Storage.set(`show_${key}`, true); - - const toggle = document.getElementById(element.toggle); - const elementNode = document.getElementById(element.id); - - if (toggle && elementNode) { - toggle.checked = isVisible !== false; - if (isVisible === false) { - elementNode.style.visibility = 'hidden'; - elementNode.style.opacity = '0'; - elementNode.style.position = 'absolute'; - elementNode.style.pointerEvents = 'none'; - } - - toggle.addEventListener('change', (e) => { - const isChecked = e.target.checked; - Storage.set(`show_${key}`, isChecked); - - if (isChecked) { - elementNode.style.visibility = 'visible'; - elementNode.style.opacity = '1'; - elementNode.style.position = 'relative'; - elementNode.style.pointerEvents = 'auto'; - } else { - elementNode.style.visibility = 'hidden'; - elementNode.style.opacity = '0'; - elementNode.style.position = 'absolute'; - elementNode.style.pointerEvents = 'none'; - } - - if (key === 'shortcuts') { - const addShortcutBtn = document.getElementById('add-shortcut'); - const addShortcutVisible = Storage.get('show_addShortcut') !== false; - - if (addShortcutBtn && !isChecked && !addShortcutVisible) { - addShortcutBtn.style.visibility = 'hidden'; - addShortcutBtn.style.opacity = '0'; - addShortcutBtn.style.position = 'absolute'; - addShortcutBtn.style.pointerEvents = 'none'; - } else if (addShortcutBtn && addShortcutVisible) { - addShortcutBtn.style.visibility = 'visible'; - addShortcutBtn.style.opacity = '1'; - addShortcutBtn.style.position = 'relative'; - addShortcutBtn.style.pointerEvents = 'auto'; - } - } - - notifications.show( - `${element.name} ${isChecked ? 'shown' : 'hidden'}!`, - isChecked ? 'success' : 'info' - ); - }); - } - }); - }, - - // Initialize settings - init: () => { - const settingsButton = document.getElementById('settings-button'); - const settingsModal = document.getElementById('settings-modal'); - const closeSettings = document.getElementById('close-settings'); - - settingsButton.addEventListener('click', (e) => { - e.stopPropagation(); - const userName = Storage.get('userName') || ''; - const isAnonymous = Storage.get('anonymousMode') || false; - const currentEngine = Storage.get('searchEngine') || 'google'; - - document.getElementById('settings-name').value = userName; - document.getElementById('toggle-anonymous').checked = isAnonymous; - document.getElementById('search-engine-select').value = currentEngine; - - settingsModal.classList.remove('hidden'); - settingsModal.classList.add('active'); - }); - - closeSettings.addEventListener('click', () => { - settingsModal.classList.remove('active'); - setTimeout(() => { - settingsModal.classList.add('hidden'); - }, 300); - }); - - const themeToggle = document.getElementById('toggle-theme'); - themeToggle.addEventListener('click', settings.toggleTheme); - - const anonymousToggle = document.getElementById('toggle-anonymous'); - anonymousToggle.addEventListener('change', settings.toggleAnonymousMode); - - const searchEngineSelect = document.getElementById('search-engine-select'); - searchEngineSelect.addEventListener('change', (e) => { - settings.updateSearchEngine(e.target.value); - }); - - const nameInput = document.getElementById('settings-name'); - nameInput.addEventListener('change', (e) => { - const newName = e.target.value.trim(); - if (newName) { - Storage.set('userName', newName); - updateGreeting(); - notifications.show('Name updated successfully!', 'success'); - } - }); - - const savedTheme = Storage.get('theme') || 'light'; - document.body.setAttribute('data-theme', savedTheme); - const themeIcon = document.querySelector('#toggle-theme i'); - themeIcon.className = `fas fa-${savedTheme === 'dark' ? 'sun' : 'moon'}`; - - settings.initDataManagement(); - settings.updateVisibility(); - } -}; - -// Initialize data management -settings.initDataManagement = () => { - const exportBtn = document.getElementById('export-data'); - const importBtn = document.getElementById('import-data'); - const resetBtn = document.getElementById('reset-data'); - const fileInput = document.getElementById('import-file'); - - // Export Data - exportBtn.addEventListener('click', () => { - try { - const data = { - settings: { - theme: Storage.get('theme'), - userName: Storage.get('userName'), - anonymousMode: Storage.get('anonymousMode'), - anonymousName: Storage.get('anonymousName'), - searchEngine: Storage.get('searchEngine'), - show_greeting: Storage.get('show_greeting'), - show_search: Storage.get('show_search'), - show_shortcuts: Storage.get('show_shortcuts'), - show_addShortcut: Storage.get('show_addShortcut') - }, - shortcuts: Storage.get('shortcuts') || [] - }; - - 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 = 'jstar-tab-backup.json'; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - - notifications.show('Data exported successfully!', 'success'); - } catch (error) { - notifications.show('Failed to export data!', 'error'); - console.error('Export error:', error); - } - }); - - // Import Data - importBtn.addEventListener('click', () => fileInput.click()); - - fileInput.addEventListener('change', (e) => { - const file = e.target.files[0]; - if (!file) return; - - const reader = new FileReader(); - reader.onload = (event) => { - try { - const data = JSON.parse(event.target.result); - - if (!data.shortcuts || !data.settings) { - throw new Error('Invalid backup file format'); - } - - Object.entries(data.settings).forEach(([key, value]) => { - Storage.set(key, value); - }); - - Storage.set('shortcuts', data.shortcuts); - - fileInput.value = ''; - - ['greeting', 'search', 'shortcuts', 'addShortcut'].forEach(element => { - const isVisible = data.settings[`show_${element}`]; - const elementNode = document.getElementById(element === 'search' ? 'search-container' : element); - const toggle = document.getElementById(`toggle-${element}`); - - if (elementNode && toggle) { - toggle.checked = isVisible !== false; - if (isVisible === false) { - elementNode.style.visibility = 'hidden'; - elementNode.style.opacity = '0'; - elementNode.style.position = 'absolute'; - elementNode.style.pointerEvents = 'none'; - } else { - elementNode.style.visibility = 'visible'; - elementNode.style.opacity = '1'; - elementNode.style.position = 'relative'; - elementNode.style.pointerEvents = 'auto'; - } - } - }); - - const shortcutsVisible = data.settings.show_shortcuts !== false; - const addShortcutVisible = data.settings.show_addShortcut !== false; - const addShortcutBtn = document.getElementById('add-shortcut'); - - if (addShortcutBtn) { - if (!shortcutsVisible && !addShortcutVisible) { - addShortcutBtn.style.visibility = 'hidden'; - addShortcutBtn.style.opacity = '0'; - addShortcutBtn.style.position = 'absolute'; - addShortcutBtn.style.pointerEvents = 'none'; - } else if (addShortcutVisible) { - addShortcutBtn.style.visibility = 'visible'; - addShortcutBtn.style.opacity = '1'; - addShortcutBtn.style.position = 'relative'; - addShortcutBtn.style.pointerEvents = 'auto'; - } - } - - shortcuts.render(); - updateGreeting(); - document.body.setAttribute('data-theme', data.settings.theme || 'light'); - - notifications.show('Data imported successfully!', 'success'); - } catch (error) { - notifications.show('Failed to import data: Invalid file format!', 'error'); - console.error('Import error:', error); - } - }; - - reader.onerror = () => { - notifications.show('Failed to read file!', 'error'); - }; - - reader.readAsText(file); - }); - - // Reset Data - resetBtn.addEventListener('click', () => { - const confirmReset = confirm('Are you sure you want to reset all data? This action cannot be undone.'); - - if (confirmReset) { - try { - Storage.clear(); - closeModal(document.getElementById('settings-modal')); - notifications.show('All data has been reset!', 'success'); - setTimeout(() => { - window.location.reload(); - }, 1000); - } catch (error) { - notifications.show('Failed to reset data!', 'error'); - console.error('Reset error:', error); - } - } - }); -}; \ No newline at end of file diff --git a/js/shortcuts.js b/js/shortcuts.js deleted file mode 100644 index 909803f..0000000 --- a/js/shortcuts.js +++ /dev/null @@ -1,255 +0,0 @@ -const shortcuts = { - MAX_SHORTCUTS: 12, - - // Validate and format URL - validateAndFormatUrl: (url) => { - if (!/^https?:\/\//i.test(url)) { - url = 'https://' + url; - } - - try { - new URL(url); - return url; - } catch (e) { - return false; - } - }, - - // Add new shortcut - add: (url, name) => { - const currentShortcuts = Storage.get('shortcuts') || []; - if (currentShortcuts.length >= shortcuts.MAX_SHORTCUTS) { - notifications.show('Maximum shortcuts limit reached!', 'error'); - return; - } - - const formattedUrl = shortcuts.validateAndFormatUrl(url); - if (!formattedUrl) { - notifications.show('Invalid URL format!', 'error'); - return; - } - - currentShortcuts.push({ url: formattedUrl, name }); - Storage.set('shortcuts', currentShortcuts); - shortcuts.render(); - }, - - // Remove shortcut - remove: (index) => { - const currentShortcuts = Storage.get('shortcuts') || []; - currentShortcuts.splice(index, 1); - Storage.set('shortcuts', currentShortcuts); - shortcuts.render(); - notifications.show('Shortcut removed!', 'success'); - }, - - // Edit existing shortcut - edit: (index, newUrl, newName) => { - const currentShortcuts = Storage.get('shortcuts') || []; - currentShortcuts[index] = { url: newUrl, name: newName }; - Storage.set('shortcuts', currentShortcuts); - shortcuts.render(); - notifications.show('Shortcut updated!', 'success'); - }, - - // Show context menu for shortcut - showContextMenu: (e, index) => { - e.preventDefault(); - const menu = document.getElementById('context-menu'); - const rect = e.target.getBoundingClientRect(); - - menu.style.top = `${e.clientY}px`; - menu.style.left = `${e.clientX}px`; - menu.classList.remove('hidden'); - menu.dataset.shortcutIndex = index; - - const handleClickOutside = (event) => { - if (!menu.contains(event.target)) { - menu.classList.add('hidden'); - document.removeEventListener('click', handleClickOutside); - } - }; - - setTimeout(() => { - document.addEventListener('click', handleClickOutside); - }, 0); - }, - - // Render shortcuts grid - render: () => { - const grid = document.getElementById('shortcuts-grid'); - const currentShortcuts = Storage.get('shortcuts') || []; - const isAnonymous = Storage.get('anonymousMode') || false; - - grid.innerHTML = ''; - - currentShortcuts.forEach((shortcut, index) => { - const element = document.createElement('div'); - element.className = `shortcut ${isAnonymous ? 'blurred' : ''}`; - - const icon = document.createElement('img'); - icon.src = `https://www.google.com/s2/favicons?domain=${shortcut.url}&sz=64`; - icon.alt = shortcut.name; - - const name = document.createElement('span'); - name.textContent = shortcut.name; - - element.appendChild(icon); - element.appendChild(name); - - element.addEventListener('click', (e) => { - if (e.ctrlKey) { - window.open(shortcut.url, '_blank'); - } else { - window.location.href = shortcut.url; - } - }); - - element.addEventListener('contextmenu', (e) => { - e.preventDefault(); - const menu = document.getElementById('context-menu'); - - menu.style.top = `${e.pageY}px`; - menu.style.left = `${e.pageX}px`; - menu.classList.remove('hidden'); - menu.dataset.shortcutIndex = index; - - const closeMenu = (event) => { - if (!menu.contains(event.target)) { - menu.classList.add('hidden'); - document.removeEventListener('click', closeMenu); - } - }; - - setTimeout(() => { - document.addEventListener('click', closeMenu); - }, 0); - }); - - grid.appendChild(element); - }); - }, - - // Initialize shortcuts functionality - init: () => { - const addShortcutButton = document.getElementById('add-shortcut'); - if (addShortcutButton) { - addShortcutButton.addEventListener('click', (e) => { - e.stopPropagation(); - const currentShortcuts = Storage.get('shortcuts') || []; - - if (currentShortcuts.length >= shortcuts.MAX_SHORTCUTS) { - notifications.show('Maximum shortcuts limit reached!', 'error'); - return; - } - - const modal = document.getElementById('add-shortcut-modal'); - if (modal) { - modal.classList.remove('hidden'); - modal.classList.add('active'); - - const urlInput = document.getElementById('shortcut-url'); - const nameInput = document.getElementById('shortcut-name'); - - const saveShortcutButton = document.getElementById('save-shortcut'); - if (saveShortcutButton) { - saveShortcutButton.onclick = () => { - const url = urlInput.value.trim(); - const name = nameInput.value.trim(); - - if (url && name) { - try { - new URL(url); - shortcuts.add(url, name); - modal.classList.remove('active'); - setTimeout(() => { - modal.classList.add('hidden'); - urlInput.value = ''; - nameInput.value = ''; - }, 300); - notifications.show('Shortcut added successfully!', 'success'); - } catch (e) { - notifications.show('Invalid URL format!', 'error'); - } - } - }; - } - - const cancelShortcutButton = document.getElementById('cancel-shortcut'); - if (cancelShortcutButton) { - cancelShortcutButton.onclick = () => { - modal.classList.remove('active'); - setTimeout(() => { - modal.classList.add('hidden'); - urlInput.value = ''; - nameInput.value = ''; - }, 300); - }; - } - } - }); - } - - // Context menu actions - const contextMenu = document.getElementById('context-menu'); - if (contextMenu) { - contextMenu.addEventListener('click', (e) => { - const action = e.target.closest('.context-menu-item')?.dataset.action; - const index = parseInt(contextMenu.dataset.shortcutIndex); - - if (action === 'edit') { - const currentShortcuts = Storage.get('shortcuts') || []; - const shortcut = currentShortcuts[index]; - const modal = document.getElementById('edit-shortcut-modal'); - - if (modal) { - const urlInput = document.getElementById('edit-shortcut-url'); - const nameInput = document.getElementById('edit-shortcut-name'); - - urlInput.value = shortcut.url; - nameInput.value = shortcut.name; - - modal.classList.remove('hidden'); - modal.classList.add('active'); - - const saveButton = document.getElementById('save-edit-shortcut'); - const closeButton = document.getElementById('close-edit-shortcut'); - const cancelButton = document.getElementById('cancel-edit-shortcut'); - - const closeModal = () => { - modal.classList.remove('active'); - setTimeout(() => { - modal.classList.add('hidden'); - }, 300); - }; - - const handleSave = () => { - const newUrl = urlInput.value.trim(); - const newName = nameInput.value.trim(); - - if (newUrl && newName) { - const formattedUrl = shortcuts.validateAndFormatUrl(newUrl); - if (formattedUrl) { - shortcuts.edit(index, formattedUrl, newName); - closeModal(); - } else { - notifications.show('Invalid URL format!', 'error'); - } - } - }; - - saveButton.onclick = handleSave; - closeButton.onclick = closeModal; - cancelButton.onclick = closeModal; - } - } else if (action === 'delete') { - shortcuts.remove(index); - } - - contextMenu.classList.add('hidden'); - }); - } - - shortcuts.render(); - } -}; \ No newline at end of file diff --git a/js/storage.js b/js/storage.js deleted file mode 100644 index 2f451e8..0000000 --- a/js/storage.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Storage utility object for managing localStorage operations - * All methods handle JSON parsing/stringifying and error cases - */ -const Storage = { - // Retrieve and parse stored value - get: (key) => { - try { - return JSON.parse(localStorage.getItem(key)); - } catch (e) { - return null; - } - }, - - // Store value as JSON string - set: (key, value) => { - try { - localStorage.setItem(key, JSON.stringify(value)); - return true; - } catch (e) { - return false; - } - }, - - // Delete specific key - remove: (key) => { - try { - localStorage.removeItem(key); - return true; - } catch (e) { - return false; - } - }, - - // Remove all stored data - clear: () => { - try { - localStorage.clear(); - return true; - } catch (e) { - return false; - } - } -}; \ No newline at end of file