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 = {
|
const user = {
|
||||||
["about_me"]: {},
|
["about_me.txt"]: Entry(""),
|
||||||
["services"]: {}
|
["services.txt"]: Entry("")
|
||||||
}
|
}
|
||||||
const home = {
|
const home = {
|
||||||
["user"]: user
|
["user"]: Entry(user)
|
||||||
}
|
}
|
||||||
const root = {
|
const root = {
|
||||||
["bin"]: {},
|
["bin"]: Entry({}),
|
||||||
["home"]: {}
|
["home"]: Entry(home)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fs = {
|
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">
|
<style is:global lang="scss">
|
||||||
@forward "../scss/fonts";
|
@forward "../scss/fonts";
|
||||||
@forward "../scss/terminal";
|
|
||||||
|
|
||||||
* {
|
|
||||||
font-family: 'Terminus', monospace;
|
|
||||||
font-size: 15px;
|
|
||||||
letter-spacing: 2px;
|
|
||||||
cursor: text;
|
|
||||||
text-wrap: nowrap;
|
|
||||||
}
|
|
||||||
:root {
|
:root {
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
|
|
||||||
@ -58,7 +50,6 @@ const {title} = Astro.props
|
|||||||
a {
|
a {
|
||||||
color: white;
|
color: white;
|
||||||
cursor: unset;
|
cursor: unset;
|
||||||
|
|
||||||
&:hover, &:active, &:link { text-decoration: none; }
|
&:hover, &:active, &:link { text-decoration: none; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,64 +1,27 @@
|
|||||||
---
|
---
|
||||||
import Webpage from '../layouts/Webpage.astro';
|
import Webpage from '../layouts/Webpage.astro';
|
||||||
import { Links } from '../ts/links';
|
import Motd from '../components/terminal/motd.astro';
|
||||||
import Shell from '../components/react/shell';
|
import Terminal from '../components/react/terminal';
|
||||||
---
|
---
|
||||||
|
|
||||||
<Webpage title="Home">
|
<Webpage title="Home">
|
||||||
<main>
|
<main>
|
||||||
<p>Welcome to rhpidfyre.io!</p>
|
<Motd/>
|
||||||
<div class="return"></div>
|
<Terminal client:only/>
|
||||||
<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/>
|
|
||||||
</main>
|
</main>
|
||||||
</Webpage>
|
</Webpage>
|
||||||
|
|
||||||
<style lang="scss" is:global>
|
<style lang="scss" is:global>
|
||||||
@use "../scss/variables";
|
@use "../scss/variables";
|
||||||
|
@use "../scss/terminal";
|
||||||
@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; }
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
@include terminal.formatting;
|
||||||
|
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: calc(99.3vh - variables.$header-Y - variables.$footer-Y);
|
height: calc(99.3vh - variables.$header-Y - variables.$footer-Y);
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
overflow-y: auto;
|
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 {
|
input {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
|
@ -4,4 +4,14 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
src: url('/Terminus.woff2') format('woff2');
|
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