// ==UserScript==
// @name CMB - Custom Mpp Buttons by gtnntg
// @name:ru КПМ - Настраиваемые кнопки Mpp от gtnntg
// @version 0.1.3
// @devversion 0.6.3
// @description Custom buttons for Multiplayer Piano with panel navigation
// @description:ru Настраиваемые кнопки для Multiplayer Piano с системой навигации по панелям
// @author gtnntg
// @remixauthor /
// @license MIT
// @namespace https://vscode.dev/?connectTo=tampermonkey
// @match *://multiplayerpiano.org/*
// @match *://multiplayerpiano.net/*
// @match *://piano.ourworldofpixels.com/*
// @match *://playground-mpp.hyye.tk/*
// @match *://rgbmpp.qwerty0301.repl.co/*
// @match *://mpp.hyye.tk/*
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
/* globals MPP */
/*---------[Author info]-------------
[discord: gtnntg]
[e-mail: [email protected]]
[github: https://github.com/zeroxel]
--------------------------------------*/
/*---------[Remix Author info]-------------
If you would like to modify the script or change it in any way.
Please fill in your information
You can use author as an example
--------------------------------------*/
/*---------[RU:info]------------
настоящая версия скрипта: 0.6.0
Лицензия и авторское право:
Copyright (C) 2024 Georgiy Shvedov ([email protected])
Эта программа является свободным программным обеспечением: вы можете распространять ее и/или модифицировать
ее в соответствии с условиями MIT License.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии
ТОВАРНОГО ВИДА или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. См.
MIT License для получения более подробных сведений.
Вы должны были получить копию MIT License
вместе с этой программой. Если нет, см.
<https://opensource.org/licenses/MIT>.
-----------------------------*/
/*---------[EN:info]------------
Current script version: 0.6.0
License and Copyright:
Copyright (C) 2024 Georgiy Shvedov ([email protected])
This program is free software: you can redistribute it and/or modify
it under the terms of the MIT License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
MIT License for more details.
You should have received a copy of the MIT License
along with this program. If not, see <https://opensource.org/licenses/MIT>.
-----------------------------*/
//-------script-----------
(function() {
'use strict';
// CSS для панелей и кнопок
const CSS = `
:root {
--panel-bg-color: rgba(255, 255, 255, 0.9);
--panel-header-color: rgba(51, 51, 51, 0.9);
--panel-header-text-color: #ffffff;
--button-bg-color: rgba(0, 123, 255, 0.9);
--button-text-color: #ffffff;
--category-bg-color: rgba(255, 255, 255, 0.5); /* Прозрачный фон для подзаголовков */
--border-radius: 5px; /* Закругление краев */
}
.custom-panel {
position: fixed;
top: 20px;
left: 0;
width: 250px;
background-color: var(--panel-bg-color);
border: 1px solid #ccc;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
z-index: 1000;
display: none;
overflow: hidden;
border-radius: var(--border-radius);
}
.panel-header {
background-color: var(--panel-header-color);
color: var(--panel-header-text-color);
padding: 10px;
font-weight: bold;
cursor: move;
border-radius: var(--border-radius) var(--border-radius) 0 0;
}
.custom-button {
background-color: var(--button-bg-color);
color: var(--button-text-color);
border: none;
padding: 10px;
margin: 5px;
cursor: pointer;
border-radius: var(--border-radius);
display: block;
width: calc(100% - 20px);
box-sizing: border-box;
}
.panel-category {
background-color: var(--category-bg-color); /* Прозрачный фон */
padding: 10px;
font-weight: bold;
border-bottom: 1px solid #ddd;
margin-bottom: 5px;
border-radius: var(--border-radius); /* Закругленные углы */
}
.panel-content {
padding: 10px;
}
.slide-panel {
position: fixed;
top: 0;
left: 0;
width: 300px;
height: 100%;
background: var(--panel-bg-color);
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.2);
transform: translateX(-100%);
transition: transform 0.3s ease;
overflow: hidden;
z-index: 1001;
display: flex;
flex-direction: column;
border-radius: var(--border-radius);
}
.slide-panel.open {
transform: translateX(0);
}
.close-button {
background: red;
color: white;
border: none;
padding: 10px;
cursor: pointer;
position: absolute;
top: 10px;
right: 10px;
border-radius: 50%;
z-index: 1002;
}
.toggle-button {
position: fixed;
top: 20px;
left: 20px;
background: var(--panel-header-color);
color: var(--panel-header-text-color);
border: none;
padding: 10px;
cursor: pointer;
border-radius: var(--border-radius);
z-index: 1002;
}
.style-customizer {
margin: 20px;
padding: 10px;
background: var(--panel-bg-color);
border: 1px solid #ccc;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
border-radius: var(--border-radius);
}
.style-section {
margin-bottom: 15px;
}
.field-container {
margin-bottom: 10px;
}
.field-container label {
display: block;
margin-bottom: 5px;
}
.field-container input[type="color"],
.field-container input[type="range"] {
width: 100%;
}
`;
// Добавление стилей в документ
const styleSheet = document.createElement('style');
styleSheet.type = 'text/css';
styleSheet.innerText = CSS;
document.head.appendChild(styleSheet);
// Переменные для настроек стилей
const DEFAULT_STYLES = {
panelBackgroundColor: 'rgba(255, 255, 255, 0.9)',
panelHeaderColor: 'rgba(51, 51, 51, 0.9)',
panelHeaderTextColor: '#ffffff',
buttonBackgroundColor: 'rgba(0, 123, 255, 0.9)',
buttonTextColor: '#ffffff',
categoryBackgroundColor: 'rgba(255, 255, 255, 0.5)', /* Прозрачный фон для подзаголовков */
borderRadius: '5px'
};
// Проверка активности скрипта
const SCRIPT_ACTIVE_KEY = 'scriptActive';
function isScriptActive() {
return GM_getValue(SCRIPT_ACTIVE_KEY, true);
}
// Функция для активации/деактивации скрипта
function setScriptActive(state) {
GM_setValue(SCRIPT_ACTIVE_KEY, state);
if (state) {
showPanels();
createSlidePanel();
} else {
hidePanels();
}
}
// Получение и сохранение стилей
function getStyles() {
return GM_getValue('panelStyles', DEFAULT_STYLES);
}
function setStyles(styles) {
GM_setValue('panelStyles', styles);
applyStyles();
}
// Применение стилей
function applyStyles() {
const styles = getStyles();
document.documentElement.style.setProperty('--panel-bg-color', styles.panelBackgroundColor);
document.documentElement.style.setProperty('--panel-header-color', styles.panelHeaderColor);
document.documentElement.style.setProperty('--panel-header-text-color', styles.panelHeaderTextColor);
document.documentElement.style.setProperty('--button-bg-color', styles.buttonBackgroundColor);
document.documentElement.style.setProperty('--button-text-color', styles.buttonTextColor);
document.documentElement.style.setProperty('--category-bg-color', styles.categoryBackgroundColor); /* Прозрачный фон для подзаголовков */
document.documentElement.style.setProperty('--border-radius', styles.borderRadius);
}
// Создание панели
function createPanel(title, id, categories) {
const panel = document.createElement('div');
panel.id = id;
panel.className = 'custom-panel';
const header = document.createElement('div');
header.className = 'panel-header';
header.textContent = title;
panel.appendChild(header);
// Создание контента для панелей
const panelContent = document.createElement('div');
panelContent.className = 'panel-content';
categories.forEach(category => {
const categoryHeader = document.createElement('div');
categoryHeader.className = 'panel-category';
categoryHeader.textContent = category.title;
panelContent.appendChild(categoryHeader);
category.buttons.forEach(button => {
const btn = createButton(button.text, button.action);
panelContent.appendChild(btn);
});
});
panel.appendChild(panelContent);
document.body.appendChild(panel);
makeElementDraggable(panel, header);
return panel;
}
// Функция для создания кнопок
function createButton(text, onClick) {
const button = document.createElement('button');
button.textContent = text;
button.className = 'custom-button';
button.onclick = onClick;
return button;
}
// Создание и отображение панелей
function showPanels() {
const panelsConfig = [
{
title: 'Panel 1',
id: 'custom-panel-1',
categories: [
{
title: 'Category 1',
buttons: [
{ text: 'Button 1', action: () => alert('Button 1 clicked') },
{ text: 'Button 2', action: () => alert('Button 2 clicked') }
]
},
{
title: 'Category 2',
buttons: [
{ text: 'Button 3', action: () => alert('Button 3 clicked') },
{ text: 'Button 4', action: () => alert('Button 4 clicked') }
]
}
]
},
{
title: 'Panel 2',
id: 'custom-panel-2',
categories: [
{
title: 'General',
buttons: [
{ text: 'General 1', action: () => alert('General 1 clicked') },
{ text: 'General 2', action: () => alert('General 2 clicked') }
]
}
]
}
];
panelsConfig.forEach(config => {
const panel = createPanel(config.title, config.id, config.categories);
panel.style.display = 'block';
});
applyStyles();
}
// Скрытие панелей
function hidePanels() {
const panels = document.querySelectorAll('.custom-panel');
panels.forEach(panel => panel.style.display = 'none');
}
// Функция для создания выдвижной панели
function createSlidePanel() {
const slidePanel = document.createElement('div');
slidePanel.id = 'slide-panel';
slidePanel.className = 'slide-panel';
document.body.appendChild(slidePanel);
const closeButton = document.createElement('button');
closeButton.id = 'close-slide-panel';
closeButton.className = 'close-button';
closeButton.textContent = '✖';
closeButton.onclick = () => {
slidePanel.classList.remove('open');
document.getElementById('toggle-slide-panel').style.display = 'block';
};
slidePanel.appendChild(closeButton);
const toggleButton = document.createElement('button');
toggleButton.id = 'toggle-slide-panel';
toggleButton.className = 'toggle-button';
toggleButton.textContent = '☰';
toggleButton.onclick = () => {
slidePanel.classList.toggle('open');
toggleButton.style.display = 'none';
closeButton.style.display = 'block';
};
document.body.appendChild(toggleButton);
const panelButtons = document.createElement('div');
panelButtons.className = 'panel-buttons';
slidePanel.appendChild(panelButtons);
const panel1Button = createButton('Show Panel 1', () => togglePanel('custom-panel-1'));
const panel2Button = createButton('Show Panel 2', () => togglePanel('custom-panel-2'));
panelButtons.appendChild(panel1Button);
panelButtons.appendChild(panel2Button);
createStyleCustomizer(slidePanel);
}
// Функция для переключения видимости панелей
function togglePanel(panelId) {
const panel = document.getElementById(panelId);
if (panel) {
panel.style.display = panel.style.display === 'block' ? 'none' : 'block';
}
}
// Функция для создания кастомизатора стилей
function createStyleCustomizer(parentElement) {
const customizer = document.createElement('div');
customizer.className = 'style-customizer';
parentElement.appendChild(customizer);
const styleSections = [
{ name: 'Panel Background Color', key: 'panelBackgroundColor', type: 'color' },
{ name: 'Panel Header Color', key: 'panelHeaderColor', type: 'color' },
{ name: 'Panel Header Text Color', key: 'panelHeaderTextColor', type: 'color' },
{ name: 'Button Background Color', key: 'buttonBackgroundColor', type: 'color' },
{ name: 'Button Text Color', key: 'buttonTextColor', type: 'color' },
{ name: 'Category Background Color', key: 'categoryBackgroundColor', type: 'color' }, /* Новый параметр */
{ name: 'Border Radius', key: 'borderRadius', type: 'range', min: 0, max: 50, step: 1 }
];
styleSections.forEach(section => {
const sectionDiv = document.createElement('div');
sectionDiv.className = 'style-section';
const label = document.createElement('label');
label.textContent = section.name;
sectionDiv.appendChild(label);
const input = document.createElement('input');
input.type = section.type;
input.value = getStyles()[section.key];
if (section.type === 'range') {
input.min = section.min;
input.max = section.max;
input.step = section.step;
}
input.onchange = (e) => {
const newStyles = getStyles();
newStyles[section.key] = section.type === 'range' ? `${e.target.value}px` : e.target.value;
setStyles(newStyles);
};
sectionDiv.appendChild(input);
customizer.appendChild(sectionDiv);
});
}
// Функция для перемещения элементов
function makeElementDraggable(element, handle) {
handle.onmousedown = function(e) {
e.preventDefault();
let shiftX = e.clientX - element.getBoundingClientRect().left;
let shiftY = e.clientY - element.getBoundingClientRect().top;
function moveAt(pageX, pageY) {
element.style.left = pageX - shiftX + 'px';
element.style.top = pageY - shiftY + 'px';
}
moveAt(e.pageX, e.pageY);
function onMouseMove(e) {
moveAt(e.pageX, e.pageY);
}
document.addEventListener('mousemove', onMouseMove);
handle.onmouseup = function() {
document.removeEventListener('mousemove', onMouseMove);
handle.onmouseup = null;
};
};
handle.ondragstart = function() {
return false;
};
}
// Запуск скрипта
setScriptActive(isScriptActive());
})();