Compare commits
3 Commits
c872f6c4c4
...
2d7a5d157b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d7a5d157b | ||
|
|
9ddc36e014 | ||
|
|
238b3c4dd6 |
19
bin/mode.ts
Normal file
19
bin/mode.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
/// <reference lib="dom" />
|
||||||
|
// Swap UI between cinema mode (fix 16:9) and 100% height.
|
||||||
|
|
||||||
|
import { content } from "@/js/dom"
|
||||||
|
import { focusInput } from "@/js/focus"
|
||||||
|
import { resize } from "@/js/resize"
|
||||||
|
import { send } from "@/js/websocket"
|
||||||
|
|
||||||
|
export default function (mode?: string) {
|
||||||
|
if (!mode) {
|
||||||
|
mode = document.body.dataset.mode === "tall" ? "cinema" : "tall"
|
||||||
|
send({ type: "session:update", data: { "ui:mode": mode } })
|
||||||
|
}
|
||||||
|
|
||||||
|
content.style.display = ""
|
||||||
|
document.body.dataset.mode = mode
|
||||||
|
resize()
|
||||||
|
focusInput()
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import { join, basename } from "path"
|
||||||
import { isFile } from "./utils"
|
import { isFile } from "./utils"
|
||||||
import { sendAll } from "./websocket"
|
import { sendAll } from "./websocket"
|
||||||
import { expectDir } from "./utils"
|
import { expectDir } from "./utils"
|
||||||
|
import { importUrl } from "./shared/utils"
|
||||||
import type { Command, Commands } from "./shared/types"
|
import type { Command, Commands } from "./shared/types"
|
||||||
import { projectBin, projectName } from "./project"
|
import { projectBin, projectName } from "./project"
|
||||||
import { DEFAULT_PROJECT, NOSE_DIR, NOSE_ROOT_BIN, NOSE_BIN } from "./config"
|
import { DEFAULT_PROJECT, NOSE_DIR, NOSE_ROOT_BIN, NOSE_BIN } from "./config"
|
||||||
|
|
@ -81,7 +82,7 @@ export async function commandSource(name: string): Promise<string> {
|
||||||
export async function loadCommandModule(cmd: string) {
|
export async function loadCommandModule(cmd: string) {
|
||||||
const path = commandPath(cmd)
|
const path = commandPath(cmd)
|
||||||
if (!path) return
|
if (!path) return
|
||||||
return await import(path + "?t+" + Date.now())
|
return await importUrl(path + "?t+" + Date.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
let noseDirWatcher
|
let noseDirWatcher
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,18 @@
|
||||||
////
|
////
|
||||||
// temporary hack for browser commands
|
// Keep track of all NOSE commands.
|
||||||
|
|
||||||
import type { CommandOutput, Commands } from "../shared/types"
|
import type { Commands } from "../shared/types"
|
||||||
import { content } from "./dom"
|
import { runCommand } from "./shell"
|
||||||
import { focusInput } from "./focus"
|
|
||||||
import { resize } from "./resize"
|
|
||||||
import { send } from "./websocket"
|
|
||||||
|
|
||||||
export const commands: Commands = {}
|
export const commands: Commands = {}
|
||||||
|
|
||||||
// TODO: convert to bin/shell "browser" commands
|
|
||||||
export const browserCommands: Record<string, (...args: string[]) => void | Promise<void> | CommandOutput> = {
|
|
||||||
mode: (mode?: string) => {
|
|
||||||
if (!mode) {
|
|
||||||
mode = document.body.dataset.mode === "tall" ? "cinema" : "tall"
|
|
||||||
send({ type: "session:update", data: { "ui:mode": mode } })
|
|
||||||
}
|
|
||||||
|
|
||||||
content.style.display = ""
|
|
||||||
document.body.dataset.mode = mode
|
|
||||||
resize()
|
|
||||||
focusInput()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cacheCommands(cmds: Commands) {
|
export function cacheCommands(cmds: Commands) {
|
||||||
for (const key in commands)
|
for (const key in commands)
|
||||||
delete commands[key]
|
delete commands[key]
|
||||||
|
|
||||||
Object.assign(commands, cmds)
|
Object.assign(commands, cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function mode(mode?: string) {
|
||||||
|
await runCommand(mode ? `mode ${mode}` : "mode", false)
|
||||||
|
}
|
||||||
|
|
@ -2,10 +2,10 @@ import type { GameStartMessage } from "../shared/types"
|
||||||
import { GameContext, type InputState } from "../shared/game"
|
import { GameContext, type InputState } from "../shared/game"
|
||||||
import { focusInput } from "./focus"
|
import { focusInput } from "./focus"
|
||||||
import { $$ } from "./dom"
|
import { $$ } from "./dom"
|
||||||
import { randomId } from "../shared/utils"
|
import { randomId, importUrl } from "../shared/utils"
|
||||||
import { setStatus, addOutput, insert } from "./scrollback"
|
import { setStatus, addOutput, insert } from "./scrollback"
|
||||||
import { browserCommands } from "./commands"
|
|
||||||
import { sessionId } from "./session"
|
import { sessionId } from "./session"
|
||||||
|
import { mode } from "./commands"
|
||||||
|
|
||||||
const FPS = 30
|
const FPS = 30
|
||||||
const HEIGHT = 540
|
const HEIGHT = 540
|
||||||
|
|
@ -35,7 +35,7 @@ export async function handleGameStart(msg: GameStartMessage) {
|
||||||
|
|
||||||
let game
|
let game
|
||||||
try {
|
try {
|
||||||
game = await import(`/source/${name}?session=${sessionId}`)
|
game = await importUrl(`/source/${name}?session=${sessionId}&t=${Date.now()}`)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setStatus(msgId, "error")
|
setStatus(msgId, "error")
|
||||||
addOutput(msgId, `Error: ${err.message ? err.message : err}`)
|
addOutput(msgId, `Error: ${err.message ? err.message : err}`)
|
||||||
|
|
@ -43,7 +43,7 @@ export async function handleGameStart(msg: GameStartMessage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.body.dataset.mode === "tall") {
|
if (document.body.dataset.mode === "tall") {
|
||||||
browserCommands.mode?.()
|
mode()
|
||||||
oldMode = "tall"
|
oldMode = "tall"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,7 +143,7 @@ function endGame() {
|
||||||
window.removeEventListener("keyup", handleKeyup)
|
window.removeEventListener("keyup", handleKeyup)
|
||||||
window.removeEventListener("resize", resizeCanvas)
|
window.removeEventListener("resize", resizeCanvas)
|
||||||
|
|
||||||
if (oldMode === "tall") browserCommands.mode?.()
|
if (oldMode === "tall") mode()
|
||||||
|
|
||||||
const main = document.querySelector("main")
|
const main = document.querySelector("main")
|
||||||
main?.classList.remove("game")
|
main?.classList.remove("game")
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
// in the same browser.
|
// in the same browser.
|
||||||
|
|
||||||
import type { SessionStartMessage, SessionUpdateMessage } from "@/shared/types"
|
import type { SessionStartMessage, SessionUpdateMessage } from "@/shared/types"
|
||||||
import { browserCommands } from "./commands"
|
|
||||||
import { randomId } from "../shared/utils"
|
import { randomId } from "../shared/utils"
|
||||||
import { apps } from "./webapp"
|
import { apps } from "./webapp"
|
||||||
import { $ } from "./dom"
|
import { $ } from "./dom"
|
||||||
|
import { mode } from "./commands"
|
||||||
|
|
||||||
export const sessionId = randomId()
|
export const sessionId = randomId()
|
||||||
export const projectName = $("project-name") as HTMLAnchorElement
|
export const projectName = $("project-name") as HTMLAnchorElement
|
||||||
|
|
@ -25,7 +25,7 @@ export function handleSessionStart(msg: SessionStartMessage) {
|
||||||
sessionStore.set("hostname", msg.data.hostname)
|
sessionStore.set("hostname", msg.data.hostname)
|
||||||
updateProjectName(msg.data.project)
|
updateProjectName(msg.data.project)
|
||||||
updateCwd(msg.data.cwd)
|
updateCwd(msg.data.cwd)
|
||||||
browserCommands.mode?.(msg.data.mode)
|
mode(msg.data.mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleSessionUpdate(msg: SessionUpdateMessage) {
|
export function handleSessionUpdate(msg: SessionUpdateMessage) {
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@
|
||||||
import type { InputMessage } from "../shared/types"
|
import type { InputMessage } from "../shared/types"
|
||||||
import { addInput, setStatus, addOutput } from "./scrollback"
|
import { addInput, setStatus, addOutput } from "./scrollback"
|
||||||
import { send } from "./websocket"
|
import { send } from "./websocket"
|
||||||
import { randomId } from "../shared/utils"
|
import { randomId, importUrl } from "../shared/utils"
|
||||||
import { addToHistory } from "./history"
|
import { addToHistory } from "./history"
|
||||||
import { browserCommands, commands } from "./commands"
|
import { commands } from "./commands"
|
||||||
|
|
||||||
export async function runCommand(input: string) {
|
export async function runCommand(input: string, showInput = true) {
|
||||||
if (!input.trim()) return
|
if (!input.trim()) return
|
||||||
|
|
||||||
if (input.includes(";")) {
|
if (input.includes(";")) {
|
||||||
|
|
@ -19,19 +19,21 @@ export async function runCommand(input: string) {
|
||||||
const id = randomId()
|
const id = randomId()
|
||||||
|
|
||||||
addToHistory(input)
|
addToHistory(input)
|
||||||
addInput(id, input)
|
if (showInput)
|
||||||
|
addInput(id, input)
|
||||||
|
|
||||||
const [cmd = "", ...args] = input.split(" ")
|
const [cmd = "", ...args] = input.split(" ")
|
||||||
|
|
||||||
if (commands[cmd]?.type === "browser") {
|
if (commands[cmd]?.type === "browser") {
|
||||||
const mod = await import(`/source/${cmd}?t=${Date.now()}`)
|
const mod = await importUrl(`/source/${cmd}?t=${Date.now()}`)
|
||||||
|
if (!mod.default) {
|
||||||
|
addOutput(id, `no default export in ${cmd}`)
|
||||||
|
setStatus(id, "error")
|
||||||
|
return
|
||||||
|
}
|
||||||
const result = mod.default(...args)
|
const result = mod.default(...args)
|
||||||
if (result) addOutput(id, result)
|
if (result) addOutput(id, result)
|
||||||
setStatus(id, "ok")
|
setStatus(id, "ok")
|
||||||
} else if (browserCommands[cmd]) {
|
|
||||||
const result = await browserCommands[cmd](...args)
|
|
||||||
if (result) addOutput(id, result)
|
|
||||||
setStatus(id, "ok")
|
|
||||||
} else {
|
} else {
|
||||||
send({ id, type: "input", data: input } as InputMessage)
|
send({ id, type: "input", data: input } as InputMessage)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,3 +39,8 @@ export function randomIndex<T>(list: T[]): number | undefined {
|
||||||
export function unique<T>(array: T[]): T[] {
|
export function unique<T>(array: T[]): T[] {
|
||||||
return [...new Set(array)]
|
return [...new Set(array)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function importUrl(url: string) {
|
||||||
|
console.log("-> import", url)
|
||||||
|
return import(url)
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ import { sendAll } from "./websocket"
|
||||||
import { expectDir } from "./utils"
|
import { expectDir } from "./utils"
|
||||||
import { NOSE_DIR } from "./config"
|
import { NOSE_DIR } from "./config"
|
||||||
import { isFile, isDir } from "./utils"
|
import { isFile, isDir } from "./utils"
|
||||||
|
import { importUrl } from "./shared/utils"
|
||||||
|
|
||||||
export type Handler = (r: Context) => string | Child | Response | Promise<Response>
|
export type Handler = (r: Context) => string | Child | Response | Promise<Response>
|
||||||
export type App = Hono | Handler
|
export type App = Hono | Handler
|
||||||
|
|
@ -73,7 +74,7 @@ async function findApp(name: string): Promise<App | undefined> {
|
||||||
async function loadApp(path: string): Promise<App | undefined> {
|
async function loadApp(path: string): Promise<App | undefined> {
|
||||||
if (!await Bun.file(path).exists()) return
|
if (!await Bun.file(path).exists()) return
|
||||||
|
|
||||||
const mod = await import(path + `?t=${Date.now()}`)
|
const mod = await importUrl(path + `?t=${Date.now()}`)
|
||||||
if (mod?.default)
|
if (mod?.default)
|
||||||
return mod.default as App
|
return mod.default as App
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user