21 Commits

Author SHA1 Message Date
c5692b1b7f there is now a subcommand system and history command 2025-02-22 00:49:47 -05:00
b5f279691c update tsconfig.json to be more strict 2025-02-22 00:23:55 -05:00
4663aca074 create the builtin directory and move history.ts to it 2025-02-21 23:49:03 -05:00
e468155bb1 ::spelling-error for chromium browsers 2025-02-21 20:18:07 -05:00
1e938b19b0 rename run.ts -> command.ts 2025-02-21 17:34:59 -05:00
4f5602a5df builder for commands now and history help 2025-02-20 22:01:04 -05:00
129d0ff6b4 the prompt and command input works but the history does not 2025-02-18 17:36:54 -05:00
578aebcae1 init the docker file for later user
https://github.com/static-web-server/static-web-server
2025-02-18 17:31:56 -05:00
375427b16e the ps1 prompt displays properly 2025-02-17 15:02:06 -05:00
84e7089140 no more react 2025-02-16 19:36:08 -05:00
28d71a6ed1 add react compiler 2025-02-13 15:37:54 -05:00
9970c58e2b cd needs work 2025-02-11 15:20:57 -05:00
ee7b2168d9 fs functions wip, set_working_dir needs to work 2025-02-07 02:45:36 -05:00
acf460772c the prompt now displays and works with unknown command 2025-02-06 20:51:25 -05:00
273f748ff1 create commands folder 2025-02-05 17:49:46 -05:00
0303bb733a the prompt now works properly 2025-02-05 17:49:00 -05:00
bb7e2a4ae3 the prompt now displays and repeats on enter 2025-02-04 23:55:09 -05:00
1306a23ec8 i like committing bun.lock 2025-02-03 03:01:15 -05:00
49a62df236 terminal prompt needs to be recyclable 2025-02-03 03:01:06 -05:00
390ff9bccf javascript time 😮‍💨 2025-02-02 03:04:49 -05:00
f0a9566c24 astro setup for react is ready 2025-02-02 03:04:26 -05:00
27 changed files with 765 additions and 94 deletions

View File

@ -0,0 +1,7 @@
FROM oven/bun AS build
COPY package.json astro.config.mjs /tmp/
COPY src public /tmp/
RUN bun run build

View File

@ -1,9 +1,5 @@
// @ts-check
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
// https://astro.build/config
export default defineConfig({
integrations: [react()]
});
export default defineConfig({});

View File

