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 red = (s: string) => newcolor(s, Colors.red )
|
||||||
const green = (s: string) => <span className="green">{s}</span>
|
const green = (s: string) => newcolor(s, Colors.green)
|
||||||
const blue = (s: string) => <span className="blue">{s}</span>
|
const blue = (s: string) => newcolor(s, Colors.blue)
|
||||||
const cyan = (s: string) => <span className="cyan">{s}</span>
|
const cyan = (s: string) => newcolor(s, Colors.cyan)
|
||||||
const bold = (s: string) => <span className="bold">{s}</span>
|
const bold = (s: string) => newcolor(s, Colors.bold)
|
||||||
|
|
||||||
export default function rgb(s: string, Ru8: number, Gu8: number, Bu8: number) {
|
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 {
|
export {
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import Display from "./prompt"
|
import Display from "./prompt"
|
||||||
import run from "./command/run"
|
import run from "./command/run"
|
||||||
|
|
||||||
import { type newElement } from "../terminal/exec";
|
|
||||||
import type { JSX } from "react";
|
|
||||||
|
|
||||||
const enum Key {
|
const enum Key {
|
||||||
Enter = "Enter",
|
Enter = "Enter",
|
||||||
ArrowUp = "ArrowUp",
|
ArrowUp = "ArrowUp",
|
||||||
@ -11,28 +8,6 @@ const enum Key {
|
|||||||
Tab = "Tab"
|
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) {
|
function keyboard_events(terminal_window: HTMLElement, new_elements_f: newElement) {
|
||||||
const terminal_event = (keyboard_event: KeyboardEvent) => {
|
const terminal_event = (keyboard_event: KeyboardEvent) => {
|
||||||
if (keyboard_event.key === Key.Enter) {
|
if (keyboard_event.key === Key.Enter) {
|
||||||
@ -57,6 +32,4 @@ function keyboard_events(terminal_window: HTMLElement, new_elements_f: newElemen
|
|||||||
|
|
||||||
export {
|
export {
|
||||||
keyboard_events,
|
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>
|
<Webpage>
|
||||||
<main>
|
<main>
|
||||||
<Motd/>
|
<Motd/>
|
||||||
<script src="../components/client/terminal/exec.ts"></script>
|
<script src="../components/client/terminal.ts"></script>
|
||||||
</main>
|
</main>
|
||||||
</Webpage>
|
</Webpage>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user