terminal prompt needs to be recyclable
This commit is contained in:
21
src/components/react/commands.ts
Normal file
21
src/components/react/commands.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { working_dir } from "./fs"
|
||||
|
||||
function ls() {
|
||||
|
||||
}
|
||||
|
||||
function pwd() {
|
||||
|
||||
}
|
||||
|
||||
function cat() {
|
||||
|
||||
}
|
||||
|
||||
const commands = {
|
||||
["ls"]: ls,
|
||||
["pwd"]: pwd,
|
||||
["cat"]: cat,
|
||||
}
|
||||
|
||||
export { commands }
|
@ -1,17 +1,32 @@
|
||||
let working_dir = "user"
|
||||
|
||||
const enum EntryType {
|
||||
Directory,
|
||||
File
|
||||
}
|
||||
type File = string
|
||||
type Entry<T> = {
|
||||
readonly inner: T,
|
||||
readonly type: EntryType
|
||||
}
|
||||
function Entry<T = File>(inner: T): Entry<T> {
|
||||
const type = typeof inner == "object" ? EntryType.Directory : EntryType.File
|
||||
return { inner: inner, type: type }
|
||||
}
|
||||
|
||||
const user = {
|
||||
["about_me"]: {},
|
||||
["services"]: {}
|
||||
["about_me.txt"]: Entry(""),
|
||||
["services.txt"]: Entry("")
|
||||
}
|
||||
const home = {
|
||||
["user"]: user
|
||||
["user"]: Entry(user)
|
||||
}
|
||||
const root = {
|
||||
["bin"]: {},
|
||||
["home"]: {}
|
||||
["bin"]: Entry({}),
|
||||
["home"]: Entry(home)
|
||||
}
|
||||
|
||||
const fs = {
|
||||
["/"]: root
|
||||
["/"]: Entry(root)
|
||||
}
|
||||
|
||||
export { fs }
|
||||
export { fs, working_dir }
|
@ -1,45 +0,0 @@
|
||||
import { TermEvents } from "./terminal"
|
||||
|
||||
let working_fs_dir = "user"
|
||||
function GetWorkingDir(): string {
|
||||
if (working_fs_dir === "user") {
|
||||
return "~"
|
||||
}
|
||||
return working_fs_dir
|
||||
}
|
||||
|
||||
function ls() {
|
||||
|
||||
}
|
||||
|
||||
function Prompt() {
|
||||
const cyan_user = <span className="cyan">user</span>
|
||||
const green_dir = <span className="green">{GetWorkingDir()}</span>
|
||||
return <p>{cyan_user}@host {green_dir}{"> "}</p>
|
||||
}
|
||||
|
||||
function ShellEvents() {
|
||||
const shell_input = document.getElementById("shell-input")
|
||||
if (shell_input) {
|
||||
shell_input.addEventListener("keydown", (keyboard_event) => {
|
||||
if (keyboard_event.key === "Enter") {
|
||||
console.log("woah its the enter key")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function ShellPrompt() {
|
||||
return <div className="shell-prompt">
|
||||
<Prompt/>
|
||||
<input id="shell-input" type="text" spellCheck={false}/>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default function Shell() {
|
||||
const shell_prompt = ShellPrompt()
|
||||
TermEvents()
|
||||
ShellEvents()
|
||||
|
||||
return shell_prompt
|
||||
}
|
15
src/components/react/shell/color.tsx
Normal file
15
src/components/react/shell/color.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
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>
|
||||
|
||||
export default function rgb(s: string, Ru8: number, Gu8: number, Bu8: number) {
|
||||
return <span style={{color: `rgb(${Ru8},${Gu8},${Bu8})`}}>{s}</span>
|
||||
}
|
||||
|
||||
export {
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
cyan
|
||||
}
|
10
src/components/react/shell/prompt.tsx
Normal file
10
src/components/react/shell/prompt.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { working_dir } from "../fs"
|
||||
import rgb, { cyan, green } from "./color"
|
||||
|
||||
const GetWorkingDir = () => working_dir === "user" ? "~" : working_dir
|
||||
|
||||
export default function Prompt() {
|
||||
const user = cyan("user")
|
||||
const dir = green(GetWorkingDir())
|
||||
return <p>{user}@host {dir}{"> "}</p>
|
||||
}
|
10
src/components/react/term_events.ts
Normal file
10
src/components/react/term_events.ts
Normal file
@ -0,0 +1,10 @@
|
||||
const terminal_window = document.querySelector("main");
|
||||
|
||||
export function TermEvents() {
|
||||
if (terminal_window) {
|
||||
// terminal_window.addEventListener("click", (_event) => {
|
||||
// const shell_input = document.getElementById("shell-input")
|
||||
// if (shell_input) { shell_input.focus() }
|
||||
// })
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
const terminal_window = document.querySelector("main");
|
||||
|
||||
export function TermEvents() {
|
||||
if (terminal_window) {
|
||||
terminal_window.addEventListener("click", (_event) => {
|
||||
const shell_input = document.getElementById("shell-input")
|
||||
if (shell_input) { shell_input.focus() }
|
||||
})
|
||||
}
|
||||
}
|
33
src/components/react/terminal.tsx
Normal file
33
src/components/react/terminal.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import type { JSX } from "react/jsx-dev-runtime"
|
||||
import { TermEvents } from "./term_events"
|
||||
import { createRoot } from "react-dom/client"
|
||||
import { useState } from "react"
|
||||
|
||||
import Prompt from "./shell/prompt"
|
||||
|
||||
const active_shell_prompt = ShellPrompt()
|
||||
|
||||
function ShellEvents() {
|
||||
const shell_input = document.querySelector("main")
|
||||
if (shell_input) {
|
||||
const [prompts, newPrompt] = useState([])
|
||||
shell_input.addEventListener("keydown", (keyboard_event) => {
|
||||
if (keyboard_event.key == "Enter") {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function ShellPrompt() {
|
||||
return <div className="shell-prompt">
|
||||
<Prompt/>
|
||||
<input id="shell-input" type="text" spellCheck={false} autoFocus/>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default function Shell() {
|
||||
TermEvents()
|
||||
ShellEvents()
|
||||
return active_shell_prompt
|
||||
}
|
21
src/components/terminal/motd.astro
Normal file
21
src/components/terminal/motd.astro
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
import { Links } from "../../ts/links"
|
||||
---
|
||||
|
||||
<p>Welcome to rhpidfyre.io!</p>
|
||||
<div class="return"></div>
|
||||
<p>This is a personal website by rhpidfyre / Brandon.</p>
|
||||
<p>You can find my services here or learn about me.</p>
|
||||
<div class="return"></div>
|
||||
<p>You can also contribute or view the source code of my website via the links:</p>
|
||||
<p>{"<"}<a href={Links.RepoGitea} target="_blank">{Links.RepoGitea}</a>{">."}</p>
|
||||
<p>{"<"}<a href={Links.RepoGithub} target="_blank">{Links.RepoGithub}</a>{">."}</p>
|
||||
<div class="return"></div>
|
||||
<p>You can get started with the command: <span class="bold">help</span></p>
|
||||
<div class="return"></div>
|
||||
<noscript>
|
||||
<p><span class="red">=================================================</span></p>
|
||||
<p><span class="red">JavaScript is disabled, functionality will be limited. :(</span></p>
|
||||
<p><span class="red">But, you will not be limited at exploring my services which you can find by navigating towards the top-right.</span></p>
|
||||
<p><span class="red">=================================================</span></p>
|
||||
</noscript>
|
@ -25,15 +25,7 @@ const {title} = Astro.props
|
||||
|
||||
<style is:global lang="scss">
|
||||
@forward "../scss/fonts";
|
||||
@forward "../scss/terminal";
|
||||
|
||||
* {
|
||||
font-family: 'Terminus', monospace;
|
||||
font-size: 15px;
|
||||
letter-spacing: 2px;
|
||||
cursor: text;
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
|
||||
@ -58,7 +50,6 @@ const {title} = Astro.props
|
||||
a {
|
||||
color: white;
|
||||
cursor: unset;
|
||||
|
||||
&:hover, &:active, &:link { text-decoration: none; }
|
||||
}
|
||||
</style>
|
||||
|
@ -1,64 +1,27 @@
|
||||
---
|
||||
import Webpage from '../layouts/Webpage.astro';
|
||||
import { Links } from '../ts/links';
|
||||
import Shell from '../components/react/shell';
|
||||
import Motd from '../components/terminal/motd.astro';
|
||||
import Terminal from '../components/react/terminal';
|
||||
---
|
||||
|
||||
<Webpage title="Home">
|
||||
<main>
|
||||
<p>Welcome to rhpidfyre.io!</p>
|
||||
<div class="return"></div>
|
||||
<p>This is a personal website by rhpidfyre / Brandon.</p>
|
||||
<p>You can find my services here or learn about me.</p>
|
||||
<div class="return"></div>
|
||||
<p>You can also contribute or view the source code of my website via the links:</p>
|
||||
<p>{"<"}<a href={Links.RepoGitea} target="_blank">{Links.RepoGitea}</a>{">."}</p>
|
||||
<p>{"<"}<a href={Links.RepoGithub} target="_blank">{Links.RepoGithub}</a>{">."}</p>
|
||||
<div class="return"></div>
|
||||
<p>You can get started with the command: help</p>
|
||||
<div class="return"></div>
|
||||
<noscript>
|
||||
<p><span class="red">=================================================</span></p>
|
||||
<p><span class="red">JavaScript is disabled, functionality will be limited. :(</span></p>
|
||||
<p><span class="red">But, you will not be limited at exploring my services which you can find by navigating towards the top-right.</span></p>
|
||||
<p><span class="red">=================================================</span></p>
|
||||
</noscript>
|
||||
<Shell client:only/>
|
||||
<Motd/>
|
||||
<Terminal client:only/>
|
||||
</main>
|
||||
</Webpage>
|
||||
|
||||
<style lang="scss" is:global>
|
||||
@use "../scss/variables";
|
||||
|
||||
@mixin text-styles {
|
||||
.red { color: rgb(200, 0, 0); }
|
||||
.green { color: rgb(0, 200, 0); }
|
||||
.blue { color: rgb(0, 0, 200); }
|
||||
.cyan { color: rgb(18,167,148); }
|
||||
}
|
||||
|
||||
.shell-prompt { display: flex; }
|
||||
@use "../scss/terminal";
|
||||
|
||||
main {
|
||||
@include terminal.formatting;
|
||||
|
||||
width: 100vw;
|
||||
height: calc(99.3vh - variables.$header-Y - variables.$footer-Y);
|
||||
padding: 5px;
|
||||
overflow-y: auto;
|
||||
|
||||
p {
|
||||
@include text-styles;
|
||||
font-size: 1.2rem;
|
||||
margin: 5px;
|
||||
|
||||
a {
|
||||
font-size: inherit;
|
||||
&:hover { text-decoration: underline; }
|
||||
}
|
||||
span { font-size: inherit }
|
||||
}
|
||||
.return {
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
input {
|
||||
font-size: 1.2rem;
|
||||
|
@ -5,3 +5,13 @@
|
||||
font-weight: 500;
|
||||
src: url('/Terminus.woff2') format('woff2');
|
||||
}
|
||||
|
||||
* {
|
||||
font: {
|
||||
family: 'Terminus', monospace;
|
||||
size: 15px;
|
||||
};
|
||||
letter-spacing: 2px;
|
||||
text-wrap: nowrap;
|
||||
cursor: text;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
@mixin color-matrix {
|
||||
.red { color: rgb(200, 0, 0); }
|
||||
.green { color: rgb(0, 200, 0); }
|
||||
.blue { color: rgb(0, 0, 200); }
|
||||
.cyan { color: rgb(18,167,148); }
|
||||
}
|
||||
|
||||
@mixin text-styles {
|
||||
.bold { font-weight: bold; }
|
||||
}
|
||||
|
||||
@mixin formatting {
|
||||
.return { margin-top: 25px; }
|
||||
.shell-prompt { display: flex; }
|
||||
|
||||
p {
|
||||
@include color-matrix;
|
||||
@include text-styles;
|
||||
|
||||
font-size: 1.2rem;
|
||||
margin: 5px;
|
||||
|
||||
span { font-size: inherit; }
|
||||
a {
|
||||
font-size: inherit;
|
||||
&:hover { text-decoration: underline; }
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user