LogVisualizer Visual Unit Filter

Auto-detect units, toggle-select, color buttons visually

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

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

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

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

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

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.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         LogVisualizer Visual Unit Filter
// @namespace    logvisualizer
// @version      6.0
// @description  Auto-detect units, toggle-select, color buttons visually
// @match        https://www.logvisualizer.app/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    let panel;
    let knownUnits = new Set();
    let activeUnits = new Set(); // visual state

    function createPanel() {
        panel = document.createElement("div");
        panel.style.cssText = `
            position: fixed;
            top: 80px;
            right: 20px;
            z-index: 999999;
            background: #0b0b0b;
            border: 1px solid #333;
            border-radius: 10px;
            padding: 10px;
            font-family: monospace;
            font-size: 12px;
            color: #fff;
            box-shadow: 0 0 15px rgba(0,0,0,.7);
            min-width: 160px;
            max-height: 75vh;
            overflow-y: auto;
        `;

        panel.innerHTML = `
            <div style="text-align:center;font-weight:bold;margin-bottom:8px;">
                Unit Filter
            </div>
            <div id="unit-buttons"></div>
        `;

        document.body.appendChild(panel);
    }

    function addUnitButton(unit) {
        const container = document.getElementById("unit-buttons");
        if ([...container.querySelectorAll("button")].some(b => b.dataset.unit === unit)) return;

        const btn = document.createElement("button");
        btn.textContent = unit;
        btn.dataset.unit = unit;

        btn.style.cssText = `
            display:block;
            width:100%;
            margin:5px 0;
            padding:6px;
            background:#151515;
            color:#ddd;
            border:1px solid #333;
            border-radius:6px;
            cursor:pointer;
            transition: all 0.15s ease;
        `;

        btn.onclick = () => toggleUnit(unit, btn);

        container.appendChild(btn);
    }

    function toggleUnit(unit, btn) {
        const labels = document.querySelectorAll("li.group label");

        // toggle visual state
        if (activeUnits.has(unit)) {
            activeUnits.delete(unit);
            setButtonInactive(btn);
        } else {
            activeUnits.add(unit);
            setButtonActive(btn);
        }

        // toggle actual checkboxes
        labels.forEach(label => {
            const unitSpan = label.querySelector("span.text-neutral-400, span.dark\\:text-neutral-600");
            if (!unitSpan) return;

            if (unitSpan.textContent.trim() === unit) {
                const checkbox = label.querySelector('button[role="checkbox"]');
                if (checkbox) checkbox.click();
            }
        });
    }

    function setButtonActive(btn) {
        btn.style.background = "#1f2937";   // dark blue
        btn.style.border = "1px solid #3b82f6";
        btn.style.color = "#93c5fd";
        btn.style.boxShadow = "0 0 8px rgba(59,130,246,0.6)";
    }

    function setButtonInactive(btn) {
        btn.style.background = "#151515";
        btn.style.border = "1px solid #333";
        btn.style.color = "#ddd";
        btn.style.boxShadow = "none";
    }

    function scanUnits() {
        const spans = document.querySelectorAll(
            "li.group span.text-neutral-400, li.group span.dark\\:text-neutral-600"
        );

        spans.forEach(span => {
            const unit = span.textContent.trim();
            if (!unit.startsWith("[") || !unit.endsWith("]")) return;

            if (!knownUnits.has(unit)) {
                knownUnits.add(unit);
                addUnitButton(unit);
            }
        });
    }

    function init() {
        createPanel();
        scanUnits();

        const observer = new MutationObserver(() => scanUnits());
        observer.observe(document.body, { childList: true, subtree: true });
    }

    const wait = setInterval(() => {
        if (document.querySelector("li.group")) {
            clearInterval(wait);
            init();
        }
    }, 300);

})();