@ -4,14 +4,16 @@
"": {
"name": "rhpidfyre.io",
"dependencies": {
"astro": "^5.2.3",
"astro": "^5.3.0",
"sass": "^1.85.0",
"scss": "^0.2.4",
},
},
},
"packages": {
"@astrojs/compiler": ["@astrojs/compiler@2.10.3", "", {}, "sha512-bL/O7YBxsFt55YHU021oL+xz+B/9HvGNId3F9xURN16aeqDK9juHGktdkCSXz+U4nqFACq6ZFvWomOzhV+zfPw=="],
"@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.5.0", "", {}, "sha512-CgB5ZaZO1PFG+rbjF3HnA7G6gIBjJ070xb7bUjeu5Gqqufma+t6fpuRWMXnK2iEO3zVyX7e/xplPlqtFKy/lvw=="],
"@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.5.1", "", {}, "sha512-M7rAge1n2+aOSxNvKUFa0u/KFn0W+sZy7EW91KOSERotm2Ti8qs+1K0xx3zbOxtAVrmJb5/J98eohVvvEqtNkw=="],
"@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.1.0", "", { "dependencies": { "@astrojs/prism": "3.2.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.1.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.1", "remark-smartypants": "^3.0.2", "shiki": "^1.29.1", "smol-toml": "^1.3.1", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1", "vfile": "^6.0.3" } }, "sha512-emZNNSTPGgPc3V399Cazpp5+snogjaF04ocOSQn9vy3Kw/eIC4vTQjXOrWDEoSEy+AwPDZX9bQ4wd3bxhpmGgQ=="],
@ -243,7 +245,7 @@
"array-iterate": ["array-iterate@2.0.1", "", {}, "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg=="],
"astro": ["astro@5.2.3", "", { "dependencies": { "@astrojs/compiler": "^2.10.3", "@astrojs/internal-helpers": "0.5.0", "@astrojs/markdown-remark": "6.1.0", "@astrojs/telemetry": "3.2.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.1.4", "@types/cookie": "^0.6.0", "acorn": "^8.14.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.1.0", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^0.7.2", "cssesc": "^3.0.0", "debug": "^4.4.0", "deterministic-object-hash": "^2.0.2", "devalue": "^5.1.1", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.6.0", "esbuild": "^0.24.2", "estree-walker": "^3.0.3", "fast-glob": "^3.3.3", "flattie": "^1.1.1", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.1.1", "js-yaml": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.17", "magicast": "^0.3.5", "micromatch": "^4.0.8", "mrmime": "^2.0.0", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.0", "preferred-pm": "^4.1.0", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.0", "shiki": "^1.29.2", "tinyexec": "^0.3.2", "tsconfck": "^3.1.4", "ultrahtml": "^1.5.3", "unist-util-visit": "^5.0.0", "unstorage": "^1.14.4", "vfile": "^6.0.3", "vite": "^6.0.11", "vitefu": "^1.0.5", "which-pm": "^3.0.0", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.0", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.1", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.33.3" }, "bin": { "astro": "astro.js" } }, "sha512-04AceE/gVihtO3V28Ss0+tPPgLHGoulXrm1E7fUVPYyQu7y6w8+oXfYyzh1lpy+uEYiebjH7AFlJoz73anBmZA=="],
"astro": ["astro@5.3.0", "", { "dependencies": { "@astrojs/compiler": "^2.10.3", "@astrojs/internal-helpers": "0.5.1", "@astrojs/markdown-remark": "6.1.0", "@astrojs/telemetry": "3.2.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.1.4", "@types/cookie": "^0.6.0", "acorn": "^8.14.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.1.0", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^0.7.2", "cssesc": "^3.0.0", "debug": "^4.4.0", "deterministic-object-hash": "^2.0.2", "devalue": "^5.1.1", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.6.0", "esbuild": "^0.24.2", "estree-walker": "^3.0.3", "fast-glob": "^3.3.3", "flattie": "^1.1.1", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.1.1", "js-yaml": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.17", "magicast": "^0.3.5", "micromatch": "^4.0.8", "mrmime": "^2.0.0", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.0", "preferred-pm": "^4.1.1", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.1", "shiki": "^1.29.2", "tinyexec": "^0.3.2", "tsconfck": "^3.1.4", "ultrahtml": "^1.5.3", "unist-util-visit": "^5.0.0", "unstorage": "^1.14.4", "vfile": "^6.0.3", "vite": "^6.0.11", "vitefu": "^1.0.5", "which-pm": "^3.0.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.0", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.1", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.33.3" }, "bin": { "astro": "astro.js" } }, "sha512-e88l/Yk/6enR/ZDddLbqtM+oblBFk5mneNSmNesyVYGL/6Dj4UA67GPAZOk79VxT5dbLlclZSyyw/wlxN1aj3A=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
@ -269,7 +271,7 @@
"character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"ci-info": ["ci-info@4.1.0", "", {}, "sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A=="],
@ -547,6 +549,8 @@
"ohash": ["ohash@1.1.4", "", {}, "sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g=="],
"ometa": ["ometa@0.2.2", "", {}, "sha512-LZuoK/yjU3FvrxPjUXUlZ1bavCfBPqauA7fsNdwi+AVhRdyk2IzgP3JRnevvjzQ6fKHdUw8YISshf53FmpHrng=="],
"oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="],
"p-limit": ["p-limit@6.2.0", "", { "dependencies": { "yocto-queue": "^1.1.1" } }, "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA=="],
@ -577,7 +581,7 @@
"postcss": ["postcss@8.5.1", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ=="],
"preferred-pm": ["preferred-pm@4.1.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "find-yarn-workspace-root2": "1.2.16", "which-pm": "^3.0.0" } }, "sha512-cNKMVcSvE3hZBRukdRsvPtlUaM2fYLFbIvBz620XaDA5SjHsCRsAjNE2baI90Hh7QvJIjCHJYnpPtyqJ1/kOjQ=="],
"preferred-pm": ["preferred-pm@4.1.1", "", { "dependencies": { "find-up-simple": "^1.0.0", "find-yarn-workspace-root2": "1.2.16", "which-pm": "^3.0.1" } }, "sha512-rU+ZAv1Ur9jAUZtGPebQVQPzdGhNzaEiQ7VL9+cjsAWPHFYOccNXPNiev1CCDSOg/2j7UujM7ojNhpkuILEVNQ=="],
"prismjs": ["prismjs@1.29.0", "", {}, "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q=="],
@ -589,7 +593,7 @@
"radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"readdirp": ["readdirp@4.1.1", "", {}, "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw=="],
"regex": ["regex@5.1.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw=="],
@ -629,9 +633,11 @@
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"sass": ["sass@1.83.4", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA=="],
"sass": ["sass@1.85.0", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww=="],
"semver": ["semver@7.7.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ=="],
"scss": ["scss@0.2.4", "", { "dependencies": { "ometa": "0.2.2" } }, "sha512-4u8V87F+Q/upVhUmhPnB4C1R11xojkRkWjExL2v0CX2EXTg18VrKd+9JWoeyCp2VEMdSpJsyAvVU+rVjogh51A=="],
"semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
"sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
@ -715,7 +721,7 @@
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
"which-pm": ["which-pm@3.0.0", "", { "dependencies": { "load-yaml-file": "^0.2.0" } }, "sha512-ysVYmw6+ZBhx3+ZkcPwRuJi38ZOTLJJ33PSHaitLxSKUMsh0LkKd0nC69zZCwt5D+AYUcMK2hhw4yWny20vSGg=="],
"which-pm": ["which-pm@3.0.1", "", { "dependencies": { "load-yaml-file": "^0.2.0" } }, "sha512-v2JrMq0waAI4ju1xU5x3blsxBBMgdgZve580iYMN5frDaLGjbA24fok7wKCsya8KLVO19Ju4XDc5+zTZCJkQfg=="],
"which-pm-runs": ["which-pm-runs@1.1.0", "", {}, "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA=="],
@ -757,9 +763,9 @@
"prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"sharp/semver": ["semver@7.7.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ=="],
"sass/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"unstorage/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
"ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
@ -767,8 +773,10 @@
"load-yaml-file/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
"sass/chokidar/readdirp": ["readdirp@4.1.1", "", {}, "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw=="],
"unstorage/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"unstorage/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
}
}

View File

@ -9,13 +9,9 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/react": "^4.2.0",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"astro": "^5.2.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"sass": "^1.83.4",
"astro": "^5.3.0",
"sass": "^1.85.0",
"scss": "^0.2.4"
}
},
"devDependencies": {}
}

View File

@ -16,6 +16,10 @@ const {href, display, color = "transparent"} = Astro.props
height: 100%;
padding: 0 20px 0 20px;
&:hover { background-color: var(--hf-button-hover-color) }
&:hover {
background-color: var(--hf-button-hover-color) !important;
& > a { color: black }
}
}
</style>

View 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

View 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
}
}

View File

@ -0,0 +1,43 @@
import { bold } from "../shell/color";
import create from "./create";
function stdout_grid(left: string[], right: string[]) {
const root = create("div", "stdout-horizontal")
const container_left = create("div", "stdout-vertical")
const container_right = create("div", "stdout-vertical")
left.forEach(str => container_left.appendChild(stdout_bold(str)))
right.forEach(str => container_right.appendChild(stdout(str)))
root.appendChild(container_left)
root.appendChild(container_right)
return root
}
function stdout_horizontal(strs: string[]) {
const p = create("p")
strs.forEach((str, i) => {
const tab = i !== strs.length-1 ? "\t" : ""
p.innerText+=str+tab
})
return p
}
function stdout_bold(str: string) {
const p = stdout("")
p.appendChild(bold(str))
return p
}
export default function stdout(str: string) {
const p = create("p")
p.innerText = str
return p
}
export {
stdout_grid,
stdout_horizontal,
stdout_bold
}

View File

@ -0,0 +1,34 @@
import run from "./shell/command/command"
import history from "./shell/history"
type InputClosure = (key_event: KeyboardEvent) => void
interface EnterArgs {
readonly term_win_safe: HTMLElement,
readonly ps1input: HTMLInputElement,
readonly closure: InputClosure
}
interface Keys {
enter: (input: EnterArgs) => void,
up_arrow: (ps1input: HTMLInputElement) => void,
down_arrow: (ps1input: HTMLInputElement) => void,
}
const keys = {} as Keys
keys.enter = function(input: EnterArgs) {
const unknown_command_msg = run(input.term_win_safe, input.ps1input.value)
if (unknown_command_msg) {
input.term_win_safe.appendChild(unknown_command_msg)
}
input.ps1input.removeEventListener("keydown", input.closure)
}
keys.up_arrow = function(ps1input: HTMLInputElement) {
history.index_up(ps1input)
}
keys.down_arrow = function(ps1input: HTMLInputElement) {
history.index_down(ps1input)
}
export default keys

View File

@ -0,0 +1,34 @@
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) => 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) {
const rgb_span = newcolor(s)
rgb_span.style.color = `rgb(${Ru8},${Gu8},${Bu8})`
return rgb_span
}
export {
red,
green,
blue,
cyan,
bold
}

