WSJ Dark Mode

Elegant dark mode for Wall Street Journal when system dark mode is enabled

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

You will need to install an extension such as Tampermonkey to install this script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name         WSJ Dark Mode
// @namespace    https://www.wsj.com
// @version      0.0.4
// @description  Elegant dark mode for Wall Street Journal when system dark mode is enabled
// @author       hxueh
// @match        *://*.wsj.com/*
// @grant        GM_addStyle
// @run-at       document-start
// @icon         https://s.wsj.net/img/meta/wsj_favicon.svg
// @license      MIT
// ==/UserScript==
 
(function () {
  'use strict';
 
  // Color palette - elegant dark theme
  const colors = {
    bg: '#000000',
    bgElevated: '#000000',
    bgCard: '#000000',
    bgHover: '#0a0a0a',
    text: '#e8e6e3',
    textMuted: '#a8a5a0',
    textSubtle: '#888888',
    accent: '#d4a853',
    accentHover: '#e6bc6a',
    link: '#7eb8da',
    linkHover: '#a3d0eb',
    border: '#1a1a1a',
    borderSubtle: '#111111',
  };
 
  const darkModeCSS = `
    /*========================================
      WSJ Dark Mode - Base Styles
    ========================================*/
 
    :root {
      color-scheme: dark;
    }
 
    /* Global resets */
    html, body {
      background-color: ${colors.bg} !important;
      color: ${colors.text} !important;
    }
 
    /* Main content areas */
    body,
    main,
    article,
    section,
    div,
    header,
    footer,
    nav,
    aside {
      background-color: transparent !important;
    }
 
    /* Override specific WSJ containers */
    .WSJTheme--page-container--,
    .WSJTheme--pageWrapper--,
    [class*="PageWrapper"],
    [class*="page-container"],
    [class*="MainContent"],
    [class*="ArticleBody"],
    [class*="wrapper"],
    #root,
    #__next,
    .container {
      background-color: ${colors.bg} !important;
    }
 
    /*========================================
      Typography
    ========================================*/
 
    /* Headings */
    h1, h2, h3, h4, h5, h6,
    [class*="Headline"],
    [class*="headline"],
    [class*="Title"],
    [class*="title"] {
      color: ${colors.text} !important;
    }
 
    /* Body text */
    p, span, li, td, th, label,
    [class*="Paragraph"],
    [class*="paragraph"],
    [class*="Body"],
    [class*="Summary"],
    [class*="summary"],
    [class*="Description"],
    [class*="description"] {
      color: ${colors.text} !important;
    }
 
    /* Muted text */
    [class*="Byline"],
    [class*="byline"],
    [class*="Timestamp"],
    [class*="timestamp"],
    [class*="Meta"],
    [class*="meta"],
    time,
    figcaption,
    .caption,
    [class*="Caption"] {
      color: ${colors.textMuted} !important;
    }
 
    /* Subtle text */
    [class*="Label"],
    [class*="Tag"],
    small {
      color: ${colors.textSubtle} !important;
    }
 
    /*========================================
      Links
    ========================================*/
 
    a {
      color: ${colors.link} !important;
      transition: color 0.15s ease !important;
    }
 
    a:hover {
      color: ${colors.linkHover} !important;
    }
 
    /* Article headlines as links */
    a h1, a h2, a h3, a h4,
    h1 a, h2 a, h3 a, h4 a,
    [class*="Headline"] a,
    a[class*="Headline"] {
      color: ${colors.text} !important;
    }
 
    a:hover h1, a:hover h2, a:hover h3, a:hover h4,
    h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover {
      color: ${colors.accent} !important;
    }
 
    /*========================================
      Cards & Containers
    ========================================*/
 
    [class*="Card"],
    [class*="card"],
    [class*="Module"],
    [class*="module"],
    [class*="Story"],
    [class*="story"],
    [class*="Item"],
    [class*="Promo"],
    [class*="promo"] {
      background-color: ${colors.bgCard} !important;
      border-color: ${colors.border} !important;
      border-radius: 8px !important;
    }
 
    /* Elevated surfaces */
    [class*="Modal"],
    [class*="modal"],
    [class*="Popup"],
    [class*="popup"],
    [class*="Tooltip"],
    [class*="tooltip"] {
      background-color: #000000 !important;
      border-color: ${colors.border} !important;
      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.8) !important;
    }
 
    /* Menu-specific styles - high specificity */
    [class*="Menu"],
    [class*="menu"],
    div[class*="Menu"],
    div[class*="menu"],
    ul[class*="Menu"],
    ul[class*="menu"] {
      background-color: #000000 !important;
      border: 1px solid ${colors.border} !important;
    }
 
    /* Menu items */
    [class*="Menu"] > *,
    [class*="menu"] > *,
    [class*="Menu"] li,
    [class*="menu"] li,
    [class*="Menu"] a,
    [class*="menu"] a {
      background-color: #000000 !important;
    }
 
    [class*="Menu"] a:hover,
    [class*="menu"] a:hover,
    [class*="Menu"] li:hover,
    [class*="menu"] li:hover {
      background-color: ${colors.bgHover} !important;
    }
 
    /*========================================
      Navigation & Header
    ========================================*/
 
    header,
    nav,
    [class*="Header"],
    [class*="header"],
    [class*="Nav"],
    [class*="nav"],
    [class*="Masthead"],
    [class*="masthead"],
    [class*="TopBar"],
    [class*="topbar"] {
      background-color: ${colors.bgElevated} !important;
      border-bottom-color: ${colors.border} !important;
    }
 
    /* Navigation dropdown menus */
    [class*="Dropdown"],
    [class*="dropdown"],
    [class*="Flyout"],
    [class*="flyout"],
    [class*="Submenu"],
    [class*="submenu"],
    [class*="SubNav"],
    [class*="subnav"],
    [class*="MenuPanel"],
    [class*="menu-panel"],
    [class*="NavPanel"],
    [class*="nav-panel"],
    [class*="DropdownMenu"],
    [class*="dropdown-menu"],
    nav ul ul,
    nav > div > div,
    [role="menu"],
    [aria-expanded="true"] + div,
    [aria-expanded="true"] + ul,
    header [class*="expanded"],
    header [class*="open"],
    header [class*="active"] > div,
    header [class*="hover"] > div {
      background-color: #000000 !important;
      border: 1px solid ${colors.border} !important;
      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.9) !important;
    }
 
    /* Nested navigation links in dropdowns */
    nav a,
    [class*="Nav"] a,
    [class*="nav"] a,
    header a {
      background-color: transparent !important;
    }
 
    nav li,
    [class*="Nav"] li,
    header li {
      background-color: transparent !important;
    }
 
    /* Dropdown container backgrounds */
    nav [class*="container"],
    nav [class*="wrapper"],
    nav [class*="content"],
    header [class*="container"],
    header [class*="wrapper"] {
      background-color: #000000 !important;
    }
 
    /* WSJ Logo - invert images for dark mode */
    [class*="Logo"] img,
    [class*="logo"] img,
    .wsj-logo img {
      filter: brightness(0) invert(1) !important;
    }

    /* WSJ Logo - SVG logos */
    [class*="Logo"] svg,
    [class*="logo"] svg,
    [class*="WSJLogo"] svg,
    [class*="wsj-logo"] svg,
    [class*="Masthead"] svg,
    [class*="masthead"] svg,
    header svg[class*="logo" i],
    nav svg[class*="logo" i] {
      filter: brightness(0) invert(1) !important;
    }

    /* WSJ specific logo classes */
    [class*="WSJLogo"],
    [class*="wsj-logo"],
    [class*="wsjLogo"],
    [class*="WSJTheme--logo"],
    [class*="SiteLogo"],
    [class*="site-logo"],
    [class*="BrandLogo"],
    [class*="brand-logo"] {
      filter: brightness(0) invert(1) !important;
    }

    /* Header logo links - target the logo container */
    header [class*="Logo"],
    header [class*="logo"],
    nav [class*="Logo"],
    nav [class*="logo"],
    [class*="Masthead"] [class*="Logo"],
    [class*="masthead"] [class*="logo"] {
      filter: brightness(0) invert(1) !important;
    }

    /* Ensure child elements of logo also get inverted */
    [class*="Logo"] *,
    [class*="logo"][class*="wsj" i] *,
    [class*="WSJLogo"] *,
    [class*="wsj-logo"] * {
      filter: inherit !important;
    }

    /* Reset filter for non-logo header elements */
    header a:not([class*="logo" i]):not([class*="Logo"]),
    nav a:not([class*="logo" i]):not([class*="Logo"]) {
      filter: none !important;
    }
 
    /*========================================
      Footer
    ========================================*/
 
    footer,
    [class*="Footer"],
    [class*="footer"] {
      background-color: ${colors.bgElevated} !important;
      border-top-color: ${colors.border} !important;
    }
 
    /*========================================
      Sidebar & Secondary Content
    ========================================*/
 
    aside,
    [class*="Sidebar"],
    [class*="sidebar"],
    [class*="Rail"],
    [class*="rail"],
    [class*="Secondary"],
    [class*="secondary"] {
      background-color: ${colors.bg} !important;
    }
 
    /*========================================
      Forms & Inputs
    ========================================*/
 
    input,
    textarea,
    select {
      background-color: ${colors.bgCard} !important;
      color: ${colors.text} !important;
      border-color: ${colors.border} !important;
      border-radius: 6px !important;
    }
 
    input:focus,
    textarea:focus,
    select:focus {
      border-color: ${colors.accent} !important;
      outline: none !important;
      box-shadow: 0 0 0 2px rgba(212, 168, 83, 0.2) !important;
    }
 
    input::placeholder,
    textarea::placeholder {
      color: ${colors.textSubtle} !important;
    }
 
    /*========================================
      Buttons
    ========================================*/
 
    button,
    [class*="Button"],
    [class*="button"],
    [class*="Btn"],
    [class*="btn"],
    [role="button"] {
      background-color: ${colors.bgCard} !important;
      color: ${colors.text} !important;
      border-color: ${colors.border} !important;
      transition: all 0.15s ease !important;
    }
 
    button:hover,
    [class*="Button"]:hover,
    [class*="button"]:hover,
    [class*="Btn"]:hover,
    [class*="btn"]:hover,
    [role="button"]:hover {
      background-color: ${colors.bgHover} !important;
      border-color: ${colors.accent} !important;
    }
 
    /* Primary buttons */
    [class*="Primary"],
    [class*="primary"],
    button[class*="subscribe" i],
    button[class*="Subscribe" i] {
      background-color: ${colors.accent} !important;
      color: ${colors.bg} !important;
      border-color: ${colors.accent} !important;
    }
 
    [class*="Primary"]:hover,
    [class*="primary"]:hover {
      background-color: ${colors.accentHover} !important;
      border-color: ${colors.accentHover} !important;
    }
 
    /*========================================
      Tables
    ========================================*/
 
    table {
      background-color: ${colors.bg} !important;
      border-color: ${colors.border} !important;
    }
 
    th {
      background-color: ${colors.bgElevated} !important;
      color: ${colors.text} !important;
      border-color: ${colors.border} !important;
    }
 
    td {
      background-color: ${colors.bg} !important;
      color: ${colors.text} !important;
      border-color: ${colors.borderSubtle} !important;
    }
 
    tr:hover td {
      background-color: ${colors.bgHover} !important;
    }
 
    /*========================================
      Borders & Dividers
    ========================================*/
 
    hr,
    [class*="Divider"],
    [class*="divider"],
    [class*="Border"],
    [class*="border"],
    [class*="Separator"],
    [class*="separator"] {
      border-color: ${colors.border} !important;
      background-color: ${colors.border} !important;
    }
 
    /*========================================
      Images & Media
    ========================================*/
 
    img {
      opacity: 0.92;
      transition: opacity 0.2s ease;
    }
 
    img:hover {
      opacity: 1;
    }
 
    figure {
      background-color: transparent !important;
    }
 
    /* Video containers */
    [class*="Video"],
    [class*="video"],
    [class*="Player"],
    [class*="player"] {
      background-color: ${colors.bgCard} !important;
    }
 
    /*========================================
      Article Specific
    ========================================*/
 
    /* Article body */
    article,
    [class*="Article"],
    [class*="article"] {
      background-color: ${colors.bg} !important;
    }
 
    /* Blockquotes */
    blockquote,
    [class*="Quote"],
    [class*="quote"],
    [class*="Pullquote"],
    [class*="pullquote"] {
      background-color: ${colors.bgCard} !important;
      border-left-color: ${colors.accent} !important;
      color: ${colors.text} !important;
      border-radius: 0 8px 8px 0 !important;
      padding: 1rem 1.5rem !important;
    }
 
    /* Code blocks */
    pre, code {
      background-color: ${colors.bgCard} !important;
      color: ${colors.text} !important;
      border-color: ${colors.border} !important;
    }
 
    /*========================================
      Ads & Promotions (dim them)
    ========================================*/
 
    [class*="Ad"],
    [class*="ad-"],
    [id*="ad-"],
    [class*="Advertisement"],
    [class*="advertisement"],
    [class*="Promo"],
    [data-ad],
    iframe[src*="ad"] {
      opacity: 0.7 !important;
      filter: brightness(0.85) !important;
    }
 
    /*========================================
      Scrollbar
    ========================================*/
 
    ::-webkit-scrollbar {
      width: 10px;
      height: 10px;
    }
 
    ::-webkit-scrollbar-track {
      background: ${colors.bg};
    }
 
    ::-webkit-scrollbar-thumb {
      background: ${colors.border};
      border-radius: 5px;
    }
 
    ::-webkit-scrollbar-thumb:hover {
      background: ${colors.textSubtle};
    }
 
    /* Firefox scrollbar */
    * {
      scrollbar-width: thin;
      scrollbar-color: ${colors.border} ${colors.bg};
    }
 
    /*========================================
      Selection
    ========================================*/
 
    ::selection {
      background-color: ${colors.accent} !important;
      color: ${colors.bg} !important;
    }
 
    ::-moz-selection {
      background-color: ${colors.accent} !important;
      color: ${colors.bg} !important;
    }
 
    /*========================================
      Override inline styles (nuclear option)
    ========================================*/
 
    [style*="background-color: rgb(255"],
    [style*="background-color: #fff"],
    [style*="background-color: white"],
    [style*="background: rgb(255"],
    [style*="background: #fff"],
    [style*="background: white"] {
      background-color: ${colors.bg} !important;
    }
 
    [style*="color: rgb(0"],
    [style*="color: #000"],
    [style*="color: black"] {
      color: ${colors.text} !important;
    }
 
    /*========================================
      WSJ-Specific Overrides
    ========================================*/
 
    /* Market data colors - keep green/red for stocks */
    [class*="positive"],
    [class*="Positive"],
    [class*="gain"],
    [class*="Gain"],
    [class*="up"] {
      color: #4ade80 !important;
    }
 
    [class*="negative"],
    [class*="Negative"],
    [class*="loss"],
    [class*="Loss"],
    [class*="down"] {
      color: #f87171 !important;
    }
 
    /* Paywall/subscription modals */
    [class*="Paywall"],
    [class*="paywall"],
    [class*="Subscribe"],
    [class*="subscribe"] {
      background-color: ${colors.bgElevated} !important;
    }
 
    /* Search results */
    [class*="Search"],
    [class*="search"] {
      background-color: ${colors.bg} !important;
    }
 
    /* Comments section */
    [class*="Comment"],
    [class*="comment"] {
      background-color: ${colors.bgCard} !important;
      border-color: ${colors.border} !important;
    }
 
    /*========================================
      Smooth transitions for dynamic content
    ========================================*/
 
    * {
      transition: background-color 0.1s ease, border-color 0.1s ease;
    }
 
    /* Disable transitions for specific elements */
    a, button, input, img, video {
      transition: none;
    }
 
    a {
      transition: color 0.15s ease !important;
    }
  `;
 
  // Check for dark mode preference
  function isDarkMode() {
    return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
  }
 
  // Apply or remove dark mode styles
  let styleElement = null;
 
  function applyDarkMode() {
    if (!styleElement) {
      styleElement = document.createElement('style');
      styleElement.id = 'wsj-dark-mode-styles';
      styleElement.textContent = darkModeCSS;
    }
    if (!document.getElementById('wsj-dark-mode-styles')) {
      (document.head || document.documentElement).appendChild(styleElement);
    }
  }
 
  function removeDarkMode() {
    const existing = document.getElementById('wsj-dark-mode-styles');
    if (existing) {
      existing.remove();
    }
  }
 
  function updateTheme() {
    if (isDarkMode()) {
      applyDarkMode();
    } else {
      removeDarkMode();
    }
  }
 
  // Initial application
  updateTheme();
 
  // Listen for system theme changes
  if (window.matchMedia) {
    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateTheme);
  }
 
  // Re-apply styles when DOM is ready (for dynamic content)
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', updateTheme);
  }
 
  // Observe for dynamic content changes
  const observer = new MutationObserver((mutations) => {
    if (isDarkMode() && !document.getElementById('wsj-dark-mode-styles')) {
      applyDarkMode();
    }
  });
 
  // Start observing when body is available
  function startObserver() {
    if (document.body) {
      observer.observe(document.body, {
        childList: true,
        subtree: true,
      });
    } else {
      requestAnimationFrame(startObserver);
    }
  }
 
  startObserver();
 
  console.log('🌙 WSJ Dark Mode loaded - respects system preference');
})();