您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add and save notes for different website paths
您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
- // ==UserScript==
- // @name Path Notes
- // @namespace Violentmonkey Scripts
- // @version 2.0
- // @description Add and save notes for different website paths
- // @author maanimis
- // @match *://*/*
- // @grant GM_registerMenuCommand
- // @run-at document-end
- // @license MIT
- // ==/UserScript==
- (function() {
- 'use strict';
- // Configuration
- const CONFIG = {
- notesPanelClass: 'path-notes-container',
- overlayClass: 'path-notes-overlay',
- textareaClass: 'path-notes-textarea',
- toggleBtnClass: 'path-notes-toggle',
- storageKey: 'pathNotes',
- animationDuration: 300, // ms
- debounceInterval: 500, // ms for autosave debounce
- };
- // DOM Elements (initialized later)
- let elements = {
- container: null,
- overlay: null,
- textarea: null,
- toggleBtn: null
- };
- // State management
- const state = {
- isVisible: false,
- currentPath: window.location.pathname + window.location.search,
- notes: {},
- saveTimeout: null
- };
- // Styles
- const styles = `
- .${CONFIG.overlayClass} {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.5);
- backdrop-filter: blur(3px);
- z-index: 9999;
- opacity: 0;
- visibility: hidden;
- transition: opacity ${CONFIG.animationDuration}ms ease;
- }
- .${CONFIG.notesPanelClass} {
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%) scale(0.95);
- background-color: #ffffff;
- box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
- border-radius: 12px;
- padding: 20px;
- z-index: 10000;
- max-width: 500px;
- width: 90%;
- display: flex;
- flex-direction: column;
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- opacity: 0;
- visibility: hidden;
- transition: opacity ${CONFIG.animationDuration}ms ease,
- transform ${CONFIG.animationDuration}ms ease;
- }
- .${CONFIG.notesPanelClass}.visible {
- opacity: 1;
- visibility: visible;
- transform: translate(-50%, -50%) scale(1);
- }
- .${CONFIG.overlayClass}.visible {
- opacity: 1;
- visibility: visible;
- }
- .path-notes-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 15px;
- border-bottom: 1px solid #eee;
- padding-bottom: 10px;
- }
- .path-notes-title {
- margin: 0;
- color: #333;
- font-size: 18px;
- font-weight: 600;
- }
- .path-notes-content {
- display: flex;
- flex-direction: column;
- flex-grow: 1;
- }
- .path-notes-path {
- font-size: 14px;
- color: #666;
- margin-bottom: 10px;
- word-break: break-all;
- }
- .${CONFIG.textareaClass} {
- width: 100%;
- min-height: 180px;
- padding: 12px;
- border: 1px solid #ddd;
- border-radius: 8px;
- resize: vertical;
- font-family: inherit;
- font-size: 14px;
- line-height: 1.5;
- color: #333;
- transition: border-color 0.2s;
- }
- .${CONFIG.textareaClass}:focus {
- outline: none;
- border-color: #4d90fe;
- box-shadow: 0 0 0 2px rgba(77, 144, 254, 0.2);
- }
- .${CONFIG.toggleBtnClass} {
- position: fixed;
- bottom: 20px;
- right: 20px;
- width: 50px;
- height: 50px;
- border-radius: 50%;
- background-color: #4d90fe;
- color: white;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 24px;
- cursor: pointer;
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
- z-index: 9999;
- transition: background-color 0.2s, transform 0.2s;
- }
- .${CONFIG.toggleBtnClass}:hover {
- background-color: #3a7be0;
- transform: scale(1.05);
- }
- @media (max-width: 600px) {
- .${CONFIG.notesPanelClass} {
- width: 85%;
- max-width: none;
- }
- .${CONFIG.textareaClass} {
- min-height: 140px;
- }
- }
- `;
- // Load notes from localStorage
- function loadNotes() {
- try {
- state.notes = JSON.parse(localStorage.getItem(CONFIG.storageKey)) || {};
- } catch (e) {
- state.notes = {};
- }
- return state.notes;
- }
- // Save notes to localStorage
- function saveNotes() {
- localStorage.setItem(CONFIG.storageKey, JSON.stringify(state.notes));
- }
- // Save current note with debounce
- function saveCurrentNote(text) {
- clearTimeout(state.saveTimeout);
- state.saveTimeout = setTimeout(() => {
- state.notes[state.currentPath] = text;
- saveNotes();
- }, CONFIG.debounceInterval);
- }
- // Show/hide the notes panel
- function toggleNotesPanel() {
- state.isVisible = !state.isVisible;
- if (state.isVisible) {
- elements.container.classList.add('visible');
- elements.overlay.classList.add('visible');
- elements.textarea.focus();
- } else {
- elements.container.classList.remove('visible');
- elements.overlay.classList.remove('visible');
- }
- }
- // Create UI elements
- function createUI() {
- // Add styles
- const styleElement = document.createElement('style');
- styleElement.textContent = styles;
- document.head.appendChild(styleElement);
- // Create overlay for background blur
- const overlay = document.createElement('div');
- overlay.className = CONFIG.overlayClass;
- document.body.appendChild(overlay);
- // Create notes container
- const container = document.createElement('div');
- container.className = CONFIG.notesPanelClass;
- // Load stored notes
- loadNotes();
- const currentNote = state.notes[state.currentPath] || '';
- // Create notes UI
- container.innerHTML = `
- <div class="path-notes-header">
- <h3 class="path-notes-title">Path Notes</h3>
- </div>
- <div class="path-notes-content">
- <div class="path-notes-path">Current path: ${state.currentPath}</div>
- <textarea class="${CONFIG.textareaClass}" placeholder="Add your notes for this page...">${currentNote}</textarea>
- </div>
- `;
- document.body.appendChild(container);
- // Create toggle button
- const toggleButton = document.createElement('div');
- toggleButton.className = CONFIG.toggleBtnClass;
- toggleButton.innerHTML = '📝';
- toggleButton.title = 'Toggle Path Notes';
- document.body.appendChild(toggleButton);
- // Store elements references
- elements.container = container;
- elements.overlay = overlay;
- elements.textarea = container.querySelector(`.${CONFIG.textareaClass}`);
- elements.toggleBtn = toggleButton;
- // Setup event listeners
- setupEventListeners();
- }
- // Setup event listeners
- function setupEventListeners() {
- // Toggle button click
- elements.toggleBtn.addEventListener('click', toggleNotesPanel);
- // Clicking overlay closes panel
- elements.overlay.addEventListener('click', () => {
- if (state.isVisible) {
- toggleNotesPanel();
- }
- });
- // Auto-save on typing
- elements.textarea.addEventListener('input', (e) => {
- saveCurrentNote(e.target.value);
- });
- }
- // Register menu command
- function registerMenuCommand() {
- if (typeof GM_registerMenuCommand !== 'undefined') {
- GM_registerMenuCommand('Open Path Notes', toggleNotesPanel);
- }
- }
- // Initialize the userscript
- function initialize() {
- createUI();
- registerMenuCommand();
- }
- // Start when the page is fully loaded
- window.addEventListener('load', initialize);
- })();