View File

@ -0,0 +1,22 @@
import type { Args, Term } from "../list";
import stdout from "../../../elements/stdout";
import SubCommand from "../subcommand";
import history from "../../history";
const history_command = new SubCommand("Show and manipulate command history")
history_command.add("show", "Show the history", function(term: Term, _args: Args) {
history.file.inner.forEach((entry, ind) => term.appendChild(stdout(`${ind} ${entry}`)))
})
history_command.add("clear", "Delete the entire command history", function(term: Term, _args: Args) {
const entries = history.file.inner.length
history.file.inner = []
term.appendChild(stdout(`Cleared ${entries} entries from the history.`))
})
export default function history_cmd(term: Term, args: Args) {
history_command.process(term, args)
return true
}

View File

@ -0,0 +1,38 @@
import { bold } from "../color";
import { to_args, trim } from "./parse";
import commands, { type Command } from "./list";
import history from "../history";
import stdout from "../../elements/stdout";
type Term = HTMLElement
function valid_command(term: Term, args: string[]) {
for (const command_in_list in commands) {
const command = args[0]
if (command === command_in_list) {
return (commands[command_in_list] as Command)(term, args)
}
}
return
}
function unknown_command(cmd_name: string) {
const unknown_element = stdout("shell: Unknown command: ")
unknown_element.appendChild(bold(cmd_name))
return unknown_element
}
export default function run(term: Term, stdin: string) {
const args = to_args(trim(stdin))
const valid = valid_command(term, args)
const command = args[0] as string
if (command !== "" && !valid) {
return unknown_command(command)
}
history.add(args.join(" "))
return false
}
export { unknown_command }

