notes panel

notes panel from catliife

// ==UserScript==
// @name         notes panel
// @namespace    http://tampermonkey.net/
// @version      2025-01-19
// @description  notes panel from catliife
// @author       https://m.vk.com/modsforcatlife?from=groups
// @match        https://worldcats.ru/play/
// @match        https://worldcats.ru/play/?v=b
// @match        https://catlifeonline.com/play/
// @match        https://catlifeonline.com/play/?v=b
// @icon         https://www.google.com/s2/favicons?sz=64&domain=catlifeonline.com
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    if (window.gameNotesModAdded) return;
    window.gameNotesModAdded = true;

    // Стили для всех элементов (остаются без изменений)
    var style = document.createElement('style');
    style.textContent = `
        #notes-mod-container {
            position: fixed;
            top: 10px;
            right: 150px;
            z-index: 9999;
            font-family: 'Roboto', sans-serif;
        }

        #notes-toggle-btn {
            background: rgba(34, 34, 34, 0.8);
            color: #FF9500;
            border: none;
            padding: 8px 16px;
            border-radius: 18px;
            cursor: pointer;
            font-weight: 500;
            box-shadow: 0 2px 10px rgba(0,0,0,0.3);
            display: flex;
            align-items: center;
            gap: 8px;
            backdrop-filter: blur(5px);
        }

        #notes-toggle-btn:hover {
            background: rgba(42, 42, 42, 0.8);
        }

        #notes-toggle-btn::before {
            content: "✏️";
        }

        #notes-panel {
            display: none;
            background: rgba(30, 30, 30, 0.9);
            border-radius: 12px;
            width: 350px;
            height: 500px;
            overflow: hidden;
            box-shadow: 0 4px 20px rgba(0,0,0,0.5);
            flex-direction: column;
            backdrop-filter: blur(5px);
        }

        .notes-header {
            background: rgba(37, 37, 37, 0.9);
            color: #FF9500;
            padding: 16px;
            font-weight: 500;
            border-bottom: 1px solid #333;
            flex-shrink: 0;
        }

        .notes-tabs {
            display: flex;
            background: rgba(37, 37, 37, 0.9);
            padding: 8px;
            overflow-x: auto;
            border-bottom: 1px solid #333;
            flex-shrink: 0;
            scrollbar-width: none;
        }

        .notes-tabs::-webkit-scrollbar {
            display: none;
        }

        .notes-tab {
            padding: 8px 16px;
            cursor: pointer;
            white-space: nowrap;
            border-radius: 8px;
            color: #AAA;
            font-size: 14px;
            margin-right: 4px;
            transition: all 0.2s;
            flex-shrink: 0;
        }

        .notes-tab.active {
            background: rgba(51, 51, 51, 0.9);
            color: #FF9500;
            font-weight: 500;
        }

        .notes-content-wrapper {
            flex-grow: 1;
            overflow: hidden;
            display: flex;
            flex-direction: column;
        }

        .notes-content {
            padding: 16px;
            overflow-y: auto;
            line-height: 1.5;
            border: 1px solid rgba(51, 51, 51, 0.5);
            margin: 16px;
            border-radius: 8px;
            background: rgba(37, 37, 37, 0.7);
            flex-grow: 1;
            white-space: pre-wrap;
        }

        .note-editor {
            display: none;
            padding: 0 16px;
            flex-grow: 1;
            overflow: hidden;
            flex-direction: column;
        }

        .note-editor.active {
            display: flex;
        }

        .note-title-input {
            width: calc(100% - 24px);
            padding: 8px 12px;
            margin: 16px 12px 12px;
            background: rgba(51, 51, 51, 0.7);
            color: #FFF;
            border: 1px solid rgba(68, 68, 68, 0.5);
            border-radius: 8px;
            font-size: 16px;
        }

        .note-content-textarea {
            width: calc(100% - 24px);
            padding: 12px;
            margin: 0 12px;
            background: rgba(51, 51, 51, 0.7);
            color: #FFF;
            border: 1px solid rgba(68, 68, 68, 0.5);
            border-radius: 8px;
            resize: none;
            flex-grow: 1;
            min-height: 100px;
            font-family: 'Roboto', monospace;
            white-space: pre-wrap;
        }

        .notes-controls {
            display: flex;
            padding: 8px 12px;
            background: rgba(37, 37, 37, 0.9);
            border-top: 1px solid #333;
            gap: 6px;
            flex-shrink: 0;
        }

        .notes-btn {
            padding: 6px 10px;
            border-radius: 6px;
            cursor: pointer;
            font-weight: 500;
            border: none;
            transition: background 0.2s;
            font-size: 13px;
        }

        .add-btn {
            background: #FF9500;
            color: #222;
            margin-right: auto;
            padding: 6px 12px;
        }

        .add-btn:hover {
            background: #ffaa33;
        }

        .delete-btn {
            background: rgba(51, 51, 51, 0.7);
            color: #FF3B30;
        }

        .delete-btn:hover {
            background: rgba(68, 68, 68, 0.7);
        }

        .save-btn {
            background: rgba(51, 51, 51, 0.7);
            color: #34C759;
        }

        .save-btn:hover {
            background: rgba(68, 68, 68, 0.7);
        }

        .edit-btn {
            background: rgba(51, 51, 51, 0.7);
            color: #4DABFF;
            display: none;
        }

        .edit-btn:hover {
            background: rgba(68, 68, 68, 0.7);
        }

        .notes-btn:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        .no-notes {
            padding: 20px;
            text-align: center;
            color: #666;
        }

        .note-date {
            font-size: 12px;
            color: #666;
            margin-top: 8px;
        }

        /* Стили для HTML-элементов */
        .notes-content h1, .notes-content h2, .notes-content h3,
        .notes-content h4, .notes-content h5, .notes-content h6 {
            color: #FF9500;
            margin: 0.8em 0 0.4em;
            line-height: 1.2;
        }

        .notes-content h1 { font-size: 2em; font-weight: 500; }
        .notes-content h2 { font-size: 1.7em; font-weight: 500; }
        .notes-content h3 { font-size: 1.4em; }
        .notes-content h4 { font-size: 1.2em; }
        .notes-content h5 { font-size: 1em; }
        .notes-content h6 { font-size: 0.9em; color: #AAA; }

        .notes-content p {
            margin: 0.7em 0;
            line-height: 1.5;
        }

        .notes-content a {
            color: #4DABFF;
            text-decoration: none;
        }

        .notes-content a:hover {
            text-decoration: underline;
        }

        .notes-content strong, .notes-content b {
            font-weight: bold;
            color: #FFAA33;
        }

        .notes-content em, .notes-content i {
            font-style: italic;
        }

        .notes-content u {
            text-decoration: underline;
        }

        .notes-content del {
            text-decoration: line-through;
            color: #888;
        }

        .notes-content blockquote {
            border-left: 3px solid #FF9500;
            padding-left: 12px;
            margin: 12px 0;
            color: #CCC;
        }

        .notes-content pre {
            background: rgba(37, 37, 37, 0.7);
            padding: 12px;
            border-radius: 6px;
            overflow-x: auto;
            font-family: 'JetBrains Mono', monospace;
            margin: 12px 0;
            white-space: pre-wrap;
        }

        .notes-content code {
            font-family: 'JetBrains Mono', monospace;
            background: rgba(37, 37, 37, 0.7);
            padding: 2px 4px;
            border-radius: 3px;
            font-size: 0.9em;
        }

        .notes-content ul, .notes-content ol {
            padding-left: 24px;
            margin: 12px 0;
        }

        .notes-content li {
            margin: 6px 0;
        }

        .notes-content hr {
            border: none;
            height: 1px;
            background: #333;
            margin: 16px 0;
        }

        .notes-content table {
            border-collapse: collapse;
            width: 100%;
            margin: 12px 0;
        }

        .notes-content th, .notes-content td {
            border: 1px solid #333;
            padding: 8px 12px;
            text-align: left;
        }

        .notes-content th {
            background: rgba(37, 37, 37, 0.7);
            color: #FF9500;
        }

        .notes-content img {
            max-width: 100%;
            border-radius: 4px;
            margin: 8px 0;
        }

        /* Цвета через style */
        .notes-content span[style*="color"] {
            padding: 0 2px;
        }

        /* Прокрутка */
        #notes-panel {
            scroll-behavior: smooth;
        }

        .notes-content::-webkit-scrollbar,
        .note-content-textarea::-webkit-scrollbar {
            width: 8px;
        }

        .notes-content::-webkit-scrollbar-track,
        .note-content-textarea::-webkit-scrollbar-track {
            background: rgba(37, 37, 37, 0.5);
        }

        .notes-content::-webkit-scrollbar-thumb,
        .note-content-textarea::-webkit-scrollbar-thumb {
            background: #FF9500;
            border-radius: 4px;
        }
    `;
    document.head.appendChild(style);

    // Добавляем шрифты
    var fontLink = document.createElement('link');
    fontLink.href = 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&family=JetBrains+Mono&display=swap';
    fontLink.rel = 'stylesheet';
    document.head.appendChild(fontLink);

    // Создаем структуру интерфейса
    var container = document.createElement('div');
    container.id = 'notes-mod-container';

    var toggleBtn = document.createElement('button');
    toggleBtn.id = 'notes-toggle-btn';
    toggleBtn.textContent = 'Заметки';

    var notesPanel = document.createElement('div');
    notesPanel.id = 'notes-panel';

    var header = document.createElement('div');
    header.className = 'notes-header';
    header.textContent = 'Мои заметки';

    var tabsContainer = document.createElement('div');
    tabsContainer.className = 'notes-tabs';

    var contentWrapper = document.createElement('div');
    contentWrapper.className = 'notes-content-wrapper';

    var contentContainer = document.createElement('div');
    contentContainer.className = 'notes-content';

    var editorContainer = document.createElement('div');
    editorContainer.className = 'note-editor';

    var titleInput = document.createElement('input');
    titleInput.className = 'note-title-input';
    titleInput.placeholder = 'Название заметки';

    var contentTextarea = document.createElement('textarea');
    contentTextarea.className = 'note-content-textarea';
    contentTextarea.placeholder = 'Введите текст с HTML-тегами (<h1>, <b>, <color="red"> и др.)';

    editorContainer.appendChild(titleInput);
    editorContainer.appendChild(contentTextarea);

    var controlsContainer = document.createElement('div');
    controlsContainer.className = 'notes-controls';

    var addBtn = document.createElement('button');
    addBtn.className = 'notes-btn add-btn';
    addBtn.textContent = 'Новая';

    var deleteBtn = document.createElement('button');
    deleteBtn.className = 'notes-btn delete-btn';
    deleteBtn.textContent = 'Удалить';
    deleteBtn.disabled = true;

    var saveBtn = document.createElement('button');
    saveBtn.className = 'notes-btn save-btn';
    saveBtn.textContent = 'Сохранить';

    var editBtn = document.createElement('button');
    editBtn.className = 'notes-btn edit-btn';
    editBtn.textContent = 'Ред.';

    controlsContainer.appendChild(addBtn);
    controlsContainer.appendChild(deleteBtn);
    controlsContainer.appendChild(saveBtn);
    controlsContainer.appendChild(editBtn);

    contentWrapper.appendChild(contentContainer);
    notesPanel.appendChild(header);
    notesPanel.appendChild(tabsContainer);
    notesPanel.appendChild(contentWrapper);
    notesPanel.appendChild(editorContainer);
    notesPanel.appendChild(controlsContainer);

    container.appendChild(toggleBtn);
    container.appendChild(notesPanel);
    document.body.appendChild(container);

    // Логика работы
    var notes = JSON.parse(localStorage.getItem('game-notes') || '[]');
    var currentNoteIndex = notes.length > 0 ? notes.length - 1 : -1;
    var isScrolling = false;

    function saveNotes() {
        localStorage.setItem('game-notes', JSON.stringify(notes));
    }

    function formatDate(date) {
        return new Date(date).toLocaleString('ru-RU', {
            day: 'numeric',
            month: 'short',
            hour: '2-digit',
            minute: '2-digit'
        });
    }

    function renderNotes() {
        tabsContainer.innerHTML = '';

        if (notes.length === 0) {
            contentContainer.innerHTML = '<div class="no-notes">Нет заметок</div>';
            editorContainer.classList.remove('active');
            contentWrapper.style.display = 'block';
            deleteBtn.disabled = true;
            saveBtn.disabled = true;
            editBtn.style.display = 'none';
            return;
        }

        notes.forEach(function(note, index) {
            var tab = document.createElement('div');
            tab.className = 'notes-tab ' + (index === currentNoteIndex ? 'active' : '');
            tab.textContent = note.title || 'Без названия';
            tab.onclick = function() {
                currentNoteIndex = index;
                showNoteView(); // Добавлено: переключаем в режим просмотра при выборе заметки
                renderNotes();
            };
            tabsContainer.appendChild(tab);
        });

        var note = notes[currentNoteIndex];
        if (editorContainer.classList.contains('active')) {
            titleInput.value = note.title || '';
            contentTextarea.value = note.content || '';
        } else {
            // Безопасный рендеринг HTML
            var content = note.content || '';
            // Исправляем тег color
            content = content.replace(/<color=(['"])(.*?)\1>/gi, '<span style="color: $2">');
            content = content.replace(/<\/color>/gi, '</span>');
            contentContainer.innerHTML = content;

            if (note.updatedAt) {
                var dateElement = document.createElement('div');
                dateElement.className = 'note-date';
                dateElement.textContent = formatDate(note.updatedAt);
                contentContainer.appendChild(dateElement);
            }
        }

        deleteBtn.disabled = false;
        saveBtn.disabled = false;

        // Прокручиваем к активной вкладке
        if (tabsContainer.scrollWidth > tabsContainer.clientWidth) {
            var activeTab = tabsContainer.querySelector('.notes-tab.active');
            if (activeTab) {
                activeTab.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' });
            }
        }
    }

    function showNoteView() {
        editorContainer.classList.remove('active');
        contentWrapper.style.display = 'block';
        saveBtn.style.display = 'inline-block';
        editBtn.style.display = 'inline-block';
        deleteBtn.style.display = 'inline-block';

        // Обновляем содержимое заметки при переключении в режим просмотра
        if (currentNoteIndex >= 0) {
            var note = notes[currentNoteIndex];
            var content = note.content || '';
            content = content.replace(/<color=(['"])(.*?)\1>/gi, '<span style="color: $2">');
            content = content.replace(/<\/color>/gi, '</span>');
            contentContainer.innerHTML = content;

            if (note.updatedAt) {
                var dateElement = document.createElement('div');
                dateElement.className = 'note-date';
                dateElement.textContent = formatDate(note.updatedAt);
                contentContainer.appendChild(dateElement);
            }
        }
    }

    function showEditorView() {
        editorContainer.classList.add('active');
        contentWrapper.style.display = 'none';
        saveBtn.style.display = 'inline-block';
        editBtn.style.display = 'none';
        deleteBtn.style.display = 'inline-block';
        contentTextarea.focus();

        // Обновляем содержимое редактора при переключении в режим редактирования
        if (currentNoteIndex >= 0) {
            var note = notes[currentNoteIndex];
            titleInput.value = note.title || '';
            contentTextarea.value = note.content || '';
        }
    }

    // Обработчики событий
    toggleBtn.addEventListener('click', function() {
        notesPanel.style.display = notesPanel.style.display === 'none' ? 'flex' : 'none';
        if (notesPanel.style.display === 'flex') {
            renderNotes();
        }
    });

    addBtn.addEventListener('click', function() {
        var newNote = {
            title: 'Новая заметка',
            content: '',
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString()
        };
        notes.push(newNote);
        currentNoteIndex = notes.length - 1;
        saveNotes();
        renderNotes();
        showEditorView();
        titleInput.focus();
    });

    deleteBtn.addEventListener('click', function() {
        if (currentNoteIndex >= 0 && confirm('Удалить эту заметку?')) {
            notes.splice(currentNoteIndex, 1);
            currentNoteIndex = notes.length > 0 ? Math.min(currentNoteIndex, notes.length - 1) : -1;
            saveNotes();
            renderNotes();
        }
    });

    titleInput.addEventListener('input', function() {
        if (currentNoteIndex >= 0) {
            notes[currentNoteIndex].title = titleInput.value;
            notes[currentNoteIndex].updatedAt = new Date().toISOString();
            saveNotes();
            renderNotes();
        }
    });

    contentTextarea.addEventListener('input', function() {
        if (currentNoteIndex >= 0) {
            notes[currentNoteIndex].content = contentTextarea.value;
            notes[currentNoteIndex].updatedAt = new Date().toISOString();
            saveNotes();
        }
    });

    saveBtn.addEventListener('click', function() {
        if (currentNoteIndex >= 0) {
            saveNotes();
            showNoteView();
        }
    });

    editBtn.addEventListener('click', function() {
        if (currentNoteIndex >= 0) {
            showEditorView();
        }
    });

    contentContainer.addEventListener('dblclick', function() {
        if (currentNoteIndex >= 0) {
            showEditorView();
        }
    });

    // Прокрутка между заметками колесиком
    tabsContainer.addEventListener('wheel', function(e) {
        if (isScrolling) return;

        isScrolling = true;
        e.preventDefault();

        if (notes.length > 1) {
            currentNoteIndex = (currentNoteIndex + (e.deltaY > 0 ? 1 : -1) + notes.length) % notes.length;
            showNoteView(); // Добавлено: переключаем в режим просмотра при прокрутке
            renderNotes();
        }

        setTimeout(() => { isScrolling = false; }, 100);
    });

    // Прокрутка содержимого заметки колесиком
    contentContainer.addEventListener('wheel', function(e) {
        this.scrollTop += e.deltaY;
        e.preventDefault();
    });

    // Прокрутка всей панели
    notesPanel.addEventListener('wheel', function(e) {
        if (e.target === notesPanel) {
            this.scrollTop += e.deltaY;
            e.preventDefault();
        }
    });

    // Инициализация
    notesPanel.style.display = 'none'
    editBtn.style.display = 'none';
    if (notes.length > 0) {
        renderNotes();
    }

    console.log('Мод "Заметки" с полной HTML-поддержкой успешно загружен!');
})();