您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Colorizes items based on their source feed
// ==UserScript== // @name Folo Colorful Listview // @namespace http://folo.colorful.list.view // @description Colorizes items based on their source feed // @author ObenK // @license MIT // @match https://app.follow.is/* // @match https://follow.is/* // @match https://*.follow.is/* // @version 1.0.0 // @grant none // @run-at document-start // ==/UserScript== (function() { 'use strict'; const colors = {}; const processedEntries = new Set(); // Function to add CSS styles const addStyle = (styleText) => { const style = document.createElement('style'); style.appendChild(document.createTextNode(styleText)); document.head.appendChild(style); }; // Clean title for consistent coloring const cleanTitle = (title) => { return title?.replace?.(/[^\p{L}\s]/gu, '') || title; }; // Compute color based on source title - Morandi colors (muted, desaturated) const computeColor = (title) => { if (colors[title]) return colors[title]; let h = 0; const clean = cleanTitle(title); for (let i = 0; i < clean.length; i++) { let s = i !== 0 ? clean.length % i : 1; let r = s !== 0 ? clean.charCodeAt(i) % s : clean.charCodeAt(i); h += r; } // Morandi color palette - muted, soft tones const morandiColors = [ { h: 210, s: 15, l: 85 }, // Soft blue-gray { h: 25, s: 20, l: 88 }, // Warm beige { h: 160, s: 18, l: 82 }, // Sage green { h: 45, s: 22, l: 86 }, // Warm gray { h: 280, s: 16, l: 84 }, // Soft lavender { h: 200, s: 14, l: 87 }, // Powder blue { h: 350, s: 18, l: 85 }, // Dusty rose { h: 170, s: 15, l: 83 }, // Mint gray { h: 30, s: 16, l: 89 }, // Cream { h: 220, s: 12, l: 86 }, // Steel blue { h: 260, s: 14, l: 84 }, // Mauve { h: 15, s: 19, l: 87 } // Warm taupe ]; const index = h % morandiColors.length; const color = morandiColors[index]; colors[title] = color; return color; }; // Add base styles addStyle(` .folo-colored-item { transition: background-color 0.2s ease !important; } .folo-colored-item:hover { background-color: rgba(0, 0, 0, 0.05) !important; } .dark .folo-colored-item:hover { background-color: rgba(255, 255, 255, 0.05) !important; } `); // Function to apply color to an entry const colorizeEntry = (entry) => { if (!entry || processedEntries.has(entry)) return; // Find the feed title element - look for the actual feed name const feedTitleElements = entry.querySelectorAll('.truncate, [class*="truncate"], .text-xs.font-bold'); let feedTitle = null; for (const el of feedTitleElements) { const text = el.textContent?.trim(); if (text && !text.includes('·') && text.length > 0) { feedTitle = text; break; } } if (!feedTitle) return; const color = computeColor(feedTitle); // Apply color directly to the element entry.style.backgroundColor = `hsl(${color.h}, ${color.s}%, ${color.l}%)`; entry.style.borderRadius = '8px'; entry.style.margin = '2px 0'; entry.style.padding = '8px'; // Store the color info entry.setAttribute('data-folo-source', feedTitle); entry.setAttribute('data-folo-color', `hsl(${color.h}, ${color.s}%, ${color.l}%)`); processedEntries.add(entry); }; // Function to find and colorize all entries const colorizeAllEntries = () => { // Use the same selector as the working merger script const entries = document.querySelectorAll('[class*="group"][class*="relative"][class*="flex"]'); entries.forEach(entry => { if (!processedEntries.has(entry)) { colorizeEntry(entry); } }); }; // Removed unused observer code function waitForContent() { let attempts = 0; const maxAttempts = 20; const checkInterval = setInterval(() => { attempts++; const hasEntries = document.querySelectorAll('[class*="group"]').length > 5; if (hasEntries || attempts > maxAttempts) { clearInterval(checkInterval); colorizeAllEntries(); // 设置观察器 const observer = new MutationObserver(() => { setTimeout(colorizeAllEntries, 500); }); observer.observe(document.body, { childList: true, subtree: true }); } }, 500); } // 启动 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', waitForContent); } else { waitForContent(); } // 处理SPA路由变化 let lastUrl = location.href; setInterval(() => { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(waitForContent, 1000); } }, 1000); // Expose for debugging window.foloColorful = { colors, processedEntries, colorizeAllEntries, recompute: () => { processedEntries.clear(); colorizeAllEntries(); } }; })();