Refactor org web platform and remove legacy code
All checks were successful
Build Org Website / build (push) Successful in 39s

This commit is contained in:
gitea-actions
2026-07-30 11:29:20 +01:00
parent dc1ca5c00e
commit fe8acac707
74 changed files with 2776 additions and 3386 deletions

View File

@@ -0,0 +1,179 @@
(function (root) {
"use strict";
const Data = root.PrincessLimaData;
const Systems = root.PrincessLimaSystems;
function create(container, actions) {
const overlay = container.querySelector("[data-lima-overlay]");
const panel = container.querySelector("[data-lima-panel]");
const title = container.querySelector("[data-lima-panel-title]");
const body = container.querySelector("[data-lima-panel-body]");
const closeButton = container.querySelector("[data-lima-panel-close]");
let returnFocus = null;
let dialogue = null;
let dialogueIndex = 0;
function lock(value) {
actions.onLock(value);
overlay.hidden = !value;
container.classList.toggle("is-overlay-open", value);
}
function show(kind, heading, html, closable) {
returnFocus = document.activeElement;
panel.dataset.kind = kind;
title.textContent = heading;
body.innerHTML = html;
closeButton.hidden = closable === false;
lock(true);
const target = body.querySelector("button, input, select") || closeButton;
target.focus();
}
function close() {
if (dialogue) return advanceDialogue();
lock(false);
body.innerHTML = "";
if (returnFocus && document.contains(returnFocus)) returnFocus.focus();
else container.querySelector("[data-lima-game]").focus();
}
function openDialogue(id, done) {
const npc = Data.NPCS[id];
if (!npc) return;
dialogue = { id, lines: npc.dialogue.slice(), done };
dialogueIndex = 0;
renderDialogue();
}
function renderDialogue() {
const npc = Data.NPCS[dialogue.id];
const line = dialogue.lines[dialogueIndex];
show("dialogue", npc.name, `
<div class="lima-dialogue">
<div class="lima-dialogue__portrait lima-sprite lima-sprite--${npc.frame}" aria-hidden="true"></div>
<p data-lima-dialogue-text>${escapeHtml(line)}</p>
</div>
<button type="button" class="lima-primary" data-lima-advance>${dialogueIndex + 1 < dialogue.lines.length ? "Continue" : "Finish"}</button>
`, false);
body.querySelector("[data-lima-advance]").addEventListener("click", advanceDialogue, { once: true });
}
function advanceDialogue() {
if (!dialogue) return;
dialogueIndex += 1;
if (dialogueIndex < dialogue.lines.length) return renderDialogue();
const done = dialogue.done;
dialogue = null;
lock(false);
body.innerHTML = "";
container.querySelector("[data-lima-game]").focus();
if (done) done();
}
function openPanel(kind, state) {
if (kind === "inventory") {
const entries = state.inventory.length ? state.inventory.map((entry) => {
const item = Data.ITEMS[entry.id];
const equipped = Object.values(state.equipment).includes(entry.id) ? " · Equipped" : "";
return `<li><strong>${escapeHtml(item.name)}</strong><span>×${entry.quantity}${equipped}</span><p>${escapeHtml(item.description)}</p></li>`;
}).join("") : "<li>No items yet.</li>";
show("inventory", "Inventory", `<ul class="lima-list">${entries}</ul><button type="button" data-lima-use-tonic>Use Healing Tonic</button>`);
const use = body.querySelector("[data-lima-use-tonic]");
use.addEventListener("click", () => { actions.onUseTonic(); openPanel("inventory", actions.getState()); });
} else if (kind === "quests") {
const quests = Data.QUEST_IDS.filter((id) => state.quests[id].status !== "locked").map((id) => {
const quest = Data.QUESTS[id];
const progress = state.quests[id];
return `<li class="${progress.status === "complete" ? "is-complete" : ""}">
<strong>${quest.main ? "Main · " : "Optional · "}${escapeHtml(quest.title)}</strong>
<span>${progress.status === "complete" ? "Complete" : `${progress.count} / ${quest.target}`}</span>
<p>${escapeHtml(quest.description)} · ${escapeHtml(quest.region)}</p>
</li>`;
}).join("");
show("quests", "Quest Log", `<p class="lima-panel-lead">${escapeHtml(Systems.currentObjective(state))}</p><ul class="lima-list">${quests || "<li>No quests yet.</li>"}</ul>`);
} else if (kind === "settings") {
show("settings", "Settings", `
<label class="lima-setting"><span>Master volume</span><input type="range" min="0" max="1" step="0.05" value="${state.settings.master}" data-setting="master"></label>
<label class="lima-setting"><span>Music</span><input type="range" min="0" max="1" step="0.05" value="${state.settings.music}" data-setting="music"></label>
<label class="lima-setting"><span>Effects</span><input type="range" min="0" max="1" step="0.05" value="${state.settings.effects}" data-setting="effects"></label>
<label class="lima-check"><input type="checkbox" data-setting="reducedMotion" ${state.settings.reducedMotion ? "checked" : ""}> Reduced motion</label>
<label class="lima-check"><input type="checkbox" data-setting="screenShake" ${state.settings.screenShake ? "checked" : ""}> Screen shake</label>
<label class="lima-check"><input type="checkbox" data-setting="highContrast" ${state.settings.highContrast ? "checked" : ""}> High-contrast interface</label>
<label class="lima-setting"><span>Text speed</span><select data-setting="textSpeed">${["slow", "normal", "fast", "instant"].map((value) => `<option ${state.settings.textSpeed === value ? "selected" : ""}>${value}</option>`).join("")}</select></label>
`);
body.querySelectorAll("[data-setting]").forEach((control) => control.addEventListener("change", () => {
const value = control.type === "checkbox" ? control.checked : control.type === "range" ? Number(control.value) : control.value;
actions.onSetting(control.dataset.setting, value);
}));
} else if (kind === "pause") {
show("pause", "Paused", `
<p>${escapeHtml(Systems.currentObjective(state))}</p>
<div class="lima-menu-stack">
<button type="button" data-panel="inventory">Inventory</button>
<button type="button" data-panel="quests">Quest Log</button>
<button type="button" data-panel="settings">Settings & accessibility</button>
<button type="button" data-lima-fullscreen-panel>Toggle fullscreen</button>
<button type="button" data-lima-reset-request>Reset save</button>
<a href="/">Exit to Website</a>
</div>
`);
body.querySelectorAll("[data-panel]").forEach((button) => button.addEventListener("click", () => openPanel(button.dataset.panel, actions.getState())));
body.querySelector("[data-lima-fullscreen-panel]").addEventListener("click", actions.onFullscreen);
body.querySelector("[data-lima-reset-request]").addEventListener("click", confirmReset);
}
}
function confirmReset() {
show("confirm", "Delete this adventure?", `
<p>This permanently removes the Princess Lima save on this device.</p>
<div class="lima-confirm"><button type="button" class="lima-danger" data-confirm-reset>Delete save</button><button type="button" data-cancel-reset>Keep progress</button></div>
`, false);
body.querySelector("[data-confirm-reset]").addEventListener("click", actions.onReset, { once: true });
body.querySelector("[data-cancel-reset]").addEventListener("click", () => openPanel("pause", actions.getState()), { once: true });
}
function gameOver(state) {
show("defeat", "The road is not finished", `
<p>You awaken at the latest safe checkpoint with your quests and important items intact.</p>
<button type="button" class="lima-primary" data-respawn>Return to checkpoint</button>
`, false);
body.querySelector("[data-respawn]").addEventListener("click", actions.onRespawn, { once: true });
}
function ending(state) {
show("ending", "Princess Lima Rescued", `
<p>At dawn, the roads reopen. The villages ring their bells, the forest paths quiet, and the mountain fires become beacons instead of warnings.</p>
<p><strong>${escapeHtml(state.player.name)}</strong> is offered a place at the royal table—and chooses first to walk the repaired road home with Lima.</p>
<p class="lima-ending-note">The kingdom remains explorable from your final save.</p>
<button type="button" class="lima-primary" data-ending-continue>Continue exploring</button>
<a class="lima-button-link" href="/">Exit to Website</a>
`, false);
body.querySelector("[data-ending-continue]").addEventListener("click", close, { once: true });
}
closeButton.addEventListener("click", close);
overlay.addEventListener("click", (event) => { if (event.target === overlay && !dialogue) close(); });
document.addEventListener("keydown", (event) => {
if (event.key === "Escape" && !overlay.hidden && !dialogue) {
event.preventDefault();
close();
}
if ((event.key === "Enter" || event.key === " ") && dialogue && !overlay.hidden) {
event.preventDefault();
advanceDialogue();
}
});
return Object.freeze({ show, close, openDialogue, openPanel, gameOver, ending, confirmReset });
}
function escapeHtml(value) {
return String(value).replace(/[&<>"']/g, (character) => ({
"&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;"
}[character]));
}
root.PrincessLimaUI = Object.freeze({ create });
}(typeof globalThis !== "undefined" ? globalThis : this));