fandom bookmark

Custom bookmark system for Aigis Wiki (but wok for any fandom)

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         fandom bookmark
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Custom bookmark system for Aigis Wiki (but wok for any fandom) 
// @author       veho
// @match        https://*.fandom.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Store user preferences
    const preferences = {
        openInNewTab: JSON.parse(localStorage.getItem('aigisOpenInNewTab') || 'true'),
        autoRefresh: JSON.parse(localStorage.getItem('aigisAutoRefresh') || 'false'),
        showThumbnails: JSON.parse(localStorage.getItem('aigisShowThumbnails') || 'true')
    };

    // CSS styles
    const style = document.createElement('style');
    style.textContent = `
        #bookmark-panel {
            position: fixed;
            top: 50px;
            right: 20px;
            z-index: 9999;
            background: white;
            border: 1px solid #ccc;
            border-radius: 8px;
            padding: 10px;
            width: 300px;
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
            max-height: 80vh;
            overflow-y: auto;
            display: none;
        }
        #bookmark-header {
            position: relative;
            display: flex;
            align-items: center;
            margin-bottom: 10px;
        }
        #bookmark-header h4 {
            margin: 0 45px 0 0; /* Espace pour le bouton collapse */
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        #bookmark-toggle {
            position: fixed;
            top: 50px;
            right: 20px;
            z-index: 9998;
            background: #2E86AB;
            color: white;
            border: none;
            border-radius: 8px;
            padding: 8px 12px;
            cursor: pointer;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
        }
        .bookmark-entry {
            display: flex;
            align-items: center;
            margin: 5px 0;
            padding: 5px;
            border-bottom: 1px solid #eee;
        }
        .bookmark-entry img {
            width: 32px;
            height: 32px;
            margin-right: 8px;
            object-fit: contain;
        }
        .remove-btn {
            background: #e74c3c;
            color: white;
            border: none;
            border-radius: 4px;
            padding: 3px 6px;
            cursor: pointer;
            margin-left: auto;
        }
        .refresh-btn, .add-btn, .options-btn, .collapse-btn {
            background: #f0f0f0;
            color: #333;
            border: none;
            border-radius: 4px;
            padding: 3px 6px;
            cursor: pointer;
            margin-left: 5px;
        }
        .collapse-btn {
            position: absolute;
            top: 0;
            right: 0;
            min-width: 45px;
            z-index: 10;
        }
        .options-menu {
            position: absolute;
            top: 100%;
            right: 0;
            background: white;
            border: 1px solid #ccc;
            border-radius: 4px;
            padding: 10px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
            display: none;
            z-index: 10000;
            min-width: 150px;
        }
        .options-menu label {
            display: block;
            margin: 5px 0;
        }
        /* Nouveau style pour le conteneur de boutons principaux */
        .main-buttons {
            display: flex;
            align-items: center;
            margin-right: 50px; /* Espace pour le bouton collapse */
        }
    `;
    document.head.appendChild(style);

    // DOM elements
    const panel = document.createElement('div');
    panel.id = 'bookmark-panel';
    panel.innerHTML = `
        <div id="bookmark-header">
            <button class="options-btn">⚙️</button>
            <div class="main-buttons">
                <h4>Bookmarks</h4>
                <button class="refresh-btn" title="Manual refresh (Auto-refresh is enabled)">🔄</button>
                <span style="flex-grow:1;"></span>
                <button class="add-btn">+</button>
            </div>
            <button class="collapse-btn">▼</button>
            <div class="options-menu">
                <label><input type="radio" name="openTabOption" value="new" checked> Open in new tab</label>
                <label><input type="radio" name="openTabOption" value="current"> Open in current tab</label>
                <hr>
                <label><input type="checkbox" id="autoRefreshOption"> Auto-refresh on open</label>
                <label><input type="checkbox" id="showThumbnails"> Show thumbnails</label>
            </div>
        </div>
        <div id="bookmark-list"></div>
        <button id="add-bookmark" style="width:100%; margin-top:10px;">Add Page</button>
    `;
    document.body.appendChild(panel);

    const toggleBtn = document.createElement('button');
    toggleBtn.id = 'bookmark-toggle';
    toggleBtn.textContent = '☰ Bookmarks';
    document.body.appendChild(toggleBtn);

    // Initialize preferences
    function initializePreferences() {
        const savedPref = localStorage.getItem('aigisOpenInNewTab');
        const autoRefresh = localStorage.getItem('aigisAutoRefresh');
        const showThumbs = localStorage.getItem('aigisShowThumbnails');
        
        preferences.openInNewTab = savedPref !== null ? JSON.parse(savedPref) : true;
        preferences.autoRefresh = autoRefresh !== null ? JSON.parse(autoRefresh) : false;
        preferences.showThumbnails = showThumbs !== null ? JSON.parse(showThumbs) : true;

        const autoRefreshCheckbox = panel.querySelector('#autoRefreshOption');
        const thumbsCheckbox = panel.querySelector('#showThumbnails');
        
        if (autoRefreshCheckbox) autoRefreshCheckbox.checked = preferences.autoRefresh;
        if (thumbsCheckbox) thumbsCheckbox.checked = preferences.showThumbnails;

        if (autoRefreshCheckbox) {
            autoRefreshCheckbox.addEventListener('change', () => {
                preferences.autoRefresh = autoRefreshCheckbox.checked;
                localStorage.setItem('aigisAutoRefresh', preferences.autoRefresh);
                updateRefreshButtonState();
            });
        }

        if (thumbsCheckbox) {
            thumbsCheckbox.addEventListener('change', () => {
                preferences.showThumbnails = thumbsCheckbox.checked;
                localStorage.setItem('aigisShowThumbnails', preferences.showThumbnails);
                renderBookmarks();
            });
        }

        const radioButtons = panel.querySelectorAll('input[name="openTabOption"]');
        radioButtons.forEach(radio => {
            radio.checked = radio.value === (preferences.openInNewTab ? 'new' : 'current');
            radio.addEventListener('change', () => {
                preferences.openInNewTab = document.querySelector('input[name="openTabOption"]:checked').value === 'new';
                localStorage.setItem('aigisOpenInNewTab', preferences.openInNewTab);
            });
        });
    }

    // Update refresh button state based on auto-refresh
    function updateRefreshButtonState() {
        const refreshBtn = panel.querySelector('.refresh-btn');
        if (refreshBtn) {
            refreshBtn.title = preferences.autoRefresh 
                ? "Manual refresh (Auto-refresh is enabled)" 
                : "Manual refresh (Auto-refresh is disabled)";
            refreshBtn.style.opacity = preferences.autoRefresh ? "0.5" : "1";
        }
    }

    // Bookmark management
    function getBookmarks() {
        return JSON.parse(localStorage.getItem('aigisBookmarks') || '[]');
    }

    function saveBookmarks(bookmarks) {
        localStorage.setItem('aigisBookmarks', JSON.stringify(bookmarks));
    }

    function addBookmark(url, title, imageUrl) {
        const bookmarks = getBookmarks();
        if (!bookmarks.some(b => b.url === url)) {
            bookmarks.push({url, title, imageUrl});
            saveBookmarks(bookmarks);
            renderBookmarks();
        }
    }

    function removeBookmark(url) {
        const bookmarks = getBookmarks().filter(b => b.url !== url);
        saveBookmarks(bookmarks);
        renderBookmarks();
    }

    function renderBookmarks() {
        const list = document.getElementById('bookmark-list');
        list.innerHTML = '';
        const bookmarks = getBookmarks();

        bookmarks.forEach(b => {
            const entry = document.createElement('div');
            entry.className = 'bookmark-entry';
            
            if (preferences.showThumbnails) {
                entry.innerHTML = `
                    <img src="${b.imageUrl}" alt="">
                    <span>${b.title}</span>
                    <button class="remove-btn">✕</button>
                `;
            } else {
                entry.innerHTML = `
                    <span>${b.title}</span>
                    <button class="remove-btn">✕</button>
                `;
            }
            
            entry.querySelector('.remove-btn').addEventListener('click', (e) => {
                e.stopPropagation();
                removeBookmark(b.url);
            });

            entry.addEventListener('click', () => {
                if (preferences.openInNewTab) {
                    window.open(b.url, '_blank');
                } else {
                    window.location.href = b.url;
                }
            });

            list.appendChild(entry);
        });
    }

    // Event listeners
    toggleBtn.addEventListener('click', () => {
        if (preferences.autoRefresh) {
            renderBookmarks();
        }
        panel.style.display = panel.style.display === 'block' ? 'none' : 'block';
    });

    panel.querySelector('.collapse-btn').addEventListener('click', () => {
        panel.style.display = 'none';
    });

    panel.querySelector('.refresh-btn').addEventListener('click', () => {
        if (preferences.autoRefresh) {
            preferences.autoRefresh = false;
            localStorage.setItem('aigisAutoRefresh', false);
            updateRefreshButtonState();
        }
        renderBookmarks();
    });

    panel.querySelector('.add-btn').addEventListener('click', () => {
        const pageTitle = document.title.replace(/\s*\|\s*Aigis\s*Wiki\s*\|\s*Fandom/g, "").trim();
        const icon = document.querySelector(".page-header__main .wds-image img") || 
                     document.querySelector(".article-image img") || 
                     document.querySelector(".mw-parser-output img");
        
        const imageUrl = icon ? icon.src : "https://static.wikia.nocookie.net/aigis/images/0/05/Time_Crystal_Icon.png ";
        addBookmark(window.location.href, pageTitle, imageUrl);
    });

    // Options button toggle
    const optionsBtn = panel.querySelector('.options-btn');
    const optionsMenu = panel.querySelector('.options-menu');
    
    optionsBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        optionsMenu.style.display = optionsMenu.style.display === 'block' ? 'none' : 'block';
    });

    // Close options menu when clicking outside
    document.addEventListener('click', (e) => {
        if (!optionsMenu.contains(e.target) && !optionsBtn.contains(e.target)) {
            optionsMenu.style.display = 'none';
        }
    });

    document.getElementById('add-bookmark').addEventListener('click', () => {
        const pageTitle = document.title.replace(/\s*\|\s*Aigis\s*Wiki\s*\|\s*Fandom/g, "").trim();
        const icon = document.querySelector(".page-header__main .wds-image img") || 
                     document.querySelector(".article-image img") || 
                     document.querySelector(".mw-parser-output img");
        
        const imageUrl = icon ? icon.src : "https://static.wikia.nocookie.net/aigis/images/0/05/Time_Crystal_Icon.png ";
        addBookmark(window.location.href, pageTitle, imageUrl);
    });

    // Initial setup
    initializePreferences();
    updateRefreshButtonState();
    
    // Initial render
    window.addEventListener('load', () => {
        renderBookmarks();
    });
})();