Add Teleport/Effects options to player list
This commit is contained in:
168
public/app.js
168
public/app.js
@ -84,7 +84,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
backupBtn: document.getElementById('backupBtn'),
|
backupBtn: document.getElementById('backupBtn'),
|
||||||
modListSearch: document.getElementById('modListSearch'),
|
modListSearch: document.getElementById('modListSearch'),
|
||||||
clearModListSearch: document.getElementById('clearModListSearch'),
|
clearModListSearch: document.getElementById('clearModListSearch'),
|
||||||
modListPagination: document.getElementById('modListPagination')
|
modListPagination: document.getElementById('modListPagination'),
|
||||||
|
teleportModal: document.getElementById('teleportModal'),
|
||||||
|
teleportPlayerName: document.getElementById('teleportPlayerName'),
|
||||||
|
teleportDestination: document.getElementById('teleportDestination'),
|
||||||
|
teleportForm: document.getElementById('teleportForm'),
|
||||||
|
effectModal: document.getElementById('effectModal'),
|
||||||
|
effectPlayerName: document.getElementById('effectPlayerName'),
|
||||||
|
effectSelect: document.getElementById('effectSelect'),
|
||||||
|
effectForm: document.getElementById('effectForm')
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadouts = {
|
const loadouts = {
|
||||||
@ -168,7 +176,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
geyserStatus: '',
|
geyserStatus: '',
|
||||||
sftpStatus: '',
|
sftpStatus: '',
|
||||||
activeNotifications: new Map(),
|
activeNotifications: new Map(),
|
||||||
allMods: []
|
allMods: [],
|
||||||
|
currentPlayers: []
|
||||||
};
|
};
|
||||||
|
|
||||||
function showNotification(message, type = 'loading', key = null) {
|
function showNotification(message, type = 'loading', key = null) {
|
||||||
@ -646,6 +655,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
if (message.type === 'list-players' && message.data?.players) {
|
if (message.type === 'list-players' && message.data?.players) {
|
||||||
const players = message.data.players || [];
|
const players = message.data.players || [];
|
||||||
|
state.currentPlayers = players;
|
||||||
|
const isSinglePlayer = players.length <= 1;
|
||||||
const playerListHtml = players.length > 0
|
const playerListHtml = players.length > 0
|
||||||
? players.map(player => `
|
? players.map(player => `
|
||||||
<div class="flex items-center space-x-4 mb-2">
|
<div class="flex items-center space-x-4 mb-2">
|
||||||
@ -653,6 +664,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<button class="tell-player bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded text-sm" data-player="${player}">Tell</button>
|
<button class="tell-player bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded text-sm" data-player="${player}">Tell</button>
|
||||||
<button class="give-player bg-green-600 hover:bg-green-700 px-2 py-1 rounded text-sm" data-player="${player}">Give</button>
|
<button class="give-player bg-green-600 hover:bg-green-700 px-2 py-1 rounded text-sm" data-player="${player}">Give</button>
|
||||||
|
<button class="teleport-player bg-cyan-600 hover:bg-cyan-700 px-2 py-1 rounded text-sm ${isSinglePlayer ? 'opacity-50 cursor-not-allowed' : ''}" data-player="${player}" ${isSinglePlayer ? 'disabled' : ''}>Teleport</button>
|
||||||
|
<button class="effect-player bg-teal-600 hover:bg-teal-700 px-2 py-1 rounded text-sm" data-player="${player}">Effect</button>
|
||||||
<button class="op-player bg-purple-600 hover:bg-purple-700 px-2 py-1 rounded text-sm" data-player="${player}">Op</button>
|
<button class="op-player bg-purple-600 hover:bg-purple-700 px-2 py-1 rounded text-sm" data-player="${player}">Op</button>
|
||||||
<button class="deop-player bg-purple-600 hover:bg-purple-700 px-2 py-1 rounded text-sm" data-player="${player}">Deop</button>
|
<button class="deop-player bg-purple-600 hover:bg-purple-700 px-2 py-1 rounded text-sm" data-player="${player}">Deop</button>
|
||||||
<button class="kick-player bg-red-600 hover:bg-red-700 px-2 py-1 rounded text-sm" data-player="${player}">Kick</button>
|
<button class="kick-player bg-red-600 hover:bg-red-700 px-2 py-1 rounded text-sm" data-player="${player}">Kick</button>
|
||||||
@ -664,6 +677,66 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
if (state.playerList !== playerListHtml && elements.playerList) {
|
if (state.playerList !== playerListHtml && elements.playerList) {
|
||||||
elements.playerList.innerHTML = playerListHtml;
|
elements.playerList.innerHTML = playerListHtml;
|
||||||
state.playerList = playerListHtml;
|
state.playerList = playerListHtml;
|
||||||
|
|
||||||
|
document.querySelectorAll('.tell-player').forEach(button => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
const player = button.getAttribute('data-player').trim();
|
||||||
|
if (!player) {
|
||||||
|
showNotification('Invalid player name.', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elements.tellPlayerName.textContent = player;
|
||||||
|
elements.tellMessage.value = '';
|
||||||
|
elements.tellModal.classList.remove('hidden');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.give-player').forEach(button => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
const player = button.getAttribute('data-player').trim();
|
||||||
|
if (!player) {
|
||||||
|
showNotification('Invalid player name.', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elements.givePlayerName.textContent = player;
|
||||||
|
elements.loadoutSelect.value = 'custom';
|
||||||
|
elements.customGiveFields.classList.remove('hidden');
|
||||||
|
resetItemFields();
|
||||||
|
elements.giveModal.classList.remove('hidden');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.teleport-player').forEach(button => {
|
||||||
|
if (!button.disabled) {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
const player = button.getAttribute('data-player').trim();
|
||||||
|
if (!player) {
|
||||||
|
showNotification('Invalid player name.', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elements.teleportPlayerName.textContent = player;
|
||||||
|
elements.teleportDestination.innerHTML = state.currentPlayers
|
||||||
|
.filter(p => p !== player)
|
||||||
|
.map(p => `<option value="${p}">${p}</option>`)
|
||||||
|
.join('');
|
||||||
|
elements.teleportModal.classList.remove('hidden');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.effect-player').forEach(button => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
const player = button.getAttribute('data-player').trim();
|
||||||
|
if (!player) {
|
||||||
|
showNotification('Invalid player name.', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elements.effectPlayerName.textContent = player;
|
||||||
|
elements.effectSelect.value = 'speed:30:1';
|
||||||
|
elements.effectModal.classList.remove('hidden');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
document.querySelectorAll('.kick-player').forEach(button => {
|
document.querySelectorAll('.kick-player').forEach(button => {
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
const player = button.getAttribute('data-player').trim();
|
const player = button.getAttribute('data-player').trim();
|
||||||
@ -791,34 +864,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll('.tell-player').forEach(button => {
|
|
||||||
button.addEventListener('click', () => {
|
|
||||||
const player = button.getAttribute('data-player').trim();
|
|
||||||
if (!player) {
|
|
||||||
showNotification('Invalid player name.', 'error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
elements.tellPlayerName.textContent = player;
|
|
||||||
elements.tellMessage.value = '';
|
|
||||||
elements.tellModal.classList.remove('hidden');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
document.querySelectorAll('.give-player').forEach(button => {
|
|
||||||
button.addEventListener('click', () => {
|
|
||||||
const player = button.getAttribute('data-player').trim();
|
|
||||||
if (!player) {
|
|
||||||
showNotification('Invalid player name.', 'error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
elements.givePlayerName.textContent = player;
|
|
||||||
elements.loadoutSelect.value = 'custom';
|
|
||||||
elements.customGiveFields.classList.remove('hidden');
|
|
||||||
resetItemFields();
|
|
||||||
elements.giveModal.classList.remove('hidden');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1052,7 +1097,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
renderModList();
|
renderModList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debounce function to limit the rate of search execution
|
|
||||||
function debounce(func, wait) {
|
function debounce(func, wait) {
|
||||||
let timeout;
|
let timeout;
|
||||||
return function executedFunction(...args) {
|
return function executedFunction(...args) {
|
||||||
@ -1204,6 +1248,49 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function sendTeleportCommand() {
|
||||||
|
const player = elements.teleportPlayerName.textContent.trim();
|
||||||
|
const destination = elements.teleportDestination.value.trim();
|
||||||
|
if (!player || !destination) {
|
||||||
|
showNotification('Source and destination players are required.', 'error', 'teleport-error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const command = `tp ${player} ${destination}`;
|
||||||
|
const key = `action-teleport-player-${player}`;
|
||||||
|
const notification = showNotification(`Teleporting ${player} to ${destination}...`, 'loading', key);
|
||||||
|
const response = await wsRequest('/console', 'POST', { command });
|
||||||
|
updateNotification(notification, `Teleported ${player} to ${destination} successfully`, 'success', key);
|
||||||
|
elements.teleportModal.classList.add('hidden');
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Teleport ${player} error:`, error);
|
||||||
|
showNotification(`Failed to teleport ${player}: ${error.message}`, 'error', 'teleport-error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendEffectCommand() {
|
||||||
|
const player = elements.effectPlayerName.textContent.trim();
|
||||||
|
const effectData = elements.effectSelect.value.split(':');
|
||||||
|
const effect = effectData[0];
|
||||||
|
const duration = parseInt(effectData[1], 10);
|
||||||
|
const amplifier = parseInt(effectData[2], 10);
|
||||||
|
if (!player || !effect) {
|
||||||
|
showNotification('Player name and effect are required.', 'error', 'effect-error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const command = `effect give ${player} minecraft:${effect} ${duration} ${amplifier}`;
|
||||||
|
const key = `action-effect-player-${player}`;
|
||||||
|
const notification = showNotification(`Applying ${effect} to ${player}...`, 'loading', key);
|
||||||
|
const response = await wsRequest('/console', 'POST', { command });
|
||||||
|
updateNotification(notification, `Applied ${effect} to ${player} successfully`, 'success', key);
|
||||||
|
elements.effectModal.classList.add('hidden');
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Apply effect to ${player} error:`, error);
|
||||||
|
showNotification(`Failed to apply effect to ${player}: ${error.message}`, 'error', 'effect-error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addItemField() {
|
function addItemField() {
|
||||||
const itemList = elements.itemList;
|
const itemList = elements.itemList;
|
||||||
const itemEntry = document.createElement('div');
|
const itemEntry = document.createElement('div');
|
||||||
@ -1637,6 +1724,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
elements.giveModal.classList.add('hidden');
|
elements.giveModal.classList.add('hidden');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
elements.teleportModal.querySelector('.modal-close').addEventListener('click', () => {
|
||||||
|
elements.teleportModal.classList.add('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
|
elements.effectModal.querySelector('.modal-close').addEventListener('click', () => {
|
||||||
|
elements.effectModal.classList.add('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
elements.loadoutSelect.addEventListener('change', () => {
|
elements.loadoutSelect.addEventListener('change', () => {
|
||||||
const isCustom = elements.loadoutSelect.value === 'custom';
|
const isCustom = elements.loadoutSelect.value === 'custom';
|
||||||
elements.customGiveFields.classList.toggle('hidden', !isCustom);
|
elements.customGiveFields.classList.toggle('hidden', !isCustom);
|
||||||
@ -1659,6 +1754,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
elements.teleportForm.addEventListener('submit', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
sendTeleportCommand();
|
||||||
|
});
|
||||||
|
|
||||||
|
elements.effectForm.addEventListener('submit', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
sendEffectCommand();
|
||||||
|
});
|
||||||
|
|
||||||
elements.tellForm.addEventListener('submit', (e) => {
|
elements.tellForm.addEventListener('submit', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
sendTellMessage();
|
sendTellMessage();
|
||||||
@ -1684,7 +1789,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
elements.clearModListSearch.addEventListener('click', clearModListSearch);
|
elements.clearModListSearch.addEventListener('click', clearModListSearch);
|
||||||
|
|
||||||
// Debounced search for installed mods
|
|
||||||
const debouncedModListSearch = debounce((query) => {
|
const debouncedModListSearch = debounce((query) => {
|
||||||
modListSearchQuery = query.trim();
|
modListSearchQuery = query.trim();
|
||||||
modListCurrentPage = 1;
|
modListCurrentPage = 1;
|
||||||
|
@ -128,6 +128,7 @@
|
|||||||
min-width: 80px;
|
min-width: 80px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
font-family: 'Minecraft', sans-serif; /* Apply Minecraft font */
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-btn:hover:not(.disabled-btn) {
|
.control-btn:hover:not(.disabled-btn) {
|
||||||
@ -138,6 +139,60 @@
|
|||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Existing player button styles */
|
||||||
|
.tell-player {
|
||||||
|
@apply bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded text-sm;
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.give-player {
|
||||||
|
@apply bg-green-600 hover:bg-green-700 px-2 py-1 rounded text-sm;
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.op-player, .deop-player {
|
||||||
|
@apply bg-purple-600 hover:bg-purple-700 px-2 py-1 rounded text-sm;
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kick-player, .ban-player {
|
||||||
|
@apply bg-red-600 hover:bg-red-700 px-2 py-1 rounded text-sm;
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* New player button styles */
|
||||||
|
.teleport-player {
|
||||||
|
@apply bg-cyan-600 hover:bg-cyan-700 px-2 py-1 rounded text-sm;
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teleport-player:hover:not(.disabled-btn) {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.teleport-player:active:not(.disabled-btn) {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.effect-player {
|
||||||
|
@apply bg-teal-600 hover:bg-teal-700 px-2 py-1 rounded text-sm;
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.effect-player:hover:not(.disabled-btn) {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.effect-player:active:not(.disabled-btn) {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@ -228,6 +283,20 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure player buttons stack nicely on mobile */
|
||||||
|
.tell-player,
|
||||||
|
.give-player,
|
||||||
|
.teleport-player,
|
||||||
|
.effect-player,
|
||||||
|
.op-player,
|
||||||
|
.deop-player,
|
||||||
|
.kick-player,
|
||||||
|
.ban-player {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Additional styles */
|
/* Additional styles */
|
||||||
|
135
public/css/styles.min.css
vendored
135
public/css/styles.min.css
vendored
@ -21,6 +21,10 @@
|
|||||||
--color-yellow-700: oklch(55.4% 0.135 66.442);
|
--color-yellow-700: oklch(55.4% 0.135 66.442);
|
||||||
--color-green-600: oklch(62.7% 0.194 149.214);
|
--color-green-600: oklch(62.7% 0.194 149.214);
|
||||||
--color-green-700: oklch(52.7% 0.154 150.069);
|
--color-green-700: oklch(52.7% 0.154 150.069);
|
||||||
|
--color-teal-600: oklch(60% 0.118 184.704);
|
||||||
|
--color-teal-700: oklch(51.1% 0.096 186.391);
|
||||||
|
--color-cyan-600: oklch(60.9% 0.126 221.723);
|
||||||
|
--color-cyan-700: oklch(52% 0.105 223.128);
|
||||||
--color-blue-400: oklch(70.7% 0.165 254.624);
|
--color-blue-400: oklch(70.7% 0.165 254.624);
|
||||||
--color-blue-500: oklch(62.3% 0.214 259.815);
|
--color-blue-500: oklch(62.3% 0.214 259.815);
|
||||||
--color-blue-600: oklch(54.6% 0.245 262.881);
|
--color-blue-600: oklch(54.6% 0.245 262.881);
|
||||||
@ -401,6 +405,9 @@
|
|||||||
.bg-blue-600 {
|
.bg-blue-600 {
|
||||||
background-color: var(--color-blue-600);
|
background-color: var(--color-blue-600);
|
||||||
}
|
}
|
||||||
|
.bg-cyan-600 {
|
||||||
|
background-color: var(--color-cyan-600);
|
||||||
|
}
|
||||||
.bg-gray-600 {
|
.bg-gray-600 {
|
||||||
background-color: var(--color-gray-600);
|
background-color: var(--color-gray-600);
|
||||||
}
|
}
|
||||||
@ -422,6 +429,9 @@
|
|||||||
.bg-red-600 {
|
.bg-red-600 {
|
||||||
background-color: var(--color-red-600);
|
background-color: var(--color-red-600);
|
||||||
}
|
}
|
||||||
|
.bg-teal-600 {
|
||||||
|
background-color: var(--color-teal-600);
|
||||||
|
}
|
||||||
.bg-yellow-600 {
|
.bg-yellow-600 {
|
||||||
background-color: var(--color-yellow-600);
|
background-color: var(--color-yellow-600);
|
||||||
}
|
}
|
||||||
@ -511,6 +521,9 @@
|
|||||||
.text-white {
|
.text-white {
|
||||||
color: var(--color-white);
|
color: var(--color-white);
|
||||||
}
|
}
|
||||||
|
.opacity-50 {
|
||||||
|
opacity: 50%;
|
||||||
|
}
|
||||||
.shadow-lg {
|
.shadow-lg {
|
||||||
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||||
@ -522,6 +535,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hover\:bg-cyan-700 {
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
background-color: var(--color-cyan-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.hover\:bg-gray-700 {
|
.hover\:bg-gray-700 {
|
||||||
&:hover {
|
&:hover {
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
@ -550,6 +570,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hover\:bg-teal-700 {
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
background-color: var(--color-teal-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.hover\:bg-yellow-700 {
|
.hover\:bg-yellow-700 {
|
||||||
&:hover {
|
&:hover {
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
@ -699,6 +726,7 @@
|
|||||||
min-width: 80px;
|
min-width: 80px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
}
|
}
|
||||||
.control-btn:hover:not(.disabled-btn) {
|
.control-btn:hover:not(.disabled-btn) {
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
@ -706,6 +734,108 @@
|
|||||||
.control-btn:active:not(.disabled-btn) {
|
.control-btn:active:not(.disabled-btn) {
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
|
.tell-player {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
background-color: var(--color-blue-600);
|
||||||
|
padding-inline: calc(var(--spacing) * 2);
|
||||||
|
padding-block: calc(var(--spacing) * 1);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
background-color: var(--color-blue-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.give-player {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
background-color: var(--color-green-600);
|
||||||
|
padding-inline: calc(var(--spacing) * 2);
|
||||||
|
padding-block: calc(var(--spacing) * 1);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
background-color: var(--color-green-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.op-player, .deop-player {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
background-color: var(--color-purple-600);
|
||||||
|
padding-inline: calc(var(--spacing) * 2);
|
||||||
|
padding-block: calc(var(--spacing) * 1);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
background-color: var(--color-purple-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.kick-player, .ban-player {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
background-color: var(--color-red-600);
|
||||||
|
padding-inline: calc(var(--spacing) * 2);
|
||||||
|
padding-block: calc(var(--spacing) * 1);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
background-color: var(--color-red-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.teleport-player {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
background-color: var(--color-cyan-600);
|
||||||
|
padding-inline: calc(var(--spacing) * 2);
|
||||||
|
padding-block: calc(var(--spacing) * 1);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
background-color: var(--color-cyan-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.teleport-player:hover:not(.disabled-btn) {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
.teleport-player:active:not(.disabled-btn) {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
.effect-player {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
background-color: var(--color-teal-600);
|
||||||
|
padding-inline: calc(var(--spacing) * 2);
|
||||||
|
padding-block: calc(var(--spacing) * 1);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
background-color: var(--color-teal-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font-family: 'Minecraft', sans-serif;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.effect-player:hover:not(.disabled-btn) {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
.effect-player:active:not(.disabled-btn) {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
.modal {
|
.modal {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@ -779,6 +909,11 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
.tell-player, .give-player, .teleport-player, .effect-player, .op-player, .deop-player, .kick-player, .ban-player {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.bg-gray-800.p-6.rounded-lg.shadow-lg .grid {
|
.bg-gray-800.p-6.rounded-lg.shadow-lg .grid {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
@ -75,6 +75,45 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="teleportModal" class="modal hidden">
|
||||||
|
<div class="modal-content">
|
||||||
|
<button class="modal-close">×</button>
|
||||||
|
<h2 class="text-xl font-semibold mb-4">Teleport <span id="teleportPlayerName"></span></h2>
|
||||||
|
<form id="teleportForm">
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="teleportDestination" class="block text-sm font-medium mb-1">Select Destination Player</label>
|
||||||
|
<select id="teleportDestination" class="bg-gray-700 px-4 py-2 rounded text-white w-full">
|
||||||
|
<!-- Options populated dynamically -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded w-full">Teleport</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="effectModal" class="modal hidden">
|
||||||
|
<div class="modal-content">
|
||||||
|
<button class="modal-close">×</button>
|
||||||
|
<h2 class="text-xl font-semibold mb-4">Apply Effect to <span id="effectPlayerName"></span></h2>
|
||||||
|
<form id="effectForm">
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="effectSelect" class="block text-sm font-medium mb-1">Select Effect</label>
|
||||||
|
<select id="effectSelect" class="bg-gray-700 px-4 py-2 rounded text-white w-full">
|
||||||
|
<option value="speed:30:1">Speed (30s, Level 1)</option>
|
||||||
|
<option value="strength:30:1">Strength (30s, Level 1)</option>
|
||||||
|
<option value="regeneration:30:1">Regeneration (30s, Level 1)</option>
|
||||||
|
<option value="jump_boost:30:1">Jump Boost (30s, Level 1)</option>
|
||||||
|
<option value="invisibility:30:1">Invisibility (30s, Level 1)</option>
|
||||||
|
<option value="night_vision:60:1">Night Vision (60s, Level 1)</option>
|
||||||
|
<option value="fire_resistance:60:1">Fire Resistance (60s, Level 1)</option>
|
||||||
|
<option value="water_breathing:60:1">Water Breathing (60s, Level 1)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded w-full">Apply Effect</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="editPropertiesModal" class="modal hidden">
|
<div id="editPropertiesModal" class="modal hidden">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<button class="modal-close">×</button>
|
<button class="modal-close">×</button>
|
||||||
|
Reference in New Issue
Block a user