View File

@ -0,0 +1,75 @@
import { get_working_dir_name_full, set_working_dir, SetDirStatus } from "../fs/fn"
import history_cmd from "./builtin/history"
import stdout from "../../elements/stdout"
type Term = HTMLElement
type Args = string[]
function clear(term: Term, args: Args): boolean {
Array.from(term.children).forEach(node => {
if (node.tagName === "DIV") {
if (node.className === "shell-prompt") {
const input = node.getElementsByClassName("shell-ps1")[0] as HTMLInputElement
if (input.disabled || input.value === "clear") {
node.remove()
}
} else {
node.remove()
}
} else if (node.tagName === "P") {
node.remove()
}
})
return true
}
function cd(term: Term, args: Args): boolean {
const new_dir_status = set_working_dir(args[1])
if (new_dir_status === SetDirStatus.NotADirectory) {
// return <p>{"cd: \""}{bold(args[1])}{"\" is not a directory"}</p>
} else if (new_dir_status === SetDirStatus.NotFound) {
// return <p>{"cd: The directory \""}{bold(args[1])}{"\" does not exist"}</p>
}
return true
}
function ls(term: Term, args: Args): boolean {
// if (args[1] === undefined) {
// for (const dir_name in working_dir) {
// }
// return <p>{`${working_dir}`}</p>
// }
return true
}
function pwd(term: Term, args: Args): boolean {
term.appendChild(stdout(get_working_dir_name_full()))
return true
}
function cat(term: Term, args: Args): boolean {
return true
}
type Command = (term: Term, args: Args) => boolean
interface CommandsList {
[index: string]: Command,
}
const commands: CommandsList = {
["clear"]: clear,
["cd"]: cd,
["ls"]: ls,
["pwd"]: pwd,
["cat"]: cat,
["history"]: history_cmd,
}
export default commands
export {
type Command,
type Term,
type Args
}

