Greasy Fork

GoodNote - 网页笔记助手

在任何网页添加笔记功能

目前为 2025-02-07 提交的版本。查看 最新版本

// ==UserScript==
// @name         GoodNote - 网页笔记助手
// @namespace    http://tampermonkey.net/
// @version      0.2.8
// @description  在任何网页添加笔记功能
// @author       kasusa
// @license MIT
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 创建样式
    const style = document.createElement('style');
    style.textContent = `
        .note-icon {
            position: fixed;
            top: 20px;
            right: 20px;
            width: 40px;
            height: 40px;
            background-color: #4CAF50;
            border-radius: 50%;
            cursor: move;
            z-index: 9999;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            transition: all 0.3s ease;
            user-select: none;
            will-change: transform;
            transform: translate3d(0, 0, 0);
            transform: scale(0.8);
            opacity:50%;
        }

        .note-icon:hover {
            transform: scale(1);
            opacity:1;
        }
        .note-icon:active {
            transform: scale(0.9);
            opacity:1;
        }

        .note-icon svg {
            width: 24px;
            height: 24px;
            fill: white;
        }

        .note-container {
            position: fixed;
            background: ;
            backdrop-filter: blur(10px);
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
            z-index: 9998;
            padding: 10px;
            transition: all 0.3s ease;
            opacity: 0;
            transform-origin: center;

        }

        .note-container.active {
            opacity: 1;
            transform: scale(1);
        }

        .note-textarea {
            width: 100%;
            min-height: 250px;
            border: 1px solid #ddd;
            border-radius: 4px;
            padding: 12px;
            font-size: 14px;
            resize: all;
            font-family: Arial, sans-serif;
            line-height: 1.5;
    min-width: 350px;
        }

        .note-textarea:focus {
            outline: none;
            border-color: #4CAF50;
        }
    `;
    document.head.appendChild(style);

    // 创建笔记图标
    const noteIcon = document.createElement('div');
    noteIcon.className = 'note-icon';
    noteIcon.innerHTML = `
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <path d="M14,10H19.5L14,4.5V10M5,3H15L21,9V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3M5,12V14H19V12H5M5,16V18H14V16H5Z"/>
        </svg>
    `;

    // 创建笔记容器
    const noteContainer = document.createElement('div');
    noteContainer.className = 'note-container';

    // 创建文本框
    const textarea = document.createElement('textarea');
    textarea.className = 'note-textarea';
    textarea.placeholder = '在这里输入你的笔记...';

    noteContainer.appendChild(textarea);

    // 添加到页面
    document.body.appendChild(noteIcon);
    document.body.appendChild(noteContainer);

    // 获取当前域名作为存储键
    const storageKey = `goodnote_${window.location.hostname}`;
    const positionKey = `goodnote_position_${window.location.hostname}`;

    // 从localStorage加载笔记
    const savedNote = localStorage.getItem(storageKey);
    if (savedNote) {
        textarea.value = savedNote;
    }

    // 实现拖拽功能
    let isDragging = false;
    let currentX;
    let currentY;
    let initialX;
    let initialY;
    let xOffset = 0;
    let yOffset = 0;

    let rafId = null;

    noteIcon.addEventListener('mousedown', dragStart);
    document.addEventListener('mousemove', drag);
    document.addEventListener('mouseup', dragEnd);

    function dragStart(e) {
        if (e.target === noteIcon || noteIcon.contains(e.target)) {
            isDragging = true;
            const rect = noteIcon.getBoundingClientRect();
            initialX = e.clientX - rect.left;
            initialY = e.clientY - rect.top;

            noteIcon.style.transition = 'none';
        }
    }

    function drag(e) {
        if (isDragging) {
            e.preventDefault();

            if (rafId) {
                cancelAnimationFrame(rafId);
            }

            rafId = requestAnimationFrame(() => {
                const newX = e.clientX - initialX;
                const newY = e.clientY - initialY;

                currentX = Math.min(Math.max(0, newX), window.innerWidth - noteIcon.offsetWidth);
                currentY = Math.min(Math.max(0, newY), window.innerHeight - noteIcon.offsetHeight);

                setTranslate(currentX, currentY);
            });
        }
    }

    function setTranslate(xPos, yPos) {
        noteIcon.style.left = `${xPos}px`;
        noteIcon.style.top = `${yPos}px`;
        noteIcon.style.right = 'auto';
        noteIcon.style.bottom = 'auto';
    }

    function dragEnd(e) {
        if (isDragging) {
            isDragging = false;
            noteIcon.style.transition = 'all 0.1s ease';

            localStorage.setItem(positionKey, JSON.stringify({
                top: noteIcon.style.top,
                left: noteIcon.style.left
            }));

            if (rafId) {
                cancelAnimationFrame(rafId);
            }
        }
    }

    // 加载保存的位置
    const savedPosition = localStorage.getItem(positionKey);
    if (savedPosition) {
        try {
            const { top, left } = JSON.parse(savedPosition);
            setTranslate(parseInt(left), parseInt(top));
        } catch (e) {
            console.error('Failed to load saved position');
        }
    }

    // 修改笔记显示逻辑
    noteContainer.style.position = 'fixed';
    let isVisible = false;

    noteIcon.addEventListener('click', (e) => {
        if (!isDragging) {
            isVisible = !isVisible;

            if (isVisible) {
                const iconRect = noteIcon.getBoundingClientRect();
                const windowWidth = window.innerWidth;
                const windowHeight = window.innerHeight;
                const noteHeight = 300; // 预估笔记窗口高度

                let left = iconRect.right - 10;
                let top = iconRect.top;

                // 检查水平方向是否超出
                if (left + 400 > windowWidth) {
                    left = iconRect.left - 360;
                }

                // 检查垂直方向是否超出
                if (top + noteHeight > windowHeight) {
                    top = windowHeight - noteHeight - 10; // 留出10px边距
                }

                noteContainer.style.top = `${top}px`;
                noteContainer.style.left = `${left}px`;
                noteContainer.style.display = 'block';

                requestAnimationFrame(() => {
                    noteContainer.classList.add('active');
                });
            } else {
                noteContainer.classList.remove('active');
                setTimeout(() => {
                    noteContainer.style.display = 'none';
                }, 300);
            }
        }
    });

    // 修改点击其他地方关闭笔记的逻辑
    document.addEventListener('click', (e) => {
        if (!noteContainer.contains(e.target) && !noteIcon.contains(e.target) && isVisible) {
            isVisible = false;
            noteContainer.classList.remove('active');
            setTimeout(() => {
                noteContainer.style.display = 'none';
            }, 300);
        }
    });

    // 自动保存功能
    let saveTimeout;
    textarea.addEventListener('input', () => {
        clearTimeout(saveTimeout);
        saveTimeout = setTimeout(() => {
            localStorage.setItem(storageKey, textarea.value);
        }, 500); // 延迟500ms保存,避免频繁保存
    });
})();