feat: add styles for layout

This commit is contained in:
Dmitriy Pleshevskiy 2022-03-18 00:06:01 +03:00
parent bae5c0d8be
commit 9146a6ead8
7 changed files with 104 additions and 32 deletions

1
.gitignore vendored
View File

@ -19,3 +19,4 @@
# sources # sources
!/src !/src
!/static

22
package-lock.json generated
View File

@ -5,7 +5,7 @@
"packages": { "packages": {
"": { "": {
"dependencies": { "dependencies": {
"ren": "github:pleshevskiy/ren" "ren": "file:../../sandbox/ren"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^17.0.21", "@types/node": "^17.0.21",
@ -21,7 +21,6 @@
}, },
"../../sandbox/ren": { "../../sandbox/ren": {
"version": "0.0.1", "version": "0.0.1",
"extraneous": true,
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@types/node": "^17.0.21", "@types/node": "^17.0.21",
@ -1347,9 +1346,8 @@
} }
}, },
"node_modules/ren": { "node_modules/ren": {
"version": "0.0.1", "resolved": "../../sandbox/ren",
"resolved": "git+ssh://git@github.com/pleshevskiy/ren.git#9a783eba321b32fdbbb385fee3277fc08e80cb92", "link": true
"license": "MIT"
}, },
"node_modules/resolve-from": { "node_modules/resolve-from": {
"version": "4.0.0", "version": "4.0.0",
@ -2622,8 +2620,18 @@
"dev": true "dev": true
}, },
"ren": { "ren": {
"version": "git+ssh://git@github.com/pleshevskiy/ren.git#9a783eba321b32fdbbb385fee3277fc08e80cb92", "version": "file:../../sandbox/ren",
"from": "ren@git+ssh://git@github.com:pleshevskiy/ren.git" "requires": {
"@types/node": "^17.0.21",
"@typescript-eslint/eslint-plugin": "^5.14.0",
"@typescript-eslint/parser": "^5.14.0",
"eslint": "^8.10.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"prettier": "^2.5.1",
"tsc-watch": "^4.6.0",
"typescript": "^4.6.2"
}
}, },
"resolve-from": { "resolve-from": {
"version": "4.0.0", "version": "4.0.0",

View File

@ -11,6 +11,6 @@
"typescript": "^4.6.2" "typescript": "^4.6.2"
}, },
"dependencies": { "dependencies": {
"ren": "github:pleshevskiy/ren" "ren": "file:../../sandbox/ren"
} }
} }

View File

@ -4,9 +4,18 @@ export async function Layout(page: AnyNode): Promise<Elem> {
return new Elem("html") return new Elem("html")
.withAttr("lang", "ru") .withAttr("lang", "ru")
.withChild( .withChild(
new Elem("head") new Elem("head").withChildren([
.withChild(new Elem("meta").withAttr("charset", "utf-8")) new Elem("meta").withAttr("charset", "utf-8"),
.withChild(new Elem("title").withText("hello world")) new Elem("link").withAttrs({
rel: "stylesheet",
href: "/static/styles.css",
}),
new Elem("title").withText("hello world"),
])
) )
.withChild(new Elem("body").withChild(page)); .withChild(
new Elem("body").withChild(
new Elem("div").withAttr("id", "root").withChild(page)
)
);
} }

View File

@ -1,12 +1,13 @@
import { AnyNode, Elem, Frag } from "ren"; import { AnyNode, Elem } from "ren";
export async function PageLayout(children: AnyNode[]): Promise<Frag> { export async function PageLayout(children: AnyNode[]): Promise<Elem> {
return new Frag() return new Elem("div")
.withChild(Header()) .withAttr("id", "main")
.withChild( .withChildren([
new Elem("div").withAttr("class", "content").withChildren(children) Header(),
) new Elem("div").withAttr("class", "content").withChildren(children),
.withChild(Footer()); Footer(),
]);
} }
export function Header(): Elem { export function Header(): Elem {

View File

@ -1,4 +1,6 @@
import * as http from "http"; import * as http from "http";
import * as fs from "fs/promises";
import * as path from "path";
import { Layout } from "./components/layout.mjs"; import { Layout } from "./components/layout.mjs";
import { ServerConfig } from "./config.mjs"; import { ServerConfig } from "./config.mjs";
import { debug, info } from "./log.mjs"; import { debug, info } from "./log.mjs";
@ -23,19 +25,34 @@ async function handleHttpReq(
debug("[server]", { req }); debug("[server]", { req });
const ren = new StrRenderer(); if (req.url.startsWith("/static")) {
if (/^[/](?:about[/]?)?$/.test(req.url)) { const relFilePath = path.join(process.cwd(), req.url.slice(1));
httpRes const mimeType = mimeTypeByExt.get(path.extname(relFilePath));
.writeHead(200, { "content-type": "text/html" })
.end(await ren.render(Layout(AboutPage()))); const fileContent = await fs
} else if (/^[/]works[/]?/.test(req.url)) { .readFile(relFilePath, { encoding: "utf-8" })
httpRes .catch((_e) => null);
.writeHead(200, { "content-type": "text/html" })
.end(await ren.render(Layout(WorksPage()))); if (fileContent && mimeType) {
httpRes.writeHead(200, { "content-type": mimeType }).end(fileContent);
} else {
httpRes.writeHead(404).end("Not found");
}
} else { } else {
httpRes const ren = new StrRenderer();
.writeHead(404, { "content-type": "text/html" }) if (/^[/](?:about[/]?)?$/.test(req.url)) {
.end(await ren.render(Layout(E404()))); httpRes
.writeHead(200, { "content-type": "text/html" })
.end(await ren.render(Layout(AboutPage())));
} else if (/^[/]works[/]?/.test(req.url)) {
httpRes
.writeHead(200, { "content-type": "text/html" })
.end(await ren.render(Layout(WorksPage())));
} else {
httpRes
.writeHead(404, { "content-type": "text/html" })
.end(await ren.render(Layout(E404())));
}
} }
} catch (err) { } catch (err) {
if (err instanceof InvalidServerRequest) { if (err instanceof InvalidServerRequest) {
@ -46,6 +63,11 @@ async function handleHttpReq(
} }
} }
const mimeTypeByExt = new Map([
[".html", "text/html"],
[".css", "text/css"],
]);
export function tryIntoAppServerRequest( export function tryIntoAppServerRequest(
req: http.IncomingMessage req: http.IncomingMessage
): ServerRequest { ): ServerRequest {

31
static/styles.css Normal file
View File

@ -0,0 +1,31 @@
*, ::before, ::after {
box-sizing: border-box;
padding: 0;
margin: 0;
}
html {
height: 100%;
background-color: #eee;
}
body {
height: 100%;
}
#root {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: stretch;
}
#main {
display: flex;
flex: 1 0;
flex-direction: column;
}
.content {
flex: 1 0;
}