View File

@ -0,0 +1,14 @@
function trim(stdin: string): string {
const trimmed_str: string[] = []
stdin.split(" ").forEach(s => { if (s !== "") { trimmed_str.push(s) } })
return trimmed_str.join(" ")
}
function to_args(trimmed_str: string): string[] {
return trimmed_str.split(" ")
}
export {
trim,
to_args
}

View File

@ -0,0 +1,63 @@
import stdout, { stdout_grid } from "../../elements/stdout";
import { bold } from "../color";
import type { Args, Term } from "./list";
type SubCommandClosure = (term: Term, args: Args) => void
interface SubCommandAction {
inner: SubCommandClosure,
description: string,
}
interface SubCommands {
[index: string]: SubCommandAction,
}
const SubCommand = class {
public data: SubCommands //data? less goo!
constructor(description: string) {
this.data = {}
this.data.help = {} as SubCommandAction
this.data.help.description = "Display help info"
this.data.help.inner = (term: Term, _args: Args) => {
const descriptions: string[] = []
Object.values(this.data).forEach(sub_cmd => descriptions.push(sub_cmd.description))
term.appendChild(stdout(description))
term.appendChild(stdout_grid(Object.keys(this.data), descriptions))
}
}
public process(term: Term, args: Args) {
const subc = args[1]
if (subc) {
const subc_f = this.data[subc]
if (subc_f) {
subc_f.inner(term, args)
} else {
term.appendChild(SubCommand.unknown(subc))
this.data.help.inner(term, args)
}
} else {
this.data.help.inner(term, args)
}
}
public add(name: string, description: string, f: SubCommandClosure) {
this.data[name] = {} as SubCommandAction
this.data[name].description = description
this.data[name].inner = f
}
public static unknown(subcmd_name: string) {
const subcmd_unknown = stdout("Unknown sub-command: ")
subcmd_unknown.appendChild(bold(subcmd_name))
return subcmd_unknown
}
}
export default SubCommand
export {
type SubCommand,
type SubCommandAction
}

View File

@ -0,0 +1,75 @@
import { Entry, EntryType, fs, type FsEntrySignature } from "./fs"
let working_dir = ["/", "home", "user"]
function get_working_dir_name() {
return working_dir[working_dir.length-1]
}
function get_working_dir_name_full(): string {
const w_dir_clone = [...working_dir]
const root = w_dir_clone.shift()
if (root) {
return root+w_dir_clone.join("/")
}
return "shift-error"
}
const enum SetDirStatus {
Valid,
NotFound,
NotADirectory
}
interface FsIterEntry {
readonly entry: FsEntrySignature | null,
readonly status: SetDirStatus
}
function iter_fs_to_goal(w_dir_clone: string[]): FsIterEntry {
let next_iter = fs[0]
for (const w_dir of w_dir_clone) {
if (w_dir === "/") { continue }
if (next_iter && next_iter.inner) {
const found = next_iter.inner.find(entry => entry.name === w_dir)
if (!found) {
return { entry: null, status: SetDirStatus.NotFound }
}
if (found.type !== EntryType.Directory) {
return { entry: null, status: SetDirStatus.NotADirectory }
}
if (found.name === w_dir_clone[w_dir_clone.length-1]) {
return { entry: next_iter, status: SetDirStatus.Valid }
} else {
next_iter = found.inner as FsEntrySignature
}
}
}
return { entry: null, status: SetDirStatus.NotFound }
}
function set_working_dir(name: string): SetDirStatus {
if (name === ".") { return SetDirStatus.Valid }
const w_dir_clone = [...working_dir]
if (name === "..") { w_dir_clone.pop() } else { w_dir_clone.push(name) }
const iter_status = iter_fs_to_goal(w_dir_clone)
if (iter_status.status === SetDirStatus.Valid) {
working_dir = w_dir_clone
}
return iter_status.status
}
function working_dir_entries() {
const w_dir_clone = [...working_dir]
const iter_status = iter_fs_to_goal(w_dir_clone)
}
export {
get_working_dir_name,
get_working_dir_name_full,
set_working_dir,
SetDirStatus
}

