您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Makes blog articles responsive on widescreen monitors by utilizing empty sidebar space on Substack, Medium, Ghost, WordPress and other platforms
当前为
// ==UserScript== // @name Blog Widescreen Responsive // @namespace http://greasyfork.icu/users/yourusername // @version 2.4.0 // @description Makes blog articles responsive on widescreen monitors by utilizing empty sidebar space on Substack, Medium, Ghost, WordPress and other platforms // @author YourName // @match https://*.substack.com/* // @match https://*thedailybrief.zerodha.com/* // @match https://substack.com/* // @match https://*.medium.com/* // @match https://medium.com/* // @match https://*.ghost.io/* // @match https://*.ghost.org/* // @match https://*.wordpress.com/* // @match https://*.wordpress.org/* // @match https://*.blogspot.com/* // @match https://*.blogger.com/* // @match https://*.dev.to/* // @match https://dev.to/* // @match https://*.hashnode.dev/* // @match https://*.notion.site/* // @match https://*.beehiiv.com/* // @match https://*.convertkit.com/* // @match https://*.mailchimp.com/* // @match https://*.github.io/* // @match https://*.netlify.app/* // @match https://*.vercel.app/* // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @supportURL http://greasyfork.icu/scripts/yourscriptid/feedback // @license MIT // ==/UserScript== (function() { 'use strict'; // Configuration const CONFIG = { maxWidth: GM_getValue('maxWidth', '1400px'), padding: GM_getValue('padding', '2rem'), enabled: GM_getValue('enabled', true), preserveReadability: GM_getValue('preserveReadability', true), animationDuration: '0.3s' }; // Platform-specific selectors using modern CSS techniques const PLATFORM_SELECTORS = { // Substack selectors substack: [ '.single-post', '.post-content', '.reader2-post-content', '.post-header', '.frontend-pencraft-Box-module__Box--4o0Ow', 'article[data-testid="post-content"]', '.post', 'main article' ], // Medium selectors medium: [ 'article', '.postArticle-content', '.meteredContent', 'main article', '[data-testid="storyBody"]', '.ab.cd.ce.cf.cg' ], // Ghost selectors ghost: [ '.post-content', '.post-full-content', 'article.post', '.gh-content', '.gh-article', 'main article' ], // WordPress selectors wordpress: [ '.post-content', '.entry-content', 'article.post', '.single-post-container', 'main article', '.wp-block-post-content' ], // Dev.to selectors devto: [ '#article-wrapper', '.crayons-article', 'article[data-article-path]', 'main .crayons-article__main' ], // Hashnode selectors hashnode: [ '.prose', 'article', '.post-content-wrapper' ], // Generic blog selectors generic: [ 'article', '.post', '.post-content', '.entry-content', '.content', 'main article', '[role="main"] article' ] }; // Detect platform function detectPlatform() { const hostname = window.location.hostname.toLowerCase(); if (hostname.includes('substack')) return 'substack'; if (hostname.includes('medium')) return 'medium'; if (hostname.includes('ghost')) return 'ghost'; if (hostname.includes('wordpress') || hostname.includes('wp.')) return 'wordpress'; if (hostname.includes('dev.to')) return 'devto'; if (hostname.includes('hashnode')) return 'hashnode'; return 'generic'; } // Modern CSS styles using 2024/2025 features function createStyles() { return ` /* Blog Widescreen Responsive - Enhanced with modern CSS */ /* CSS Custom Properties for dynamic theming */ :root { --bwr-max-width: ${CONFIG.maxWidth}; --bwr-padding: ${CONFIG.padding}; --bwr-transition: all ${CONFIG.animationDuration} ease-in-out; --bwr-reading-measure: ${CONFIG.preserveReadability ? '75ch' : 'none'}; } /* Modern container query support */ @container (min-width: 1200px) { .bwr-enhanced { container-type: inline-size; } } /* Enhanced selectors using :is() and :where() for better performance */ ${PLATFORM_SELECTORS[detectPlatform()].concat(PLATFORM_SELECTORS.generic) .map(selector => `${selector}:is(.bwr-enhanced)`) .join(',\n ')} { max-width: var(--bwr-max-width) !important; width: 100% !important; margin-left: auto !important; margin-right: auto !important; padding-left: var(--bwr-padding) !important; padding-right: var(--bwr-padding) !important; transition: var(--bwr-transition) !important; box-sizing: border-box !important; } /* Typography enhancement for readability */ .bwr-enhanced :where(p, li, blockquote, .prose) { max-width: var(--bwr-reading-measure); ${CONFIG.preserveReadability ? 'margin-left: auto; margin-right: auto;' : ''} } /* Responsive images and media */ .bwr-enhanced :where(img, video, iframe, embed, object) { max-width: 100% !important; height: auto !important; display: block !important; margin-left: auto !important; margin-right: auto !important; } /* Code blocks responsive handling */ .bwr-enhanced :where(pre, code) { max-width: 100% !important; overflow-x: auto !important; white-space: pre-wrap !important; word-wrap: break-word !important; } /* Platform-specific enhancements using CSS nesting */ .bwr-enhanced { /* Substack specific */ &:has(.frontend-pencraft-Box-module__Box--4o0Ow) { .frontend-pencraft-Box-module__Box--4o0Ow { max-width: none !important; } } /* Medium specific */ &:has(.meteredContent) { .meteredContent { max-width: none !important; } } /* WordPress specific */ &:has(.wp-block-post-content) { .wp-block-post-content { max-width: none !important; } } } /* Responsive breakpoints using modern syntax */ @media (max-width: 768px) { .bwr-enhanced { padding-left: 1rem !important; padding-right: 1rem !important; } } @media (min-width: 1600px) { .bwr-enhanced { max-width: 1600px !important; } } @media (min-width: 1920px) { .bwr-enhanced { max-width: 1800px !important; } } /* Dark mode support using color-scheme */ @media (prefers-color-scheme: dark) { .bwr-enhanced { /* Inherit platform's dark mode colors */ color-scheme: dark; } } /* Reduced motion support */ @media (prefers-reduced-motion: reduce) { .bwr-enhanced { transition: none !important; } } /* Status indicator */ .bwr-status { position: fixed; top: 10px; right: 10px; background: #4CAF50; color: white; padding: 8px 12px; border-radius: 6px; font-size: 12px; font-family: system-ui, -apple-system, sans-serif; z-index: 10000; opacity: 0; transform: translateX(100%); transition: all 0.3s ease; cursor: pointer; user-select: none; } .bwr-status.show { opacity: 1; transform: translateX(0); } .bwr-status.disabled { background: #f44336; } `; } // Enhanced element detection using modern selectors function findContentElements() { const platform = detectPlatform(); const selectors = PLATFORM_SELECTORS[platform].concat(PLATFORM_SELECTORS.generic); for (const selector of selectors) { const elements = document.querySelectorAll(selector); if (elements.length > 0) { return Array.from(elements).filter(el => { // Use getBoundingClientRect for better detection const rect = el.getBoundingClientRect(); return rect.width > 100 && rect.height > 100; }); } } return []; } // Apply enhancements to elements function applyEnhancements() { if (!CONFIG.enabled) return; const elements = findContentElements(); elements.forEach(element => { if (!element.classList.contains('bwr-enhanced')) { element.classList.add('bwr-enhanced'); // Add container query support for modern browsers if (CSS.supports('container-type: inline-size')) { element.style.containerType = 'inline-size'; } } }); showStatus(`Enhanced ${elements.length} elements`); } // Status notification function showStatus(message) { let status = document.querySelector('.bwr-status'); if (!status) { status = document.createElement('div'); status.className = 'bwr-status'; status.addEventListener('click', toggleScript); document.body.appendChild(status); } status.textContent = CONFIG.enabled ? `✓ BWR: ${message}` : '✗ BWR: Disabled'; status.classList.toggle('disabled', !CONFIG.enabled); status.classList.add('show'); setTimeout(() => { status.classList.remove('show'); }, 3000); } // Toggle script functionality function toggleScript() { CONFIG.enabled = !CONFIG.enabled; GM_setValue('enabled', CONFIG.enabled); if (CONFIG.enabled) { applyEnhancements(); } else { document.querySelectorAll('.bwr-enhanced').forEach(el => { el.classList.remove('bwr-enhanced'); }); } showStatus(CONFIG.enabled ? 'Enabled' : 'Disabled'); } // Settings management function openSettings() { const newMaxWidth = prompt('Enter max width (e.g., 1400px):', CONFIG.maxWidth); if (newMaxWidth) { CONFIG.maxWidth = newMaxWidth; GM_setValue('maxWidth', newMaxWidth); } const newPadding = prompt('Enter padding (e.g., 2rem):', CONFIG.padding); if (newPadding) { CONFIG.padding = newPadding; GM_setValue('padding', newPadding); } const preserveReadability = confirm('Preserve reading line length for better readability?'); CONFIG.preserveReadability = preserveReadability; GM_setValue('preserveReadability', preserveReadability); // Reapply styles with new settings initializeScript(); } // Main initialization function initializeScript() { // Inject CSS GM_addStyle(createStyles()); // Apply enhancements immediately applyEnhancements(); // Use modern ResizeObserver for better performance if (window.ResizeObserver) { const resizeObserver = new ResizeObserver(() => { applyEnhancements(); }); resizeObserver.observe(document.body); } // Fallback to MutationObserver for content changes const mutationObserver = new MutationObserver((mutations) => { let shouldReapply = false; mutations.forEach(mutation => { if (mutation.addedNodes.length > 0) { shouldReapply = true; } }); if (shouldReapply) { setTimeout(applyEnhancements, 100); } }); mutationObserver.observe(document.body, { childList: true, subtree: true }); } // Register menu commands GM_registerMenuCommand('Toggle Blog Widescreen', toggleScript); GM_registerMenuCommand('BWR Settings', openSettings); // Wait for DOM and initialize if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initializeScript); } else { initializeScript(); } // Handle SPA navigation let lastUrl = location.href; new MutationObserver(() => { const url = location.href; if (url !== lastUrl) { lastUrl = url; setTimeout(applyEnhancements, 500); } }).observe(document, { subtree: true, childList: true }); })();