Blog Widescreen Responsive

Expands blog articles to use full widescreen space by removing restrictive max-width constraints on Substack, Medium, Ghost, WordPress and other platforms

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Blog Widescreen Responsive
// @namespace    https://greasyfork.org/users/umsibaba
// @version      2.5.0
// @description  Expands blog articles to use full widescreen space by removing restrictive max-width constraints on Substack, Medium, Ghost, WordPress and other platforms
// @author       umsibaba
// @match        https://*.substack.com/*
// @match        https://substack.com/*
// @match        https://*.zerodha.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   https://greasyfork.org/scripts/yourscriptid/feedback
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';
    
    // Configuration
    const CONFIG = {
        maxWidth: GM_getValue('maxWidth', '95%'),
        padding: GM_getValue('padding', '2rem'),
        enabled: GM_getValue('enabled', true),
        preserveReadability: GM_getValue('preserveReadability', false),
        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 - Fixed to expand content, not constrain it */
            
            /* 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'};
            }
            
            /* Remove restrictive max-width constraints from blog platforms */
            ${PLATFORM_SELECTORS[detectPlatform()].concat(PLATFORM_SELECTORS.generic)
                .map(selector => selector)
                .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;
            }
            
            /* Override platform-specific narrow constraints */
            .bwr-enhanced,
            .bwr-enhanced * {
                max-width: none !important;
            }
            
            /* Re-apply our desired max-width only to the main container */
            .bwr-enhanced {
                max-width: var(--bwr-max-width) !important;
                width: 100% !important;
                margin: 0 auto !important;
                padding-left: var(--bwr-padding) !important;
                padding-right: var(--bwr-padding) !important;
            }
            
            /* Typography enhancement - only if preserveReadability is enabled */
            ${CONFIG.preserveReadability ? `
            .bwr-enhanced :where(p, li, blockquote) {
                max-width: var(--bwr-reading-measure) !important;
                margin-left: auto !important;
                margin-right: auto !important;
            }` : ''}
            
            /* Responsive images and media - make them use full available width */
            .bwr-enhanced :where(img, video, iframe, embed, object, figure) {
                max-width: 100% !important;
                width: auto !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 fixes to remove narrow constraints */
            
            /* Substack specific overrides */
            .substack-post-content,
            .single-post,
            .post-content,
            .reader2-post-content,
            .frontend-pencraft-Box-module__Box--4o0Ow {
                max-width: var(--bwr-max-width) !important;
                width: 100% !important;
            }
            
            /* Medium specific overrides */
            .postArticle-content,
            .meteredContent,
            [data-testid="storyBody"] {
                max-width: var(--bwr-max-width) !important;
                width: 100% !important;
            }
            
            /* Ghost specific overrides */
            .post-content,
            .post-full-content,
            .gh-content,
            .gh-article {
                max-width: var(--bwr-max-width) !important;
                width: 100% !important;
            }
            
            /* WordPress specific overrides */
            .entry-content,
            .post-content,
            .wp-block-post-content {
                max-width: var(--bwr-max-width) !important;
                width: 100% !important;
            }
            
            /* Responsive breakpoints */
            @media (max-width: 768px) {
                .bwr-enhanced {
                    padding-left: 1rem !important;
                    padding-right: 1rem !important;
                }
            }
            
            @media (min-width: 1600px) {
                .bwr-enhanced {
                    max-width: 95% !important;
                }
            }
            
            @media (min-width: 1920px) {
                .bwr-enhanced {
                    max-width: 90% !important;
                }
            }
            
            /* Dark mode support */
            @media (prefers-color-scheme: dark) {
                .bwr-enhanced {
                    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., 95%, 1400px, or 100%):', CONFIG.maxWidth);
        if (newMaxWidth) {
            CONFIG.maxWidth = newMaxWidth;
            GM_setValue('maxWidth', newMaxWidth);
        }
        
        const newPadding = prompt('Enter side padding (e.g., 2rem, 20px):', CONFIG.padding);
        if (newPadding) {
            CONFIG.padding = newPadding;
            GM_setValue('padding', newPadding);
        }
        
        const preserveReadability = confirm('Limit paragraph width for better readability? (Unchecked = full width)');
        CONFIG.preserveReadability = preserveReadability;
        GM_setValue('preserveReadability', preserveReadability);
        
        // Reapply styles with new settings
        initializeScript();
        showStatus('Settings updated');
    }
    
    // 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 });
    
})();