View File

@ -0,0 +1,51 @@
const enum EntryType {
Directory,
File
}
const enum Permissions {
r,
w,
rw
}
type FsEntrySignature = Entry<Entry<{}>[]> //I did this!
const user = [
Entry("about_me.txt", "about me inside", Permissions.rw),
Entry("services.txt", "services inside", Permissions.rw),
Entry("hi", [], Permissions.rw)
]
const home = [
Entry("user", user, Permissions.rw)
]
const root = [
Entry("home", home, Permissions.r),
Entry("bin", {}, Permissions.r),
]
const fs = [
Entry("/", root, Permissions.r)
]
type File = string
interface Entry<T = File> {
readonly inner?: T,
readonly name: string,
readonly type: EntryType,
readonly permissions: Permissions
}
function Entry<T = File>(name: string, inner: T, permissions: Permissions): Entry<T> {
return {
type: typeof inner == "object" ? EntryType.Directory : EntryType.File,
inner: inner,
name: name,
permissions: permissions
}
}
export {
fs,
type FsEntrySignature,
EntryType,
Permissions,
Entry
}

View File

@ -0,0 +1,48 @@
interface HistoryFile {
inner: string[],
cursor: number,
cursor_reset: () => void
}
interface History {
file: HistoryFile
add: (cmd: string) => void,
index_up: (ps1input: HTMLInputElement) => void,
index_down: (ps1input: HTMLInputElement) => void
}
const history = {} as History
history.file = {} as HistoryFile
history.file.inner = []
history.file.cursor = 0
history.file.cursor_reset = function() {
this.cursor = 0
}
history.add = function(cmd: string) {
if (this.file.inner[this.file.inner.length-1] !== cmd) {
this.file.inner.push(cmd)
}
}
history.index_up = function(ps1input: HTMLInputElement) {
const item = this.file.inner[this.file.cursor]
if (item) {
this.file.cursor+=1
ps1input.value = item
}
}
history.index_down = function(ps1input: HTMLInputElement) {
if (this.file.cursor!==0) {
this.file.cursor-=1
if (this.file.cursor!==0) {
const item = this.file.inner[this.file.cursor]
if (item) { ps1input.value = item }
} else {
this.file.cursor_reset()
ps1input.value = ""
}
}
}
export default history

View File

@ -0,0 +1,53 @@
import history from "./shell/history"
import prompt from "./elements/prompt"
import keys from "./keys"
const term_win_unsafe = document.querySelector("main")
const enum Key {
Enter = "Enter",
ArrowRight = "ArrowRight",
ArrowUp = "ArrowUp",
ArrowDown = "ArrowDown",
Tab = "Tab"
}
function spawnps1(term_win_safe: HTMLElement) {
const ps1prompt = prompt()
term_win_safe.appendChild(ps1prompt.body)
bind_processor(term_win_safe, ps1prompt.input)
history.file.cursor_reset()
ps1prompt.input.focus()
}
function bind_processor(term_win_safe: HTMLElement, ps1prompt_input: HTMLInputElement) {
const input_closure = (key_event: KeyboardEvent) => {
if (key_event.key === Key.Enter) {
key_event.preventDefault()
keys.enter({
term_win_safe: term_win_safe,
ps1input: ps1prompt_input,
closure: input_closure
})
spawnps1(term_win_safe)
} else if (key_event.key === Key.Tab) {
key_event.preventDefault()
} else if (key_event.key === Key.ArrowRight) {
key_event.preventDefault()
} else if (key_event.key === Key.ArrowUp) {
key_event.preventDefault()
keys.up_arrow(ps1prompt_input)
} else if (key_event.key === Key.ArrowDown) {
key_event.preventDefault()
keys.down_arrow(ps1prompt_input)
}
}
ps1prompt_input.addEventListener("keydown", input_closure)
}
if (term_win_unsafe) {
spawnps1(term_win_unsafe)
} else {
}

