From dc4309ae381e127938a90a603b88176568a5cc3f Mon Sep 17 00:00:00 2001 From: trinkey Date: Mon, 10 Mar 2025 18:09:59 -0400 Subject: [PATCH] tab completions + more testimonials + velzie button --- css/base.css | 9 ++ img/emoji/neodog_bite_neocat.png | Bin 0 -> 21044 bytes index.html | 20 +-- js/index.js | 223 +++++++++++++++++++++--------- js/shell.js | 67 +++++---- no-js.html | 4 +- ts/index.ts | 230 ++++++++++++++++++++++--------- ts/shell.ts | 86 +++++++----- 8 files changed, 417 insertions(+), 222 deletions(-) create mode 100644 img/emoji/neodog_bite_neocat.png diff --git a/css/base.css b/css/base.css index 8fb2401..49fb404 100644 --- a/css/base.css +++ b/css/base.css @@ -86,6 +86,15 @@ nav { margin: 0 auto; } +.emoji { + --emoji-size: 1.1em; + height: var(--emoji-size); + width: var(--emoji-size); + object-fit: contain; + position: relative; + top: 0.2em; +} + .cursor { color: var(--crust); background-color: var(--text); diff --git a/img/emoji/neodog_bite_neocat.png b/img/emoji/neodog_bite_neocat.png new file mode 100644 index 0000000000000000000000000000000000000000..5c83d5c8ed5e7c80faf382ef29d261a10ecc899a GIT binary patch literal 21044 zcmZsBWmH^E6Xwj|?(PJFySs(pF2UUi7J@@?cL?rIaCdiiCwOpoA9mhv_vg+zbFQ>h zbyw9>aywjEQ3?f-5D@?XpvXvnQ3U{ikXs-C9u{)Z`%!8EdGN88kWjWZH3a}@<9*_V zr29pQ2MyI4C3T3;$amxN+N|(!F!W?`B8~DIaCBT)Tknw4IjQKFV*+e@dt(R70we3I zP^$vSpMbk(+l5Dz)L<66hOqnX7P89=p^HtRctM|fJq==Mx_RL)8(W4hj!*SbAeq>N zv7SkBwls^yjEnb1fB$kj{PfAMi)jq?o6k^!luo~oLnJ%I1naGjGathxDyZlN4hOJc z_2Zu6PwU1VG9yuu1UbyiRBs0;Olntpf56oz-?!*5_(30 z^01?xbV>gdW{QA7MIrtb#a!KpLcIKIL^$^OaNAQTiEn})d+V6dKP^!lda7YGFkE*# z7m`|{y(&5EUDwLPFzxm_OuEZDSh(r@0Abq)wyL42dktVAB2(Smc!j}QgQBO`%;kaB z@)sDA{c|*qcvMb}7TfQUh{yg*+09RUC?tN_4?5dgrS3IO0aX11va zLKH@^H9k{J1s-R z-RG&U^;6Z@jok5vgN5~XbMl`aj^^b5lRs~Ck(zeZKXT-^Lu_a0JuYGz|1asUhDOLC zn+A`GI;M2ubP}!KBkr1)?n*)lKOgxESZT~zKug-{JRl#eS?S>TVxg%)BmLpge@YLFIsq%%n5Mk5y

Q|S92 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

trinkey's website!
-
-
- -
-
- @@ -59,7 +55,7 @@ this page instead - My cat + my cat
- - diff --git a/js/index.js b/js/index.js index 77d0f7d..af603a2 100644 --- a/js/index.js +++ b/js/index.js @@ -53,6 +53,74 @@ function edgeMoveEvent(x, y, pos, windowID) { w.element.querySelector(".window").style.width = `${w.width}px`; w.element.querySelector(".window").style.height = `${w.height}px`; } +function mouseMoveEvent(windowID, x, y) { + let w = WINDOWS[windowID]; + w.posX = Math.max(0, Math.min(innerWidth - w.width - _windowPaddingX, x - w.vars.mouseOffsetX)); + w.posY = Math.max(0, Math.min(innerHeight - w.height - _windowPaddingY, y - w.vars.mouseOffsetY)); + w.element.style.left = `${w.posX}px`; + w.element.style.top = `${w.posY}px`; +} +function syncInputs(windowID) { + let windowInput = WINDOWS[windowID].element.querySelector("input.window-input"); + let windowVisualText = WINDOWS[windowID].element.querySelector("[data-type-area]"); + let w = WINDOWS[windowID].element.querySelector(".window"); + if (!windowVisualText) { + return; + } + setTimeout(function () { + let text = windowInput.value; + let cursor = windowInput.selectionStart; + if (cursor == text.length) { + windowVisualText.innerHTML = `${escapeHTML(text)} `; + } + else { + windowVisualText.innerHTML = `${escapeHTML(text.slice(0, cursor))}${escapeHTML(text[cursor])}${escapeHTML(text.slice(cursor + 1))}`; + } + }, 1); + w.scrollTop = w.scrollHeight; +} +function setCursor(windowID) { + let windowInput = WINDOWS[windowID].element.querySelector("input.window-input"); + setTimeout(() => { + windowInput.setSelectionRange(windowInput.value.length, windowInput.value.length); + syncInputs(windowID); + }, 1); +} +function toggleFullscreen(windowID) { + let w = WINDOWS[windowID]; + if (w.fullscreen) { + w.posX = Math.max(0, Math.min(innerWidth - w.vars.oldWidth - _windowPaddingX, w.vars.oldPosX)); + w.posY = Math.max(0, Math.min(innerHeight - w.vars.oldHeight - _windowPaddingY, w.vars.oldPosY)); + w.width = Math.max(w.minWidth, Math.min(w.vars.oldWidth, innerWidth - _windowPaddingX)); + w.height = Math.max(w.minHeight, Math.min(w.vars.oldHeight, innerHeight - _windowPaddingY)); + w.fullscreen = false; + delete w.vars.oldPosX; + delete w.vars.oldPosY; + delete w.vars.oldWidth; + delete w.vars.oldHeight; + w.element.style.left = `${w.posX}px`; + w.element.style.top = `${w.posY}px`; + w.element.style.width = `${w.width + _windowPaddingX - 2}px`; + w.element.querySelector(".window").style.width = `${w.width}px`; + w.element.querySelector(".window").style.height = `${w.height}px`; + } + else { + w.vars.oldPosX = w.posX; + w.vars.oldPosY = w.posY; + w.vars.oldWidth = w.width; + w.vars.oldHeight = w.height; + w.fullscreen = true; + w.posX = 0; + w.posY = 0; + w.width = innerWidth; + w.height = innerHeight; + w.element.style.left = "0px"; + w.element.style.top = "0px"; + w.element.style.width = `${w.width}px`; + w.element.querySelector(".window").style.width = `${w.width - _windowPaddingX}px`; + w.element.querySelector(".window").style.height = `${w.height - _windowPaddingY}px`; + } +} function createWindow(config) { if (document.getElementById(config.id)) { incrementZIndex(config.id); @@ -90,30 +158,8 @@ function createWindow(config) { wI = document.createElement("input"); wI.classList.add("window-input"); wI.id = `${config.id}__input`; - function syncInputs() { - setTimeout(function () { - let text = wI.value; - let cursor = wI.selectionStart; - let el = wC.querySelector("[data-type-area]"); - if (!el) { - return; - } - if (cursor == text.length) { - el.innerHTML = `${escapeHTML(text)} `; - } - else { - el.innerHTML = `${escapeHTML(text.slice(0, cursor))}${escapeHTML(text[cursor])}${escapeHTML(text.slice(cursor + 1))}`; - } - }, 1); - } - function setCursor() { - setTimeout(() => { - wI.setSelectionRange(wI.value.length, wI.value.length); - syncInputs(); - }, 0); - } wI.oninput = (event) => { - syncInputs(); + syncInputs(config.id); w.scrollTop = w.scrollHeight; }; wI.onkeydown = (event) => { @@ -122,12 +168,88 @@ function createWindow(config) { w.scrollTop = w.scrollHeight; wI.value = ""; } + else if (event.key == "Tab") { + event.preventDefault(); + let val = wI.value.trim(); + let possibilities = []; + let parent; + if (!val) { + return; + } + if (val.split(" ").length == 1 && wI.value[wI.value.length - 1] != " ") { + possibilities = Object.keys(_internal_commands).filter((cmd) => (cmd.startsWith(val) && !cmd.startsWith("_"))); + } + else if (_internal_commands[val.split(" ")[0]] && _internal_commands[val.split(" ")[0]].autocomplete) { + let ac = _internal_commands[val.split(" ")[0]].autocomplete; + let path = val.split(" ").slice(1).join(" ").trim(); + let sw = path.split("/")[path.split("/").length - 1]; + if (typeof ac == "object") { + possibilities = ac; + } + else { + if (path) { + if (path[path.length - 1] == "/") { + parent = _internal_getFile(_internal_sanitizePath(_internal_joinPaths(windowInformation[config.id].PWD, path))); + } + else { + parent = _internal_getFile(_internal_sanitizePath(_internal_joinPaths(windowInformation[config.id].PWD, path + "/.."))); + } + } + else { + parent = _internal_getFile(windowInformation[config.id].PWD); + } + if (parent && parent.type == "directory") { + let f = parent.files; + possibilities = Object.keys(f); + if (ac == "dir") { + possibilities = possibilities.filter((file) => (f[file] && f[file].type == "directory")); + } + } + else { + parent = null; + } + } + possibilities = possibilities.filter((v) => v.startsWith(sw)); + } + if (possibilities.length == 1) { + if (val.split(" ").length == 1 && wI.value[wI.value.length - 1] != " ") { + wI.value = possibilities[0] + " "; + } + else if (_internal_commands[val.split(" ")[0]] && _internal_commands[val.split(" ")[0]].autocomplete) { + let path = val; + if (val[val.length - 1] == "/") { + path += possibilities[0]; + } + else { + let p = path.split("/"); + if (p.length == 1) { + p = p[0].split(" ", 2); + if (p.length == 1) { + p.push(""); + } + p.pop(); + path = p.join(" ") + " " + possibilities[0]; + } + else { + p.pop(); + path = p.join("/") + "/" + possibilities[0]; + } + } + wI.value = path + (parent && parent.type == "directory" && parent.files[possibilities[0]].type == "directory" ? "/" : " "); + } + syncInputs(config.id); + } + else if (possibilities) { + addWindowCommand(config.id, possibilities.join(" ")); + syncInputs(config.id); + } + } else { - syncInputs(); + syncInputs(config.id); } }; - wI.onfocus = setCursor; - wI.onclick = setCursor; + wI.onfocus = () => { setCursor(config.id); }; + wI.onclick = () => { setCursor(config.id); }; wC = document.createElement("label"); wC.htmlFor = `${config.id}__input`; } @@ -146,6 +268,7 @@ function createWindow(config) { let el = document.createElement("div"); el.classList.add("edge", pos); el.addEventListener("mousedown", function (e) { + incrementZIndex(config.id); e.preventDefault(); WINDOWS[config.id].vars.mouseOffsetX = e.clientX - WINDOWS[config.id].posX; WINDOWS[config.id].vars.mouseOffsetY = e.clientY - WINDOWS[config.id].posY; @@ -182,12 +305,9 @@ function createWindow(config) { zIndex: globalIncrement, vars: {} }; - function mouseMoveEvent(x, y) { - WINDOWS[config.id].posX = Math.max(0, Math.min(innerWidth - WINDOWS[config.id].width - _windowPaddingX, x - WINDOWS[config.id].vars.mouseOffsetX)); - WINDOWS[config.id].posY = Math.max(0, Math.min(innerHeight - WINDOWS[config.id].height - _windowPaddingY, y - WINDOWS[config.id].vars.mouseOffsetY)); - wC.style.left = `${WINDOWS[config.id].posX}px`; - wC.style.top = `${WINDOWS[config.id].posY}px`; - } + windowInformation[config.id] = { + PWD: HOME_DIR + }; wC.addEventListener("focus", function () { incrementZIndex(config.id); }); for (const link of wC.querySelectorAll("a")) { link.addEventListener("focus", function () { incrementZIndex(config.id); }); @@ -199,7 +319,7 @@ function createWindow(config) { WINDOWS[config.id].vars.mouseOffsetX = e.clientX - WINDOWS[config.id].posX; WINDOWS[config.id].vars.mouseOffsetY = e.clientY - WINDOWS[config.id].posY; MOUSE_MOVE_PROCESSING[config.id] = { - callback: mouseMoveEvent, + callback: (x, y) => { mouseMoveEvent(config.id, x, y); }, mouseUp: true }; }); @@ -212,41 +332,8 @@ function createWindow(config) { config.onDestroy(); } }); - wH.querySelector(".fullscreen").addEventListener("click", function () { - let window = WINDOWS[config.id]; - if (window.fullscreen) { - window.posX = Math.max(0, Math.min(innerWidth - window.vars.oldWidth - _windowPaddingX, window.vars.oldPosX)); - window.posY = Math.max(0, Math.min(innerHeight - window.vars.oldHeight - _windowPaddingY, window.vars.oldPosY)); - window.width = Math.max(window.minWidth, Math.min(window.vars.oldWidth, innerWidth - _windowPaddingX)); - window.height = Math.max(window.minHeight, Math.min(window.vars.oldHeight, innerHeight - _windowPaddingY)); - window.fullscreen = false; - delete window.vars.oldPosX; - delete window.vars.oldPosY; - delete window.vars.oldWidth; - delete window.vars.oldHeight; - wC.style.left = `${window.posX}px`; - wC.style.top = `${window.posY}px`; - wC.style.width = `${window.width + _windowPaddingX - 2}px`; - w.style.width = `${window.width}px`; - w.style.height = `${window.height}px`; - } - else { - window.vars.oldPosX = window.posX; - window.vars.oldPosY = window.posY; - window.vars.oldWidth = window.width; - window.vars.oldHeight = window.height; - window.fullscreen = true; - window.posX = 0; - window.posY = 0; - window.width = innerWidth; - window.height = innerHeight; - wC.style.left = "0px"; - wC.style.top = "0px"; - wC.style.width = `${window.width}px`; - w.style.width = `${window.width - _windowPaddingX}px`; - w.style.height = `${window.height - _windowPaddingY}px`; - } - }); + wH.querySelector(".fullscreen").addEventListener("click", () => (toggleFullscreen(config.id))); + wH.addEventListener("dblclick", () => (toggleFullscreen(config.id))); globalIncrement++; } function windowPreset(template, dontDisableTyping = false) { diff --git a/js/shell.js b/js/shell.js index 40c667f..63899cd 100644 --- a/js/shell.js +++ b/js/shell.js @@ -209,19 +209,21 @@ function _internal_neofetch(args, windowID) { return _internal_neofetchOutputs[args]; } const _internal_commands = { - cat: cat, - cd: cd, - clear: clear, - help: help, - ls: ls, - exit: exit, - _internal_set_ps1: _internal_set_ps1, - _internal_neofetch: _internal_neofetch + cat: { callback: cat, autocomplete: "file" }, + cd: { callback: cd, autocomplete: "dir" }, + clear: { callback: clear, autocomplete: null }, + help: { callback: help, autocomplete: null }, + ls: { callback: ls, autocomplete: "file" }, + exit: { callback: exit, autocomplete: null }, + _internal_set_ps1: { callback: _internal_set_ps1, autocomplete: null }, + _internal_neofetch: { callback: _internal_neofetch, autocomplete: null }, + spin: { callback: (args, windowID) => { createBlob(); return ""; }, autocomplete: null }, }; const _internal_defaultFiles = { - about: `
hi there! i'm trinkey!
+ about: `
hi there!
+
i'm trinkey, but you can call me katie too! (trinkey is more of a username)
--------------------
-
i'm a silly little kitty cat who lives in the usa (sadly).
+
i'm a silly little cat who lives in the usa (new york time zone).
i'm trans (she/it, they/them is also fine).
i'm not actively in a relationship, however i'm also not looking to get into one either.
--------------------
@@ -236,6 +238,7 @@ const _internal_defaultFiles = {
- signal - @trinkey.01
- email - trinkey [at] proton [dot] me
- youtube - @trinkey (inactive)
+
- discord - @trinkey_ (mostly inactive)
- gpg key (1D6E 5D28 BDD4 D7FA 96B8 8799 2B33 C6C6 14F2 591A)
`, projects: `
projects - the things i made
- smiggins (website) - a social media platform i made
@@ -247,23 +250,28 @@ const _internal_defaultFiles = { buttons: `
my button: (click to copy html)
trinkey's 88x31. image of her cat on the right with the word 'trinkey' taking up the rest of the button.
--------------------
-
cool people:
notfire.cc - a non-spinning demigirl blobcat angled slightly with a black border to the left of "Micro" + a non-spinning demigirl blobcat angled slightly with a black border to the left of "Micro" kopper's button Sneexy unnick Autumn Town Café the text 'red is purple' on a purple background doskel + velzie
`, testimonials: `
"warning: this user is trinkey"

"This user is only slightly crazy once was I. 10/10 would recommend"

"the f slur but repeated 36 times"
- `, +
+
"silly cute kitn"
+
+
"very bitable neodog_bite_neocat
+ + `, webrings: `
catppuccin webring @@ -301,6 +309,7 @@ const _internal_defaultFiles = {
the outpost frontend for fedi made by kopper

official jerimiah smiggins instance, that being my own social media platform

+
there's also a qna for me at *trinkey.com/qna

(asterisk (*) means i haven't written the code for it)

` }; const _internal_neofetchOutputs = { @@ -343,25 +352,28 @@ const _internal_neofetchOutputs = { '-MMMMMMMMMMMMM-' \`\`-:::::-\`\`` }; -const helpText = `
 -=== tSh help ===-
+const helpText = ` +
 -=== tSh help ===-
--------------------
-= cat =-
-
Displays the contents of a file.
+
displays the contents of a file
-= cd =-
-
Changes the working directory.
+
changes the working directory
-= clear =-
-
Clears the terminal output.
+
clears the terminal output
-= help =-
-
Shows this help menu.
+
shows this help menu
-= ls =-
-
Lists all files in a directory.
+
lists all files in a directory
  -l - displays more information about each file
  -a - displays all files
  -A - displays all files except implied . and ..
  -r - reverses the order of the files
  -R - recurse through all subdirectories
+
-= spin =-
+
creates a new window with a spinning blobcat wireframe
-= exit =-
-
Closes the terminal.
`; +
closes the terminal window
`; const HOME_DIR = "/home/trinkey"; let FILESYSTEM = { home: { @@ -393,22 +405,16 @@ let FILESYSTEM = { cd: { type: "file", name: "cd", content: "
function cd(directory: string): void { ... }
" }, clear: { type: "file", name: "clear", content: "
function clear(): void { ... }
" }, help: { type: "file", name: "help", content: "
function help(): string { ... }
" }, - ls: { type: "file", name: "ls", content: "
function ls(directory: string): string { ... }
" }, - neofetch: { type: "file", name: "neofetch", content: "
function neofetch(): string { ... }
" } + ls: { type: "file", name: "ls", content: "
function ls(directory?: string): string { ... }
" } } }, ".secret-file": { type: "file", name: ".secret-file", content: "
meow :3
" } }; let windowInformation = {}; function commandManager(windowID, command) { - if (!windowInformation[windowID]) { - windowInformation[windowID] = { - PWD: HOME_DIR - }; - } let out; if (_internal_commands[command.split(" ")[0]]) { - out = _internal_commands[command.split(" ")[0]](command.split(" ").slice(1).join(" ").trim(), windowID); + out = _internal_commands[command.split(" ")[0]].callback(command.split(" ").slice(1).join(" ").trim(), windowID); } else if (command == "") { out = ""; @@ -416,8 +422,11 @@ function commandManager(windowID, command) { else { out = `
Unknown command '${escapeHTML(command.split(" ")[0])}'.
Type 'help' for a list of commands
`; } + addWindowCommand(windowID, out); +} +function addWindowCommand(windowID, value) { let el = document.createElement("div"); - el.innerHTML = out; + el.innerHTML = value; WINDOWS[windowID].element.querySelector(".window").append(el); let dTE = WINDOWS[windowID].element.querySelector("[data-type-area]"); if (dTE) { diff --git a/no-js.html b/no-js.html index 2a49288..53fc24f 100644 --- a/no-js.html +++ b/no-js.html @@ -61,10 +61,9 @@
html:
<a href="https://trinkey.com/" target="_blank"><img src="https://trinkey.com/img/88x31.png" alt="trinkey's 88x31. image of her cat on the right with the word trinkey name taking up the rest of the button." title="trinkey's 88x31. image of her cat on the right with the word trinkey name taking up the rest of the button."></a>
--------------------
-

cool people:

notfire.cc - a non-spinning demigirl blobcat angled slightly with a black border to the left of "Micro" + a non-spinning demigirl blobcat angled slightly with a black border to the left of "Micro" kopper's button Sneexy unnick @@ -119,6 +118,7 @@
the outpost frontend for fedi made by kopper

official jerimiah smiggins instance, that being my own social media platform

+
there's also a qna for me at *trinkey.com/qna

(asterisk (*) means i haven't written the code for it)
diff --git a/ts/index.ts b/ts/index.ts index cd9bb60..5ffc06e 100644 --- a/ts/index.ts +++ b/ts/index.ts @@ -68,6 +68,79 @@ function edgeMoveEvent(x: number, y: number, pos: "top" | "bottom" | "left" | "r (w.element.querySelector(".window") as HTMLElement).style.height = `${w.height}px`; } +function mouseMoveEvent(windowID: string, x: number, y: number): void { + let w: _winConf = WINDOWS[windowID]; + w.posX = Math.max(0, Math.min(innerWidth - w.width - _windowPaddingX, x - w.vars.mouseOffsetX)); + w.posY = Math.max(0, Math.min(innerHeight - w.height - _windowPaddingY, y - w.vars.mouseOffsetY)); + w.element.style.left = `${w.posX}px`; + w.element.style.top = `${w.posY}px`; +} + +function syncInputs(windowID: string): void { + let windowInput: HTMLInputElement = WINDOWS[windowID].element.querySelector("input.window-input"); + let windowVisualText: HTMLDivElement = WINDOWS[windowID].element.querySelector("[data-type-area]"); + let w: HTMLDivElement = WINDOWS[windowID].element.querySelector(".window"); + + if (!windowVisualText) { return; } + + setTimeout(function(): void { + let text: string = windowInput.value; + let cursor: number = windowInput.selectionStart; + + if (cursor == text.length) { + windowVisualText.innerHTML = `${escapeHTML(text)} `; + } else { + windowVisualText.innerHTML = `${escapeHTML(text.slice(0, cursor))}${escapeHTML(text[cursor])}${escapeHTML(text.slice(cursor + 1))}`; + } + }, 1); + + w.scrollTop = w.scrollHeight; +} + +function setCursor(windowID: string): void { + let windowInput: HTMLInputElement = WINDOWS[windowID].element.querySelector("input.window-input"); + + setTimeout((): void => { + windowInput.setSelectionRange(windowInput.value.length, windowInput.value.length); + syncInputs(windowID); + }, 1); +} + +function toggleFullscreen(windowID: string): void { + let w: _winConf = WINDOWS[windowID]; + if (w.fullscreen) { + w.posX = Math.max(0, Math.min(innerWidth - w.vars.oldWidth - _windowPaddingX, w.vars.oldPosX)); // window.vars.oldPosX; + w.posY = Math.max(0, Math.min(innerHeight - w.vars.oldHeight - _windowPaddingY, w.vars.oldPosY)); // window.vars.oldPosY; + w.width = Math.max(w.minWidth, Math.min(w.vars.oldWidth, innerWidth - _windowPaddingX)); // window.vars.oldWidth; + w.height = Math.max(w.minHeight, Math.min(w.vars.oldHeight, innerHeight - _windowPaddingY)); // window.vars.oldHeight; + w.fullscreen = false; + delete w.vars.oldPosX; + delete w.vars.oldPosY; + delete w.vars.oldWidth; + delete w.vars.oldHeight; + w.element.style.left = `${w.posX}px`; + w.element.style.top = `${w.posY}px`; + w.element.style.width = `${w.width + _windowPaddingX - 2}px`; + (w.element.querySelector(".window") as HTMLElement).style.width = `${w.width}px`; + (w.element.querySelector(".window") as HTMLElement).style.height = `${w.height}px`; + } else { + w.vars.oldPosX = w.posX; + w.vars.oldPosY = w.posY; + w.vars.oldWidth = w.width; + w.vars.oldHeight = w.height; + w.fullscreen = true; + w.posX = 0; + w.posY = 0; + w.width = innerWidth; + w.height = innerHeight; + w.element.style.left = "0px"; + w.element.style.top = "0px"; + w.element.style.width = `${w.width}px`; + (w.element.querySelector(".window") as HTMLElement).style.width = `${w.width - _windowPaddingX}px`; + (w.element.querySelector(".window") as HTMLElement).style.height = `${w.height - _windowPaddingY}px`; + } +} + function createWindow(config: _winInitConf): void { if (document.getElementById(config.id)) { incrementZIndex(config.id); @@ -114,31 +187,8 @@ function createWindow(config: _winInitConf): void { wI.classList.add("window-input"); wI.id = `${config.id}__input`; - function syncInputs(): void { - setTimeout(function(): void { - let text: string = wI.value; - let cursor: number = wI.selectionStart; - let el: HTMLElement = wC.querySelector("[data-type-area]"); - - if (!el) { return; } - - if (cursor == text.length) { - el.innerHTML = `${escapeHTML(text)} `; - } else { - el.innerHTML = `${escapeHTML(text.slice(0, cursor))}${escapeHTML(text[cursor])}${escapeHTML(text.slice(cursor + 1))}`; - } - }, 1); - } - - function setCursor(): void { - setTimeout((): void => { - wI.setSelectionRange(wI.value.length, wI.value.length); - syncInputs(); - }, 0); - } - wI.oninput = (event: KeyboardEvent): void => { - syncInputs(); + syncInputs(config.id); w.scrollTop = w.scrollHeight; }; @@ -147,13 +197,91 @@ function createWindow(config: _winInitConf): void { commandManager(config.id, wI.value.trim()); w.scrollTop = w.scrollHeight; wI.value = ""; + } else if (event.key == "Tab") { + event.preventDefault(); + + let val: string = wI.value.trim(); + let possibilities: string[] = []; + let parent: _file | null; + + if (!val) { return; } + + if (val.split(" ").length == 1 && wI.value[wI.value.length - 1] != " ") { + possibilities = Object.keys(_internal_commands).filter((cmd: string): boolean => (cmd.startsWith(val) && !cmd.startsWith("_"))); + } else if (_internal_commands[val.split(" ")[0]] && _internal_commands[val.split(" ")[0]].autocomplete) { + let ac: "dir" | "file" | string[] = _internal_commands[val.split(" ")[0]].autocomplete; + let path: string = val.split(" ").slice(1).join(" ").trim(); + let sw: string = path.split("/")[path.split("/").length - 1]; + + if (typeof ac == "object") { + possibilities = ac; + } else { + if (path) { + if (path[path.length - 1] == "/") { + parent = _internal_getFile(_internal_sanitizePath(_internal_joinPaths(windowInformation[config.id].PWD, path))); + } else { + parent = _internal_getFile(_internal_sanitizePath(_internal_joinPaths(windowInformation[config.id].PWD, path + "/.."))); + } + } else { + parent = _internal_getFile(windowInformation[config.id].PWD); + } + + if (parent && parent.type == "directory") { + let f: _files = parent.files; + possibilities = Object.keys(f); + + if (ac == "dir") { + possibilities = possibilities.filter((file: string): boolean => (f[file] && f[file].type == "directory")); + } + } else { + parent = null; + } + } + + possibilities = possibilities.filter((v: string): boolean => v.startsWith(sw)); + } + + if (possibilities.length == 1) { + if (val.split(" ").length == 1 && wI.value[wI.value.length - 1] != " ") { + wI.value = possibilities[0] + " "; + } else if (_internal_commands[val.split(" ")[0]] && _internal_commands[val.split(" ")[0]].autocomplete) { + let path: string = val; + + if (val[val.length - 1] == "/") { + path += possibilities[0]; + } else { + let p: string[] = path.split("/"); + + if (p.length == 1) { + p = p[0].split(" ", 2); + + if (p.length == 1) { + p.push(""); + } + + p.pop(); + path = p.join(" ") + " " + possibilities[0]; + } else { + p.pop(); + path = p.join("/") + "/" + possibilities[0]; + } + } + + wI.value = path + (parent && parent.type == "directory" && parent.files[possibilities[0]].type == "directory" ? "/" : " "); + } + + syncInputs(config.id); + } else if (possibilities) { + addWindowCommand(config.id, possibilities.join(" ")); + syncInputs(config.id); + } } else { - syncInputs(); + syncInputs(config.id); } }; - wI.onfocus = setCursor; - wI.onclick = setCursor; + wI.onfocus = (): void => { setCursor(config.id); }; + wI.onclick = (): void => { setCursor(config.id); }; wC = document.createElement("label"); wC.htmlFor = `${config.id}__input`; @@ -174,6 +302,7 @@ function createWindow(config: _winInitConf): void { let el: HTMLDivElement = document.createElement("div"); el.classList.add("edge", pos); el.addEventListener("mousedown", function(e: MouseEvent): void { + incrementZIndex(config.id); e.preventDefault(); WINDOWS[config.id].vars.mouseOffsetX = e.clientX - WINDOWS[config.id].posX; @@ -215,12 +344,9 @@ function createWindow(config: _winInitConf): void { vars: {} }; - function mouseMoveEvent(x: number, y: number): void { - WINDOWS[config.id].posX = Math.max(0, Math.min(innerWidth - WINDOWS[config.id].width - _windowPaddingX, x - WINDOWS[config.id].vars.mouseOffsetX)); - WINDOWS[config.id].posY = Math.max(0, Math.min(innerHeight - WINDOWS[config.id].height - _windowPaddingY, y - WINDOWS[config.id].vars.mouseOffsetY)); - wC.style.left = `${WINDOWS[config.id].posX}px`; - wC.style.top = `${WINDOWS[config.id].posY}px`; - } + windowInformation[config.id] = { + PWD: HOME_DIR + }; // wC.addEventListener("mousedown", function(): void { incrementZIndex(config.id); }); wC.addEventListener("focus", function(): void { incrementZIndex(config.id); }); @@ -237,7 +363,7 @@ function createWindow(config: _winInitConf): void { WINDOWS[config.id].vars.mouseOffsetX = e.clientX - WINDOWS[config.id].posX; WINDOWS[config.id].vars.mouseOffsetY = e.clientY - WINDOWS[config.id].posY; MOUSE_MOVE_PROCESSING[config.id] = { - callback: mouseMoveEvent, + callback: (x: number, y: number): void => { mouseMoveEvent(config.id, x, y); }, mouseUp: true }; }); @@ -253,40 +379,8 @@ function createWindow(config: _winInitConf): void { } }); - wH.querySelector(".fullscreen").addEventListener("click", function(): void { - let window: _winConf = WINDOWS[config.id]; - if (window.fullscreen) { - window.posX = Math.max(0, Math.min(innerWidth - window.vars.oldWidth - _windowPaddingX, window.vars.oldPosX)); // window.vars.oldPosX; - window.posY = Math.max(0, Math.min(innerHeight - window.vars.oldHeight - _windowPaddingY, window.vars.oldPosY)); // window.vars.oldPosY; - window.width = Math.max(window.minWidth, Math.min(window.vars.oldWidth, innerWidth - _windowPaddingX)); // window.vars.oldWidth; - window.height = Math.max(window.minHeight, Math.min(window.vars.oldHeight, innerHeight - _windowPaddingY)); // window.vars.oldHeight; - window.fullscreen = false; - delete window.vars.oldPosX; - delete window.vars.oldPosY; - delete window.vars.oldWidth; - delete window.vars.oldHeight; - wC.style.left = `${window.posX}px`; - wC.style.top = `${window.posY}px`; - wC.style.width = `${window.width + _windowPaddingX - 2}px`; - w.style.width = `${window.width}px`; - w.style.height = `${window.height}px`; - } else { - window.vars.oldPosX = window.posX; - window.vars.oldPosY = window.posY; - window.vars.oldWidth = window.width; - window.vars.oldHeight = window.height; - window.fullscreen = true; - window.posX = 0; - window.posY = 0; - window.width = innerWidth; - window.height = innerHeight; - wC.style.left = "0px"; - wC.style.top = "0px"; - wC.style.width = `${window.width}px`; - w.style.width = `${window.width - _windowPaddingX}px`; - w.style.height = `${window.height - _windowPaddingY}px`; - } - }); + wH.querySelector(".fullscreen").addEventListener("click", (): void => (toggleFullscreen(config.id))); + wH.addEventListener("dblclick", (): void => (toggleFullscreen(config.id))); globalIncrement++; } diff --git a/ts/shell.ts b/ts/shell.ts index a21b0e7..79dd37f 100644 --- a/ts/shell.ts +++ b/ts/shell.ts @@ -251,23 +251,30 @@ function _internal_neofetch(args: string, windowID: string): string { return _internal_neofetchOutputs[args]; } -const _internal_commands: { [key: string]: (args: string, windowID: string) => string } = { - cat: cat, - cd: cd, - clear: clear, - help: help, // NEEDS UPDATING - ls: ls, - exit: exit, - _internal_set_ps1: _internal_set_ps1, - _internal_neofetch: _internal_neofetch +const _internal_commands: { + [key: string]: { + callback: (args: string, windowID: string) => string, + autocomplete: "dir" | "file" | null | string[] + } +} = { + cat: { callback: cat, autocomplete: "file" }, + cd: { callback: cd, autocomplete: "dir" }, + clear: { callback: clear, autocomplete: null }, + help: { callback: help, autocomplete: null }, + ls: { callback: ls, autocomplete: "file" }, + exit: { callback: exit, autocomplete: null }, + _internal_set_ps1: { callback: _internal_set_ps1, autocomplete: null }, + _internal_neofetch: { callback: _internal_neofetch, autocomplete: null }, + spin: { callback: (args: string, windowID: string): string => { createBlob(); return ""; }, autocomplete: null }, }; // -= Variables + Other =- // const _internal_defaultFiles: StringDict = { - about: `
hi there! i'm trinkey!
+ about: `
hi there!
+
i'm trinkey, but you can call me katie too! (trinkey is more of a username)
--------------------
-
i'm a silly little kitty cat who lives in the usa (sadly).
-
i'm trans (she/is, they/them is also fine).
+
i'm a silly little cat who lives in the usa (new york time zone).
+
i'm trans (she/it, they/them is also fine).
i'm not actively in a relationship, however i'm also not looking to get into one either.
--------------------
i like to code stuff (mostly websites)! some of my programs can be found in projects section. i know a few languages, those being python, javascript/typescript, html/css (if you count those), and a little bit of java.
@@ -281,6 +288,7 @@ const _internal_defaultFiles: StringDict = {
- signal - @trinkey.01
- email - trinkey [at] proton [dot] me
- youtube - @trinkey (inactive)
+
- discord - @trinkey_ (mostly inactive)
- gpg key (1D6E 5D28 BDD4 D7FA 96B8 8799 2B33 C6C6 14F2 591A)
`, projects: `
projects - the things i made
- smiggins (website) - a social media platform i made
@@ -292,23 +300,28 @@ const _internal_defaultFiles: StringDict = { buttons: `
my button: (click to copy html)
trinkey's 88x31. image of her cat on the right with the word 'trinkey' taking up the rest of the button.
--------------------
-
cool people:
notfire.cc - a non-spinning demigirl blobcat angled slightly with a black border to the left of "Micro" + a non-spinning demigirl blobcat angled slightly with a black border to the left of "Micro" kopper's button Sneexy unnick Autumn Town Café the text 'red is purple' on a purple background doskel + velzie
`, testimonials: `
"warning: this user is trinkey"

"This user is only slightly crazy once was I. 10/10 would recommend"

"the f slur but repeated 36 times"
- `, +
+
"silly cute kitn"
+
+
"very bitable neodog_bite_neocat
+ + `, webrings: `
catppuccin webring @@ -346,6 +359,7 @@ const _internal_defaultFiles: StringDict = {
the outpost frontend for fedi made by kopper

official jerimiah smiggins instance, that being my own social media platform

+
there's also a qna for me at *trinkey.com/qna

(asterisk (*) means i haven't written the code for it)

` }; @@ -390,25 +404,28 @@ const _internal_neofetchOutputs: StringDict = { \`\`-:::::-\`\`` }; -const helpText: string = `
 -=== tSh help ===-
+const helpText: string = ` +
 -=== tSh help ===-
--------------------
-= cat =-
-
Displays the contents of a file.
+
displays the contents of a file
-= cd =-
-
Changes the working directory.
+
changes the working directory
-= clear =-
-
Clears the terminal output.
+
clears the terminal output
-= help =-
-
Shows this help menu.
+
shows this help menu
-= ls =-
-
Lists all files in a directory.
+
lists all files in a directory
  -l - displays more information about each file
  -a - displays all files
  -A - displays all files except implied . and ..
  -r - reverses the order of the files
  -R - recurse through all subdirectories
+
-= spin =-
+
creates a new window with a spinning blobcat wireframe
-= exit =-
-
Closes the terminal.
`; +
closes the terminal window
`; const HOME_DIR: string = "/home/trinkey"; @@ -438,12 +455,11 @@ let FILESYSTEM: _files = { type: "directory", name: "bin", files: { - cat: { type: "file", name: "cat", content: "
function cat(file: string): string { ... }
" }, - cd: { type: "file", name: "cd", content: "
function cd(directory: string): void { ... }
" }, - clear: { type: "file", name: "clear", content: "
function clear(): void { ... }
" }, - help: { type: "file", name: "help", content: "
function help(): string { ... }
" }, - ls: { type: "file", name: "ls", content: "
function ls(directory: string): string { ... }
" }, - neofetch: { type: "file", name: "neofetch", content: "
function neofetch(): string { ... }
" } + cat: { type: "file", name: "cat", content: "
function cat(file: string): string { ... }
" }, + cd: { type: "file", name: "cd", content: "
function cd(directory: string): void { ... }
" }, + clear: { type: "file", name: "clear", content: "
function clear(): void { ... }
" }, + help: { type: "file", name: "help", content: "
function help(): string { ... }
" }, + ls: { type: "file", name: "ls", content: "
function ls(directory?: string): string { ... }
" } } }, ".secret-file": { type: "file", name: ".secret-file", content: "
meow :3
" } @@ -452,23 +468,21 @@ let FILESYSTEM: _files = { let windowInformation: { [key: string]: _tShWinInfo } = {}; function commandManager(windowID: string, command: string): void { - if (!windowInformation[windowID]) { - windowInformation[windowID] = { - PWD: HOME_DIR - }; - } - let out: string; if (_internal_commands[command.split(" ")[0]]) { - out = _internal_commands[command.split(" ")[0]](command.split(" ").slice(1).join(" ").trim(), windowID); + out = _internal_commands[command.split(" ")[0]].callback(command.split(" ").slice(1).join(" ").trim(), windowID); } else if (command == "") { out = "" } else { out = `
Unknown command '${escapeHTML(command.split(" ")[0])}'.
Type 'help' for a list of commands
`; } + addWindowCommand(windowID, out); +} + +function addWindowCommand(windowID: string, value: string): void { let el: HTMLDivElement = document.createElement("div"); - el.innerHTML = out; + el.innerHTML = value; WINDOWS[windowID].element.querySelector(".window").append(el); let dTE: HTMLElement = WINDOWS[windowID].element.querySelector("[data-type-area]");