SanuliHacksGUI

Sanuli huijaus Käyttöliittymä

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         SanuliHacksGUI
// @namespace    http://tampermonkey.net/
// @version      2025-05-24
// @description  Sanuli huijaus Käyttöliittymä
// @author       @theyhoppingonme on discord
// @match        https://sanuli.fi/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=sanuli.fi
// @grant        none
// ==/UserScript==
function isMobile() {
    const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
    const smallScreen = window.innerWidth <= 820;
    const isPortrait = window.matchMedia('(orientation: portrait)').matches;

    const userAgentMobile = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);

    return (hasTouch && smallScreen && isPortrait) || userAgentMobile;
}

function encode(input, key) {
    let encoded = '';
    for (let i = 0; i < input.length; i++) {
        let charCode = input.charCodeAt(i);
        let keyCharCode = key.charCodeAt(i % key.length);
        let shifted = (charCode + keyCharCode) % 256;
        encoded += shifted.toString(16).padStart(2, '0');
    }
    return encoded;
}

function decode(encoded, key) {
    let decoded = '';
    for (let i = 0; i < encoded.length; i += 2) {
        let byte = parseInt(encoded.substr(i, 2), 16);
        let keyCharCode = key.charCodeAt((i/2) % key.length);
        let originalCharCode = (byte - keyCharCode + 256) % 256;
        decoded += String.fromCharCode(originalCharCode);
    }
    return decoded;
}

