diff --git a/src/components/layout.tsx b/src/components/layout.tsx
index dd4a84d..d79d06f 100644
--- a/src/components/layout.tsx
+++ b/src/components/layout.tsx
@@ -6,8 +6,9 @@ export const Layout: FC = async ({ children, title }) => (
{title || "Nose"}
-
-
+
+
+
diff --git a/src/components/terminal.tsx b/src/components/terminal.tsx
index d0f4a01..12225ae 100644
--- a/src/components/terminal.tsx
+++ b/src/components/terminal.tsx
@@ -2,7 +2,30 @@ import type { FC } from "hono/jsx"
export const Terminal: FC = async () => (
<>
- Hello NOSE!
- This is 960×540 space.
+
+
+
+ >
+
+
+
+
+
+ - **** NOSE PLUTO V{new Date().getMonth() + 1}.{new Date().getDate()} ****
+ - VRAM 000KB
+
>
)
\ No newline at end of file
diff --git a/src/css/main.css b/src/css/main.css
index b44e680..29cf059 100644
--- a/src/css/main.css
+++ b/src/css/main.css
@@ -87,6 +87,7 @@ main {
width: 960px;
height: 540px;
background: var(--c64-dark-blue);
+ color: var(--c64-light-blue);
/* nearest-neighbor scaling */
image-rendering: pixelated;
transform-origin: center center;
@@ -95,4 +96,8 @@ main {
body[data-mode=tall] #content {
height: 100%;
overflow-x: hidden;
+}
+
+textarea {
+ color: var(--c64-light-blue);
}
\ No newline at end of file
diff --git a/src/css/reset.css b/src/css/reset.css
new file mode 100644
index 0000000..f4c498e
--- /dev/null
+++ b/src/css/reset.css
@@ -0,0 +1,78 @@
+/* https://www.joshwcomeau.com/css/custom-css-reset/ */
+
+/* 1. Use a more-intuitive box-sizing model */
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+/* 2. Remove default margin */
+* {
+ margin: 0;
+}
+
+/* 3. Enable keyword animations */
+@media (prefers-reduced-motion: no-preference) {
+ html {
+ interpolate-size: allow-keywords;
+ }
+}
+
+body {
+ /* 4. Add accessible line-height */
+ line-height: 1.5;
+ /* 5. Improve text rendering */
+ -webkit-font-smoothing: antialiased;
+}
+
+/* 6. Improve media defaults */
+img,
+picture,
+video,
+canvas,
+svg {
+ display: block;
+ max-width: 100%;
+}
+
+/* 7. Inherit fonts for form controls */
+input,
+button,
+textarea,
+select {
+ font: inherit;
+}
+
+/* 8. Avoid text overflows */
+p,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ overflow-wrap: break-word;
+}
+
+/* 9. Improve line wrapping */
+p {
+ text-wrap: pretty;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ text-wrap: balance;
+}
+
+/*
+ 10. Create a root stacking context
+ */
+#root,
+#__next {
+ isolation: isolate;
+}
\ No newline at end of file
diff --git a/src/css/terminal.css b/src/css/terminal.css
new file mode 100644
index 0000000..5ab8215
--- /dev/null
+++ b/src/css/terminal.css
@@ -0,0 +1,85 @@
+:root {
+ --cli-spacing-vertical: 5px;
+ --cli-spacing-horizontal: 5px;
+ --cli-margin: 10px 0 0 25px;
+ --cli-font-size: 20px;
+ --cli-height: 30px;
+}
+
+#command-line {
+ position: relative;
+ display: inline-block;
+ width: 100%;
+ font-size: var(--cli-font-size);
+}
+
+#command-prompt {
+ position: absolute;
+ top: 10px;
+}
+
+#command-textbox {
+ position: relative;
+ z-index: 2;
+
+ background: transparent;
+ padding: var(--cli-spacing-vertical) var(--cli-element-spacing-horizontal);
+ min-height: 1.2em;
+ resize: none;
+ overflow: hidden;
+ font: inherit;
+ letter-spacing: inherit;
+ line-height: inherit;
+
+ height: var(--cli-height);
+ width: 100%;
+ box-shadow: none;
+ box-sizing: border-box;
+ outline: 0;
+ margin: var(--cli-margin);
+ border: none;
+}
+
+#command-hint {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 1;
+
+ pointer-events: none;
+ padding: var(--cli-spacing-vertical) var(--cli-spacing-horizontal);
+ color: #666;
+ background: transparent;
+ resize: none;
+ overflow: hidden;
+ min-height: 1.2em;
+ height: auto;
+ font: inherit;
+ letter-spacing: inherit;
+ line-height: inherit;
+
+ height: var(--cli-height);
+ width: 100%;
+ box-shadow: none;
+ box-sizing: border-box;
+ outline: 0;
+ margin: var(--cli-margin);
+ border: none;
+}
+
+#command-history {
+ margin: 0;
+ padding: 0;
+ font-size: var(--cli-font-size);
+}
+
+#command-history li {
+ list-style: none;
+ margin: 0;
+}
+
+.center {
+ text-align: center;
+}
\ No newline at end of file
diff --git a/src/js/dom.ts b/src/js/dom.ts
new file mode 100644
index 0000000..7686191
--- /dev/null
+++ b/src/js/dom.ts
@@ -0,0 +1,13 @@
+// finds an element by ID
+export const $ = (id: string): HTMLElement | null =>
+ document.getElementById(id)
+
+// creates an HTML element
+export const $$ = (tag: string, innerHTML = ""): HTMLElement => {
+ const el = document.createElement(tag)
+ if (innerHTML) el.innerHTML = innerHTML
+ return el
+}
+
+// elements we know will be there... right?
+export const cmdTextbox = document.getElementById("command-textbox")!
\ No newline at end of file
diff --git a/src/js/focus.ts b/src/js/focus.ts
new file mode 100644
index 0000000..3b14a94
--- /dev/null
+++ b/src/js/focus.ts
@@ -0,0 +1,32 @@
+import { cmdTextbox } from "./dom.js"
+
+export function focusTextbox() {
+ cmdTextbox.focus()
+}
+
+// clicking anywhere outside of a link should focus the prompt, unless the user is
+// selecting text or focusing an input
+export function focusHandler(e: MouseEvent) {
+ const target = e.target
+
+ // who knows where they clicked... just focus the textbox
+ if (!(target instanceof HTMLElement)) {
+ cmdTextbox.focus()
+ return
+ }
+
+ // let them click on links
+ const a = target.closest("a")
+
+ if (!a) {
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA")
+ return false
+
+ const selection = window.getSelection() || ""
+ if (selection.toString() === "")
+ cmdTextbox.focus()
+
+ e.preventDefault()
+ return true
+ }
+}
\ No newline at end of file
diff --git a/src/js/main.ts b/src/js/main.ts
index 0261ce6..05c2fc4 100644
--- a/src/js/main.ts
+++ b/src/js/main.ts
@@ -1,28 +1,11 @@
-const content = document.getElementById("content")!
+import { resize } from "./resize.js"
+import { focusTextbox, focusHandler } from "./focus.js"
+import { startVramCounter } from "./vram.js"
-function resize() {
- if (document.body.dataset.mode === "tall") {
- resizeTall()
- } else {
- resizeCinema()
- }
-}
-
-function resizeTall() {
- const scale = Math.min(1, window.innerWidth / 960)
- content.style.transformOrigin = 'top center'
- content.style.transform = `scaleX(${scale})`
-}
-
-function resizeCinema() {
- const scale = Math.min(
- window.innerWidth / 960,
- window.innerHeight / 540
- )
-
- content.style.transformOrigin = 'center center'
- content.style.transform = `scale(${scale})`
-}
+window.addEventListener("click", focusHandler)
+focusTextbox()
window.addEventListener("resize", resize)
-resize()
\ No newline at end of file
+resize()
+
+startVramCounter()
\ No newline at end of file
diff --git a/src/js/resize.ts b/src/js/resize.ts
new file mode 100644
index 0000000..2991e1d
--- /dev/null
+++ b/src/js/resize.ts
@@ -0,0 +1,26 @@
+const content = document.getElementById("content")!
+
+export function resize() {
+ if (document.body.dataset.mode === "tall") {
+ resizeTall()
+ } else {
+ resizeCinema()
+ }
+}
+
+function resizeTall() {
+ const scale = Math.min(1, window.innerWidth / 960)
+ content.style.transformOrigin = 'top center'
+ content.style.transform = `scaleX(${scale})`
+}
+
+function resizeCinema() {
+ const scale = Math.min(
+ window.innerWidth / 960,
+ window.innerHeight / 540
+ )
+
+ content.style.transformOrigin = 'center center'
+ content.style.transform = `scale(${scale})`
+}
+
diff --git a/src/js/vram.ts b/src/js/vram.ts
new file mode 100644
index 0000000..cd6cf8e
--- /dev/null
+++ b/src/js/vram.ts
@@ -0,0 +1,25 @@
+//
+// vram
+//
+
+import { $ } from "./dom.js"
+
+const vramCounter = $("vram-size")!
+
+export const startVramCounter = () => {
+ const timer = setInterval(() => {
+ const count = parseInt(vramCounter.textContent!) + 1
+ let val = count + "KB"
+ if (count < 10)
+ val = "00" + val
+ else if (count < 100)
+ val = "0" + val
+
+ vramCounter.textContent = val
+
+ if (count >= 640) {
+ vramCounter.textContent += " OK"
+ clearInterval(timer)
+ }
+ }, 5)
+}
\ No newline at end of file