html, 16:9
This commit is contained in:
parent
ab3877ff51
commit
7c37ba9e80
|
|
@ -5,7 +5,7 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "bun src/server.tsx",
|
"start": "bun src/server.tsx",
|
||||||
"dev": "bun --hot src/server.tsx"
|
"dev": "env BUN_HOT=1 bun --hot src/server.tsx"
|
||||||
},
|
},
|
||||||
"alias": {
|
"alias": {
|
||||||
"@utils": "./src/utils.tsx",
|
"@utils": "./src/utils.tsx",
|
||||||
|
|
@ -21,4 +21,4 @@
|
||||||
"hono": "^4.9.7",
|
"hono": "^4.9.7",
|
||||||
"kleur": "^4.1.5"
|
"kleur": "^4.1.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
public/vendor/C64_Pro_Mono-STYLE.woff2
vendored
Normal file
BIN
public/vendor/C64_Pro_Mono-STYLE.woff2
vendored
Normal file
Binary file not shown.
21
src/components/layout.tsx
Normal file
21
src/components/layout.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import type { FC } from "hono/jsx"
|
||||||
|
|
||||||
|
export const Layout: FC = async ({ children, title }) => (
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>{title || "Nose"}</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta name="color-scheme" content="light dark" />
|
||||||
|
<link rel="stylesheet" href="/css/main.css" />
|
||||||
|
<script src="/js/main.js" async></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<div id="content">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
8
src/components/terminal.tsx
Normal file
8
src/components/terminal.tsx
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import type { FC } from "hono/jsx"
|
||||||
|
|
||||||
|
export const Terminal: FC = async () => (
|
||||||
|
<>
|
||||||
|
<h1>Hello NOSE!</h1>
|
||||||
|
<p>This is 960×540 space.</p>
|
||||||
|
</>
|
||||||
|
)
|
||||||
88
src/css/main.css
Normal file
88
src/css/main.css
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: 'C64ProMono';
|
||||||
|
src: url('/vendor/C64_Pro_Mono-STYLE.woff2') format('woff2');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--font-family: 'C64ProMono', monospace;
|
||||||
|
--black: #000000;
|
||||||
|
--white: #E0E0E0;
|
||||||
|
--cyan: #00A8C8;
|
||||||
|
--red: #C62828;
|
||||||
|
--green: green;
|
||||||
|
--yellow: #C4A000;
|
||||||
|
--purple: #7C3AED;
|
||||||
|
--blue: #1565C0;
|
||||||
|
--magenta: #ff66cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.black {
|
||||||
|
color: var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.white {
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cyan {
|
||||||
|
color: var(--cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
.red {
|
||||||
|
color: var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
|
.green {
|
||||||
|
color: var(--green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yellow {
|
||||||
|
color: var(--yellow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.purple {
|
||||||
|
color: var(--purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
.blue {
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.magenta {
|
||||||
|
color: var(--magenta);
|
||||||
|
}
|
||||||
|
|
||||||
|
:fullscreen::backdrop {
|
||||||
|
background: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
font-family: var(--font-family);
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
/* black bars */
|
||||||
|
background: black;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
width: 960px;
|
||||||
|
height: 540px;
|
||||||
|
background: white;
|
||||||
|
/* nearest-neighbor scaling */
|
||||||
|
image-rendering: pixelated;
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
0
src/js/.gitignore
vendored
0
src/js/.gitignore
vendored
11
src/js/main.ts
Normal file
11
src/js/main.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
function resize() {
|
||||||
|
const scale = Math.min(
|
||||||
|
window.innerWidth / 960,
|
||||||
|
window.innerHeight / 540
|
||||||
|
);
|
||||||
|
const content = document.getElementById("content")!
|
||||||
|
content.style.transform = `scale(${scale})`
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("resize", resize)
|
||||||
|
resize()
|
||||||
|
|
@ -7,6 +7,9 @@ import { NOSE_ICON, NOSE_DIR, NOSE_BIN, NOSE_APP } from "./config"
|
||||||
import { transpile, isFile } from "./utils"
|
import { transpile, isFile } from "./utils"
|
||||||
import { apps, serveApp } from "./webapp"
|
import { apps, serveApp } from "./webapp"
|
||||||
|
|
||||||
|
import { Layout } from "./components/layout"
|
||||||
|
import { Terminal } from "./components/terminal"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Hono setup
|
// Hono setup
|
||||||
//
|
//
|
||||||
|
|
@ -56,36 +59,42 @@ app.use("*", async (c, next) => {
|
||||||
return next()
|
return next()
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get("/", c => {
|
app.get("/apps", c => {
|
||||||
const url = new URL(c.req.url)
|
const url = new URL(c.req.url)
|
||||||
const domain = url.hostname
|
const domain = url.hostname
|
||||||
const port = url.port
|
let port = url.port
|
||||||
|
port = port && port !== "80" ? `:${port}` : ""
|
||||||
|
|
||||||
return c.html(<>
|
return c.html(<>
|
||||||
<h1>apps</h1>
|
<h1>apps</h1>
|
||||||
<ul>{apps().map(app => <li><a href={`http://${app}.${domain}:${port}`}>{app}</a></li>)}
|
<ul>{apps().map(app => <li><a href={`http://${app}.${domain}${port}`}>{app}</a></li>)}
|
||||||
</ul>
|
</ul>
|
||||||
</>)
|
</>)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.get("/", c => c.html(<Layout><Terminal /></Layout>))
|
||||||
|
|
||||||
//
|
//
|
||||||
// server shutdown
|
// hot mode cleanup
|
||||||
//
|
//
|
||||||
|
|
||||||
// @ts-ignore
|
if (process.env.BUN_HOT) {
|
||||||
globalThis.__nose_cleanup?.()
|
// @ts-ignore
|
||||||
|
globalThis.__hot_reload_cleanup?.()
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
globalThis.__nose_cleanup = () => {
|
globalThis.__hot_reload_cleanup = () => {
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const sig of ["SIGINT", "SIGTERM"] as const) {
|
||||||
|
process.on(sig, () => {
|
||||||
|
// @ts-ignore
|
||||||
|
globalThis.__hot_reload_cleanup?.()
|
||||||
|
process.exit()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const sig of ["SIGINT", "SIGTERM"] as const) {
|
|
||||||
process.on(sig, () => {
|
|
||||||
// @ts-ignore
|
|
||||||
globalThis.__nose_cleanup?.()
|
|
||||||
process.exit()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,40 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
// Environment setup & latest features
|
// Environment setup & latest features
|
||||||
"lib": ["ESNext"],
|
"lib": [
|
||||||
|
"ESNext",
|
||||||
|
"DOM"
|
||||||
|
],
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"module": "Preserve",
|
"module": "Preserve",
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "hono/jsx",
|
"jsxImportSource": "hono/jsx",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
|
||||||
// Bundler mode
|
// Bundler mode
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"verbatimModuleSyntax": true,
|
"verbatimModuleSyntax": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
|
|
||||||
// Best practices
|
// Best practices
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedIndexedAccess": true,
|
"noUncheckedIndexedAccess": true,
|
||||||
"noImplicitOverride": true,
|
"noImplicitOverride": true,
|
||||||
|
|
||||||
// Some stricter flags (disabled by default)
|
// Some stricter flags (disabled by default)
|
||||||
"noUnusedLocals": false,
|
"noUnusedLocals": false,
|
||||||
"noUnusedParameters": false,
|
"noUnusedParameters": false,
|
||||||
"noPropertyAccessFromIndexSignature": false,
|
"noPropertyAccessFromIndexSignature": false,
|
||||||
|
|
||||||
// paths?
|
// paths?
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@utils": ["src/utils.tsx"],
|
"@utils": [
|
||||||
"@/*": ["src/*"]
|
"src/utils.tsx"
|
||||||
|
],
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user