the ps1 prompt displays properly
This commit is contained in:
9
src/components/client/elements/create.ts
Normal file
9
src/components/client/elements/create.ts
Normal file
@ -0,0 +1,9 @@
|
||||
function create<T extends keyof HTMLElementTagNameMap>(element: T, className?: string): HTMLElementTagNameMap[T] {
|
||||
const new_element = document.createElement(element)
|
||||
if (className) {
|
||||
new_element.className = className
|
||||
}
|
||||
return new_element
|
||||
}
|
||||
|
||||
export default create
|
66
src/components/client/elements/prompt.ts
Normal file
66
src/components/client/elements/prompt.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { cyan, green } from "../shell/color"
|
||||
import { get_working_dir_name } from "../shell/fs/fn"
|
||||
|
||||
import create from "./create"
|
||||
|
||||
const userAgent = navigator.userAgent
|
||||
const browser_name_fallible = userAgent.match(/Firefox.\d+[\d.\d]+|Chrome.\d+[\d.\d]+/gm)?.map(f => f.split("/")[0])
|
||||
let browser_name = "unknown"
|
||||
if (browser_name_fallible) {
|
||||
browser_name = browser_name_fallible[0] === "Firefox" ? "gecko" : "chromium"
|
||||
}
|
||||
|
||||
interface Ps1Prompt {
|
||||
readonly body: HTMLDivElement,
|
||||
readonly input: HTMLInputElement
|
||||
}
|
||||
interface Inputs {
|
||||
old?: HTMLInputElement,
|
||||
new?: HTMLInputElement
|
||||
}
|
||||
let inputs: Inputs = {
|
||||
old: undefined,
|
||||
new: undefined
|
||||
}
|
||||
|
||||
function ps1_element(user: HTMLSpanElement, dir: HTMLSpanElement) {
|
||||
const display = create("p")
|
||||
display.appendChild(user)
|
||||
display.append(`@${browser_name}`)
|
||||
display.appendChild(dir)
|
||||
display.append("> ")
|
||||
return display
|
||||
}
|
||||
|
||||
function working_dir() {
|
||||
const dir_name = get_working_dir_name()
|
||||
return dir_name === "user" ? "~" : dir_name
|
||||
}
|
||||
|
||||
function working_dir_element() {
|
||||
const user = cyan("user")
|
||||
const dir = green(" "+working_dir())
|
||||
return ps1_element(user, dir)
|
||||
}
|
||||
|
||||
export default function prompt(): Ps1Prompt {
|
||||
const prompt_div = create("div", "shell-prompt")
|
||||
const ps1 = working_dir_element()
|
||||
const input = create("input", "shell-ps1")
|
||||
input.type = "text"
|
||||
input.spellcheck = false
|
||||
|
||||
inputs.old = inputs.new
|
||||
if (inputs.old) {
|
||||
inputs.old.disabled = true
|
||||
}
|
||||
inputs.new = input
|
||||
|
||||
prompt_div.appendChild(ps1)
|
||||
prompt_div.appendChild(input)
|
||||
|
||||
return {
|
||||
body: prompt_div,
|
||||
input: input
|
||||
}
|
||||
}
|
@ -1,13 +1,28 @@
|
||||
import create from "../elements/create"
|
||||
|
||||
const enum Colors {
|
||||
red = "red",
|
||||
green = "green",
|
||||
blue = "blue",
|
||||
cyan = "cyan",
|
||||
bold = "bold"
|
||||
}
|
||||
function newcolor(inner: string, color?: Colors) {
|
||||
const span = create("span", color)
|
||||
span.innerText = inner
|
||||
return span
|
||||
}
|
||||
|
||||
const red = (s: string) => <span className="red">{s}</span>
|
||||
const green = (s: string) => <span className="green">{s}</span>
|
||||
const blue = (s: string) => <span className="blue">{s}</span>
|
||||
const cyan = (s: string) => <span className="cyan">{s}</span>
|
||||
const bold = (s: string) => <span className="bold">{s}</span>
|
||||
const red = (s: string) => newcolor(s, Colors.red )
|
||||
const green = (s: string) => newcolor(s, Colors.green)
|
||||
const blue = (s: string) => newcolor(s, Colors.blue)
|
||||
const cyan = (s: string) => newcolor(s, Colors.cyan)
|
||||
const bold = (s: string) => newcolor(s, Colors.bold)
|
||||
|
||||
export default function rgb(s: string, Ru8: number, Gu8: number, Bu8: number) {
|
||||
return <span style={{color: `rgb(${Ru8},${Gu8},${Bu8})`}}>{s}</span>
|
||||
const rgb_span = newcolor(s)
|
||||
rgb_span.style.color = `rgb(${Ru8},${Gu8},${Bu8})`
|
||||
return rgb_span
|
||||
}
|
||||
|
||||
export {
|
||||
|
@ -1,9 +1,6 @@
|
||||
import Display from "./prompt"
|
||||
import run from "./command/run"
|
||||
|
||||
import { type newElement } from "../terminal/exec";
|
||||
import type { JSX } from "react";
|
||||
|
||||
const enum Key {
|
||||
Enter = "Enter",
|
||||
ArrowUp = "ArrowUp",
|
||||
@ -11,28 +8,6 @@ const enum Key {
|
||||
Tab = "Tab"
|
||||
}
|
||||
|
||||
function display_prompt() {
|
||||
return <div className="shell-prompt">
|
||||
<Display/>
|
||||
<input className="shell-ps1" type="text" spellCheck={false}/>
|
||||
</div>
|
||||
}
|
||||
|
||||
function get_current_prompt(): HTMLInputElement | undefined {
|
||||
const shell_input = document.getElementsByClassName("shell-ps1")
|
||||
|
||||
return shell_input[shell_input.length-1] as HTMLInputElement
|
||||
}
|
||||
|
||||
function new_prompt(): JSX.Element {
|
||||
const shell_prompts = document.getElementsByClassName("shell-ps1")
|
||||
|
||||
Array.from(shell_prompts).forEach(shellps1 => {
|
||||
(shellps1 as HTMLInputElement).disabled = true
|
||||
})
|
||||
return display_prompt()
|
||||
}
|
||||
|
||||
function keyboard_events(terminal_window: HTMLElement, new_elements_f: newElement) {
|
||||
const terminal_event = (keyboard_event: KeyboardEvent) => {
|
||||
if (keyboard_event.key === Key.Enter) {
|
||||
@ -57,6 +32,4 @@ function keyboard_events(terminal_window: HTMLElement, new_elements_f: newElemen
|
||||
|
||||
export {
|
||||
keyboard_events,
|
||||
display_prompt,
|
||||
get_current_prompt
|
||||
}
|
42
src/components/client/terminal.ts
Normal file
42
src/components/client/terminal.ts
Normal file
@ -0,0 +1,42 @@
|
||||
// import { red } from "../shell/color"
|
||||
// import { display_prompt, keyboard_events } from "../shell/events"
|
||||
|
||||
import prompt from "./elements/prompt"
|
||||
// import run from "./shell/command/run"
|
||||
|
||||
const terminal_window = document.querySelector("main")
|
||||
|
||||
const enum Key {
|
||||
Enter = "Enter",
|
||||
ArrowUp = "ArrowUp",
|
||||
ArrowDown = "ArrowDown",
|
||||
Tab = "Tab"
|
||||
}
|
||||
|
||||
function spawnps1(terminal_window_safe: HTMLElement) {
|
||||
const ps1prompt = prompt()
|
||||
terminal_window_safe.appendChild(ps1prompt.body)
|
||||
input_processor(ps1prompt.input)
|
||||
}
|
||||
|
||||
type InputClosure = (key_event: KeyboardEvent) => void
|
||||
function key_enter(ps1input: HTMLInputElement, key_event: KeyboardEvent, input_closure: InputClosure) {
|
||||
key_event.preventDefault()
|
||||
// run(ps1input.value)
|
||||
ps1input.removeEventListener("keydown", input_closure)
|
||||
}
|
||||
|
||||
function input_processor(ps1input: HTMLInputElement) {
|
||||
const input_closure = (key_event: KeyboardEvent) => {
|
||||
if (key_event.key === Key.Enter) {
|
||||
key_enter(ps1input, key_event, input_closure)
|
||||
}
|
||||
}
|
||||
ps1input.addEventListener("keydown", input_closure)
|
||||
}
|
||||
|
||||
if (terminal_window) {
|
||||
spawnps1(terminal_window)
|
||||
} else {
|
||||
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
const terminal_window = document.querySelector("main")
|
||||
|
||||
interface PromptPosition {
|
||||
x: number,
|
||||
y: number,
|
||||
}
|
||||
|
||||
interface PromptContext extends PromptPosition {
|
||||
enabled: boolean,
|
||||
}
|
||||
|
||||
function Menu(pos: PromptPosition) {
|
||||
console.log(pos.x, pos.y)
|
||||
}
|
||||
|
||||
export default function ContextMenu() {
|
||||
if (terminal_window) {
|
||||
useEffect(() => {
|
||||
const [contextMenu, newContextMenu] = useState(false)
|
||||
const [_, toggleRightClick] = useState({enabled: false, x: 0, y: 0})
|
||||
|
||||
terminal_window.addEventListener("contextmenu", (menuEvent) => {
|
||||
menuEvent.preventDefault()
|
||||
toggleRightClick({enabled: true, x: menuEvent.pageX, y: menuEvent.pageY})
|
||||
Menu({x: menuEvent.pageX, y: menuEvent.pageY})
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
import { red } from "../shell/color"
|
||||
import { display_prompt, keyboard_events } from "../shell/events"
|
||||
|
||||
const terminal_window = document.getElementById("interactive-area")
|
||||
|
||||
// function panic(message: string) {
|
||||
// return <>
|
||||
// <p>{red("=================================================")}</p>
|
||||
// <p>{red("An unexpected JavaScript error occured:")}</p>
|
||||
// <p>{red(message)}</p>
|
||||
// <p>{red("=================================================")}</p>
|
||||
// </>
|
||||
// }
|
||||
|
||||
// function ps1(terminal_window_safe: HTMLElement): JSX.Element[] {
|
||||
// const [renderedElements, renderElement] = useState([display_prompt()])
|
||||
// const new_elements_f = (elements: JSX.Element[]) => renderElement([...renderedElements, ...elements])
|
||||
|
||||
// keyboard_events(terminal_window_safe, new_elements_f)
|
||||
|
||||
// return renderedElements
|
||||
// }
|
||||
|
||||
// export default function Shell() {
|
||||
// if (terminal_window) {
|
||||
// return ps1(terminal_window).map((element, k) => <React.Fragment key={k}>{element}</React.Fragment>)
|
||||
// }
|
||||
// return panic("The <main> element is missing")
|
||||
// }
|
||||
|
||||
// export {
|
||||
// panic,
|
||||
// type newElement,
|
||||
// }
|
@ -6,7 +6,7 @@ import Motd from '../components/terminal/motd.astro';
|
||||
<Webpage>
|
||||
<main>
|
||||
<Motd/>
|
||||
<script src="../components/client/terminal/exec.ts"></script>
|
||||
<script src="../components/client/terminal.ts"></script>
|
||||
</main>
|
||||
</Webpage>
|
||||
|
||||
|
Reference in New Issue
Block a user