update build.js

This commit is contained in:
Chris Wanstrath 2025-10-06 20:43:42 -07:00
parent 384a0bd111
commit abc2b9f2fa

View File

@ -1,5 +1,5 @@
////
// version: 7d7febe
// version: 384a0bd
// src/js/dom.ts
var content2 = $("content");
@ -24,28 +24,26 @@ var $$ = (tag, innerHTML = "") => {
return el;
};
// src/js/resize.ts
var content3 = document.getElementById("content");
function initResize() {
window.addEventListener("resize", resize);
resize();
// src/js/focus.ts
function initFocus() {
window.addEventListener("click", focusHandler);
focusInput();
}
function resize() {
if (document.body.dataset.mode === "tall") {
resizeTall();
} else {
resizeCinema();
function focusInput() {
cmdInput.focus();
}
function focusHandler(e) {
const target = e.target;
if (!(target instanceof HTMLElement)) {
focusInput();
return;
}
function resizeTall() {
const scale = Math.min(1, window.innerWidth / 960);
content3.style.transformOrigin = "top center";
content3.style.transform = `scaleX(${scale})`;
}
function resizeCinema() {
const scale = Math.min(window.innerWidth / 960, window.innerHeight / 540);
content3.style.transformOrigin = "center center";
content3.style.transform = `scale(${scale})`;
if (["INPUT", "TEXTAREA", "CANVAS", "A"].includes(target.tagName))
return false;
const selection = window.getSelection() || "";
if (selection.toString() === "")
focusInput();
e.preventDefault();
}
// src/shared/utils.ts
@ -54,18 +52,23 @@ function randomId() {
}
// src/js/scrollback.ts
var statusColors = {
waiting: "yellow",
streaming: "purple",
ok: "green",
error: "red"
};
function initScrollback() {
window.addEventListener("click", handleInputClick);
}
function autoScroll() {}
function insert(node) {
scrollback.append(node);
}
function addInput(id, input) {
function addInput(id, input, status) {
const parent = $$("li.input");
const status = $$("span.status.yellow", "•");
const content4 = $$("span.content", input);
parent.append(status, content4);
const statusSpan = $$(`span.status.${statusColors[status || "waiting"]}`, "•");
const content3 = $$("span.content", input);
parent.append(statusSpan, content3);
parent.dataset.id = id;
insert(parent);
scrollback.scrollTop = scrollback.scrollHeight - scrollback.clientHeight;
@ -74,31 +77,24 @@ function setStatus(id, status) {
const statusEl = document.querySelector(`[data-id="${id}"].input .status`);
if (!statusEl)
return;
const colors = {
waiting: "yellow",
streaming: "purple",
ok: "green",
error: "red"
};
statusEl.classList.remove(...Object.values(colors));
statusEl.classList.add(colors[status]);
statusEl.classList.remove(...Object.values(statusColors));
statusEl.classList.add(statusColors[status]);
}
function addOutput(id, output2) {
const item = $$("li");
item.classList.add("output");
item.dataset.id = id || randomId();
const [format, content4] = processOutput(output2);
const [format, content3] = processOutput(output2);
if (format === "html")
item.innerHTML = content4;
item.innerHTML = content3;
else
item.textContent = content4;
item.textContent = content3;
const input = document.querySelector(`[data-id="${id}"].input`);
if (input instanceof HTMLLIElement) {
input.parentNode.insertBefore(item, input.nextSibling);
} else {
insert(item);
}
autoScroll();
}
function addErrorMessage(message) {
addOutput("", { html: `<span class="red">${message}</span>` });
@ -109,12 +105,11 @@ function appendOutput(id, output2) {
console.error(`output id ${id} not found`);
return;
}
const [format, content4] = processOutput(output2);
const [format, content3] = processOutput(output2);
if (format === "html")
item.innerHTML += content4;
item.innerHTML += content3;
else
item.textContent += content4;
autoScroll();
item.textContent += content3;
}
function replaceOutput(id, output2) {
const item = document.querySelector(`[data-id="${id}"].output`);
@ -122,12 +117,11 @@ function replaceOutput(id, output2) {
console.error(`output id ${id} not found`);
return;
}
const [format, content4] = processOutput(output2);
const [format, content3] = processOutput(output2);
if (format === "html")
item.innerHTML = content4;
item.innerHTML = content3;
else
item.textContent = content4;
autoScroll();
item.textContent = content3;
}
function processOutput(output) {
let content = "";
@ -162,8 +156,181 @@ function handleInputClick(e) {
}
function handleOutput(msg) {
const result = msg.data;
setStatus(msg.id, result.status);
addOutput(msg.id, result.output);
const id = "id" in msg ? msg.id || "" : "";
setStatus(id, result.status);
addOutput(id, result.output);
}
// src/js/browser.ts
var HEIGHT = 540;
var WIDTH = 960;
var controls = $("browser-controls");
var address = $("browser-address");
var iframe;
var realUrl = "";
var showInput = true;
function isBrowsing() {
return document.querySelector("iframe.browser.active") !== null;
}
function openBrowser(url, openedVia = "click") {
showInput = openedVia === "click";
iframe = $$("iframe.browser.active");
iframe.src = url;
iframe.sandbox.add("allow-scripts", "allow-same-origin", "allow-forms");
iframe.height = String(HEIGHT);
iframe.width = String(WIDTH);
iframe.tabIndex = 0;
window.addEventListener("message", handleAppMessage);
window.addEventListener("keydown", handleBrowserKeydown);
controls.addEventListener("click", handleClick);
iframe.addEventListener("load", handlePageLoad);
controls.style.display = "";
const main = document.querySelector("#content");
main?.prepend(iframe);
setAddress(url);
}
function closeBrowser() {
window.removeEventListener("keydown", handleBrowserKeydown);
window.removeEventListener("message", handleAppMessage);
controls.removeEventListener("click", handleClick);
iframe.removeEventListener("load", handlePageLoad);
const id = randomId();
if (showInput)
addInput(id, "browse " + realUrl, "ok");
iframe.height = String(HEIGHT / 2);
iframe.width = String(WIDTH / 2);
iframe.style.pointerEvents = "none";
iframe.tabIndex = -1;
iframe.classList.remove("fullscreen", "active");
scrollback.append(iframe);
controls.style.display = "none";
focusInput();
}
function handleAppMessage(event) {
const origin = event.origin;
if (!origin.includes("localhost") && !origin.match(/\.local$/)) {
return;
}
const { type, data } = event.data;
switch (type) {
case "NAV_READY":
break;
case "URL_CHANGED":
setAddress(data.url);
break;
case "TITLE_CHANGED":
console.log("Page title:", data.title);
break;
case "NAV_BLOCKED":
showNavigationError(data.url, data.reason);
break;
case "KEYDOWN":
const keyEvent = new KeyboardEvent("keydown", {
key: data.key,
ctrlKey: data.ctrlKey,
shiftKey: data.shiftKey,
altKey: data.altKey,
metaKey: data.metaKey,
bubbles: true
});
window.dispatchEvent(keyEvent);
break;
}
}
function handleBrowserKeydown(e) {
if (e.key === "Escape" || e.ctrlKey && e.key === "c") {
e.preventDefault();
closeBrowser();
}
}
function handleClick(e) {
const target = e.target;
if (!(target instanceof HTMLElement))
return;
switch (target.id) {
case "back-button":
navigateBack();
break;
case "forward-button":
navigateForward();
break;
case "stop-button":
stopLoading();
break;
case "reload-button":
reloadBrowser();
break;
case "fullscreen-button":
fullscreenBrowser();
break;
case "close-button":
closeBrowser();
break;
default:
return;
}
e.preventDefault();
}
function handlePageLoad() {}
function setAddress(url) {
realUrl = url;
address.textContent = url.replace(/https?:\/\//, "");
}
function navigateBack() {
sendNavCommand("back");
}
function navigateForward() {
sendNavCommand("forward");
}
function reloadBrowser() {
sendNavCommand("reload");
}
function stopLoading() {
sendNavCommand("stop");
}
function fullscreenBrowser() {
controls.style.display = "none";
iframe.classList.add("fullscreen");
document.body.append(iframe);
}
function sendNavCommand(action) {
if (!iframe.contentWindow)
return;
iframe.contentWindow.postMessage({
type: "NAV_COMMAND",
action
}, "*");
}
function showNavigationError(url, reason) {
alert(`NAVIGATION BLOCKED
${url}
${reason}`);
}
// src/js/resize.ts
var content3 = document.getElementById("content");
function initResize() {
window.addEventListener("resize", resize);
resize();
}
function resize() {
if (document.body.dataset.mode === "tall") {
resizeTall();
} else {
resizeCinema();
}
}
function resizeTall() {
const scale = Math.min(1, window.innerWidth / 960);
content3.style.transformOrigin = "top center";
content3.style.transform = `scaleX(${scale})`;
}
function resizeCinema() {
const scale = Math.min(window.innerWidth / 960, window.innerHeight / 540);
content3.style.transformOrigin = "center center";
content3.style.transform = `scale(${scale})`;
}
// src/js/session.ts
@ -391,32 +558,10 @@ class GameContext {
}
}
// src/js/focus.ts
function initFocus() {
window.addEventListener("click", focusHandler);
focusInput();
}
function focusInput() {
cmdInput.focus();
}
function focusHandler(e) {
const target = e.target;
if (!(target instanceof HTMLElement)) {
focusInput();
return;
}
if (["INPUT", "TEXTAREA", "CANVAS", "A"].includes(target.tagName))
return false;
const selection = window.getSelection() || "";
if (selection.toString() === "")
focusInput();
e.preventDefault();
}
// src/js/game.ts
var FPS = 30;
var HEIGHT = 540;
var WIDTH = 980;
var HEIGHT2 = 540;
var WIDTH2 = 960;
var oldMode = "cinema";
var running = false;
var canvas;
@ -458,8 +603,8 @@ async function handleGameStart(msg) {
function createCanvas() {
const canvas2 = $$("canvas.game.active");
canvas2.id = randomId();
canvas2.height = HEIGHT;
canvas2.width = WIDTH;
canvas2.height = HEIGHT2;
canvas2.width = WIDTH2;
canvas2.tabIndex = 0;
const main = document.querySelector("main");
main?.classList.add("game");
@ -530,8 +675,8 @@ function endGame() {
const main = document.querySelector("main");
main?.classList.remove("game");
canvas.classList.remove("active");
canvas.style.height = HEIGHT / 2 + "px";
canvas.style.width = WIDTH / 2 + "px";
canvas.style.height = HEIGHT2 / 2 + "px";
canvas.style.width = WIDTH2 / 2 + "px";
const output2 = $$("li.output");
output2.append(canvas);
insert(output2);
@ -627,6 +772,7 @@ function retryConnection() {
// src/js/commands.ts
var commands = [];
var browserCommands = {
browse: (url) => openBrowser(url, "command"),
"browser-session": () => sessionId,
clear: () => scrollback.innerHTML = "",
commands: () => {
@ -636,12 +782,11 @@ var browserCommands = {
mode: (mode) => {
if (!mode) {
mode = document.body.dataset.mode === "tall" ? "cinema" : "tall";
send({ type: "ui:mode", data: mode });
send({ type: "session:update", data: { "ui:mode": mode } });
}
content2.style.display = "";
document.body.dataset.mode = mode;
resize();
autoScroll();
focusInput();
},
reload: () => window.location.reload()
@ -770,7 +915,7 @@ function keydownHandler(e) {
} else if (e.ctrlKey && e.key === "s" || e.ctrlKey && e.key === "Enter") {
e.preventDefault();
send({
id: editor.dataset.path,
id: editor.dataset.path || "/tmp.txt",
type: "save-file",
data: editor.value
});
@ -1058,30 +1203,11 @@ async function runCommand(input) {
}
}
// src/js/statusbar.ts
var STATUS_MSG_LENGTH = 3000;
var statusbar = $("statusbar");
var statusbarMsg = $("statusbar-msg");
var timer;
function status(msg) {
showStatusMsg();
statusbarMsg.textContent = msg;
if (timer)
clearTimeout(timer);
timer = setTimeout(hideStatusMsg, STATUS_MSG_LENGTH);
}
function showStatusMsg() {
statusbar.classList.add("showing-msg");
}
function hideStatusMsg() {
statusbar.className = "";
}
// src/js/hyperlink.ts
function initHyperlink() {
window.addEventListener("click", handleClick);
window.addEventListener("click", handleClick2);
}
async function handleClick(e) {
async function handleClick2(e) {
const target = e.target;
if (!(target instanceof HTMLElement))
return;
@ -1091,13 +1217,13 @@ async function handleClick(e) {
const href = a.getAttribute("href");
if (!href)
return;
if (href.startsWith("#")) {
if (href.startsWith("#") && href.length > 1) {
e.preventDefault();
await runCommand(href.slice(1));
focusInput();
} else {
} else if (!isBrowsing()) {
e.preventDefault();
status(href);
openBrowser(href);
}
}
@ -1155,7 +1281,7 @@ function clearInput() {
// src/js/vram.ts
var vramCounter = $("vram-size");
var startVramCounter = () => {
const timer2 = setInterval(() => {
const timer = setInterval(() => {
const count = parseInt(vramCounter.textContent) + 1;
let val = count + "KB";
if (count < 10)
@ -1163,7 +1289,7 @@ var startVramCounter = () => {
vramCounter.textContent = val;
if (count >= 64) {
vramCounter.textContent += " OK";
clearInterval(timer2);
clearInterval(timer);
}
}, 15);
};