Professional Website Notes Manager

Professional notes manager with editable URLs, modern interface, and quick delete functionality

// ==UserScript==
// @name         Professional Website Notes Manager
// @namespace    http://tampermonkey.net/
// @version      0.8
// @description  Professional notes manager with editable URLs, modern interface, and quick delete functionality
// @author       Byakuran
// @match        https://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_listValues
// @grant        GM_deleteValue
// ==/UserScript==

(function() {
    'use strict';

    let scriptVersion = '0.8'

    const defaultOptions = {
        version: scriptVersion,
        darkMode: window.matchMedia('(prefers-color-scheme: dark)').matches,
        addTimestampToTitle: false,
        showUrlLinksInNotesList: true,
        autoBackup: true,
        shortcuts: {
            newNote: { ctrlKey: true, shiftKey: true, key: 'S' },
            currentPageNotes: { ctrlKey: true, shiftKey: true, key: 'C' },
            allNotes: { ctrlKey: true, shiftKey: true, key: 'L' },
            showOptions: { ctrlKey: true, altKey: true, key: 'O' }
        }
    };

    let options = checkAndUpdateOptions();
    GM_setValue('options', options);

    function checkAndUpdateOptions() {
        let currentOptions;
        try {
            currentOptions = GM_getValue('options', defaultOptions);
        } catch (error) {
            console.error('Error loading options, resetting to defaults:', error);
            return defaultOptions;
        }

        // If options is not an object for some reason
        if (!currentOptions || typeof currentOptions !== 'object') {
            console.warn('Invalid options found, resetting to defaults');
            return defaultOptions;
        }

        // Check if the version has changed or if it doesn't exist
        if (!currentOptions.version || currentOptions.version !== defaultOptions.version) {
            // Version has changed, update options
            for (let key in defaultOptions) {
                if (!(key in currentOptions)) {
                    currentOptions[key] = defaultOptions[key];
                }
            }

            // Update nested objects (shortcuts, possibly more later)
            if (!currentOptions.shortcuts || typeof currentOptions.shortcuts !== 'object') {
                currentOptions.shortcuts = defaultOptions.shortcuts;
            } else {
                for (let key in defaultOptions.shortcuts) {
                    if (!(key in currentOptions.shortcuts)) {
                        currentOptions.shortcuts[key] = defaultOptions.shortcuts[key];
                    }
                }
            }

            // Update the version
            currentOptions.version = defaultOptions.version;

            // Save the updated options
            GM_setValue('options', currentOptions);

            alert('Options updated to version ' + defaultOptions.version);
            console.log('Options updated to version ' + defaultOptions.version);
        }

        return currentOptions;
    }

    const isDarkMode = options.darkMode;

    const darkModeStyles = {
        modal: {
            bg: '#1f2937',
            text: '#f3f4f6'
        },
        input: {
            bg: '#374151',
            border: '#4b5563',
            text: '#f3f4f6'
        },
        button: {
            primary: '#3b82f6',
            primaryHover: '#2563eb',
            secondary: '#4b5563',
            secondaryHover: '#374151',
            text: '#ffffff'
        },
        listItem: {
            bg: '#374151',
            bgHover: '#4b5563',
            text: '#f3f4f6'
        }
    };

    const lightModeStyles = {
        modal: {
            bg: '#ffffff',
            text: '#111827'
        },
        input: {
            bg: '#f9fafb',
            border: '#e5e7eb',
            text: '#111827'
        },
        button: {
            primary: '#3b82f6',
            primaryHover: '#2563eb',
            secondary: '#f3f4f6',
            secondaryHover: '#e5e7eb',
            text: '#ffffff'
        },
        listItem: {
            bg: '#ffffff',
            bgHover: '#f9fafb',
            text: '#1f2937'
        }
    };

    const currentTheme = isDarkMode ? darkModeStyles : lightModeStyles;

    const styles = `
        .notes-overlay .notes-modal {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: ${currentTheme.modal.bg};
            color: ${currentTheme.modal.text};
            padding: 32px;
            border-radius: 16px;
            box-shadow: 0 8px 32px rgba(0,0,0,0.25);
            z-index: 10000;
            max-width: 700px;
            width: 90%;
            max-height: 90vh;
            overflow-y: auto;
            font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
        }
        .notes-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0,0,0,${isDarkMode ? '0.8' : '0.7'});
            z-index: 9999;
            backdrop-filter: blur(4px);
        }
        .notes-overlay .notes-input {
            width: 100%;
            margin: 12px 0;
            padding: 12px 16px;
            border: 2px solid ${currentTheme.input.border};
            border-radius: 8px;
            font-size: 15px;
            transition: all 0.2s ease;
            background: ${currentTheme.input.bg};
            color: ${currentTheme.input.text};
            box-sizing: border-box;
        }
        .notes-overlay .notes-input:focus {
            outline: none;
            border-color: #3b82f6;
            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
        }
        .notes-overlay .notes-textarea {
            width: 100%;
            height: 200px;
            margin: 12px 0;
            padding: 16px;
            border: 2px solid ${currentTheme.input.border};
            border-radius: 8px;
            font-size: 15px;
            resize: vertical;
            transition: all 0.2s ease;
            background: ${currentTheme.input.bg};
            color: ${currentTheme.input.text};
            line-height: 1.5;
            box-sizing: border-box;
        }
        .notes-overlay .notes-textarea:focus {
            outline: none;
            border-color: #3b82f6;
            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
        }
        .notes-overlay .notes-button {
            background: ${currentTheme.button.primary};
            color: ${currentTheme.button.text};
            border: none;
            padding: 12px 24px;
            border-radius: 8px;
            cursor: pointer;
            margin: 5px;
            font-size: 15px;
            font-weight: 500;
            transition: all 0.2s ease;
        }
        .notes-overlay .notes-button:hover {
            background: ${currentTheme.button.primaryHover};
            transform: translateY(-1px);
        }
        .notes-overlay .notes-button.secondary {
            background: ${currentTheme.button.secondary};
            color: ${isDarkMode ? '#f3f4f6' : '#4b5563'};
        }
        .notes-overlay .notes-button.secondary:hover {
            background: ${currentTheme.button.secondaryHover};
        }
        .notes-overlay .notes-button.delete {
            background: #ef4444;
        }
        .notes-overlayt .notes-button.delete:hover {
            background: #dc2626;
        }
        .notes-overlay .notes-button.edit {
            background: #10b981;
        }
        .notes-overlay .notes-button.edit:hover {
            background: #059669;
        }
        .notes-overlay .notes-list-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 16px;
            border: 1px solid ${currentTheme.input.border};
            border-radius: 8px;
            margin: 8px 0;
            cursor: pointer;
            transition: all 0.2s ease;
            background: ${currentTheme.listItem.bg};
            color: ${currentTheme.listItem.text};
        }
        .notes-overlay .notes-list-item:hover {
            background: ${currentTheme.listItem.bgHover};
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(0,0,0,${isDarkMode ? '0.3' : '0.05'});
        }
        .notes-overlay .close-button {
            position: absolute;
            top: 16px;
            right: 16px;
            cursor: pointer;
            font-size: 24px;
            color: ${isDarkMode ? '#9ca3af' : '#6b7280'};
            transition: all 0.2s;
            width: 32px;
            height: 32px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 6px;
        }
        .notes-overlay .close-button:hover {
            color: ${isDarkMode ? '#f3f4f6' : '#111827'};
            background: ${isDarkMode ? '#374151' : '#f3f4f6'};
        }
        .notes-overlay .modal-title {
            font-size: 20px;
            font-weight: 600;
            margin-bottom: 24px;
            color: ${currentTheme.modal.text};
        }
        .notes-overlay .url-text {
            font-size: 14px;
            color: ${isDarkMode ? '#9ca3af' : '#6b7280'};
            word-break: break-all;
            margin-bottom: 16px;
            padding: 8px 12px;
            background: ${isDarkMode ? '#374151' : '#f3f4f6'};
            border-radius: 6px;
        }
        .notes-overlay .timestamp {
            font-size: 12px;
            color: ${isDarkMode ? '#9ca3af' : '#6b7280'};
            margin-top: 4px;
        }
        .notes-overlay .delete-note-button {
            background: none;
            border: none;
            color: #ef4444;
            font-size: 18px;
            cursor: pointer;
            padding: 4px 8px;
            border-radius: 4px;
            transition: all 0.2s ease;
        }
        .notes-overlay .delete-note-button:hover {
            background: #ef4444;
            color: #ffffff;
        }
        .notes-overlay .notes-options-input {
            width: 100%;
            margin: 8px 0;
            padding: 10px 14px;
            border: 2px solid ${currentTheme.input.border};
            border-radius: 8px;
            font-size: 15px;
            transition: all 0.2s ease;
            background: ${currentTheme.input.bg};
            color: ${currentTheme.input.text};
            box-sizing: border-box;
        }

        .notes-overlay .notes-options-input:focus {
            outline: none;
            border-color: #3b82f6;
            box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
        }

        .notes-overlay .notes-options-checkbox {
            margin-right: 8px;
        }

        .notes-overlay .notes-options-label {
            display: flex;
            align-items: center;
            margin: 10px 0;
            color: ${currentTheme.modal.text};
        }

        .notes-overlay .notes-editor-toolbar {
            display: flex;
            gap: 8px;
            margin: 8px 0;
            padding: 8px;
            background: ${isDarkMode ? '#2a3441' : '#f3f4f6'};
            border-radius: 6px;
        }

        .notes-overlay .notes-tag {
            display: inline-block;
            padding: 4px 8px;
            margin: 0 4px 4px 0;
            border-radius: 4px;
            background: ${isDarkMode ? '#4b5563' : '#e5e7eb'};
            color: ${isDarkMode ? '#f3f4f6' : '#374151'};
            font-size: 12px;
        }
    `;


    const mobileStyles = `
        @media (max-width: 768px) {
            .notes-overlay .notes-modal {
                width: 95%;
                padding: 16px;
                max-height: 95vh;
            }

            .notes-overlay .notes-button {
                padding: 10px 16px;
                margin: 3px;
                font-size: 14px;
            }

            .notes-overlay .close-button {
                top: 8px;
                right: 8px;
            }

            .notes-overlay .button-group {
                display: flex;
                flex-direction: column;
            }

            .notes-overlay .notes-list-item {
                padding: 12px;
            }
        }
    `;

    const styleSheet = document.createElement("style");
    styleSheet.innerText = styles + mobileStyles;
    document.head.appendChild(styleSheet);

    function showOptionsMenu() {
        const container = document.createElement('div');
        container.innerHTML = `
            <h3 class="modal-title">Options</h3>
            <div class="notes-options-label">
                <label>
                    <input type="checkbox" class="notes-options-checkbox" id="darkModeToggle" ${options.darkMode ? 'checked' : ''}>
                    Dark Mode
                </label>
            </div>
            <div class="notes-options-label">
                <label>
                    <input type="checkbox" class="notes-options-checkbox" id="timestampToggle" ${options.addTimestampToTitle ? 'checked' : ''}>
                    Add timestamp to note titles
                </label>
            </div>
            <div class="notes-options-label">
                <label>
                    <input type="checkbox" class="notes-options-checkbox" id="showUrlLinksToggle" ${options.showUrlLinksInNotesList ? 'checked' : ''}>
                    Show URL links in notes list
                </label>
            </div>
            <div class="notes-options-label">
                <label>
                    <input type="checkbox" class="notes-options-checkbox" id="autoBackupToggle" ${options.autoBackup ? 'checked' : ''}>
                    Enable automatic backups
                </label>
            </div>
            <h4 style="margin-top: 20px;">Keyboard Shortcuts</h4>
            <div>
                <label>New Note:
                    <input type="text" class="notes-options-input" id="newNoteShortcut" value="${getShortcutString(options.shortcuts.newNote)}">
                </label>
            </div>
            <div>
                <label>Current Page Notes:
                    <input type="text" class="notes-options-input" id="currentPageNotesShortcut" value="${getShortcutString(options.shortcuts.currentPageNotes)}">
                </label>
            </div>
            <div>
                <label>All Notes:
                    <input type="text" class="notes-options-input" id="allNotesShortcut" value="${getShortcutString(options.shortcuts.allNotes)}">
                </label>
            </div>
            <div>
                <label>Show Options:
                    <input type="text" class="notes-options-input" id="showOptionsWindow" value="${getShortcutString(options.shortcuts.showOptions)}">
                </label>
            </div>
            <div style="margin-top: 20px; display: flex; gap: 10px;">
                <button id="saveOptions" class="notes-button">Save Options</button>
                <button id="exportNotesBtn" class="notes-button secondary">Export Notes</button>
                <button id="importNotesBtn" class="notes-button secondary">Import Notes</button>
            </div>
        `;

        createModal(container);

        addRestoreBackupButton();

        // Add event listeners
        document.getElementById('saveOptions').onclick = saveOptions;
        document.getElementById('exportNotesBtn').onclick = exportNotes;
        document.getElementById('importNotesBtn').onclick = importNotes;
    }

    function getShortcutString(shortcut) {
        let str = '';
        if (shortcut.ctrlKey) str += 'Ctrl+';
        if (shortcut.shiftKey) str += 'Shift+';
        if (shortcut.altKey) str += 'Alt+';
        str += shortcut.key.toUpperCase();
        return str;
    }

    function parseShortcutString(str) {
        if (!str || typeof str !== 'string') {
            console.warn('Invalid shortcut string:', str);
            // Return default values if string is invalid
            return {
                ctrlKey: true,
                shiftKey: true,
                altKey: false,
                key: 'S'
            };
        }

        const parts = str.toLowerCase().split('+');
        return {
            ctrlKey: parts.includes('ctrl'),
            shiftKey: parts.includes('shift'),
            altKey: parts.includes('alt'),
            key: parts[parts.length - 1] || 'S'
        };
    }

    // Replace the saveOptions function with this corrected version
    function saveOptions() {
        try {
            options = {
                version: scriptVersion,
                darkMode: document.getElementById('darkModeToggle').checked,
                addTimestampToTitle: document.getElementById('timestampToggle').checked,
                showUrlLinksInNotesList: document.getElementById('showUrlLinksToggle').checked,
                autoBackup: document.getElementById('autoBackupToggle').checked,
                shortcuts: {
                    newNote: parseShortcutString(document.getElementById('newNoteShortcut').value),
                    currentPageNotes: parseShortcutString(document.getElementById('currentPageNotesShortcut').value),
                    allNotes: parseShortcutString(document.getElementById('allNotesShortcut').value),
                    showOptions: parseShortcutString(document.getElementById('showOptionsWindow').value)
                }
            };
            GM_setValue('options', options);
            setupShortcutListener();
            alert('Options saved successfully. Some changes may require reloading the page.');
        } catch (error) {
            console.error('Error saving options:', error);
            alert('Failed to save options. Please try again.');
        }
    }

    function exportNotes() {
        try {
            const notes = getAllNotes();
            const dateInfo = getFormattedBackupDate();
            const blob = new Blob([JSON.stringify(notes, null, 2)], {type: 'application/json'});
            const url = URL.createObjectURL(blob);

            const a = document.createElement('a');
            a.href = url;
            a.download = `website-notes-backup-${dateInfo.formatted}.json`;
            a.click();

            URL.revokeObjectURL(url);
        } catch (error) {
            console.error('Error exporting notes:', error);
            alert('Failed to export notes. Please try again.');
        }
    }

    function importNotes() {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = '.json';

        input.onchange = (e) => {
            const file = e.target.files[0];
            if (!file) return;

            const reader = new FileReader();

            reader.onload = (event) => {
                try {
                    const importedNotes = JSON.parse(event.target.result);

                    // Create custom modal for import options
                    const overlay = document.createElement('div');
                    overlay.className = 'notes-overlay';

                    const modal = document.createElement('div');
                    modal.className = 'notes-modal';
                    modal.style.maxWidth = '500px';

                    const closeButton = document.createElement('span');
                    closeButton.className = 'close-button';
                    closeButton.textContent = '×';
                    closeButton.onclick = () => overlay.remove();

                    modal.innerHTML = `
                        <h3 class="modal-title">Import Notes</h3>
                        <p>Choose how to import the notes:</p>

                        <div class="notes-list-item" style="cursor: pointer; margin-bottom: 12px;">
                            <div>
                                <strong>Merge</strong>
                                <p style="margin: 5px 0; font-size: 14px; color: ${isDarkMode ? '#9ca3af' : '#6b7280'}">
                                    Add imported notes to your existing notes. This will keep all your current notes and may create duplicates.
                                </p>
                            </div>
                        </div>

                        <div class="notes-list-item" style="cursor: pointer;">
                            <div>
                                <strong>Replace</strong>
                                <p style="margin: 5px 0; font-size: 14px; color: ${isDarkMode ? '#9ca3af' : '#6b7280'}">
                                    Replace all your current notes with the imported ones. This will delete all your existing notes.
                                </p>
                            </div>
                        </div>

                        <div style="display: flex; justify-content: space-between; margin-top: 20px;">
                            <button id="mergeBtn" class="notes-button">Merge</button>
                            <button id="replaceBtn" class="notes-button delete">Replace</button>
                            <button id="cancelBtn" class="notes-button secondary">Cancel</button>
                        </div>
                    `;

                    modal.appendChild(closeButton);
                    overlay.appendChild(modal);
                    document.body.appendChild(overlay);

                    // Add event listeners
                    document.getElementById('mergeBtn').onclick = () => {
                        mergeNotes(importedNotes);
                        overlay.remove();
                    };

                    document.getElementById('replaceBtn').onclick = () => {
                        if (confirm('This will permanently replace all your existing notes. Are you sure?')) {
                            GM_setValue('website-notes', importedNotes);
                            alert('Notes replaced successfully!');
                            overlay.remove();
                        }
                    };

                    document.getElementById('cancelBtn').onclick = () => {
                        overlay.remove();
                    };

                } catch (error) {
                    console.error('Error parsing imported notes:', error);
                    alert('Error importing notes: Invalid format');
                }
            };

            reader.readAsText(file);
        };

        input.click();
    }

    function mergeNotes(importedNotes) {
        try {
            // Get existing notes
            const existingNotes = getAllNotes();

            // Count imported notes for notification
            let importedCount = 0;

            // Merge notes by URL
            for (const url in importedNotes) {
                if (existingNotes[url]) {
                    // If URL exists, append notes to existing array
                    existingNotes[url] = existingNotes[url].concat(importedNotes[url]);
                    importedCount += importedNotes[url].length;
                } else {
                    // If URL is new, add all notes
                    existingNotes[url] = importedNotes[url];
                    importedCount += importedNotes[url].length;
                }
            }

            // Save merged notes back to storage
            GM_setValue('website-notes', existingNotes);

            // Perform auto-backup if enabled
            if (options.autoBackup) {
                performAutoBackup();
            }

            alert(`Notes merged successfully! ${importedCount} notes were imported.`);
        } catch (error) {
            console.error('Error merging notes:', error);
            alert('Error merging notes. Please try again.');
        }
    }

    function addRestoreBackupButton() {
        // Create a restore backup button
        const restoreBackupBtn = document.createElement('button');
        restoreBackupBtn.id = 'restoreBackupBtn';
        restoreBackupBtn.className = 'notes-button secondary';
        restoreBackupBtn.textContent = 'Restore Backup';

        // Add it to the export/import button group
        const buttonGroup = document.querySelector('[id="saveOptions"]').parentNode;
        buttonGroup.appendChild(restoreBackupBtn);

        // Add event listener
        document.getElementById('restoreBackupBtn').onclick = showBackupsList;
    }

    function showBackupsList() {
        // Create modal for backup list
        const overlay = document.createElement('div');
        overlay.className = 'notes-overlay';

        const modal = document.createElement('div');
        modal.className = 'notes-modal';
        modal.style.maxWidth = '500px';

        const closeButton = document.createElement('span');
        closeButton.className = 'close-button';
        closeButton.textContent = '×';
        closeButton.onclick = () => overlay.remove();

        let backupKeys = [];
        try {
            backupKeys = GM_listValues().filter(key => key.startsWith('notes-backup-')).sort().reverse();
        } catch (error) {
            console.warn('Could not retrieve list of backups:', error);
        }

        if (backupKeys.length === 0) {
            modal.innerHTML = `
            <h3 class="modal-title">Restore Backup</h3>
            <p>No backups found. Automatic backups are ${options.autoBackup ? 'enabled' : 'disabled'} in your settings.</p>
            <button id="closeBackupsList" class="notes-button">Close</button>
            `;
        } else {
            modal.innerHTML = `
            <h3 class="modal-title">Available Backups</h3>
            <p>Select a backup to restore:</p>
            <div id="backupsList" style="max-height: 300px; overflow-y: auto;"></div>
            <button id="closeBackupsList" class="notes-button secondary" style="margin-top: 16px;">Cancel</button>
            `;

            const backupsList = modal.querySelector('#backupsList');

            backupKeys.forEach(key => {
                // Extract the timestamp from the key
                const timestampStr = key.replace('notes-backup-', '');
                let timestamp;
                let readableDate = "Unknown date";

                // Handle both timestamp formats
                if (/^\d+$/.test(timestampStr)) {
                    // It's a numeric timestamp
                    timestamp = parseInt(timestampStr, 10);
                } else if (timestampStr.includes('T')) {
                    // It's an ISO date format
                    try {
                        timestamp = new Date(timestampStr.replace(/\-/g, ':')).getTime();
                    } catch (e) {
                        console.error('Error parsing ISO date format:', e);
                    }
                }

                // Format date in a more user-friendly way
                if (!isNaN(timestamp) && timestamp > 0) {
                    const date = new Date(timestamp);

                    // Format: "Feb 25, 2025 - 3:45 PM" (with day and time)
                    const options = {
                        year: 'numeric',
                        month: 'short',
                        day: 'numeric',
                        hour: 'numeric',
                        minute: '2-digit',
                        hour12: true
                    };
                    readableDate = date.toLocaleDateString(undefined, options);

                    // Add relative time indication like "Today", "Yesterday", etc.
                    const today = new Date();
                    const yesterday = new Date(today);
                    yesterday.setDate(yesterday.getDate() - 1);

                    if (date.toDateString() === today.toDateString()) {
                        readableDate = `Today, ${date.toLocaleTimeString(undefined, {hour: 'numeric', minute: '2-digit', hour12: true})}`;
                    } else if (date.toDateString() === yesterday.toDateString()) {
                        readableDate = `Yesterday, ${date.toLocaleTimeString(undefined, {hour: 'numeric', minute: '2-digit', hour12: true})}`;
                    }
                }

                const backupItem = document.createElement('div');
                backupItem.className = 'notes-list-item';
                backupItem.innerHTML = `<span>${readableDate}</span>`;
                backupItem.onclick = () => confirmAndRestoreBackup(key);

                backupsList.appendChild(backupItem);
            });
        }

        modal.appendChild(closeButton);
        overlay.appendChild(modal);
        document.body.appendChild(overlay);
        document.getElementById('closeBackupsList')?.addEventListener('click', () => overlay.remove());
    }

    function confirmAndRestoreBackup(backupKey) {
        if (confirm('Are you sure you want to restore this backup? This will replace all your current notes.')) {
            try {
                const backupData = GM_getValue(backupKey);
                if (backupData) {
                    GM_setValue('website-notes', backupData);
                    alert('Backup restored successfully!');
                    location.reload(); // Reload the page to refresh notes display
                } else {
                    alert('Error: Backup data is empty or corrupted.');
                }
            } catch (error) {
                console.error('Error restoring backup:', error);
                alert('Failed to restore backup. Please try again.');
            }
        }
    }

    // Add search functionality
    function addSearchButton() {
        // Add a search button to the top of the all notes view
        const searchButton = document.createElement('button');
        searchButton.className = 'notes-button';
        searchButton.textContent = '🔍 Search Notes';
        searchButton.style.marginBottom = '16px';
        searchButton.onclick = showSearchModal;

        // Find the appropriate container - the div after the modal title
        const titleElement = document.querySelector('.notes-modal .modal-title');
        if (titleElement && titleElement.textContent === 'All Notes') {
            titleElement.parentNode.insertBefore(searchButton, titleElement.nextSibling);
        }
    }

    function showSearchModal() {
        const overlay = document.createElement('div');
        overlay.className = 'notes-overlay';

        const modal = document.createElement('div');
        modal.className = 'notes-modal';

        const closeButton = document.createElement('span');
        closeButton.className = 'close-button';
        closeButton.textContent = '×';
        closeButton.onclick = () => overlay.remove();

        modal.innerHTML = `
            <h3 class="modal-title">Search Notes</h3>
            <input type="text" id="searchInput" class="notes-input" placeholder="Search by title, content, tags, or URL...">
            <div class="notes-options-label">
                <label>
                    <input type="checkbox" class="notes-options-checkbox" id="searchTitle" checked>
                    Search in titles
                </label>
            </div>
            <div class="notes-options-label">
                <label>
                    <input type="checkbox" class="notes-options-checkbox" id="searchContent" checked>
                    Search in note content
                </label>
            </div>
            <div class="notes-options-label">
                <label>
                    <input type="checkbox" class="notes-options-checkbox" id="searchTags" checked>
                    Search in tags
                </label>
            </div>
            <div class="notes-options-label">
                <label>
                    <input type="checkbox" class="notes-options-checkbox" id="searchUrls">
                    Search in URLs
                </label>
            </div>
            <div id="searchResults" style="margin-top: 16px; max-height: 400px; overflow-y: auto;"></div>
            <button id="closeSearchModal" class="notes-button secondary" style="margin-top: 16px;">Close</button>
        `;

        modal.appendChild(closeButton);
        overlay.appendChild(modal);
        document.body.appendChild(overlay);

        // Set up event listeners
        const searchInput = document.getElementById('searchInput');
        searchInput.focus();

        searchInput.addEventListener('input', performSearch);
        document.getElementById('searchTitle').addEventListener('change', performSearch);
        document.getElementById('searchContent').addEventListener('change', performSearch);
        document.getElementById('searchTags').addEventListener('change', performSearch);
        document.getElementById('searchUrls').addEventListener('change', performSearch);
        document.getElementById('closeSearchModal').addEventListener('click', () => overlay.remove());

        // Perform search when input changes
        function performSearch() {
            const query = searchInput.value.toLowerCase().trim();
            const searchTitle = document.getElementById('searchTitle').checked;
            const searchContent = document.getElementById('searchContent').checked;
            const searchTags = document.getElementById('searchTags').checked;
            const searchUrls = document.getElementById('searchUrls').checked;

            const searchResults = document.getElementById('searchResults');
            searchResults.innerHTML = '';

            if (!query) {
                searchResults.innerHTML = '<p style="color: #6b7280;">Enter a search term to find notes</p>';
                return;
            }

            const notes = getAllNotes();
            let resultCount = 0;

            // Function to highlight matching text
            function highlightMatch(text, query) {
                if (!text) return '';
                const regex = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
                return text.replace(regex, '<mark style="background-color: #fde68a; color: #1f2937;">$1</mark>');
            }

            // Search through all notes
            for (const url in notes) {
                if (searchUrls && url.toLowerCase().includes(query)) {
                    // The URL itself matches
                    const urlDiv = document.createElement('div');
                    urlDiv.innerHTML = `<div class="url-text">${highlightMatch(url, query)}</div>`;

                    // Add all notes under this URL
                    notes[url].forEach((note, index) => {
                        addNoteResult(urlDiv, note, url, index);
                    });

                    searchResults.appendChild(urlDiv);
                    resultCount += notes[url].length;
                    continue;
                }

                // Check if any notes match the search criteria
                const matchingNotes = notes[url].filter(note => {
                    if (searchTitle && note.title.toLowerCase().includes(query)) return true;
                    if (searchContent && note.content.toLowerCase().includes(query)) return true;
                    if (searchTags && note.tags && note.tags.some(tag => tag.toLowerCase().includes(query))) return true;
                    return false;
                });

                if (matchingNotes.length > 0) {
                    const urlDiv = document.createElement('div');
                    urlDiv.innerHTML = `<div class="url-text">${url}</div>`;

                    matchingNotes.forEach(note => {
                        const index = notes[url].indexOf(note);
                        addNoteResult(urlDiv, note, url, index, query);
                    });

                    searchResults.appendChild(urlDiv);
                    resultCount += matchingNotes.length;
                }
            }

            if (resultCount === 0) {
                searchResults.innerHTML = '<p style="color: #6b7280;">No matching notes found</p>';
            } else {
                searchResults.insertAdjacentHTML('afterbegin', `<p style="color: #6b7280;">${resultCount} note${resultCount !== 1 ? 's' : ''} found</p>`);
            }

            // Helper function to add a note result to the results div
            function addNoteResult(container, note, url, index, query) {
                const noteDiv = document.createElement('div');
                noteDiv.className = 'notes-list-item';

                // Apply note color if available
                if (note.color) {
                    noteDiv.style.borderLeft = `4px solid ${note.color}`;
                    noteDiv.style.paddingLeft = '12px';
                }

                // Create content with highlighted matches
                let titleHtml = note.title;
                let contentPreview = '';

                if (query) {
                    // Highlight matches
                    if (searchTitle) {
                        titleHtml = highlightMatch(note.title, query);
                    }

                    if (searchContent && note.content.toLowerCase().includes(query)) {
                        // Find the context around the match
                        const matchIndex = note.content.toLowerCase().indexOf(query);
                        const startIndex = Math.max(0, matchIndex - 50);
                        const endIndex = Math.min(note.content.length, matchIndex + query.length + 50);

                        // Add ellipsis if we're not starting from the beginning
                        let preview = (startIndex > 0 ? '...' : '') +
                                     note.content.substring(startIndex, endIndex) +
                                     (endIndex < note.content.length ? '...' : '');

                        contentPreview = `<div style="margin-top: 4px; font-size: 14px; color: ${isDarkMode ? '#9ca3af' : '#6b7280'};">
                                         ${highlightMatch(preview, query)}
                                         </div>`;
                    }
                }

                // Add tags if available with highlighting
                let tagsHTML = '';
                if (note.tags && note.tags.length > 0) {
                    tagsHTML = '<div style="margin-top: 4px;">';
                    note.tags.forEach(tag => {
                        if (searchTags && query && tag.toLowerCase().includes(query)) {
                            tagsHTML += `<span class="notes-tag">${highlightMatch(tag, query)}</span>`;
                        } else {
                            tagsHTML += `<span class="notes-tag">${tag}</span>`;
                        }
                    });
                    tagsHTML += '</div>';
                }

                noteDiv.innerHTML = `
                    <div style="flex-grow: 1;">
                        <div style="font-weight: 500;">${titleHtml}</div>
                        ${contentPreview}
                        ${tagsHTML}
                    </div>
                `;

                noteDiv.onclick = () => {
                    document.querySelector('.notes-overlay').remove();
                    showNoteContent(note, url, index);
                };

                container.appendChild(noteDiv);
            }
        }
    }


    GM_registerMenuCommand('Toggle Dark Mode', () => {
        const newMode = !isDarkMode;
        GM_setValue('darkMode', newMode);
        location.reload();
    });

    function createModal(content) {
        const overlay = document.createElement('div');
        overlay.className = 'notes-overlay';

        const modal = document.createElement('div');
        modal.className = 'notes-modal';

        const closeButton = document.createElement('span');
        closeButton.className = 'close-button';
        closeButton.textContent = '×';
        closeButton.onclick = () => overlay.remove();

        modal.appendChild(closeButton);
        modal.appendChild(content);
        overlay.appendChild(modal);
        document.body.appendChild(overlay);

        const escapeListener = (e) => {
            if (e.key === 'Escape') {
                overlay.remove();
                document.removeEventListener('keydown', escapeListener);
            }
        };
        document.addEventListener('keydown', escapeListener);
    }

    function getAllNotes() {
        return GM_getValue('website-notes', {});
    }

    function saveNote(title, url, content, timestamp = Date.now(), pinned = false, tags = [], color = null) {
        const notes = getAllNotes();
        if (!notes[url]) notes[url] = [];

        // Add timestamp to title if the option is enabled
        let finalTitle = title;
        if (options.addTimestampToTitle) {
            const date = new Date(timestamp);
            const formattedDate = date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
            finalTitle = `${title} [${formattedDate}]`;
        }

        notes[url].push({
            title: finalTitle,
            content,
            timestamp,
            pinned,
            tags,
            color
        });

        GM_setValue('website-notes', notes);

        // Perform auto-backup if enabled
        if (options.autoBackup) {
            performAutoBackup();
        }
    }

    function performAutoBackup() {
        try {
            const notes = getAllNotes();
            const dateInfo = getFormattedBackupDate();
            // Use consistent format with numeric timestamp
            const backupKey = `notes-backup-${dateInfo.timestamp}`;

            // Create the new backup
            GM_setValue(backupKey, notes);
            console.log(`Auto-backup created successfully: ${dateInfo.formatted}`);

            // Now try to manage old backups
            try {
                // Try to get all backup keys
                const allBackupKeys = GM_listValues().filter(key => key.startsWith('notes-backup-')).sort();

                // Keep only the last 5 backups
                if (allBackupKeys.length > 5) {
                    // Delete oldest backups, keeping the 5 most recent
                    for (let i = 0; i < allBackupKeys.length - 5; i++) {
                        try {
                            GM_deleteValue(allBackupKeys[i]);
                            console.log(`Deleted old backup: ${allBackupKeys[i]}`);
                        } catch (deleteError) {
                            alert(`Could not delete backup ${allBackupKeys[i]}:`, deleteError);
                        }
                    }
                }
            } catch (listError) {
                console.warn('Could not retrieve list of backups to manage old backups:', listError);
                alert('Could not retrieve list of backups to manage old backups:', listError);

                // Alternative approach: Store the list of backup keys ourselves
                let storedBackupKeys = GM_getValue('backup-key-list', []);

                // Add the new backup key to our list
                storedBackupKeys.push(backupKey);

                // Only keep the most recent 5 backups
                if (storedBackupKeys.length > 5) {
                    // Get keys to delete (all except the 5 most recent)
                    const keysToDelete = storedBackupKeys.slice(0, storedBackupKeys.length - 5);

                    // Delete old backups
                    keysToDelete.forEach(keyToDelete => {
                        try {
                            GM_deleteValue(keyToDelete);
                            console.log(`Deleted old backup (using fallback method): ${keyToDelete}`);
                        } catch (deleteError) {
                            console.warn(`Could not delete backup ${keyToDelete}:`, deleteError);
                        }
                    });

                    // Update our stored list to contain only the 5 most recent keys
                    storedBackupKeys = storedBackupKeys.slice(storedBackupKeys.length - 5);
                }

                // Save the updated list of backup keys
                GM_setValue('backup-key-list', storedBackupKeys);
            }
        } catch (error) {
            console.error('Error during auto-backup:', error);
        }
    }

    function getFormattedBackupDate() {
        const now = new Date();

        // Format: YYYY-MM-DD_HH-MM-SS (e.g., 2025-02-25_14-30-45)
        const year = now.getFullYear();
        const month = String(now.getMonth() + 1).padStart(2, '0');
        const day = String(now.getDate()).padStart(2, '0');
        const hours = String(now.getHours()).padStart(2, '0');
        const minutes = String(now.getMinutes()).padStart(2, '0');
        const seconds = String(now.getSeconds()).padStart(2, '0');

        const dateString = `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;

        return {
            timestamp: now.getTime(),  // Use numeric timestamp
            formatted: dateString
        };
    }

    function updateNote(oldUrl, index, title, newUrl, content, pinned, tags = [], color = null) {
        const notes = getAllNotes();
        const existingNote = notes[oldUrl][index];

        // Delete the old note
        deleteNote(oldUrl, index);

        // Save with updated values but keep the original timestamp
        saveNote(
            title,
            newUrl,
            content,
            existingNote.timestamp,
            pinned,
            tags,
            color
        );
    }

    function togglePinNote(url, index) {
        const notes = getAllNotes();
        if (notes[url] && notes[url][index]) {
            notes[url][index].pinned = !notes[url][index].pinned;
            GM_setValue('website-notes', notes);
        }
    }

    function deleteNote(url, index) {
        const notes = getAllNotes();
        if (notes[url]) {
            notes[url].splice(index, 1);
            if (notes[url].length === 0) delete notes[url];
            GM_setValue('website-notes', notes);
        }
    }

    function showNoteForm(editMode = false, existingNote = null, url = null, index = null) {
        const container = document.createElement('div');
        container.innerHTML = `<h3 class="modal-title">${editMode ? 'Edit Note' : 'Create New Note'}</h3>`;

        const titleInput = document.createElement('input');
        titleInput.className = 'notes-input';
        titleInput.placeholder = 'Enter title';
        titleInput.value = editMode ? existingNote.title : '';

        const urlInput = document.createElement('input');
        urlInput.className = 'notes-input';
        urlInput.placeholder = 'Enter URL(s) or URL pattern(s), separated by spaces (e.g., https://domain.com/*)';
        urlInput.value = editMode ? url : window.location.href;

        const patternHelp = document.createElement('div');
        patternHelp.style.fontSize = '12px';
        patternHelp.style.color = isDarkMode ? '#9ca3af' : '#6b7280';
        patternHelp.style.marginTop = '-8px';
        patternHelp.style.marginBottom = '8px';
        patternHelp.innerHTML = 'Use * for wildcard matching. Multiple URLs: separate with spaces (e.g., https://domain1.com/* https://domain2.com/*)';

        // Add tags input
        const tagsInput = document.createElement('input');
        tagsInput.className = 'notes-input';
        tagsInput.placeholder = 'Tags (comma separated)';
        tagsInput.value = editMode && existingNote.tags ? existingNote.tags.join(', ') : '';

        const tagsHelp = document.createElement('div');
        tagsHelp.style.fontSize = '12px';
        tagsHelp.style.color = isDarkMode ? '#9ca3af' : '#6b7280';
        tagsHelp.style.marginTop = '-8px';
        tagsHelp.style.marginBottom = '8px';
        tagsHelp.innerHTML = 'Add tags to organize notes (e.g., work, personal, important)';

        // Add color picker
        const colorPicker = createColorPicker(editMode && existingNote.color ? existingNote.color : '#3b82f6');
        const colorPickerLabel = document.createElement('div');
        colorPickerLabel.style.fontSize = '14px';
        colorPickerLabel.style.marginBottom = '8px';
        colorPickerLabel.innerHTML = 'Note Color:';

        const contentArea = document.createElement('textarea');
        contentArea.className = 'notes-textarea';
        contentArea.placeholder = 'Enter your notes here';
        contentArea.value = editMode ? existingNote.content : '';

        // Add formatting toolbar
        const toolbar = enhanceTextEditor(contentArea);

        const buttonGroup = document.createElement('div');
        buttonGroup.className = 'button-group';
        buttonGroup.style.display = 'flex';
        buttonGroup.style.justifyContent = 'space-between';
        buttonGroup.style.marginTop = '16px';

        const saveButton = document.createElement('button');
        saveButton.className = 'notes-button';
        saveButton.textContent = editMode ? 'Update Note' : 'Save Note';
        saveButton.onclick = () => {
            if (titleInput.value && contentArea.value) {
                const tags = tagsInput.value.split(',').map(tag => tag.trim()).filter(tag => tag);
                const color = colorPicker.dataset.selectedColor;

                if (editMode) {
                    updateNote(url, index, titleInput.value, urlInput.value, contentArea.value,
                               existingNote.pinned, tags, color);
                } else {
                    saveNote(titleInput.value, urlInput.value, contentArea.value, Date.now(), false, tags, color);
                }
                container.parentElement.parentElement.remove();
                showCurrentPageNotes();
            } else {
                alert('Title and content are required!');
            }
        };

        const cancelButton = document.createElement('button');
        cancelButton.className = 'notes-button secondary';
        cancelButton.textContent = 'Cancel';
        cancelButton.onclick = () => container.parentElement.parentElement.remove();

        buttonGroup.appendChild(saveButton);
        buttonGroup.appendChild(cancelButton);

        container.appendChild(titleInput);
        container.appendChild(urlInput);
        container.appendChild(patternHelp);
        container.appendChild(tagsInput);
        container.appendChild(tagsHelp);
        container.appendChild(colorPickerLabel);
        container.appendChild(colorPicker);
        container.appendChild(toolbar);
        container.appendChild(contentArea);
        container.appendChild(buttonGroup);

        createModal(container);
    }

    function createColorPicker(selectedColor = '#3b82f6') {
        const colorOptions = ['#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6', '#ec4899'];

        const container = document.createElement('div');
        container.style.display = 'flex';
        container.style.gap = '8px';
        container.style.margin = '8px 0';
        container.style.flexWrap = 'wrap';

        colorOptions.forEach(color => {
            const option = document.createElement('div');
            option.style.width = '24px';
            option.style.height = '24px';
            option.style.borderRadius = '50%';
            option.style.backgroundColor = color;
            option.style.cursor = 'pointer';
            option.style.border = color === selectedColor ? '2px solid white' : '2px solid transparent';
            option.style.boxShadow = '0 0 0 1px rgba(0,0,0,0.1)';

            option.onclick = () => {
                container.querySelectorAll('div').forEach(div => {
                    div.style.border = '2px solid transparent';
                });
                option.style.border = '2px solid white';
                container.dataset.selectedColor = color;
            };

            container.appendChild(option);
        });

        container.dataset.selectedColor = selectedColor;
        return container;
    }

    function applyNoteColor(noteElement, color) {
        if (!color) return;

        // Apply color as a left border
        noteElement.style.borderLeft = `4px solid ${color}`;
        // Add subtle background tint
        const colorOpacity = isDarkMode ? '0.1' : '0.05';
        noteElement.style.backgroundColor = `${color}${colorOpacity}`;
    }

    function enhanceTextEditor(textArea) {
        const toolbar = document.createElement('div');
        toolbar.className = 'notes-editor-toolbar';

        const addButton = (text, title, action) => {
            const btn = document.createElement('button');
            btn.textContent = text;
            btn.title = title;
            btn.className = 'notes-button secondary';
            btn.style.padding = '4px 8px';
            btn.style.fontSize = '12px';
            btn.onclick = (e) => {
                e.preventDefault();
                action(textArea);
                textArea.focus(); // Keep focus on the textarea after button click
            };
            return btn;
        };

        // Add formatting buttons with icons or text
        toolbar.appendChild(addButton('B', 'Bold (Ctrl+B)', ta => {
            // If text is selected, wrap it in bold marks
            // Otherwise, just insert the marks and place cursor between them
            insertAround(ta, '**', '**');
        }));

        toolbar.appendChild(addButton('I', 'Italic (Ctrl+I)', ta => {
            insertAround(ta, '_', '_');
        }));

        toolbar.appendChild(addButton('Link', 'Insert Link', ta => {
            const selection = ta.value.substring(ta.selectionStart, ta.selectionEnd);
            if (selection) {
                insertAround(ta, '[', '](https://)');
                // Position cursor after the opening bracket of the URL
                ta.selectionStart = ta.selectionEnd - 9;
                ta.selectionEnd = ta.selectionEnd - 1;
            } else {
                insertAtCursor(ta, '[Link text](https://)');
                // Select "Link text" for easy replacement
                const cursorPos = ta.value.lastIndexOf('[Link text]');
                ta.selectionStart = cursorPos + 1;
                ta.selectionEnd = cursorPos + 10;
            }
        }));

        toolbar.appendChild(addButton('List', 'Insert List', ta => {
            insertAtCursor(ta, '\n- Item 1\n- Item 2\n- Item 3\n');
        }));

        toolbar.appendChild(addButton('H1', 'Heading 1', ta => {
            const start = ta.selectionStart;
            const lineStart = ta.value.lastIndexOf('\n', start - 1) + 1;
            const selection = ta.value.substring(ta.selectionStart, ta.selectionEnd);

            // Check if the line already starts with # to avoid duplicating
            const currentLine = ta.value.substring(lineStart, start);
            if (currentLine.trim().startsWith('# ')) {
                return; // Already has heading format
            }

            if (selection) {
                // Selected text becomes heading
                ta.value = ta.value.substring(0, ta.selectionStart) +
                           '# ' + selection +
                           ta.value.substring(ta.selectionEnd);
                ta.selectionStart = ta.selectionStart + 2;
                ta.selectionEnd = ta.selectionStart + selection.length;
            } else {
                // Insert at current line start
                ta.value = ta.value.substring(0, lineStart) +
                           '# Heading' +
                           ta.value.substring(lineStart);
                ta.selectionStart = lineStart + 2;
                ta.selectionEnd = lineStart + 9;
            }
        }));

        toolbar.appendChild(addButton('H2', 'Heading 2', ta => {
            const start = ta.selectionStart;
            const lineStart = ta.value.lastIndexOf('\n', start - 1) + 1;
            const selection = ta.value.substring(ta.selectionStart, ta.selectionEnd);

            // Check if the line already starts with ## to avoid duplicating
            const currentLine = ta.value.substring(lineStart, start);
            if (currentLine.trim().startsWith('## ')) {
                return; // Already has heading format
            }

            if (selection) {
                // Selected text becomes heading
                ta.value = ta.value.substring(0, ta.selectionStart) +
                           '## ' + selection +
                           ta.value.substring(ta.selectionEnd);
                ta.selectionStart = ta.selectionStart + 3;
                ta.selectionEnd = ta.selectionStart + selection.length;
            } else {
                // Insert at current line start
                ta.value = ta.value.substring(0, lineStart) +
                           '## Subheading' +
                           ta.value.substring(lineStart);
                ta.selectionStart = lineStart + 3;
                ta.selectionEnd = lineStart + 13;
            }
        }));

        toolbar.appendChild(addButton('Quote', 'Blockquote', ta => {
            const start = ta.selectionStart;
            const lineStart = ta.value.lastIndexOf('\n', start - 1) + 1;
            const selection = ta.value.substring(ta.selectionStart, ta.selectionEnd);

            if (selection) {
                // Add quote prefix to all selected lines
                const lines = selection.split('\n');
                const quotedText = lines.map(line => `> ${line}`).join('\n');

                ta.value = ta.value.substring(0, ta.selectionStart) +
                           quotedText +
                           ta.value.substring(ta.selectionEnd);

                ta.selectionStart = ta.selectionStart;
                ta.selectionEnd = ta.selectionStart + quotedText.length;
            } else {
                // Insert at current line start
                ta.value = ta.value.substring(0, lineStart) +
                           '> ' + ta.value.substring(lineStart);
                ta.selectionStart = lineStart + 2;
                ta.selectionEnd = lineStart + 2;
            }
        }));

        // Add keyboard event listeners for common shortcuts
        textArea.addEventListener('keydown', (e) => {
            // Ctrl+B for bold
            if (e.ctrlKey && e.key === 'b') {
                e.preventDefault();
                insertAround(textArea, '**', '**');
            }
            // Ctrl+I for italic
            if (e.ctrlKey && e.key === 'i') {
                e.preventDefault();
                insertAround(textArea, '_', '_');
            }
            // Tab key handling for indentation
            if (e.key === 'Tab') {
                e.preventDefault();
                insertAtCursor(textArea, '    ');
            }
        });

        return toolbar;
    }

    function insertAround(textArea, before, after) {
        const start = textArea.selectionStart;
        const end = textArea.selectionEnd;
        const text = textArea.value;
        const selected = text.substring(start, end);

        textArea.value = text.substring(0, start) + before + selected + after + text.substring(end);
        textArea.focus();
        textArea.setSelectionRange(start + before.length, start + before.length + selected.length);
    }

    function insertAtCursor(textArea, text) {
        const start = textArea.selectionStart;
        textArea.value = textArea.value.substring(0, start) + text + textArea.value.substring(start);
        textArea.focus();
        textArea.setSelectionRange(start + text.length, start + text.length);
    }

    function formatDate(timestamp) {
        return new Date(timestamp).toLocaleString();
    }

    function showNoteContent(note, url, index) {
        const container = document.createElement('div');

        // Function to convert URLs to clickable links and preserve line breaks
        function linkify(text) {
            // URL pattern for matching
            const urlPattern = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;

            // Replace URLs with anchor tags
            const linkedText = text.replace(urlPattern, function(url) {
                return `<a href="${url}" target="_blank" style="color: #3b82f6; text-decoration: underline; word-break: break-all;" onclick="event.stopPropagation();">${url}</a>`;
            });

            // Process markdown formatting
            let formattedText = linkedText
                // Bold
                .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
                // Italic
                .replace(/_(.*?)_/g, '<em>$1</em>')
                // Headers
                .replace(/^# (.*?)$/gm, '<h1 style="font-size: 1.5em; margin-top: 0.8em; margin-bottom: 0.5em;">$1</h1>')
                .replace(/^## (.*?)$/gm, '<h2 style="font-size: 1.3em; margin-top: 0.7em; margin-bottom: 0.4em;">$1</h2>')
                // Lists
                .replace(/^- (.*?)$/gm, '• $1<br>')
                // Blockquotes
                .replace(/^> (.*?)$/gm, '<blockquote style="border-left: 3px solid #9ca3af; padding-left: 10px; margin-left: 5px; color: #6b7280;">$1</blockquote>');

            // Convert line breaks to <br> tags and maintain whitespace
            return formattedText.replace(/\n/g, '<br>').replace(/\s{2,}/g, function(space) {
                return ' ' + '&nbsp;'.repeat(space.length - 1);
            });
        }

        // Create a hidden textarea for proper copying
        const hiddenTextarea = document.createElement('textarea');
        hiddenTextarea.style.position = 'absolute';
        hiddenTextarea.style.left = '-9999px';
        hiddenTextarea.style.top = '-9999px';
        document.body.appendChild(hiddenTextarea);

        // Create note header with title and color
        const noteHeader = document.createElement('div');
        noteHeader.className = 'note-header';
        noteHeader.style.display = 'flex';
        noteHeader.style.alignItems = 'center';
        noteHeader.style.marginBottom = '16px';

        // Create color indicator
        const colorIndicator = document.createElement('div');
        colorIndicator.style.width = '16px';
        colorIndicator.style.height = '16px';
        colorIndicator.style.borderRadius = '50%';
        colorIndicator.style.marginRight = '8px';
        colorIndicator.style.backgroundColor = note.color || '#3b82f6';

        // Create the actual content container
        const contentContainer = document.createElement('div');
        contentContainer.className = 'note-content-container';
        contentContainer.style.padding = '16px';
        contentContainer.style.borderRadius = '8px';
        contentContainer.style.marginBottom = '16px';

        // Apply the note color
        if (note.color) {
            contentContainer.style.borderLeft = `4px solid ${note.color}`;
            contentContainer.style.backgroundColor = `${note.color}${isDarkMode ? '15' : '10'}`;
        } else {
            contentContainer.style.backgroundColor = isDarkMode ? '#2a3441' : '#f9fafb';
        }

        // Add tags display if the note has tags
        let tagsHTML = '';
        if (note.tags && note.tags.length > 0) {
            tagsHTML = '<div style="margin-top: 8px; margin-bottom: 8px;">';
            note.tags.forEach(tag => {
                tagsHTML += `<span class="notes-tag">${tag}</span>`;
            });
            tagsHTML += '</div>';
        }

        container.innerHTML = `
            <h3 class="modal-title">${note.title}</h3>
            <div class="url-text">${url}</div>
            <div class="timestamp">Created: ${formatDate(note.timestamp)}</div>
            ${tagsHTML}
        `;

        // Add content to the content container
        contentContainer.innerHTML = linkify(note.content);
        container.appendChild(contentContainer);

        // Add copy event listener to the content div
        contentContainer.addEventListener('copy', (e) => {
            e.preventDefault();
            const selection = window.getSelection();
            const selectedText = selection.toString();

            // Replace <br> tags with actual newlines in the copied text
            hiddenTextarea.value = selectedText.replace(/\s*\n\s*/g, '\n');
            hiddenTextarea.select();
            document.execCommand('copy');

            // Clean up
            selection.removeAllRanges();
            selection.addRange(document.createRange());
        });

        const buttonGroup = document.createElement('div');
        buttonGroup.className = 'button-group';

        const editButton = document.createElement('button');
        editButton.className = 'notes-button edit';
        editButton.textContent = 'Edit';
        editButton.onclick = () => {
            container.parentElement.parentElement.remove();
            showNoteForm(true, note, url, index);
        };

        const deleteButton = document.createElement('button');
        deleteButton.className = 'notes-button delete';
        deleteButton.textContent = 'Delete';
        deleteButton.onclick = () => {
            if (confirm('Are you sure you want to delete this note?')) {
                deleteNote(url, index);
                container.parentElement.parentElement.remove();
                showCurrentPageNotes();
            }
        };

        const pinButton = document.createElement('button');
        pinButton.className = `notes-button ${note.pinned ? 'secondary' : ''}`;
        pinButton.textContent = note.pinned ? 'Unpin' : 'Pin';
        pinButton.onclick = () => {
            togglePinNote(url, index);
            // Get the updated notes data after toggling pin status
            const notes = getAllNotes();
            // Update the button text and class based on the updated pin status
            const isPinned = notes[url] && notes[url][index] ? notes[url][index].pinned : false;
            pinButton.textContent = isPinned ? 'Unpin' : 'Pin';
            pinButton.className = `notes-button ${isPinned ? '' : 'secondary'}`;
            // Update the pinned notes display
            displayPinnedNotes();
        };

        buttonGroup.appendChild(editButton);
        buttonGroup.appendChild(deleteButton);
        buttonGroup.appendChild(pinButton);
        container.appendChild(buttonGroup);

        createModal(container);
    }

    function displayPinnedNotes() {
        const notes = getAllNotes();
        const currentUrl = window.location.href;
        let pinnedNotesContainer = document.getElementById('pinned-notes-container');

        if (!pinnedNotesContainer) {
            pinnedNotesContainer = document.createElement('div');
            pinnedNotesContainer.id = 'pinned-notes-container';
            pinnedNotesContainer.style.position = 'fixed';
            pinnedNotesContainer.style.top = '10px';
            pinnedNotesContainer.style.right = '10px';
            pinnedNotesContainer.style.zIndex = '9999';
            pinnedNotesContainer.style.maxWidth = '300px';
            document.body.appendChild(pinnedNotesContainer);
        }

        pinnedNotesContainer.innerHTML = '';

        for (const url in notes) {
            if (doesUrlMatchPattern(url, currentUrl)) {
                notes[url].forEach((note, index) => {
                    if (note.pinned) {
                        const noteDiv = document.createElement('div');
                        noteDiv.className = 'pinned-note';
                        noteDiv.style.background = currentTheme.listItem.bg;
                        noteDiv.style.color = currentTheme.listItem.text;
                        noteDiv.style.padding = '10px';
                        noteDiv.style.margin = '5px 0';
                        noteDiv.style.borderRadius = '8px';
                        noteDiv.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
                        noteDiv.style.cursor = 'pointer';

                        // Apply note color if available
                        if (note.color) {
                            noteDiv.style.borderLeft = `4px solid ${note.color}`;
                            noteDiv.style.paddingLeft = '12px';
                        }

                        noteDiv.innerHTML = `<strong>${note.title}</strong>`;
                        noteDiv.onclick = () => showNoteContent(note, url, index);
                        pinnedNotesContainer.appendChild(noteDiv);
                    }
                });
            }
        }
    }


    function doesUrlMatchPattern(urlPatterns, currentUrl) {
        // Split the pattern string into an array of patterns
        const patterns = urlPatterns.split(/\s+/).filter(pattern => pattern.trim() !== '');

        // Check if any of the patterns match the current URL
        return patterns.some(pattern => {
            // Escape special characters for regex
            const escapeRegex = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

            // Convert Tampermonkey-style pattern to regex
            const patternToRegex = (pattern) => {
                const parts = pattern.split('*');
                let regexString = '^';
                for (let i = 0; i < parts.length; i++) {
                    regexString += escapeRegex(parts[i]);
                    if (i < parts.length - 1) {
                        if (parts[i + 1] === '') {
                            // '**' matches any number of path segments
                            regexString += '.*';
                            i++; // Skip the next '*'
                        } else {
                            // Single '*' matches anything except '/'
                            regexString += '[^/]*';
                        }
                    }
                }
                // If the pattern ends with '**', allow anything at the end
                if (pattern.endsWith('**')) {
                    regexString += '.*';
                } else if (!pattern.endsWith('*')) {
                    regexString += '$';
                }
                return new RegExp(regexString);
            };

            try {
                const regex = patternToRegex(pattern);
                return regex.test(currentUrl);
            } catch (e) {
                console.error('Invalid URL pattern:', e);
                return false;
            }
        });
    }

    function showCurrentPageNotes() {
        const notes = getAllNotes();
        const currentUrl = window.location.href;
        let matchingNotes = [];

        // Collect all matching notes
        for (const urlPattern in notes) {
            if (doesUrlMatchPattern(urlPattern, currentUrl)) {
                matchingNotes.push({
                    pattern: urlPattern,
                    notes: notes[urlPattern]
                });
            }
        }

        const container = document.createElement('div');
        container.innerHTML = `
            <h3 class="modal-title">Notes for Current Page</h3>
            <div class="url-text">${currentUrl}</div>
        `;

        if (matchingNotes.length === 0) {
            container.innerHTML += '<p style="color: #6b7280;">No matching notes found for this page</p>';
        } else {
            matchingNotes.forEach(({pattern, notes: patternNotes}) => {
                const patternDiv = document.createElement('div');

                if (options.showUrlLinksInNotesList) {
                    patternDiv.innerHTML = `<div class="url-text">Pattern: ${pattern}</div>`;
                }
                patternNotes.forEach((note, index) => {
                    const noteDiv = document.createElement('div');
                    noteDiv.className = 'notes-list-item';

                    // Apply note color if available
                    if (note.color) {
                        noteDiv.style.borderLeft = `4px solid ${note.color}`;
                        noteDiv.style.paddingLeft = '12px';
                    }

                    // Add tags if available
                    let tagsHTML = '';
                    if (note.tags && note.tags.length > 0) {
                        tagsHTML = '<div style="margin-top: 4px;">';
                        note.tags.forEach(tag => {
                            tagsHTML += `<span class="notes-tag">${tag}</span>`;
                        });
                        tagsHTML += '</div>';
                    }

                    noteDiv.innerHTML = `
                        <div style="flex-grow: 1; display: flex; flex-direction: column;">
                            <span style="font-weight: 500;">${note.title}</span>
                            ${tagsHTML}
                        </div>
                        <button class="delete-note-button" title="Delete note">×</button>
                    `;

                    noteDiv.onclick = (e) => {
                        if (!e.target.classList.contains('delete-note-button')) {
                            container.parentElement.parentElement.remove();
                            showNoteContent(note, pattern, index);
                        }
                    };

                    noteDiv.querySelector('.delete-note-button').onclick = (e) => {
                        e.stopPropagation();
                        if (confirm('Are you sure you want to delete this note?')) {
                            deleteNote(pattern, index);
                            noteDiv.remove();
                            if (patternNotes.length === 1) {
                                patternDiv.remove();
                            }
                        }
                    };

                    patternDiv.appendChild(noteDiv);
                });

                container.appendChild(patternDiv);
            });
        }

        // Add help button and dropdown
        const helpButton = document.createElement('button');
        helpButton.textContent = '?';
        helpButton.style.position = 'absolute';
        helpButton.style.top = '16px';
        helpButton.style.right = '56px';
        helpButton.style.width = '32px';
        helpButton.style.height = '32px';
        helpButton.style.borderRadius = '50%';
        helpButton.style.border = 'none';
        helpButton.style.background = isDarkMode ? '#374151' : '#e5e7eb';
        helpButton.style.color = isDarkMode ? '#f3f4f6' : '#4b5563';
        helpButton.style.fontSize = '18px';
        helpButton.style.cursor = 'pointer';
        helpButton.style.display = 'flex';
        helpButton.style.alignItems = 'center';
        helpButton.style.justifyContent = 'center';
        helpButton.title = 'URL Pattern Help';

        const helpDropdown = document.createElement('div');
        helpDropdown.style.position = 'absolute';
        helpDropdown.style.top = '52px';
        helpDropdown.style.right = '56px';
        helpDropdown.style.background = isDarkMode ? '#1f2937' : '#ffffff';
        helpDropdown.style.border = `1px solid ${isDarkMode ? '#4b5563' : '#e5e7eb'}`;
        helpDropdown.style.borderRadius = '8px';
        helpDropdown.style.padding = '16px';
        helpDropdown.style.boxShadow = '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)';
        helpDropdown.style.zIndex = '10001';
        helpDropdown.style.display = 'none';
        helpDropdown.style.maxWidth = '300px';
        helpDropdown.style.color = isDarkMode ? '#f3f4f6' : '#4b5563';
        helpDropdown.innerHTML = `
            <strong>URL Pattern Examples:</strong><br>
            - https://domain.com/* (matches entire domain, one level deep)<br>
            - https://domain.com/** (matches entire domain, any number of levels)<br>
            - https://domain.com/specific/* (matches specific path and one level below)<br>
            - https://domain.com/specific/** (matches specific path and any levels below)<br>
            - https://domain.com/*/specific (matches specific ending, one level in between)<br>
            - https://domain.com/**/specific (matches specific ending, any number of levels in between)
        `;

        let isDropdownOpen = false;

        helpButton.onmouseenter = () => {
            if (!isDropdownOpen) {
                helpDropdown.style.display = 'block';
            }
        };

        helpButton.onmouseleave = () => {
            if (!isDropdownOpen) {
                helpDropdown.style.display = 'none';
            }
        };

        helpButton.onclick = () => {
            isDropdownOpen = !isDropdownOpen;
            helpDropdown.style.display = isDropdownOpen ? 'block' : 'none';
        };

        document.addEventListener('click', (e) => {
            if (isDropdownOpen && e.target !== helpButton && !helpDropdown.contains(e.target)) {
                isDropdownOpen = false;
                helpDropdown.style.display = 'none';
            }
        });

        container.appendChild(helpButton);
        container.appendChild(helpDropdown);

        createModal(container);
    }

    function showAllNotes() {
        const notes = getAllNotes();
        const container = document.createElement('div');
        container.innerHTML = '<h3 class="modal-title">All Notes</h3>';

        // Add a search button
        const searchButton = document.createElement('button');
        searchButton.className = 'notes-button';
        searchButton.textContent = '🔍 Search Notes';
        searchButton.style.marginBottom = '16px';
        searchButton.onclick = showSearchModal;
        container.appendChild(searchButton);

        if (Object.keys(notes).length === 0) {
            container.innerHTML += '<p style="color: #6b7280;">No notes found</p>';
        } else {
            for (const url in notes) {
                const urlDiv = document.createElement('div');
                urlDiv.innerHTML = `<div class="url-text">${url}</div>`;

                notes[url].forEach((note, index) => {
                    const noteDiv = document.createElement('div');
                    noteDiv.className = 'notes-list-item';

                    // Apply note color if available
                    if (note.color) {
                        noteDiv.style.borderLeft = `4px solid ${note.color}`;
                        noteDiv.style.paddingLeft = '12px';

                        // Add subtle background tint based on the note color
                        const colorOpacity = isDarkMode ? '0.1' : '0.05';
                        noteDiv.style.backgroundColor = `${note.color}${colorOpacity}`;
                    }

                    // Add tags if available
                    let tagsHTML = '';
                    if (note.tags && note.tags.length > 0) {
                        tagsHTML = '<div style="margin-top: 4px;">';
                        note.tags.forEach(tag => {
                            tagsHTML += `<span class="notes-tag">${tag}</span>`;
                        });
                        tagsHTML += '</div>';
                    }

                    // Add pin indicator if note is pinned
                    const pinnedIndicator = note.pinned ?
                          '<span title="Pinned" style="margin-right: 5px; color: #f59e0b;">📌</span>' : '';

                    noteDiv.innerHTML = `
                    <div style="flex-grow: 1; display: flex; flex-direction: column;">
                        <span style="font-weight: 500;">${pinnedIndicator}${note.title}</span>
                        ${tagsHTML}
                    </div>
                    <button class="delete-note-button" title="Delete note">×</button>
                `;

                    noteDiv.onclick = (e) => {
                        if (!e.target.classList.contains('delete-note-button')) {
                            container.parentElement.parentElement.remove();
                            showNoteContent(note, url, index);
                        }
                    };

                    noteDiv.querySelector('.delete-note-button').onclick = (e) => {
                        e.stopPropagation();
                        if (confirm('Are you sure you want to delete this note?')) {
                            deleteNote(url, index);
                            noteDiv.remove();
                            if (notes[url].length === 1) {
                                urlDiv.remove();
                            }
                        }
                    };

                    urlDiv.appendChild(noteDiv);
                });

                container.appendChild(urlDiv);
            }
        }

        createModal(container);
    }

    function setupShortcutListener() {
        document.removeEventListener('keydown', shortcutHandler);
        document.addEventListener('keydown', shortcutHandler);
    }

    function shortcutHandler(e) {
        if (matchShortcut(e, options.shortcuts.newNote)) {
            e.preventDefault();
            showNoteForm();
        }
        if (matchShortcut(e, options.shortcuts.currentPageNotes)) {
            e.preventDefault();
            showCurrentPageNotes();
        }
        if (matchShortcut(e, options.shortcuts.allNotes)) {
            e.preventDefault();
            showAllNotes();
        }
        if (matchShortcut(e, options.shortcuts.showOptions)) {
            e.preventDefault();
            showOptionsMenu();
        }
    }

    function matchShortcut(e, shortcut) {
        return e.ctrlKey === shortcut.ctrlKey &&
               e.shiftKey === shortcut.shiftKey &&
               e.altKey === shortcut.altKey &&
               e.key.toLowerCase() === shortcut.key.toLowerCase();
    }

    displayPinnedNotes();
    setupShortcutListener();

    // Register menu commands
    GM_registerMenuCommand('New Note', () => showNoteForm());
    GM_registerMenuCommand('View Notes (Current Page)', showCurrentPageNotes);
    GM_registerMenuCommand('View All Notes', showAllNotes);
    GM_registerMenuCommand('Options', showOptionsMenu);

})();