diff options
Diffstat (limited to 'public')
| -rw-r--r-- | public/shell.js | 73 | ||||
| -rw-r--r-- | public/styles/fonts/LowresPixel-Regular.woff | bin | 0 -> 10756 bytes | |||
| -rw-r--r-- | public/styles/fonts/LowresPixel.css | 8 | ||||
| -rw-r--r-- | public/styles/fonts/Monocraft.css | 18 | ||||
| -rw-r--r-- | public/styles/main.css | 14 | ||||
| -rw-r--r-- | public/styles/style.css | 167 |
6 files changed, 280 insertions, 0 deletions
diff --git a/public/shell.js b/public/shell.js new file mode 100644 index 0000000..9a70846 --- /dev/null +++ b/public/shell.js @@ -0,0 +1,73 @@ +const shell = document.querySelector("[data-shell]"); + +if (shell) { + const area = shell.closest("[data-scroll-area]"); + const history = shell.querySelector("#shell-history"); + const input = shell.querySelector("[data-shell-input]"); + const caret = shell.querySelector("[data-shell-caret]"); + let busy = false; + + const updateCaret = () => { + const pos = input.selectionStart ?? input.value.length; + caret.style.left = `calc(${pos}ch - ${input.scrollLeft}px)`; + caret.textContent = input.value[pos] ?? "\u00a0"; + caret.style.animation = "none"; // restart the blink so the caret is solid while typing + void caret.offsetWidth; + caret.style.animation = ""; + }; + + const snapToBottom = () => { + area.scrollTop = area.scrollHeight; + }; + + const run = async (cmd) => { + busy = true; + try { + const res = await fetch("/shell/run", { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: new URLSearchParams({ cmd }), + }); + const data = await res.json(); + if (data.clear) history.replaceChildren(); + if (data.html) history.insertAdjacentHTML("beforeend", data.html); + if (data.vars) { + for (const [key, value] of Object.entries(data.vars)) { + document.documentElement.style.setProperty(`--${key}`, value); + } + } + } catch { + const el = document.createElement("p"); + el.textContent = "request failed"; + history.append(el); + } finally { + busy = false; + snapToBottom(); + } + }; + + input.addEventListener("keydown", (e) => { + if (e.key !== "Enter") return; + e.preventDefault(); + const cmd = input.value.trim(); + if (!cmd || busy) return; + input.value = ""; + updateCaret(); + run(cmd); + }); + + for (const event of ["input", "keyup", "click", "focus"]) { + input.addEventListener(event, updateCaret); + } + document.addEventListener("selectionchange", () => { + if (document.activeElement === input) updateCaret(); + }); + + area.addEventListener("click", () => { + if (!getSelection().toString()) input.focus({ preventScroll: true }); + }); + + input.focus({ preventScroll: true }); + updateCaret(); + snapToBottom(); +} diff --git a/public/styles/fonts/LowresPixel-Regular.woff b/public/styles/fonts/LowresPixel-Regular.woff Binary files differnew file mode 100644 index 0000000..a1b368a --- /dev/null +++ b/public/styles/fonts/LowresPixel-Regular.woff diff --git a/public/styles/fonts/LowresPixel.css b/public/styles/fonts/LowresPixel.css new file mode 100644 index 0000000..ae4f1d3 --- /dev/null +++ b/public/styles/fonts/LowresPixel.css @@ -0,0 +1,8 @@ +@font-face { + font-family: "LowerPixelRegular"; + font-style: normal; + font-weight: normal; + src: + local("LowerPixelRegular"), + url("LowresPixel-Regular.woff") format("woff"); +} diff --git a/public/styles/fonts/Monocraft.css b/public/styles/fonts/Monocraft.css index df2874e..af7b397 100644 --- a/public/styles/fonts/Monocraft.css +++ b/public/styles/fonts/Monocraft.css @@ -3,106 +3,124 @@ src: url("/public/fonts/Monocraft-ExtraLight.ttf") format("truetype"); font-weight: 100; font-style: normal; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-ExtraLight-Italic.ttf") format("truetype"); font-weight: 100; font-style: italic; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-ExtraLight.ttf") format("truetype"); font-weight: 200; font-style: normal; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-ExtraLight-Italic.ttf") format("truetype"); font-weight: 200; font-style: italic; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Light.ttf") format("truetype"); font-weight: 300; font-style: normal; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Light-Italic.ttf") format("truetype"); font-weight: 300; font-style: italic; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft.ttf") format("truetype"); font-weight: 400; font-style: normal; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Italic.ttf") format("truetype"); font-weight: 400; font-style: italic; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft.ttf") format("truetype"); font-weight: 500; font-style: normal; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Italic.ttf") format("truetype"); font-weight: 500; font-style: italic; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-SemiBold.ttf") format("truetype"); font-weight: 600; font-style: normal; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-SemiBold-Italic.ttf") format("truetype"); font-weight: 600; font-style: italic; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Bold.ttf") format("truetype"); font-weight: 700; font-style: normal; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Bold-Italic.ttf") format("truetype"); font-weight: 700; font-style: italic; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Black.ttf") format("truetype"); font-weight: 800; font-style: normal; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Black-Italic.ttf") format("truetype"); font-weight: 800; font-style: italic; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Black.ttf") format("truetype"); font-weight: 900; font-style: normal; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Black-Italic.ttf") format("truetype"); font-weight: 900; font-style: italic; + size-adjust: 90%; /* Adjust to JetBrainsMono width, 0.6 / 0.6666 = 0.9 */ } diff --git a/public/styles/main.css b/public/styles/main.css index 2c44266..f7539ee 100644 --- a/public/styles/main.css +++ b/public/styles/main.css @@ -1,6 +1,7 @@ @import "./fonts/Inter/inter.css"; @import "./fonts/JetBrainsMono.css"; @import "./fonts/Monocraft.css"; +@import "./fonts/LowresPixel.css"; @layer theme, base, components, utilities; @import "tailwindcss/theme.css" layer(theme); @@ -260,3 +261,16 @@ body { transform: scale(1.03); } } + +@keyframes blink { + 50% { + opacity: 0; + } +} + +[data-shell-caret] { + animation: blink 1.1s steps(1) infinite; +} +[data-shell-prompt]:not(:focus-within) [data-shell-caret] { + visibility: hidden; +} diff --git a/public/styles/style.css b/public/styles/style.css index 4aff75b..3610b64 100644 --- a/public/styles/style.css +++ b/public/styles/style.css @@ -523,108 +523,132 @@ src: url("/public/fonts/Monocraft-ExtraLight.ttf") format("truetype"); font-weight: 100; font-style: normal; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-ExtraLight-Italic.ttf") format("truetype"); font-weight: 100; font-style: italic; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-ExtraLight.ttf") format("truetype"); font-weight: 200; font-style: normal; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-ExtraLight-Italic.ttf") format("truetype"); font-weight: 200; font-style: italic; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Light.ttf") format("truetype"); font-weight: 300; font-style: normal; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Light-Italic.ttf") format("truetype"); font-weight: 300; font-style: italic; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft.ttf") format("truetype"); font-weight: 400; font-style: normal; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Italic.ttf") format("truetype"); font-weight: 400; font-style: italic; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft.ttf") format("truetype"); font-weight: 500; font-style: normal; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Italic.ttf") format("truetype"); font-weight: 500; font-style: italic; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-SemiBold.ttf") format("truetype"); font-weight: 600; font-style: normal; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-SemiBold-Italic.ttf") format("truetype"); font-weight: 600; font-style: italic; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Bold.ttf") format("truetype"); font-weight: 700; font-style: normal; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Bold-Italic.ttf") format("truetype"); font-weight: 700; font-style: italic; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Black.ttf") format("truetype"); font-weight: 800; font-style: normal; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Black-Italic.ttf") format("truetype"); font-weight: 800; font-style: italic; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Black.ttf") format("truetype"); font-weight: 900; font-style: normal; + size-adjust: 90%; } @font-face { font-family: "Monocraft"; src: url("/public/fonts/Monocraft-Black-Italic.ttf") format("truetype"); font-weight: 900; font-style: italic; + size-adjust: 90%; +} +@font-face { + font-family: "LowerPixelRegular"; + font-style: normal; + font-weight: normal; + src: local("LowerPixelRegular"), url("LowresPixel-Regular.woff") format("woff"); } @layer theme, base, components, utilities; @layer theme { @@ -796,12 +820,29 @@ } } @layer utilities { + .pointer-events-none { + pointer-events: none; + } + .collapse { + visibility: collapse; + } .invisible { visibility: hidden; } .visible { visibility: visible; } + .sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; + border-width: 0; + } .absolute { position: absolute; } @@ -817,6 +858,12 @@ .inset-x-\[0\.3rem\] { inset-inline: 0.3rem; } + .inset-y-0 { + inset-block: 0px; + } + .top-1 { + top: var(--spacing); + } .top-1\/2 { top: calc(1 / 2 * 100%); } @@ -856,6 +903,24 @@ .col-span-2 { grid-column: span 2 / span 2; } + .container { + width: 100%; + @media (width >= 40rem) { + max-width: 40rem; + } + @media (width >= 48rem) { + max-width: 48rem; + } + @media (width >= 64rem) { + max-width: 64rem; + } + @media (width >= 80rem) { + max-width: 80rem; + } + @media (width >= 96rem) { + max-width: 96rem; + } + } .-m-\[0\.4rem\] { margin: calc(0.4rem * -1); } @@ -1376,6 +1441,9 @@ .hidden { display: none; } + .inline { + display: inline; + } .inline-block { display: inline-block; } @@ -1427,6 +1495,9 @@ .w-8 { width: calc(var(--spacing) * 8); } + .w-\[1ch\] { + width: 1ch; + } .w-\[30\%\] { width: 30%; } @@ -1460,9 +1531,25 @@ .flex-1 { flex: 1; } + .flex-shrink { + flex-shrink: 1; + } .shrink-0 { flex-shrink: 0; } + .flex-grow { + flex-grow: 1; + } + .grow { + flex-grow: 1; + } + .border-collapse { + border-collapse: collapse; + } + .-translate-y-1 { + --tw-translate-y: calc(var(--spacing) * -1); + translate: var(--tw-translate-x) var(--tw-translate-y); + } .-translate-y-1\/2 { --tw-translate-y: calc(calc(1 / 2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); @@ -1542,6 +1629,9 @@ .gap-\[1ch\] { gap: 1ch; } + .gap-\[1rem\] { + gap: 1rem; + } .gap-x-4 { column-gap: calc(var(--spacing) * 4); } @@ -1684,12 +1774,18 @@ .bg-\(--secondary\) { background-color: var(--secondary); } + .bg-\(--text\) { + background-color: var(--text); + } .bg-\[var\(--background\)\] { background-color: var(--background); } .bg-\[var\(--text\)\] { background-color: var(--text); } + .bg-black { + background-color: var(--color-black); + } .bg-black\/20 { background-color: color-mix(in srgb, #000 20%, transparent); @supports (color: color-mix(in lab, red, red)) { @@ -1702,6 +1798,12 @@ background-color: color-mix(in oklab, var(--color-black) 30%, transparent); } } + .bg-transparent { + background-color: transparent; + } + .bg-white { + background-color: var(--color-white); + } .bg-white\/2 { background-color: color-mix(in srgb, #fff 2%, transparent); @supports (color: color-mix(in lab, red, red)) { @@ -1720,6 +1822,9 @@ .bg-\[linear-gradient\(to_bottom\,var\(--background\)\,var\(--cmp-bg\,transparent\)\)\] { background-image: linear-gradient(to bottom,var(--background),var(--cmp-bg,transparent)); } + .mask-repeat { + mask-repeat: repeat; + } .fill-\[\#7ed4fb\]\/50 { fill: color-mix(in oklab, #7ed4fb 50%, transparent); } @@ -1759,6 +1864,9 @@ .p-\[3vw\] { padding: 3vw; } + .px-3 { + padding-inline: calc(var(--spacing) * 3); + } .px-3\.5 { padding-inline: calc(var(--spacing) * 3.5); } @@ -1892,6 +2000,10 @@ --tw-leading: 1.7; line-height: 1.7; } + .leading-\[1\.32\] { + --tw-leading: 1.32; + line-height: 1.32; + } .leading-\[normal\] { --tw-leading: normal; line-height: normal; @@ -1914,6 +2026,9 @@ .whitespace-nowrap { white-space: nowrap; } + .whitespace-pre { + white-space: pre; + } .text-\(--accent\) { color: var(--accent); } @@ -1992,6 +2107,9 @@ .text-\[\#a34eeb\] { color: #a34eeb; } + .text-\[\#ffffff\] { + color: #ffffff; + } .text-\[\%v\] { color: %v; } @@ -2004,9 +2122,18 @@ .text-\[var\(--secondary\)\] { color: var(--secondary); } + .italic { + font-style: italic; + } .no-underline { text-decoration-line: none; } + .underline { + text-decoration-line: underline; + } + .caret-transparent { + caret-color: transparent; + } .opacity-0 { opacity: 0%; } @@ -2017,6 +2144,19 @@ } box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } + .ring { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .outline { + outline-style: var(--tw-outline-style); + outline-width: 1px; + } + .transition { + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } .transition-colors { transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); @@ -2026,6 +2166,10 @@ --tw-duration: 150ms; transition-duration: 150ms; } + .outline-none { + --tw-outline-style: none; + outline-style: none; + } .select-text { -webkit-user-select: text; user-select: text; @@ -2071,6 +2215,12 @@ background-color: color-mix(in oklab, var(--primary) 25%, transparent) !important; } } + .group-data-\[copied\]\/copy\:block:is(:where(.group\/copy)[data-copied] *) { + display: block; + } + .group-data-\[copied\]\/copy\:hidden:is(:where(.group\/copy)[data-copied] *) { + display: none; + } .after\:absolute::after { content: var(--tw-content); position: absolute; @@ -2487,6 +2637,17 @@ body { transform: scale(1.03); } } +@keyframes blink { + 50% { + opacity: 0; + } +} +[data-shell-caret] { + animation: blink 1.1s steps(1) infinite; +} +[data-shell-prompt]:not(:focus-within) [data-shell-caret] { + visibility: hidden; +} @property --tw-translate-x { syntax: "*"; inherits: false; @@ -2620,6 +2781,11 @@ body { inherits: false; initial-value: 0 0 #0000; } +@property --tw-outline-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} @property --tw-duration { syntax: "*"; inherits: false; @@ -2661,6 +2827,7 @@ body { --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; + --tw-outline-style: solid; --tw-duration: initial; --tw-content: ""; } |
