Tools Menu

comfy tools menu (with everything you need)!

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Tools Menu
// @namespace    https://tampermonkey.net/
// @version      beta-test-2
// @description  comfy tools menu (with everything you need)!
// @author       infynotarras328
// @match        https://arras.io/*
// @icon         https://www.svgrepo.com/show/489941/menu.svg
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    /*menu name               */const header = "Tools Menu";

    /*titles color            */const c1 = "#ffffff";
    /*titles outline color    */const c1o ="#484848";
    /*names color             */const c2 = "#ffffff";
    /*names outline color     */const c2o ="#484848";
 
    /*titles outline width    */const w1 = "1.5" ; // don't set them both more than 3 either it will look weird
    /*names outline width     */const w2 = "1.35";
 
    /*header font size        */const fH = "15px";
    /*titles font size        */const fT = "13px";
    /*buttons font size       */const fB = "12px";
 
    /*menu color              */const menuBG = "#a7a7af";
    /*borders color           */const border = "#484848";


    const buttons = {
        "General": [
            "Action 1",
            "Action 2",
            "Action 3",
            "Action 4",
            "Action 5",
            "Action 6",
            "Action 7",
        ],
        "Bypasses": [
            "Bypass 1",
            "Bypass 2",
            "Bypass 3",
        ],
        "Utilities": [
            "Utility 1",
            "Utility 2",
            "Utility 3",
            "Utility 4",
            "Utility 5",
            "Utility 6",
            "Utility 7",
            "Utility 8",
        ],
    };

    // hardcoded the outline :pfft::lmf::haha:
    const textShadow = `
      -${w1}px   -${w1}px ${c1o}, /* top left left */
    -${w1/2}px   -${w1}px ${c1o}, /* top left */
           0px   -${w1}px ${c1o}, /* top */
     ${w1/2}px   -${w1}px ${c1o}, /* top right */
       ${w1}px   -${w1}px ${c1o}, /* top right right */

       ${w1}px    ${w1}px ${c1o}, /* bottom right right */
     ${w1/2}px    ${w1}px ${c1o}, /* bottom right */
           0px    ${w1}px ${c1o}, /* bottom */
    -${w1/2}px    ${w1}px ${c1o}, /* bottom left */
      -${w1}px    ${w1}px ${c1o}, /* bottom left left */

       ${w1}px  ${w1/2}px ${c1o}, /* right top */
       ${w1}px        0px ${c1o}, /* right */
       ${w1}px -${w1/2}px ${c1o}, /* right bottom */

      -${w1}px  ${w1/2}px ${c1o}, /* left top */
      -${w1}px        0px ${c1o}, /* left */
      -${w1}px -${w1/2}px ${c1o}  /* left bottom */
        `;

    const textShadowNames = `
      -${w2}px   -${w2}px ${c2o}, /* top left left */
    -${w2/2}px   -${w2}px ${c2o}, /* top left */
           0px   -${w2}px ${c2o}, /* top */
     ${w2/2}px   -${w2}px ${c2o}, /* top right */
       ${w2}px   -${w2}px ${c2o}, /* top right right */

       ${w2}px    ${w2}px ${c2o}, /* bottom right right */
     ${w2/2}px    ${w2}px ${c2o}, /* bottom right */
           0px    ${w2}px ${c2o}, /* bottom */
    -${w2/2}px    ${w2}px ${c2o}, /* bottom left */
      -${w2}px    ${w2}px ${c2o}, /* bottom left left */

       ${w2}px  ${w2/2}px ${c2o}, /* right top */
       ${w2}px        0px ${c2o}, /* right */
       ${w2}px -${w2/2}px ${c2o}, /* right bottom */

      -${w2}px  ${w2/2}px ${c2o}, /* left top */
      -${w2}px        0px ${c2o}, /* left */
      -${w2}px -${w2/2}px ${c2o}  /* left bottom */
      `;






    // the menu
    const menu = document.createElement("div");
    menu.style.position = "fixed";
    menu.style.minWidth = "210px";
    menu.style.top = "1.2vw";
    menu.style.right = "1.2vw";
    menu.style.background = menuBG;
    menu.style.padding = "15px";

    menu.style.border = "solid";
    menu.style.borderRadius = "0%";
    menu.style.borderWidth = "5%";
    menu.style.borderColor = border;

    menu.style.pointerEvents = "none";
    menu.style.fontFamily = "Ubuntu";
    menu.style.fontSize = fH;
    menu.style.textAlign = "center";

    menu.style.transform = "translateX(135%)";
    menu.style.transition = "transform 0.5s ease";

    menu.style.cursor = "crosshair";
    menu.style.zIndex = "99999";
    menu.addEventListener("mousedown", (e) => {
        if (e.button === 1) e.preventDefault();
    });
    // remove the gayass scroll stripe by making its opacity and width a fucking zero
    const style = document.createElement('style');
    style.textContent = `
    #MenuScrolling::-webkit-scrollbar {
        width: 0px;
        background: transparent;
        }
    `;
    document.head.appendChild(style);

    // the title
    const title = document.createElement("div");
    title.textContent = header;
    title.style.textShadow = textShadow;
    title.style.textAlign = "center";
    title.style.color = c1;
    title.style.margin = "-4px 30px 20px 0px"
    title.style.fontWeight = "bold";
    menu.appendChild(title);


    // the button which makes the menu appear
    const revealBtn = document.createElement("div");
    revealBtn.textContent = "Tools Menu";
    revealBtn.style.position = "absolute";
    revealBtn.style.width = "130px";
    revealBtn.style.top = "1.2vw";
    revealBtn.style.right = "0vw";
    revealBtn.style.padding = "6px 0px";

    revealBtn.style.background = "#CFFFEF";
    revealBtn.style.border = "solid";
    revealBtn.style.borderRadius = "0%";
    revealBtn.style.borderWidth = "5%";
    revealBtn.style.borderColor = border;

    revealBtn.style.fontFamily = "Ubuntu";
    revealBtn.style.textAlign = "center";
    revealBtn.style.fontWeight = "bold";
    revealBtn.style.fontSize = "14px";
    revealBtn.style.textShadow = ` /* independent from other borders*/
        -1.5px    -1.5px ${border}, /* top left left */
        0.75px    -1.5px ${border}, /* top left */
           0px    -1.5px ${border}, /* top */
        0.75px    -1.5px ${border}, /* top right */
         1.5px    -1.5px ${border}, /* top right right */

         1.5px     1.5px ${border}, /* bottom right right */
        0.75px     1.5px ${border}, /* bottom right */
           0px     1.5px ${border}, /* bottom */
        0.75px     1.5px ${border}, /* bottom left */
        -1.5px     1.5px ${border}, /* bottom left left */

         1.5px    0.75px ${border}, /* right top */
         1.5px       0px ${border}, /* right */
         1.5px   -0.75px ${border}, /* right bottom */

        -1.5px    0.75px ${border}, /* left top */
        -1.5px       0px ${border}, /* left */
        -1.5px   -0.75px ${border}  /* left bottom */
        `;
    revealBtn.style.color = c1;

    revealBtn.style.cursor = "crosshair";
    revealBtn.style.zIndex = "0.2";

    // whatever that is, don't touch it since it gives a cool appearing animation
    revealBtn.style.transform = "translateX(100%)";
    setTimeout (() => {
        revealBtn.style.transform = "translateX(84%)";
    }, 100 );
    revealBtn.style.transition = "transform 0.5s ease";
    document.body.appendChild(revealBtn);

    // fuckass triangle on the button
    const revealBtn2 = document.createElement("div");
    revealBtn2.textContent = "🞀";
    revealBtn2.style.position = "fixed"
    revealBtn2.style.top = "0px";
    revealBtn2.style.right = (parseInt(revealBtn.style.width) - 21) + "px";

    revealBtn2.style.borderStyle = "none solid none none"; // make the border appear only on the right side
    revealBtn2.style.width = "18px";
    revealBtn2.style.height = "30px";
    revealBtn2.style.borderRadius = "0%";
    revealBtn2.style.borderWidth = "6px";
    revealBtn2.style.borderColor = border;

    revealBtn2.style.fontWeight = "bold";
    revealBtn2.style.fontSize = "20px";
    revealBtn2.style.textShadow = "0px 0px black";

    revealBtn.appendChild(revealBtn2);


    // red cross which makes the menu disappear
    const cross = document.createElement("div");
    cross.textContent = "✕";

    cross.style.position = "absolute";
    cross.style.top = "0%";
    cross.style.right = "0%";

    cross.style.borderStyle = "none none solid solid";
    cross.style.borderRadius = "0%";
    cross.style.borderWidth = "5%";
    cross.style.borderColor = border;
    cross.style.background = "#E03E41";

    cross.style.width = "30px";
    cross.style.height = "30px";
    cross.style.lineHeight = "30px";

    cross.style.fontSize = "24px";
    cross.style.fontFamily = "Ubuntu";
    cross.style.fontWeight = "bold";
    cross.style.textAlign = "center";

    cross.style.color = "#ffffff";
    cross.style.cursor = "crosshair";

    menu.appendChild(cross);



    // scrolling feature
    const groupsContainer = document.createElement("div");
    groupsContainer.style.maxHeight = "70vh"; // max 70% from the page zoom
    groupsContainer.style.overflowY = "auto"; // the buttons won't go out of the bounds
    groupsContainer.style.scrollBehavior = "smooth";
    groupsContainer.id = 'MenuScrolling';
    menu.appendChild(groupsContainer);



    // open button fuckery
    let menuOpen = false;
    let isAnimating = false;


    // lets the red cross work
    cross.onclick = () => {
        if (isAnimating || !menuOpen) return;
        isAnimating = true;
        menuOpen = false;

        menu.style.pointerEvents = "none";
        menu.style.transform = "translateX(135%)";

        revealBtn.style.transform = "translateX(84%)";

        setTimeout(() => {
            isAnimating = false;
        }, 400);
    };


    // makes the menu appear when you press the button
    revealBtn.onclick = () => {
        if (isAnimating || menuOpen) return;
        isAnimating = true;
        menuOpen = true;

        menu.style.pointerEvents = "auto";
        menu.style.transform = "translateX(0)";

        revealBtn.style.transform = "translateX(120%)";

        setTimeout(() => {
            isAnimating = false;
        }, 400);
    };


    // cool animation (hovering over the button makes it slide on the screen)
    revealBtn.addEventListener("mouseenter", () => {
        if (menuOpen) return;
        revealBtn.style.transform = "translateX(12%)";
    });

    revealBtn.addEventListener("mouseleave", () => {
        if (menuOpen) return;
        revealBtn.style.transform = "translateX(84%)";
    });


    function makeToggleAction(btn, config) {
        let enabled = false;
        const key = `arras_${btn.textContent}`;

        const updateColor = (state) => {
            btn.style.background = enabled
                ? colors["on" + state]
            : colors["off" + state];
        };

        const colors = {
            off: "#FFFFFF",
            offHover: "#757575",
            offDown: "#595959",

            on: "#B9E87E",
            onHover: "#C2EB91",
            onDown: "#595959"
        };

        // check localstorage upon load
        const saved = localStorage.getItem(key);
        if (saved === "1") {
            enabled = true;
            updateColor("");
            config[btn.textContent]?.Bon?.();
        } else {
            enabled = false;
            updateColor("");
        }

        btn.onmouseenter = () => updateColor("Hover");
        btn.onmouseleave = () => updateColor("");
        btn.onmousedown = () => updateColor("Down");
        btn.onmouseup = () => updateColor("Hover");

        btn.onclick = () => {
            const action = config[btn.textContent];
            if (!action) return;

            enabled = !enabled;
            updateColor("");
            localStorage.setItem(key, enabled ? "1" : "0"); // saving the button state

            if (enabled) action.Bon?.();
            else action.Boff?.();
        };

        updateColor("");
    }


    for (const groupName in buttons) {

        // group titles
        const groupTitle = document.createElement("div");
        groupTitle.textContent = groupName;
        groupTitle.style.color = c2;
        groupTitle.style.textShadow = textShadow;
        groupTitle.style.fontSize = fT;
        groupTitle.style.margin = "10px 3px 5px";
        groupTitle.style.textAlign = "left";
        groupTitle.style.fontWeight = "bold";
        groupsContainer.appendChild(groupTitle);

        // buttons
        buttons[groupName].forEach(name => {
            // buttons looks
            const btn = document.createElement("button");
            btn.textContent = name;
            btn.style.display = "block";
            btn.style.width = "100%";
            btn.style.height = "25px";
            btn.style.cursor = "crosshair";

            btn.style.border = "solid";
            btn.style.borderRadius = "2px";
            btn.style.borderWidth = "2%";
            btn.style.borderColor = border;
            btn.style.marginBottom = "2px";

            btn.style.fontFamily = "Ubuntu";
            btn.style.fontWeight = "bold";
            btn.style.fontSize = fB;
            btn.style.color = c2;
            btn.style.textShadow = textShadowNames;
            btn.style.background = "#FFFFFF";

            // cool color effects
            btn.onmouseenter = () => {btn.style.background = "#757575"}; // hovering
            btn.onmouseleave = () => {btn.style.background = "#FFFFFF"}; // not hovering
            btn.onmousedown = () => {btn.style.background = "#595959"}; // click down
            btn.onmouseup = () => {btn.style.background = "#757575"}; // click up

            revealBtn.onmouseenter = () => {revealBtn.style.background = "#D6FFF1"}; // hovering
            revealBtn.onmouseleave = () => {revealBtn.style.background = "#CFFFEF"}; // not hovering
            revealBtn.onmousedown = () => {revealBtn.style.background = "#99BAAE"}; // click down
            revealBtn.onmouseup = () => {revealBtn.style.background = "#D6FFF1"}; // click up

            cross.onmouseenter = () => {cross.style.background = "#E3595B"}; // hovering
            cross.onmouseleave = () => {cross.style.background = "#E03E41"}; // not hovering
            cross.onmousedown = () => {cross.style.background = "#A63335"}; // click down
            cross.onmouseup = () => {cross.style.background = "#E3595B"}; // click up

            makeToggleAction(btn, {
                "Action 1": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Action 2": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Action 3": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Action 4": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Action 5": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Action 6": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Action 7": {
                    Bon: () => {},
                    Boff: () => {},
                },

                "Bypass 1": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Bypass 2": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Bypass 3": {
                    Bon: () => {},
                    Boff: () => {},
                },

                "Utility 1": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Utility 2": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Utility 3": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Utility 4": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Utility 5": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Utility 6": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Utility 7": {
                    Bon: () => {},
                    Boff: () => {},
                },
                "Utility 8": {
                    Bon: () => {},
                    Boff: () => {},
                },
            });

            groupsContainer.appendChild(btn);
        });
    }
    document.body.appendChild(menu);
})();