Torn Wiki Dark

Dark-gray + cyan skin for *all* pages on wiki.torn.com.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Torn Wiki Dark
// @namespace    https://github.com/skillerious
// @version      2.6
// @description  Dark-gray + cyan skin for *all* pages on wiki.torn.com.
//               • Static sidebar, centred content column
//               • Cyan headings & links, darker logo tile
//               • Cyan scrollbar, zero white leaks
//               • 64 px progress-ring “Back to Top” button, perfectly centred, clickable & smooth-scrolling
//               2025-07-12 build 🔵⬆️🌑
// @author       Robin Doak (Skillerious)
// @match        https://wiki.torn.com/wiki/*
// @match        https://wiki.torn.com/*
// @include      /^https:\/\/wiki\.torn\.com\/.*$/
// @grant        none
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(() => {
  /*───────────────────────────────────────────────────────────────
    1.  GLOBAL CSS THEME
  ───────────────────────────────────────────────────────────────*/
  const css = `
  /* ─── Colour palette & constants ───────────────────────────── */
  :root {
    --bg          : #1b1b1b;
    --surface     : #242424;
    --surface-2   : #2e2e2e;
    --card        : #282828;

    --cyan        : #55c3ff;
    --cyan-light  : #7ad0ff;

    --border      : #3d3d3d;
    --text-main   : #d5d7da;
    --text-muted  : #9ca2a8;

    --radius      : 6px;
    --shadow      : 0 3px 10px rgb(0 0 0 / 0.5);
    --max-read    : 950px;
  }

  /* ─── Base layout & typography ─────────────────────────────── */
  body,
  #content,
  .container,
  .row,
  .content-area-wrapper,
  .mw-parser-output,
  .mw-body {
    background: var(--bg) !important;
    color: var(--text-main) !important;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                 Arial, sans-serif;
  }

  .content-area-wrapper {
    flex: 1 1 auto !important;
    padding: 0 1rem;
  }

  #content {
    max-width: var(--max-read);
    margin: 0 auto;
  }

  h1, h2, h3, h4, h5, h6 {
    color: var(--cyan) !important;
    font-weight: 700;
    line-height: 1.3;
    margin: 1.2em 0 0.6em;
  }

  h1 { font-size: 2.15rem; border: none; }
  h2 { font-size: 1.55rem; border-bottom: 1px solid var(--cyan); padding-bottom: 0.4rem; }
  h3 { font-size: 1.25rem; }
  h4, h5, h6 { font-size: 1.1rem; }

  /* ─── Links ────────────────────────────────────────────────── */
  a {
    color: var(--cyan);
    text-decoration: none;
    transition: color 0.15s;
  }

  a:hover {
    color: var(--cyan-light);
    text-decoration: underline;
  }

  a[target="_blank"]::after {
    content: "↗";
    font-size: 0.75em;
    margin-left: 2px;
    vertical-align: super;
    color: var(--text-muted);
  }

  /* ─── Sidebar & logo tile ─────────────────────────────────── */
  .side-panel-wrapper {
    background: var(--surface);
    border-right: 1px solid var(--border);
  }

  .side-panel-wrapper .card {
    background: var(--surface) !important;
    border: none !important;
  }

  .card.torn-navigation-header {
    background: var(--surface-2) !important;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1.4rem 0 1rem;
  }

  .torn-title-text {
    font-size: 2.35rem;
    font-weight: 900;
    line-height: 1;
    color: var(--cyan) !important;
    letter-spacing: 1px;
  }

  .torn-title-text span {
    font-weight: 300;
    margin-left: 0.25rem;
    color: var(--cyan) !important;
  }

  .torn-title-text::after {
    content: "";
    display: block;
    width: 80%;
    height: 4px;
    background: var(--cyan);
    margin: 0.45rem auto 0;
    border-radius: 2px;
  }

  .torn-back-button {
    margin-top: 0.85rem;
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--text-main);
    display: flex;
    align-items: center;
    gap: 4px;
    text-decoration: none;
  }

  .torn-back-button svg path { fill: #b0b0b0; }
  .torn-back-button:hover { color: var(--cyan); }
  .torn-back-button:hover svg path { fill: var(--cyan); }

  /* Navigation links inside sidebar */
  .torn-navigation-panel nav a.nav-link {
    color: var(--text-muted);
    border-radius: var(--radius);
    margin: 0.13rem 0;
    padding: 0.32rem 0.8rem;
    transition: background 0.15s, color 0.15s;
  }

  .torn-navigation-panel nav a.nav-link:hover,
  .torn-navigation-panel nav a.nav-link.active {
    background: var(--surface-2);
    color: var(--text-main);
  }

  .torn-navigation-panel nav a.nav-link.disabled {
    color: var(--cyan) !important;
    font-weight: 700;
    cursor: default;
  }

  /* ─── Table of Contents ────────────────────────────────────── */
  #toc,
  .toc {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.9rem 1rem 1rem;
    margin-bottom: 1.5rem;
  }

  #toc .toctitle h2 {
    margin: 0 0 0.55rem;
    font-size: 1.2rem;
    color: var(--cyan);
    border: none;
  }

  #toc ul,
  .toc ul { padding-left: 1.25rem; margin: 0; }

  #toc li,
  .toc li { line-height: 1.5; }

  /* ─── Tables ──────────────────────────────────────────────── */
  table, th, td { border-color: var(--border) !important; }

  table {
    background: var(--surface) !important;
    border-collapse: collapse !important;
  }

  th, td {
    background: var(--card) !important;
    color: var(--text-main) !important;
    padding: 6px 8px !important;
  }

  th[style*="background"],
  td[style*="background"] { background: var(--card) !important; }

  tr:nth-child(even) td { background: var(--surface) !important; }

  .mw-collapsible-toggle a { color: var(--cyan); font-weight: 600; }

  /* ─── Info / alert boxes ─────────────────────────────────── */
  .alert,
  .ambox,
  .mbox,
  .infobox,
  .new-infobox {
    background: var(--surface);
    border: 1px solid var(--border) !important;
    color: var(--text-main) !important;
  }

  .alert-warning,
  .alert.alert-warning {
    background: var(--surface-2) !important;
    color: var(--text-main) !important;
    border: 1px solid var(--border) !important;
  }

  .infobox th,
  .new-infobox-heading {
    background: var(--surface-2) !important;
    color: var(--text-main) !important;
  }

  /* ─── Code blocks ────────────────────────────────────────── */
  pre,
  code {
    background: var(--surface-2) !important;
    color: var(--text-main) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--radius);
  }

  pre { padding: 10px; overflow: auto; }

  /* ─── Forms ──────────────────────────────────────────────── */
  input,
  textarea,
  select {
    background: var(--surface-2) !important;
    color: var(--text-main) !important;
    border: 1px solid var(--border) !important;
  }

  input::placeholder,
  textarea::placeholder { color: var(--text-muted); }

  /* ─── Footer & scrollbar ─────────────────────────────────── */
  #footer,
  #footer-info,
  #footer-places {
    background: var(--bg) !important;
    color: var(--text-muted) !important;
  }

  #footer a { color: var(--cyan); }

  ::-webkit-scrollbar { width: 12px; height: 12px; }
  ::-webkit-scrollbar-track { background: var(--bg); }
  ::-webkit-scrollbar-thumb {
    background: var(--cyan);
    border-radius: 6px;
    transition: background 0.2s;
  }
  ::-webkit-scrollbar-thumb:hover { background: var(--cyan-light); }

  html {
    scrollbar-width: thin;
    scrollbar-color: var(--cyan) var(--bg);
  }

  /* ─── Hide Torn’s built-in back-to-top ───────────────────── */
  #torn-back-to-top { display: none !important; }

  /* ─── Back-to-Top FAB animation (no overshoot) ───────────── */
  @keyframes twPop {
    0%   { transform: scale(0.4); opacity: 0;   }
    100% { transform: scale(1);   opacity: 0.95; }
  }

  /* ─── FAB container (64 × 64 px) ─────────────────────────── */
  #tw-b2t {
    position: fixed;
    right: 1.4rem;
    bottom: 1.4rem;
    width: 64px;
    height: 64px;
    border-radius: 50%;
    backdrop-filter: blur(8px);
    background: rgba(85, 195, 255, 0.12);
    box-shadow: var(--shadow);
    cursor: pointer;

    opacity: 0;
    pointer-events: none;
    transform: scale(0.4);
    transition: box-shadow 0.25s;
    z-index: 3000;
  }

  #tw-b2t.show {
    animation: twPop 0.33s ease-out forwards;
    pointer-events: auto;   /* <— makes it clickable */
  }

  #tw-b2t:hover {
    box-shadow: 0 0 14px var(--cyan-light), var(--shadow);
  }

  /* Progress ring */
  #tw-b2t svg.ring {
    position: absolute;
    top: 0;
    left: 0;
    width: 64px;
    height: 64px;
    transform: rotate(-90deg);
  }

  #tw-ring-track {
    stroke: rgba(255, 255, 255, 0.07);
    stroke-width: 8;
    fill: none;
  }

  #tw-ring-progress {
    stroke: var(--cyan);
    stroke-width: 8;
    stroke-linecap: round;
    fill: none;
    transition: stroke-dashoffset 0.1s;
  }

  /* Arrow */
  .tw-arrow {
    position: absolute;
    width: 26px;
    height: 26px;
    fill: var(--cyan);
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    transition: transform 0.25s;
  }

  #tw-b2t:hover .tw-arrow {
    transform: translate(-50%, -55%);
  }
  `;
  document.head.appendChild(document.createElement('style')).textContent = css;

  /*───────────────────────────────────────────────────────────────
    2.  Make external links open in a new tab
  ───────────────────────────────────────────────────────────────*/
  document.querySelectorAll('a[href]').forEach(link => {
    const href = link.getAttribute('href') || '';
    if (href.startsWith('#') || href.toLowerCase().startsWith('javascript')) return;

    /* treat as external if hostname differs */
    if (link.hostname && link.hostname !== location.hostname) {
      link.target = '_blank';
      link.rel = 'noopener';
    }
  });

  /*───────────────────────────────────────────────────────────────
    3.  Build smaller (64 px) Back-to-Top FAB
  ───────────────────────────────────────────────────────────────*/
  const SIZE        = 64;  // px
  const STROKE      = 8;   // px
  const RADIUS      = 28;  //  (28 × 2) + 8 = 64
  const CIRCUMFERENCE = 2 * Math.PI * RADIUS;

  /* container */
  const fab = document.createElement('div');
  fab.id = 'tw-b2t';

  /* inner SVG (ring) + arrow */
  fab.innerHTML = `
    <svg class="ring" viewBox="0 0 ${SIZE} ${SIZE}">
      <circle
        cx="${SIZE / 2}"
        cy="${SIZE / 2}"
        r="${RADIUS}"
        stroke-width="${STROKE}"
        fill="none"
        stroke="rgba(255,255,255,0.07)"
      ></circle>

      <circle
        id="tw-ring-progress"
        cx="${SIZE / 2}"
        cy="${SIZE / 2}"
        r="${RADIUS}"
        stroke-width="${STROKE}"
        fill="none"
        stroke="var(--cyan)"
        stroke-linecap="round"
        stroke-dasharray="${CIRCUMFERENCE}"
        stroke-dashoffset="${CIRCUMFERENCE}"
      ></circle>
    </svg>

    <svg class="tw-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
      <path d="M12 6 6 12l-1.4-1.4L12 3.2l7.4 7.4L18 12z"></path>
    </svg>
  `;
  document.body.appendChild(fab);

  const ring = fab.querySelector('#tw-ring-progress');

  /* smooth scroll behaviour */
  fab.addEventListener('click', () => {
    window.scrollTo({
      top: 0,
      behavior: 'smooth'
    });
  });

  /* update ring offset + FAB visibility on scroll */
  const updateFab = () => {
    const max = document.documentElement.scrollHeight - window.innerHeight;
    const pct = max ? Math.min(window.scrollY / max, 1) : 0;

    ring.style.strokeDashoffset = CIRCUMFERENCE * (1 - pct);
    fab.classList.toggle('show', window.scrollY > 150);
  };

  window.addEventListener('scroll', updateFab, { passive: true });
  updateFab();   // run once on load

  console.info('[Torn Wiki Dark-Gray] v2.6 loaded – FAB clickable & smaller');
})();