View File

@ -6,7 +6,7 @@ import { Links } from '../ts/links';
<header>
<Button href={Links.Self} display="[rhpidfyre.io]" color="black"/>
<section>
<Button href={Links.Git} display="REPOS"/>
<Button href={Links.Git} display="GIT"/>
<Button href={Links.Cloud} display="CLOUD"/>
<Button href={Links.Gsm} display="GSM"/>
</section>

View 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>

View File

@ -2,11 +2,6 @@
import Metas from "../components/metas.astro"
import Header from "../components/header.astro"
import Footer from "../components/footer.astro"
interface Props {
title: string,
}
const {title} = Astro.props
---
<!doctype html>
@ -14,10 +9,10 @@ const {title} = Astro.props
<head>
<Metas/>
<link rel="icon" type="image/png" href="/logo.png"/>
<title>{`rhpidfyre.io | ${title}`}</title>
<title>rhpidfyre.io</title>
</head>
<body>
<Header title={title}/>
<Header/>
<slot/>
<Footer/>
</body>
@ -25,19 +20,12 @@ 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;
}
:root {
color-scheme: dark;
--body-background-color: rgb(0,0,0);
--hf-button-hover-color: rgb(50,50,50);
--hf-button-hover-color: rgb(255,255,255);
}
::selection {
background-color: rgb(255,255,255);
@ -57,7 +45,6 @@ const {title} = Astro.props
a {
color: white;
cursor: unset;
&:hover, &:active, &:link { text-decoration: none; }
}
</style>

View File

@ -1,57 +1,40 @@
---
import Webpage from '../layouts/Webpage.astro';
import { Links } from '../ts/links';
import Motd from '../components/terminal/motd.astro';
---
<Webpage title="Home">
<Webpage>
<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>
<Motd/>
<script src="../components/client/terminal.ts"></script>
</main>
</Webpage>
<style lang="scss">
<style lang="scss" is:global>
@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); }
::spelling-error {
text-decoration: none
}
:global(main) {
main {
@include terminal.formatting;
width: 100vw;
height: calc(99.3vh - variables.$header-Y - variables.$footer-Y);
padding: 5px;
overflow-y: auto;
}
input {
font-size: 1.2rem;
background-color: transparent;
border: 0;
outline: 0;
width: 90%;
/* Pester me when this gets undrafted */
caret-shape: block;
p {
@include text-styles;
font-size: 1.2rem;
margin: 5px;
a {
font-size: inherit;
&:hover { text-decoration: underline; }
}
}
.return {
margin-top: 25px;
}
&:disabled { color: white }
}
</style>

View File

@ -4,4 +4,14 @@
font-style: normal;
font-weight: 500;
src: url('/Terminus.woff2') format('woff2');
}
* {
font: {
family: 'Terminus', monospace;
size: 15px;
};
letter-spacing: 2px;
text-wrap: nowrap;
cursor: text;
}

View File

@ -0,0 +1,39 @@
@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 stdout-layouts {
.stdout-vertical { display: grid; }
.stdout-horizontal {
display: flex;
gap: 30px;
}
}
@mixin formatting {
@include stdout-layouts;
.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; }
}
}
}

View File

@ -1,15 +1,10 @@
{
"extends": "astro/tsconfigs/strict",
"include": [
".astro/types.d.ts",
"**/*"
],
"exclude": [
"dist"
],
"compilerOptions": {
"noImplicitAny": true,
"jsx": "react-jsx",
"jsxImportSource": "react"
}
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": {
"noImplicitAny": true,
"noUnusedLocals": true,
"allowUnusedLabels": false
}
}