Nitro Monkey | NT Theme

Custom Nitro Type Theme w/ Font-Size, Height Sliders, and Cursor Customization

Tính đến 20-10-2024. Xem phiên bản mới nhất.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(Tôi đã có Trình quản lý tập lệnh người dùng, hãy cài đặt nó!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Nitro Monkey | NT Theme
// @namespace    https://greasyfork.org/users/1331131-tensorflow-dvorak
// @version      2024-10-20
// @description  Custom Nitro Type Theme w/ Font-Size, Height Sliders, and Cursor Customization
// @author       TensorFlow - Dvorak
// @match        *://*.nitrotype.com/race
// @match        *://*.nitrotype.com/race/*
// @license      MIT
// @grant        none
// ==/UserScript==

(function () {
  const dynamicStyle = document.createElement("style");
  document.head.appendChild(dynamicStyle);

  let currentCursorType = localStorage.getItem("cursorType") || "line";
  let currentCursorSpeed = localStorage.getItem("cursorSpeed") || "medium";

  function updateStyles() {
    dynamicStyle.innerHTML = `
      ${generateCursorStyle(currentCursorType, currentCursorSpeed)}
      ${generateFontSizeStyle(localStorage.getItem("dashFontSize") || "40")}
    `;
  }

  function generateCursorStyle(cursorType, cursorSpeed) {
    let cursorSize = "2px";
    let cursorHeight = "1.2em";
    let animationDuration = "1s";
    let cursorTopOffset = "0.2em";
    let cursorColor = "#00FF7F";
    let cursorTransform = "";

    if (cursorType === "block") {
      cursorSize = "0.7em";
      cursorHeight = "1.1em";
      cursorTopOffset = "0";
      cursorColor = "#0075ff42";
      cursorTransform = "translateY(0.3em)";
    } else if (cursorType === "line") {
      cursorSize = "2px";
      cursorHeight = "1.2em";
      cursorColor = "#0075ff";
    } else {
      cursorSize = "0";
    }

    if (cursorSpeed === "slow") {
      animationDuration = "1.5s";
    } else if (cursorSpeed === "fast") {
      animationDuration = "0.5s";
    }

    return `
      .dash-letter {
        color: #acaaff;
      }
      .dash-letter.is-waiting {
        position: relative;
        color: #acaaff;
        background-color: #1c99f400;
      }
      .dash-letter.is-waiting::after {
        content: '';
        display: inline-block;
        width: ${cursorSize};
        height: ${cursorHeight};
        background-color: ${cursorColor};
        animation: blink ${animationDuration} step-end infinite;
        position: absolute;
        top: ${cursorTopOffset};
        left: 0;
        transform: ${cursorTransform};
      }
      .dash-letter.is-incorrect {
        color: red;
        background: #ffffff00;
        position: relative;
      }
      .dash-letter.is-incorrect::after {
        content: '';
        display: inline-block;
        width: ${cursorSize};
        height: ${cursorHeight};
        background-color: rgba(255, 0, 0, 0.5);
        animation: blink ${animationDuration} step-end infinite;
        position: absolute;
        top: ${cursorTopOffset};
        left: 0;
        transform: ${cursorTransform};
      }
      @keyframes blink {
        50% { opacity: 0; }
      }
    `;
  }

  function generateFontSizeStyle(fontSize) {
    return `
      #root {
        background-color: #060516;
      }
      .dash-copy {
        font-size: ${fontSize}px !important;
      }
      .dash-copyContainer {
        background: linear-gradient(to bottom, rgba(6, 5, 22, 0.9) 65%, rgba(6, 5, 22, 0.87) 70%, #060516 100%);
        border-radius: 5px;
        box-shadow: 0 1px 10px rgba(2, 2, 2, 0.14);
        flex: 1;
        overflow: hidden;
        padding: 15px;
        width: 100%;
        display: flex;
      }
      .dash-side, .dash-actions, .dash-nitros {
        display: none;
      }
      .dash:before {
        height: min-content;
      }
      .structure-footer {
        display: flex;
        padding-top: 2rem;
      }
      .race-results {
        background-color: #060516;
      }
      .raceResults--default {
        background: #060516;
      }
      .raceResults-rewards {
        background: #0c0b18;
      }
      .raceResults-dailyChallenges {
        background: #0c0b18;
      }
      .g-b--7of12 {
        background: #060516;
      }
      .footer-nav {
        background: #0c0b18;
      }
      .nav-list {
        background: #0c0b18;
      }
      .nav {
        background: #0c0b18;
        border-bottom: 1px solid #14141b;
      }
      .btn--primary {
        background: #403dae;
      }
      .btn--primary:hover {
        background: #8a1bdf;
      }
      .btn--secondary {
        background: #5b048a;
      }
      .btn--secondary:hover {
        background: #8d11d0;
      }
      .gridTable--raceResults .gridTable-cell {
        background: #0c0b18;
      }
      .gridTable-cell {
        background: #0c0b18;
      }
      .dashShield-layer {
        display: none;
      }
      .dash-center {
        background: #06051687;
      }
      .nt-stats-right-section {
        background: #060516;
      }
      .nt-stats-daily-challenges {
        background: #060516;
      }
      .nt-stats-body {
        background: #0c0b18;
      }
    `;
  }

  const dashElement = document.querySelector(".dash");
  const container = document.querySelector(".structure-content div");

  if (dashElement) {
    const displayContainer = document.createElement("div");
    displayContainer.style.display = "flex";
    displayContainer.style.gap = "2rem";
    displayContainer.style.marginTop = "10px";
    displayContainer.style.fontSize = "20px";
    displayContainer.style.color = "#6864f6";
    displayContainer.style.background = "rgba(6, 5, 22, 0.8)";
    displayContainer.style.padding = "10px";
    displayContainer.style.borderRadius = "5px";
    displayContainer.style.zIndex = "9999";
    displayContainer.innerHTML = `
      <div>WPM: 0 <span id="targetWPMValue" style="margin-left: 10px;">Target WPM: 100</span></div>
      <div>
        <label for="targetWPM" style="margin-right: 10px;">Target WPM:</label>
        <button id="decreaseWPM" style="margin-right: 5px;">-</button>
        <input type="number" id="targetWPM" min="50" max="200" value="100" readonly>
        <button id="increaseWPM" style="margin-left: 5px;">+</button>
      </div>
      <div>Accuracy: 0%</div>
      <div>
        <label for="cursorType" style="margin-right: 10px;">Cursor Type:</label>
        <button id="cursorTypeButton">${
          currentCursorType.charAt(0).toUpperCase() + currentCursorType.slice(1)
        }</button>
      </div>
      <div>
        <label for="cursorSpeed" style="margin-right: 10px;">Cursor Speed:</label>
        <button id="cursorSpeedButton">${
          currentCursorSpeed.charAt(0).toUpperCase() +
          currentCursorSpeed.slice(1)
        }</button>
      </div>
    `;

    container.appendChild(displayContainer);

    const wpmDisplay = displayContainer.querySelector("div:nth-child(1)");
    const targetWPMValueDisplay =
      displayContainer.querySelector("#targetWPMValue");
    const accuracyDisplay = displayContainer.querySelector("div:nth-child(3)");
    const targetWPMInput = displayContainer.querySelector("#targetWPM");
    const increaseWPMButton = displayContainer.querySelector("#increaseWPM");
    const decreaseWPMButton = displayContainer.querySelector("#decreaseWPM");
    const cursorTypeButton =
      displayContainer.querySelector("#cursorTypeButton");
    const cursorSpeedButton =
      displayContainer.querySelector("#cursorSpeedButton");

    const savedTargetWPM = localStorage.getItem("targetWPM") || "100";
    targetWPMInput.value = savedTargetWPM;
    targetWPMValueDisplay.textContent = `Target WPM: ${savedTargetWPM}`;

    function updateTargetWPM(value) {
      const targetWPM = Math.max(50, Math.min(200, parseInt(value, 10)));
      targetWPMInput.value = targetWPM;
      targetWPMValueDisplay.textContent = `Target WPM: ${targetWPM}`;
      localStorage.setItem("targetWPM", targetWPM);
    }

    increaseWPMButton.addEventListener("click", function () {
      updateTargetWPM(parseInt(targetWPMInput.value, 10) + 5);
    });

    decreaseWPMButton.addEventListener("click", function () {
      updateTargetWPM(parseInt(targetWPMInput.value, 10) - 5);
    });

    const cursorTypes = ["none", "block", "line"];
    const cursorSpeeds = ["slow", "medium", "fast"];

    cursorTypeButton.addEventListener("click", function () {
      let currentIndex = cursorTypes.indexOf(currentCursorType);
      currentCursorType = cursorTypes[(currentIndex + 1) % cursorTypes.length];
      cursorTypeButton.textContent =
        currentCursorType.charAt(0).toUpperCase() + currentCursorType.slice(1);
      localStorage.setItem("cursorType", currentCursorType);
      updateStyles();
    });

    cursorSpeedButton.addEventListener("click", function () {
      let currentIndex = cursorSpeeds.indexOf(currentCursorSpeed);
      currentCursorSpeed =
        cursorSpeeds[(currentIndex + 1) % cursorSpeeds.length];
      cursorSpeedButton.textContent =
        currentCursorSpeed.charAt(0).toUpperCase() +
        currentCursorSpeed.slice(1);
      localStorage.setItem("cursorSpeed", currentCursorSpeed);
      updateStyles();
    });

    const fetchStats = () => {
      const wpmElement = document.querySelector(
        ".dash-metrics .list-item:nth-child(1) .g-b--8of12 .h4"
      );
      const accuracyElement = document.querySelector(
        ".dash-metrics .list-item:nth-child(2) .g-b--8of12 .h4"
      );
      const targetWPM = parseInt(localStorage.getItem("targetWPM"), 10) || 100;

      const green = "#00FF7F";
      const yellow = "#FFD700";
      const red = "red";

      if (wpmElement) {
        const wpmValue = parseInt(wpmElement.textContent, 10) || 0;

        if (wpmValue >= targetWPM - 5 && wpmValue <= targetWPM + 5) {
          wpmDisplay.style.color = green;
        } else if (wpmValue < targetWPM - 10) {
          wpmDisplay.style.color = red;
        } else if (wpmValue < targetWPM - 5) {
          wpmDisplay.style.color = yellow;
        } else if (wpmValue > targetWPM + 5) {
          wpmDisplay.style.color = "blue";
        }

        wpmDisplay.innerHTML = `WPM: ${wpmValue} <span id="targetWPMValue" style="margin-left: 10px;">Target WPM: ${targetWPM}</span>`;
      }

      if (accuracyElement) {
        const accuracyValue = parseFloat(accuracyElement.textContent) || 0;

        if (accuracyValue < 94) {
          accuracyDisplay.style.color = red;
        } else if (accuracyValue >= 94 && accuracyValue < 96) {
          accuracyDisplay.style.color = yellow;
        } else {
          accuracyDisplay.style.color = green;
        }
        accuracyDisplay.textContent = `Accuracy: ${accuracyValue}%`;
      }
    };

    // Height slider
    const heightLabel = document.createElement("label");
    heightLabel.textContent = "Adjust Height:";
    heightLabel.style.color = "#00FF7F";
    heightLabel.style.display = "block";
    heightLabel.style.marginTop = "10px";

    const heightSlider = document.createElement("input");
    heightSlider.type = "range";
    heightSlider.min = "100";
    heightSlider.max = "1000";
    const savedHeight = localStorage.getItem("dashHeight") || "500";
    dashElement.style.height = `${savedHeight}px`;
    heightSlider.value = savedHeight;

    heightSlider.style.width = "100%";
    heightSlider.style.marginTop = "5px";
    heightSlider.style.cursor = "pointer";

    container.appendChild(heightLabel);
    container.appendChild(heightSlider);

    heightSlider.addEventListener("input", function () {
      const heightValue = heightSlider.value;
      dashElement.style.height = `${heightValue}px`;
      localStorage.setItem("dashHeight", heightValue);
    });

    // Font size slider
    const fontSizeLabel = document.createElement("label");
    fontSizeLabel.textContent = "Adjust Font Size:";
    fontSizeLabel.style.color = "#00FF7F";
    fontSizeLabel.style.display = "block";
    fontSizeLabel.style.marginTop = "10px";

    const fontSizeSlider = document.createElement("input");
    fontSizeSlider.type = "range";
    fontSizeSlider.min = "20";
    fontSizeSlider.max = "80";
    fontSizeSlider.value = localStorage.getItem("dashFontSize") || "40";

    fontSizeSlider.style.width = "100%";
    fontSizeSlider.style.marginTop = "5px";
    fontSizeSlider.style.cursor = "pointer";

    container.appendChild(fontSizeLabel);
    container.appendChild(fontSizeSlider);

    fontSizeSlider.addEventListener("input", function () {
      const newFontSize = fontSizeSlider.value;
      localStorage.setItem("dashFontSize", newFontSize);
      updateStyles();
    });

    setInterval(fetchStats, 100);

    updateStyles();
  }

  setInterval(() => {
    const experimentDiv = document.querySelector('.experiment');
    const lastSlider = container.querySelector('input[type="range"]:last-of-type');
    if (experimentDiv && lastSlider) {
      const experimentParent = experimentDiv.parentElement;
      if (experimentParent !== lastSlider.parentElement) {
        lastSlider.parentElement.appendChild(experimentDiv);
      }
    }
  }, 500);

  // Retain scroll position
  window.addEventListener('beforeunload', () => {
    localStorage.setItem('scrollPosition', window.scrollY);
  });

  window.addEventListener('load', () => {
    setTimeout(() => {
      const scrollPosition = localStorage.getItem('scrollPosition');
      if (scrollPosition) {
        console.log('Restoring scroll position');
        window.scrollTo(0, parseInt(scrollPosition, 10));
      }
    }, 1000);
  });
})();