mirror of
https://github.com/modernuo/ModernUO
synced 2026-08-11 22:23:06 -04:00
591 lines
18 KiB
HTML
591 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="description" content="In-game commands for the Ultima Online Server Emulator ModernUO">
|
|
<meta name="author" content="Kamron Batman">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<link rel="icon" href="https://modernuo.com/branding/favicon.png">
|
|
<title>ModernUO Commands</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;500;700&display=swap" rel="stylesheet">
|
|
<script src="https://cdn.tailwindcss.com/3.4.1?plugins=typography@0.5.10"></script>
|
|
<script>
|
|
tailwind.config = {
|
|
theme: {
|
|
colors: {
|
|
inherit: "inherit",
|
|
current: "currentColor",
|
|
transparent: "transparent",
|
|
black: "#000",
|
|
white: "#fff",
|
|
counselor: "rgb(80, 80, 200)",
|
|
gamemaster: "rgb(200, 128, 112)",
|
|
seer: "rgb(128, 168, 128)",
|
|
administrator: "rgb(0, 152, 136)",
|
|
developer: "rgb(112, 88, 160)",
|
|
owner: "rgb(208, 144, 0)",
|
|
"modern-black": "#212121",
|
|
"modern-black-hover": "#2F2F2F",
|
|
"modern-dark-black": "#1A1A1A",
|
|
gold: {
|
|
50: "#fbf3ee",
|
|
100: "#f8e9dd",
|
|
200: "#f0d9bd",
|
|
300: "#e8cea1",
|
|
400: "#dfc688",
|
|
500: "#d5bf74",
|
|
600: "#cab664",
|
|
700: "#bdab58",
|
|
800: "#b09f4f",
|
|
900: "#a29147",
|
|
},
|
|
slate: {
|
|
50: "#f8fafc",
|
|
100: "#f1f5f9",
|
|
200: "#e2e8f0",
|
|
300: "#cbd5e1",
|
|
400: "#94a3b8",
|
|
500: "#64748b",
|
|
600: "#475569",
|
|
700: "#334155",
|
|
800: "#1e293b",
|
|
900: "#0f172a",
|
|
950: "#020617"
|
|
},
|
|
gray: {
|
|
50: "#f9fafb",
|
|
100: "#f3f4f6",
|
|
200: "#e5e7eb",
|
|
300: "#d1d5db",
|
|
400: "#9ca3af",
|
|
500: "#6b7280",
|
|
600: "#4b5563",
|
|
700: "#374151",
|
|
800: "#1f2937",
|
|
900: "#111827",
|
|
950: "#030712"
|
|
},
|
|
zinc: {
|
|
50: "#fafafa",
|
|
100: "#f4f4f5",
|
|
200: "#e4e4e7",
|
|
300: "#d4d4d8",
|
|
400: "#a1a1aa",
|
|
500: "#71717a",
|
|
600: "#52525b",
|
|
700: "#3f3f46",
|
|
800: "#27272a",
|
|
900: "#18181b",
|
|
950: "#09090b"
|
|
},
|
|
neutral: {
|
|
50: "#fafafa",
|
|
100: "#f5f5f5",
|
|
200: "#e5e5e5",
|
|
300: "#d4d4d4",
|
|
400: "#a3a3a3",
|
|
500: "#737373",
|
|
600: "#525252",
|
|
700: "#404040",
|
|
800: "#262626",
|
|
900: "#171717",
|
|
950: "#0a0a0a"
|
|
},
|
|
stone: {
|
|
50: "#fafaf9",
|
|
100: "#f5f5f4",
|
|
200: "#e7e5e4",
|
|
300: "#d6d3d1",
|
|
400: "#a8a29e",
|
|
500: "#78716c",
|
|
600: "#57534e",
|
|
700: "#44403c",
|
|
800: "#292524",
|
|
900: "#1c1917",
|
|
950: "#0c0a09"
|
|
},
|
|
red: {
|
|
50: "#fef2f2",
|
|
100: "#fee2e2",
|
|
200: "#fecaca",
|
|
300: "#fca5a5",
|
|
400: "#f87171",
|
|
500: "#ef4444",
|
|
600: "#dc2626",
|
|
700: "#b91c1c",
|
|
800: "#991b1b",
|
|
900: "#7f1d1d",
|
|
950: "#450a0a"
|
|
},
|
|
orange: {
|
|
50: "#fff7ed",
|
|
100: "#ffedd5",
|
|
200: "#fed7aa",
|
|
300: "#fdba74",
|
|
400: "#fb923c",
|
|
500: "#f97316",
|
|
600: "#ea580c",
|
|
700: "#c2410c",
|
|
800: "#9a3412",
|
|
900: "#7c2d12",
|
|
950: "#431407"
|
|
},
|
|
amber: {
|
|
50: "#fffbeb",
|
|
100: "#fef3c7",
|
|
200: "#fde68a",
|
|
300: "#fcd34d",
|
|
400: "#fbbf24",
|
|
500: "#f59e0b",
|
|
600: "#d97706",
|
|
700: "#b45309",
|
|
800: "#92400e",
|
|
900: "#78350f",
|
|
950: "#451a03"
|
|
},
|
|
yellow: {
|
|
50: "#fefce8",
|
|
100: "#fef9c3",
|
|
200: "#fef08a",
|
|
300: "#fde047",
|
|
400: "#facc15",
|
|
500: "#eab308",
|
|
600: "#ca8a04",
|
|
700: "#a16207",
|
|
800: "#854d0e",
|
|
900: "#713f12",
|
|
950: "#422006"
|
|
},
|
|
lime: {
|
|
50: "#f7fee7",
|
|
100: "#ecfccb",
|
|
200: "#d9f99d",
|
|
300: "#bef264",
|
|
400: "#a3e635",
|
|
500: "#84cc16",
|
|
600: "#65a30d",
|
|
700: "#4d7c0f",
|
|
800: "#3f6212",
|
|
900: "#365314",
|
|
950: "#1a2e05"
|
|
},
|
|
green: {
|
|
50: "#f0fdf4",
|
|
100: "#dcfce7",
|
|
200: "#bbf7d0",
|
|
300: "#86efac",
|
|
400: "#4ade80",
|
|
500: "#22c55e",
|
|
600: "#16a34a",
|
|
700: "#15803d",
|
|
800: "#166534",
|
|
900: "#14532d",
|
|
950: "#052e16"
|
|
},
|
|
emerald: {
|
|
50: "#ecfdf5",
|
|
100: "#d1fae5",
|
|
200: "#a7f3d0",
|
|
300: "#6ee7b7",
|
|
400: "#34d399",
|
|
500: "#10b981",
|
|
600: "#059669",
|
|
700: "#047857",
|
|
800: "#065f46",
|
|
900: "#064e3b",
|
|
950: "#022c22"
|
|
},
|
|
teal: {
|
|
50: "#f0fdfa",
|
|
100: "#ccfbf1",
|
|
200: "#99f6e4",
|
|
300: "#5eead4",
|
|
400: "#2dd4bf",
|
|
500: "#14b8a6",
|
|
600: "#0d9488",
|
|
700: "#0f766e",
|
|
800: "#115e59",
|
|
900: "#134e4a",
|
|
950: "#042f2e"
|
|
},
|
|
cyan: {
|
|
50: "#ecfeff",
|
|
100: "#cffafe",
|
|
200: "#a5f3fc",
|
|
300: "#67e8f9",
|
|
400: "#22d3ee",
|
|
500: "#06b6d4",
|
|
600: "#0891b2",
|
|
700: "#0e7490",
|
|
800: "#155e75",
|
|
900: "#164e63",
|
|
950: "#083344"
|
|
},
|
|
sky: {
|
|
50: "#f0f9ff",
|
|
100: "#e0f2fe",
|
|
200: "#bae6fd",
|
|
300: "#7dd3fc",
|
|
400: "#38bdf8",
|
|
500: "#0ea5e9",
|
|
600: "#0284c7",
|
|
700: "#0369a1",
|
|
800: "#075985",
|
|
900: "#0c4a6e",
|
|
950: "#082f49"
|
|
},
|
|
blue: {
|
|
50: "#eff6ff",
|
|
100: "#dbeafe",
|
|
200: "#bfdbfe",
|
|
300: "#93c5fd",
|
|
400: "#60a5fa",
|
|
500: "#3b82f6",
|
|
600: "#2563eb",
|
|
700: "#1d4ed8",
|
|
800: "#1e40af",
|
|
900: "#1e3a8a",
|
|
950: "#172554"
|
|
},
|
|
indigo: {
|
|
50: "#eef2ff",
|
|
100: "#e0e7ff",
|
|
200: "#c7d2fe",
|
|
300: "#a5b4fc",
|
|
400: "#818cf8",
|
|
500: "#6366f1",
|
|
600: "#4f46e5",
|
|
700: "#4338ca",
|
|
800: "#3730a3",
|
|
900: "#312e81",
|
|
950: "#1e1b4b"
|
|
},
|
|
violet: {
|
|
50: "#f5f3ff",
|
|
100: "#ede9fe",
|
|
200: "#ddd6fe",
|
|
300: "#c4b5fd",
|
|
400: "#a78bfa",
|
|
500: "#8b5cf6",
|
|
600: "#7c3aed",
|
|
700: "#6d28d9",
|
|
800: "#5b21b6",
|
|
900: "#4c1d95",
|
|
950: "#2e1065"
|
|
},
|
|
purple: {
|
|
50: "#faf5ff",
|
|
100: "#f3e8ff",
|
|
200: "#e9d5ff",
|
|
300: "#d8b4fe",
|
|
400: "#c084fc",
|
|
500: "#a855f7",
|
|
600: "#9333ea",
|
|
700: "#7e22ce",
|
|
800: "#6b21a8",
|
|
900: "#581c87",
|
|
950: "#3b0764"
|
|
},
|
|
fuchsia: {
|
|
50: "#fdf4ff",
|
|
100: "#fae8ff",
|
|
200: "#f5d0fe",
|
|
300: "#f0abfc",
|
|
400: "#e879f9",
|
|
500: "#d946ef",
|
|
600: "#c026d3",
|
|
700: "#a21caf",
|
|
800: "#86198f",
|
|
900: "#701a75",
|
|
950: "#4a044e"
|
|
},
|
|
pink: {
|
|
50: "#fdf2f8",
|
|
100: "#fce7f3",
|
|
200: "#fbcfe8",
|
|
300: "#f9a8d4",
|
|
400: "#f472b6",
|
|
500: "#ec4899",
|
|
600: "#db2777",
|
|
700: "#be185d",
|
|
800: "#9d174d",
|
|
900: "#831843",
|
|
950: "#500724"
|
|
},
|
|
rose: {
|
|
50: "#fff1f2",
|
|
100: "#ffe4e6",
|
|
200: "#fecdd3",
|
|
300: "#fda4af",
|
|
400: "#fb7185",
|
|
500: "#f43f5e",
|
|
600: "#e11d48",
|
|
700: "#be123c",
|
|
800: "#9f1239",
|
|
900: "#881337",
|
|
950: "#4c0519"
|
|
}
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
</head>
|
|
|
|
<body class="bg-modern-dark-black text-gold-300 max-w-4xl">
|
|
<div id="app" class="min-h-screen p-2">
|
|
<div class="max-w-4xl mx-auto">
|
|
<div class="bg-modern-black p-6 rounded-lg shadow-lg">
|
|
<!-- Logo -->
|
|
<div class="flex justify-center">
|
|
<img src="https://modernuo.com/branding/logo.svg" class="h-24 w-24">
|
|
</div>
|
|
<!-- Title -->
|
|
<h1 class="text-center text-white text-3xl opacity-70 p-2 pb-12 font-light">ModernUO Commands</h1>
|
|
<!-- Tabs -->
|
|
<ul id="tabs" class="flex mb-0 list-none flex-wrap pt-3 pb-4 flex-row place-content-center">
|
|
<!-- JavaScript will populate tabs here -->
|
|
</ul>
|
|
<!-- Tab Content -->
|
|
<div id="tabContent" class="border-t border-gold-500">
|
|
<!-- JavaScript will populate tab content here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Toolip -->
|
|
<div id="tooltip" class="absolute p-2 bg-modern-black text-white rounded-md shadow-lg max-w-xs md:max-w-sm lg:max-w-md xl:max-w-lg hidden"></div>
|
|
<span id="commands" style="display:none; visibility: hidden">
|
|
<!-- COMMANDS -->
|
|
</span>
|
|
<span id="modifiers" style="display:none; visibility: hidden">
|
|
<!-- MODIFIERS -->
|
|
</span>
|
|
<script>
|
|
/*
|
|
Modifiers Structure:
|
|
{
|
|
"modifier": {
|
|
name: "Modifier",
|
|
usage: "[modifier <command> [condition]",
|
|
description: "long description. Optional condition arguments can further restrict the set of objects."
|
|
}
|
|
}
|
|
*/
|
|
let allModifiers = {};
|
|
|
|
try {
|
|
allModifiers = JSON.parse(document.querySelectorAll('#modifiers')[0].innerText.trim() || {});
|
|
} catch {}
|
|
|
|
/*
|
|
Commands Structure:
|
|
{
|
|
"AccessLevel": [
|
|
{
|
|
command: "CommandName",
|
|
aliases: ["cn"],
|
|
usage: "CommandName <options>",
|
|
modifiers: ["Global", "Online", "Region", "Multi", "Area", "Self"],
|
|
description: "Long Description"
|
|
}
|
|
]
|
|
}
|
|
*/
|
|
let commands = {};
|
|
|
|
try {
|
|
commands = JSON.parse(document.querySelectorAll('#commands')[0].innerText.trim() || {});
|
|
} catch {}
|
|
|
|
function createTab(name, selected) {
|
|
const tab = document.createElement("li");
|
|
tab.className = "mr-2 last:mr-0 flex-auto text-center";
|
|
const tabLink = document.createElement("a");
|
|
tabLink.href = "#";
|
|
tabLink.className = "text-xs font-bold uppercase px-5 py-3 rounded block leading-normal text-white bg-modern-black hover:bg-modern-black-hover hover:bg-opacity-70 transition-background-color ease-in-out duration-700";
|
|
|
|
tabLink.innerText = name;
|
|
tabLink.onclick = function (e) {
|
|
e.preventDefault();
|
|
document.querySelectorAll("#tabs a").forEach(tab => {
|
|
tab.classList.remove("bg-gold-500", "text-modern-black");
|
|
tab.classList.add("bg-modern-black", "text-white", "hover:bg-modern-black-hover", "hover:bg-opacity-70");
|
|
});
|
|
tabLink.classList.remove("bg-gold-900", "text-white", "hover:bg-modern-black-hover", "hover:bg-opacity-70");
|
|
tabLink.classList.add("bg-gold-500", "text-modern-black");
|
|
loadTabContent(name);
|
|
};
|
|
|
|
if (selected) {
|
|
tabLink.classList.remove("bg-gold-900", "text-white", "hover:bg-modern-black-hover", "hover:bg-opacity-70");
|
|
tabLink.classList.add("bg-gold-500", "text-modern-black");
|
|
}
|
|
tab.appendChild(tabLink);
|
|
return tab;
|
|
}
|
|
|
|
function createTable(tabData) {
|
|
let table = `<table class="min-w-full border-collapse table-fixed"><tbody>`;
|
|
tabData.forEach(item => {
|
|
table += `
|
|
<tr class="border-b border-gold-500">
|
|
<td class="xs:px-2 py-4 text-sm font-medium text-gold-500 w-1/3 m-w-1/2"><p class="break-all">${item.name}</p></td>
|
|
<td class="text-sm text-gold-900 pl-4 py-4">
|
|
`;
|
|
|
|
const usageParts = (item.usage || item.name).split(" ");
|
|
const usage = `${usageParts[0]} <span class='text-gold-700 font-light'>${usageParts.slice(1).join(" ")}</span>`;
|
|
|
|
table += `<div class="text-white">Usage: <span class="font-bold text-gold-500">${usage}</span></div>`;
|
|
|
|
if (item.aliases && item.aliases.length > 0) {
|
|
table += `<div class="text-white">Aliases: <span class="text-gold-500">${item.aliases.join(", ")}</span></div>`;
|
|
}
|
|
|
|
if (item.modifiers && item.modifiers.length > 0) {
|
|
table += "<div>";
|
|
item.modifiers.forEach((mod, index) => {
|
|
table += `<span class="modifier cursor-pointer italic text-gold-300"
|
|
data-modifier="${mod}"
|
|
data-command="${item.name}">${mod}</span>${index !== item.modifiers.length - 1 ? ", " : ""}`;
|
|
});
|
|
table += "</div>";
|
|
}
|
|
|
|
if (item.description) {
|
|
table += `<div class="text-white pt-2">${item.description}</div>`;
|
|
}
|
|
table += "</td></tr>";
|
|
});
|
|
table += "</tbody></table>";
|
|
return table;
|
|
}
|
|
|
|
function loadTabContent(tabName) {
|
|
const tabContent = document.getElementById("tabContent");
|
|
tabContent.innerHTML = createTable(commands[tabName]);
|
|
|
|
// Add event listeners to modifiers
|
|
const modifiers = document.querySelectorAll(".modifier");
|
|
modifiers.forEach(el => {
|
|
el.addEventListener("mouseenter", (event) => {
|
|
showTooltip(el, event);
|
|
});
|
|
|
|
el.addEventListener("touchstart", (event) => {
|
|
showTooltip(el, event, true);
|
|
});
|
|
|
|
el.addEventListener("mouseleave", hideTooltip);
|
|
// el.addEventListener('touchend', hideTooltip);
|
|
});
|
|
}
|
|
|
|
function initTabs() {
|
|
const tabsContainer = document.getElementById("tabs");
|
|
Object.keys(commands).forEach((tabName, index) => {
|
|
const tab = createTab(tabName, index === 0);
|
|
tabsContainer.appendChild(tab);
|
|
if (index === 0) { // Load first tab content by default
|
|
loadTabContent(tabName);
|
|
}
|
|
});
|
|
}
|
|
|
|
let currentShownEl = null;
|
|
|
|
// Function to show the tooltip
|
|
function showTooltip(el, event, isTouchEvent) {
|
|
const tooltip = document.getElementById('tooltip');
|
|
|
|
if (el === currentShownEl && (tooltip.classList.contains('invisible') || !tooltip.classList.contains('hidden'))) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
|
|
currentShownEl = el;
|
|
const mod = allModifiers[el.dataset.modifier];
|
|
const command = el.dataset.command.toLowerCase()
|
|
|
|
let aliases = "";
|
|
if (mod.accessors.length > 1) {
|
|
aliases = `<p class="text-white">Aliases: <span class="text-gold-500">${mod.accessors.slice(1).join(", ")}</span></p>`;
|
|
}
|
|
|
|
const usageParts = (mod.usage || mod.accessors[0]).split(" ");
|
|
const usage = `${usageParts[0]} <span class='text-gold-700 font-light'>${usageParts.slice(1).join(" ")}</span>`
|
|
.replace("<command>", command);
|
|
|
|
tooltip.innerHTML = `
|
|
<p class="font-bold text-gold-500">${mod.accessors[0]}</p>
|
|
<p class="text-white">Access Level: <span class="text-${mod.accessLevel.toLowerCase()}">${mod.accessLevel}</span></p>
|
|
${aliases}
|
|
<p class="text-white">Usage: <span class="font-bold text-gold-500">${usage}</span></p>
|
|
<p class="italic text-white pt-2">${mod.description}</p>
|
|
`;
|
|
|
|
// Make it visible to the DOM so we can get size calculations
|
|
tooltip.classList.add('invisible');
|
|
tooltip.classList.remove('hidden');
|
|
|
|
const srcRect = event.target.getBoundingClientRect();
|
|
|
|
// Calculate the size of the tooltip for positioning
|
|
const tooltipRect = tooltip.getBoundingClientRect();
|
|
const offset = 20; // Offset from the cursor for the tooltip
|
|
|
|
const startX = window.scrollX + srcRect.x;
|
|
const startY = window.scrollY + srcRect.y;
|
|
|
|
// Initial horizontal position (with viewport width check for side overflow)
|
|
let leftPosition = startX + offset;
|
|
if (leftPosition + tooltipRect.width > document.documentElement.clientWidth) {
|
|
leftPosition = document.documentElement.clientWidth - tooltipRect.width - offset;
|
|
}
|
|
|
|
// Determine vertical position based on available space
|
|
let topPosition;
|
|
const spaceAbove = startY - window.scrollY;
|
|
const spaceBelow = window.innerHeight - spaceAbove;
|
|
|
|
// Check if there's enough space below the cursor; otherwise, flip above
|
|
if (spaceBelow > tooltipRect.height + offset) {
|
|
topPosition = startY + offset;
|
|
} else if (spaceAbove > tooltipRect.height + offset) {
|
|
topPosition = startY - tooltipRect.height - offset;
|
|
} else {
|
|
// If neither above nor below has enough space, default to below and adjust to within viewport
|
|
topPosition = Math.max(window.scrollY + offset, startY - (tooltipRect.height / 2));
|
|
}
|
|
|
|
// Apply the calculated positions
|
|
tooltip.style.left = `${leftPosition}px`;
|
|
tooltip.style.top = `${topPosition}px`;
|
|
tooltip.classList.remove('invisible');
|
|
|
|
if (isTouchEvent) {
|
|
// Delay hiding tooltip to allow it to be seen
|
|
setTimeout(() => {
|
|
document.addEventListener('touchstart', hideTooltipOnNextTouch, { passive: false });
|
|
}, 10);
|
|
}
|
|
}
|
|
|
|
// Function to hide the tooltip
|
|
function hideTooltip() {
|
|
document.removeEventListener('touchstart', hideTooltipOnNextTouch);
|
|
const tooltip = document.getElementById("tooltip");
|
|
tooltip.classList.add("hidden");
|
|
}
|
|
|
|
function hideTooltipOnNextTouch(event) {
|
|
// Check if the touch is outside the tooltip, if so, hide the tooltip
|
|
if (event.target !== currentShownEl && !event.target.matches('#tooltip, #tooltip *')) {
|
|
hideTooltip();
|
|
} else { event.preventDefault(); }
|
|
}
|
|
|
|
initTabs();
|
|
</script>
|
|
</body>
|
|
</html>
|