// ==UserScript== // @name Webtoons Dark Mode // @namespace https://github.com/hervad/webtoons-dark-mode // @version 1.2.4 // @description Scoped dark theme for Webtoons (desktop + mobile) — comic panels render untouched. Elevated viewer card, accent-green active nav, WCAG-tuned contrast, optional reader dim. OS preference on first install; persistent toggle (Alt+Shift+T). // @author hervad // @match https://www.webtoons.com/* // @match https://m.webtoons.com/* // @icon https://www.webtoons.com/favicon.ico // @run-at document-start // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @noframes // @license MIT // @homepageURL https://github.com/hervad/webtoons-dark-mode // @supportURL https://github.com/hervad/webtoons-dark-mode/issues // @updateURL https://raw.githubusercontent.com/hervad/webtoons-dark-mode/main/webtoons-dark-mode.user.js // @downloadURL https://raw.githubusercontent.com/hervad/webtoons-dark-mode/main/webtoons-dark-mode.user.js // ==/UserScript== (function () { 'use strict'; const KEY_THEME = 'wt_dark_enabled'; const KEY_DIM = 'wt_reader_dim'; const VERSION = '1.2.4'; // Retry cohort for SPA-navigation work (vignette class sync, viewer cards, // banner cleanup, panel glow). Webtoons renders the new page asynchronously // after pushState; one delay never fits all subapps, so we sample three // times spanning fast → slow bundles. const SPA_RETRY_DELAYS = [200, 800, 2000]; // Log the startup banner as the FIRST runtime statement so that if anything // below throws, the console still proves the script loaded and which // version Tampermonkey is serving. console.info(`[webtoons-dark-mode] v${VERSION} starting`); /* ---------- palette (one place to retheme everything) ---------- */ const palette = ` :root { --wt-bg: #15171a; --wt-bg-elev: #22262b; --wt-bg-elev2: #2c313a; --wt-bg-hover: #30353c; --wt-bg-input: #2a2e35; --wt-border: #4a5360; --wt-border-strong: #5a6472; --wt-text: #e6e6e6; --wt-text-dim: #b5b9c0; --wt-text-mute: #878e99; --wt-text-on-accent: #0a0a0a; --wt-link: #7cb6ff; --wt-accent: #00d564; --wt-accent-soft: #4ade80; --wt-accent-like: #f06868; --wt-shadow: 0 1px 2px rgba(0,0,0,.6); } `; /* ---------- theme: targeted selectors, no global filter ---------- */ const theme = ` html, body { background-color: var(--wt-bg) !important; color: var(--wt-text) !important; scrollbar-color: var(--wt-bg-elev2) var(--wt-bg); } /* Text */ h1, h2, h3, h4, h5, h6, p, dt, dd, label, em, strong, small, .tit, .sub_tit, .subj, .author, .genre, .grade_num, .info, .summary { color: var(--wt-text) !important; } .desc, .date, .count, .from, .ico_view, .ico_grade, .num, .grade_area, .info_area .author, .nick, .meta, .help_txt, .comment_count { color: var(--wt-text-dim) !important; } /* Links */ a, a:visited { color: var(--wt-text) !important; } a:hover { color: var(--wt-link) !important; } /* Exclude button-styled anchors from the global a:hover blue. CTA buttons (e.g. age-verification "Continue", "First episode") use or