function main() {
setTimeout(function() {
(() => {
    if (document.location.href == 'https://sanuli.fi/') {
    let opacity = 0.95
    if (localStorage.getItem('gui')) {
      const guid = JSON.parse(localStorage.getItem('gui'));
      if (guid.o != undefined) {
      opacity = guid.o;
        } else {
          localStorage.removeItem('gui');
        }
    }
    const version = 1.4;
    const guiId = 'an-gui';

    if (document.getElementById(guiId)) {
        console.log('GUI already exists.');
        return;
    }
    let elz;
    let data;
    let settings = localStorage.getItem('settings');
    let sjson = JSON.parse(settings);
    let game = `game|"${sjson.current_game_mode}"|"${sjson.current_word_list}"|${sjson.current_word_length}`;
    let json;

    const tabs = [
        { id: 'set', label: 'Aseta', active: true },
        { id: 'toggle', label: 'Kytkimet', active: false },
        { id: 'button', label: 'Napit', active: false },
        { id: 'settings', label: 'Asetukset', active: false }
    ];

    const inputs = [{
            tab: 'set',
            info: 'Aseta putki',
            placeholder: 'Putki',
            buttonText: 'Aseta',
            type: 'number',
            callback: (value) => {
                try {
                    data = localStorage.getItem(game);
                    if (!data) throw new Error('No data found');
                    json = JSON.parse(data);
                    json.streak = Number(value);
                    localStorage.setItem(game, JSON.stringify(json));
                    setTimeout(function() {
                    location.reload();
                    }, 100);
                } catch (e) {
                    console.error('Failed to set streak:', e);
                }
            }

        },
        {
            tab: 'set',
            info: 'Aseta sana',
            placeholder: 'Sana',
            buttonText: 'Aseta',
            type: 'text',
            callback: (value) => {
                try {
                    data = localStorage.getItem(game);
                    if (!data) throw new Error('No data found');
                    json = JSON.parse(data);
                    value = value.toUpperCase();
                    value = value.split('');
                    json.word = value;
                    json.word_length = value.length;
                    localStorage.setItem(game, JSON.stringify(json));
                    setTimeout(function() {
                    location.reload();
                    }, 100);
                } catch (e) {
                    console.error('Failed to set word:', e);
                }
            }
        },
         {
            tab: 'set',
            info: 'Aseta viesti',
            placeholder: 'Viesti',
            buttonText: 'Aseta',
            type: 'text',
            callback: (value) => {
                try {
                    data = localStorage.getItem(game);
                    if (!data) throw new Error('No data found');
                    json = JSON.parse(data);
                    json.message = value;
                    localStorage.setItem(game, JSON.stringify(json));
                    setTimeout(function() {
                    location.reload();
                    }, 100);
                } catch (e) {
                    console.error('Failed to set message:', e);
                }
            }
        },
        {
            tab: 'settings',
            info: 'Aseta sanulin taustaväri (Heksadesimaali)',
            placeholder: 'Esim: #000000',
            buttonText: 'Aseta',
            type: 'text',
            callback: (value) => {
                try {
                    document.body.style.background = value;
                } catch (e) {
                    console.error('Failed to set color:', e);
                }
            }
        },
    ];
    let interval;
    let recent;
    let word;
    const toggles = [{
            tab: 'toggle',
            info: 'Automaattinen arvaus',
            name: 'autoguess',
            onFunc: () => {
                guess();
            },
            offFunc: () => {
                clearInterval(interval);
            }
        },
    ];
    function guess() {
        interval = setInterval(() => {
                        data = localStorage.getItem(game);
                        json = JSON.parse(data);
                        const word = json.word.join('');
                        if (recent != word) {
                        typeWord(word);
                        recent = word;
                        }
                        document.dispatchEvent(enterEvent);
                        document.dispatchEvent(enterEvent);
                 }, 100);
    }
    const buttons = [{
            tab: 'button',
            info: 'Selvitä sana',
            buttonText: 'Selvitä',
            callback: () => {
                data = localStorage.getItem(game);
                json = JSON.parse(data);
                json.message = 'Sana on: ' + json.word.join('');
                localStorage.setItem(game, JSON.stringify(json));
                alert(json.message);
            }
        },
        {
            tab: 'button',
        info: 'Aseta Maksimiputki',
            buttonText: 'Aseta',
            callback: () => {
                data = localStorage.getItem(game);
                    if (!data) throw new Error('No data found');
                    json = JSON.parse(data);
                    json.streak = 0xFFFFFFFF;
                    localStorage.setItem(game, JSON.stringify(json));
                    setTimeout(function() {
                    location.reload();
                    }, 100);
            }
        },
         {
             tab: 'button',
        info: 'Voita peli',
            buttonText: 'Voita',
            callback: () => {
                data = localStorage.getItem(game);
                    if (!data) throw new Error('No data found');
                    json = JSON.parse(data);
                    json.is_winner = true;
                    json.is_guessing = false;
                    json.is_unknown = false;
                    json.streak += 1;
                    localStorage.setItem(game, JSON.stringify(json));
                    setTimeout(function() {
                    location.reload();
                    }, 100);
            }
        },
        {
            tab: 'settings',
            info: 'Tallenna Sanulitiedot',
            buttonText: 'Tallenna',
            callback: () => {
                navigator.clipboard.writeText(encode(localStorage.getItem(game), 'SanuliHacksGUI'))
                    .then(() => {
                alert('Tallennuskoodi on tallennettu leikepöytään.');
                });
            }
        },
        {
            tab: 'settings',
            info: 'Lataa Sanulitiedot',
            buttonText: 'Lataa',
            callback: () => {
                const save = prompt('Anna tallennettu koodi.');
                if (save) {
                    const str = decode(save, 'SanuliHacksGUI');
                    try {
                        JSON.parse(str);
                        localStorage.setItem(game, str);
                        alert('Ladattu!');
                        location.reload();
                    } catch (e) {
                        alert('Virheellistä koodia!');
                    }
                } else {
                  alert('Et vastannut mitään');
                }
            }
        },
    ];

    const sliders = [{
            tab: 'settings',
            info: 'Käyttöjärjestelmän läpinäkyvyys',
            value: opacity,
            step: 100,
            min: 0,
            max: 1,
            callback: (value) => {
                const element = document.getElementById(guiId);
                if (element) {
                 element.style.opacity = value;
                    data = JSON.parse(localStorage.getItem('gui'));
                    data.o = value;
                    localStorage.setItem('gui', JSON.stringify(data));
                }
            }
        }
    ];

    function simulateKeyPress(key) {
  const keyUpper = key.toUpperCase();
  const keyCode = keyUpper.charCodeAt(0);
  const code = key === 'Enter' ? 'Enter' : 'Key' + keyUpper;

  ['keydown', 'keypress', 'keyup'].forEach(type => {
    const event = new KeyboardEvent(type, {
      key: key,
      code: code,
      keyCode: keyCode,
      which: keyCode,
      bubbles: true,
      cancelable: true,
    });
    document.dispatchEvent(event);
  });
}

function typeWord(word, delay = 10) {
  let i = 0;
  const interval = setInterval(() => {
    if (i >= word.length) return clearInterval(interval);
    simulateKeyPress(word[i++]);
  }, delay);
}

const enterEvent = new KeyboardEvent('keydown', {
  key: 'Enter',
  code: 'Enter',
  keyCode: 13,
  which: 13,
  bubbles: true,
});


    const style = document.createElement('style');
    style.textContent = `
#${guiId} {
  position: fixed;
  top: 20px;
  right: 20px;
  width: 320px;
  background: #2b2b2b;
  color: #e0e0e0;
  border-radius: 8px;
  font-family: Arial, sans-serif;
  box-shadow: 0 4px 12px rgba(0,0,0,0.4);
  z-index: 9999;
  overflow: hidden;
  transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
  opacity: ${opacity};
}
#${guiId} .gui-header {
  padding: 12px;
  background: #1e1e1e;
  cursor: move;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-radius: 8px 8px 0 0;
  user-select: none;
}
#${guiId} .gui-title {
  font-weight: bold;
  font-size: 14px;
  transition: color 0.2s ease;
}
#${guiId} .gui-tabs {
  display: flex;
  background: #262626;
  border-bottom: 1px solid #3a3a3a;
}
#${guiId} .gui-tab {
  padding: 10px 15px;
  font-size: 12px;
  cursor: pointer;
  transition: all 0.3s ease;
  user-select: none;
  border-bottom: 2px solid transparent;
  position: relative;
  overflow: hidden;
}
#${guiId} .gui-tab:hover {
  background: #303030;
}
#${guiId} .gui-tab.active {
  background: #2b2b2b;
  border-bottom: 2px solid #4CAF50;
  font-weight: bold;
}

#${guiId} .gui-tab::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 5px;
  height: 5px;
  background: rgba(255, 255, 255, 0.5);
  opacity: 0;
  border-radius: 100%;
  transform: scale(1, 1) translate(-50%);
  transform-origin: 50% 50%;
}
#${guiId} .gui-tab:focus:not(:active)::after {
  animation: ripple 0.5s ease-out;
}
@keyframes ripple {
  0% {
    transform: scale(0, 0);
    opacity: 0.5;
  }
  100% {
    transform: scale(20, 20);
    opacity: 0;
  }
}
#${guiId} .gui-content {
  padding: 16px;
  max-height: 70vh;
  overflow-y: auto;
  transition: max-height 0.4s ease-in-out;
}
#${guiId} .tab-content {
  display: none;
  animation-duration: 0.45s;
  animation-fill-mode: both;
  animation-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
}
#${guiId} .tab-content.active {
  display: block;
  animation-name: fadeIn;
}
#${guiId} .tab-content.fade-out {
  animation-name: fadeOut;
}
@keyframes fadeIn {
  0% {
    opacity: 0;
    transform: translateY(10px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}
@keyframes fadeOut {
  0% {
    opacity: 1;
    transform: translateY(0);
  }
  100% {
    opacity: 0;
    transform: translateY(-10px);
  }
}
#${guiId} .gui-item {
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
  transition: transform 0.2s ease-out;
}
#${guiId} .gui-item:hover {
  transform: translateX(2px);
}
#${guiId} .gui-item-info {
  margin-bottom: 6px;
  font-size: 12px;
  color: #b0b0b0;
  transition: color 0.2s ease;
}
#${guiId} .gui-input-container {
  display: flex;
  gap: 8px;
}
#${guiId} input {
  flex: 1;
  padding: 8px;
  background: #3a3a3a;
  border: 1px solid #4a4a4a;
  color: #e0e0e0;
  border-radius: 4px;
  outline: none;
  transition: border-color 0.25s ease, box-shadow 0.25s ease;
}
#${guiId} input:focus {
  border-color: #6a6a6a;
  box-shadow: 0 0 0 2px rgba(106, 106, 106, 0.3);
}
#${guiId} button {
  padding: 8px 12px;
  background: #4a4a4a;
  border: none;
  color: #e0e0e0;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.25s ease, transform 0.15s ease;
  outline: none;
}
#${guiId} button:hover {
  background: #5a5a5a;
  transform: translateY(-1px);
}
#${guiId} button:active {
  background: #6a6a6a;
  transform: translateY(1px);
}
#${guiId} .toggle-container {
  display: flex;
  align-items: center;
  gap: 8px;
}
#${guiId} .toggle-switch {
  position: relative;
  width: 40px;
  height: 20px;
}
#${guiId} .toggle-slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #3a3a3a;
  transition: background-color 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
  border-radius: 20px;
}
#${guiId} .toggle-slider:before {
  position: absolute;
  content: '';
  height: 16px;
  width: 16px;
  left: 2px;
  bottom: 2px;
  background-color: #e0e0e0;
  transition: transform 0.3s cubic-bezier(0.4, 0.0, 0.2, 1), background-color 0.3s ease;
  border-radius: 50%;
}
#${guiId} input:checked + .toggle-slider {
  background-color: #4CAF50;
}
#${guiId} input:checked + .toggle-slider:before {
  transform: translateX(20px);
}
#${guiId} .gui-slider-container {
  display: flex;
  flex-direction: column;
  margin-bottom: 12px;
  width: 85%;
}
#${guiId} .gui-slider-header {
  display: flex;
  justify-content: space-between;
  margin-bottom: 6px;
  font-size: 12px;
  color: #b0b0b0;
}
#${guiId} .gui-slider-value {
  font-weight: bold;
  color: #e0e0e0;
  transition: color 0.2s ease;
}
#${guiId} .gui-slider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 6px;
  background: #3a3a3a;
  border-radius: 3px;
  outline: none;
  transition: background 0.2s ease, box-shadow 0.2s ease;
}
#${guiId} .gui-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #4CAF50;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.15s ease, box-shadow 0.2s ease;
}
#${guiId} .gui-slider::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border: none;
  border-radius: 50%;
  background: #4CAF50;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.15s ease, box-shadow 0.2s ease;
}
#${guiId} .gui-slider:hover {
  background: #444444;
}
#${guiId} .gui-slider:hover::-webkit-slider-thumb {
  transform: scale(1.1);
  box-shadow: 0 0 8px rgba(76, 175, 80, 0.4);
}
#${guiId} .gui-slider:hover::-moz-range-thumb {
  transform: scale(1.1);
  box-shadow: 0 0 8px rgba(76, 175, 80, 0.4);
}
#${guiId} .gui-slider:focus {
  box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2);
}
#${guiId} .gui-slider:focus::-webkit-slider-thumb {
  background: #5dbb61;
  box-shadow: 0 0 0 4px rgba(76, 175, 80, 0.3);
}
#${guiId} .gui-slider:focus::-moz-range-thumb {
  background: #5dbb61;
  box-shadow: 0 0 0 4px rgba(76, 175, 80, 0.3);
}
#${guiId} .gui-slider:active::-webkit-slider-thumb {
  transform: scale(1.2);
  background: #3d9140;
}
#${guiId} .gui-slider:active::-moz-range-thumb {
  transform: scale(1.2);
  background: #3d9140;
}
    `;
    document.head.appendChild(style);

    const gui = document.createElement('div');
    gui.id = guiId;
    let jss;
    const guiHeader = document.createElement('div');
    guiHeader.className = 'gui-header';

    const guiTitle = document.createElement('div');
    guiTitle.className = 'gui-title';
    guiTitle.textContent = `AnGUI - Sanuli V${version}`;

    const guiTabs = document.createElement('div');
    guiTabs.className = 'gui-tabs';

    const guiContent = document.createElement('div');
    guiContent.className = 'gui-content';

    guiHeader.appendChild(guiTitle);
    gui.appendChild(guiHeader);
    gui.appendChild(guiTabs);
    gui.appendChild(guiContent);
    document.body.appendChild(gui);

     tabs.forEach(tab => {
        const tabButton = document.createElement('div');
        tabButton.className = `gui-tab ${tab.active ? 'active' : ''}`;
        tabButton.textContent = tab.label;
        tabButton.dataset.tabId = tab.id;
        guiTabs.appendChild(tabButton);

        const tabContent = document.createElement('div');
        tabContent.className = `tab-content ${tab.active ? 'active' : ''}`;
        tabContent.id = `tab-${tab.id}`;
        guiContent.appendChild(tabContent);

        tabButton.addEventListener('click', () => {
            document.querySelectorAll(`#${guiId} .gui-tab`).forEach(t => {
                t.classList.remove('active');
            });
            document.querySelectorAll(`#${guiId} .tab-content`).forEach(c => {
                c.classList.remove('active');
            });

            tabButton.classList.add('active');
            tabContent.classList.add('active');
        });
    });

        let isVisible = true;
        let dragActive = false;
        let dragStartX, dragStartY, initialX, initialY;

        document.addEventListener('keydown', (e) => {
            if (e.key === 'Insert') {
                isVisible = !isVisible;
                gui.style.display = isVisible ? 'block' : 'none';
            }
        });

        guiHeader.addEventListener('mousedown', (e) => {
            startD(e.clientX, e.clientY);
            e.preventDefault();
        });

        document.addEventListener('mousemove', (e) => {
            if (dragActive) {
                moveD(e.clientX, e.clientY);
            }
        });

        document.addEventListener('mouseup', () => {
            endD();
        });

        guiHeader.addEventListener('touchstart', (e) => {
            if (e.touches.length === 1) {
                const touch = e.touches[0];
                startD(touch.clientX, touch.clientY);
                e.preventDefault();
            }
        });

        document.addEventListener('touchmove', (e) => {
            if (dragActive && e.touches.length === 1) {
                const touch = e.touches[0];
                moveD(touch.clientX, touch.clientY);
                e.preventDefault();
            }
        });

        document.addEventListener('touchend', () => {
            endD();
        });

        document.addEventListener('touchcancel', () => {
            endD();
        });

        function startD(x, y) {
            dragActive = true;
            dragStartX = x;
            dragStartY = y;
            initialX = gui.offsetLeft;
            initialY = gui.offsetTop;
            gui.style.cursor = 'grabbing';
        }

        function moveD(x, y) {
            const dx = x - dragStartX;
            const dy = y - dragStartY;
            gui.style.left = initialX + dx + 'px';
            gui.style.top = initialY + dy + 'px';
            gui.style.right = 'auto';
            if (!localStorage.getItem('gui')) {
            const jss = {
                'l': gui.style.left,
                't': gui.style.top,
                'r': gui.style.right,
                'o': 0.95,
            };
            localStorage.setItem('gui', JSON.stringify(jss));
            } else {
                const read = JSON.parse(localStorage.getItem('gui'));
                const jss = {
                'l': gui.style.left,
                't': gui.style.top,
                'r': gui.style.right,
                'o': read.o,
                };
                localStorage.setItem('gui', JSON.stringify(jss));
            }
        }

        function endD() {
            if (dragActive) {
                dragActive = false;
                gui.style.cursor = 'default';
            }
        }

        let inputFocused = false;

        document.addEventListener('keydown', function(event) {
        if (event.key === '=') {
            if (confirm('Oletko varma, että haluat nollaa käyttöjärjestelmän?')) {
                   localStorage.removeItem('gui');
                   alert('käyttöjärjestelmä on nollattu.');
                   location.reload();
                }
        }
    });

    document.addEventListener('keydown', function(event) {
        if (event.key === '!') {
            if (confirm('Oletko varma, että haluat nollaa sanulin tiedot?')) {
                   const keep = localStorage.getItem('gui');

                   for (let i = localStorage.length - 1; i >= 0; i--) {
                       const key = localStorage.key(i);
                       if (key !== 'gui') {
                           localStorage.removeItem(key);
                       }
                   }

                if (keep !== null) {
                    localStorage.setItem('gui', keep);
                }
                   alert('sanulin tiedot on nollattu.');
                   location.reload();
                }
        }
    });

   const createInput = (tabId, info, placeholder, buttonText, type, callback) => {
       const tabContent = document.getElementById(`tab-${tabId}`);
        if (!tabContent) return;

        const item = document.createElement('div');
        item.className = 'gui-item';

        const itemInfo = document.createElement('div');
        itemInfo.className = 'gui-item-info';
        itemInfo.textContent = info;

        const inputContainer = document.createElement('div');
        inputContainer.className = 'gui-input-container';

        const input = document.createElement('input');
        input.type = type;
        input.placeholder = placeholder;

        input.addEventListener('focus', () => {
        inputFocused = true;
    });

    input.addEventListener('blur', () => {
        inputFocused = false;
    });

    input.addEventListener('keydown', (event) => {
        event.stopPropagation();
    });

        const button = document.createElement('button');
        button.textContent = buttonText;
        button.addEventListener('click', () => {
            callback(input.value);
        });

        inputContainer.appendChild(input);
        inputContainer.appendChild(button);

        item.appendChild(itemInfo);
        item.appendChild(inputContainer);
        tabContent.appendChild(item);
    };

const createSlider = (tabId, info, value, step, min, max, callback) => {
    const tabContent = document.getElementById(`tab-${tabId}`);
    if (!tabContent) return;

    const item = document.createElement('div');
    item.className = 'gui-item';

    const itemInfo = document.createElement('div');
    itemInfo.className = 'gui-item-info';
    itemInfo.textContent = info;

    const sliderContainer = document.createElement('div');
    sliderContainer.className = 'gui-slider-container';

    const sliderHeader = document.createElement('div');
    sliderHeader.className = 'gui-slider-header';

    const sliderLabel = document.createElement('span');
    sliderLabel.textContent = info;

    const valueLabel = document.createElement('span');
    valueLabel.className = 'gui-slider-value';
    valueLabel.textContent = value;

    sliderHeader.appendChild(sliderLabel);
    sliderHeader.appendChild(valueLabel);

    const slider = document.createElement('input');
    slider.className = 'gui-slider';
    slider.type = 'range';
    slider.min = min;
    slider.max = max;
    slider.step = (max - min) / step;
    slider.value = value;

    slider.addEventListener('input', () => {
        valueLabel.textContent = slider.value;
        callback(slider.value);
    });

    sliderContainer.appendChild(sliderHeader);
    sliderContainer.appendChild(slider);

    item.appendChild(sliderContainer);
    tabContent.appendChild(item);

    return slider;
};


    const createToggle = (tabId, info, name, onFunc, offFunc) => {
        const tabContent = document.getElementById(`tab-${tabId}`);
        if (!tabContent) return;

        const item = document.createElement('div');
        item.className = 'gui-item';

        const itemInfo = document.createElement('div');
        itemInfo.className = 'gui-item-info';
        itemInfo.textContent = info;

        const toggleContainer = document.createElement('div');
        toggleContainer.className = 'toggle-container';

        const toggleLabel = document.createElement('label');
        toggleLabel.className = 'toggle-switch';

        const toggleInput = document.createElement('input');
        toggleInput.type = 'checkbox';
        toggleInput.name = name;

        const toggleSlider = document.createElement('span');
        toggleSlider.className = 'toggle-slider';

        toggleInput.addEventListener('change', () => {
            if (toggleInput.checked) {
                onFunc();
            } else {
                offFunc();
            }
        });

        toggleLabel.appendChild(toggleInput);
        toggleLabel.appendChild(toggleSlider);
        toggleContainer.appendChild(toggleLabel);

        item.appendChild(itemInfo);
        item.appendChild(toggleContainer);
        tabContent.appendChild(item);

        return toggleInput;
    };

    const createButton = (tabId, info, buttonText, callback) => {
        const tabContent = document.getElementById(`tab-${tabId}`);
        if (!tabContent) return;

        const item = document.createElement('div');
        item.className = 'gui-item';

        const itemInfo = document.createElement('div');
        itemInfo.className = 'gui-item-info';
        itemInfo.textContent = info;

        const button = document.createElement('button');
        button.textContent = buttonText;
        button.addEventListener('click', callback);

        item.appendChild(itemInfo);
        item.appendChild(button);
        tabContent.appendChild(item);

        return button;
    };

    inputs.forEach(input => {
        createInput(input.tab, input.info, input.placeholder, input.buttonText, input.type, input.callback);
    });

    toggles.forEach(toggle => {
        createToggle(toggle.tab, toggle.info, toggle.name, toggle.onFunc, toggle.offFunc);
    });

    buttons.forEach(button => {
        createButton(button.tab, button.info, button.buttonText, button.callback);
    });

    sliders.forEach(slider => {
        createSlider(slider.tab, slider.info, slider.value, slider.step, slider.min, slider.max, slider.callback);
    });

    if (localStorage.getItem('gui')) {
      const vals = JSON.parse(localStorage.getItem('gui'));
       gui.style.left = vals.l;
       gui.style.right = vals.r;
       gui.style.top = vals.t;
    }
    let item = null;
    if (isMobile()) {
       const elems = document.querySelectorAll('div.keyboard-row');
        const target = Array.from(elems).find(el => el.childElementCount === 13);
        item = document.createElement('button');
        item.className = 'keyboard-button keyboard-button-submit';
        item.style.backgroundColor = 'purple';
        item.textContent = 'angui';
        target.appendChild(item);
    }
    if (item) {
        item.addEventListener('touchstart', (e) => {
            if (e.touches.length === 1) {
                isVisible = !isVisible;
                gui.style.display = isVisible ? 'block' : 'none';
            }
        });
    }

    } else {
      alert('Tämä koodi toimii vain sivustolla sanuli.fi, avataan sivu.');
        document.location.href = 'https://sanuli.fi/';
    }
})();
    // tekijä: theyhoppingonme
}, 200);
}
const waitForDiv = () => {
    const div = document.querySelector('.keyboard');
    if (div) {
        main();
    } else {
        requestAnimationFrame(waitForDiv);
    }
};

waitForDiv();