From 9146a6ead8f33c9abc7f34fb14c68d457f2930dc Mon Sep 17 00:00:00 2001 From: Dmitriy Pleshevskiy Date: Fri, 18 Mar 2022 00:06:01 +0300 Subject: [PATCH] feat: add styles for layout --- .gitignore | 1 + package-lock.json | 22 ++++++++++------ package.json | 2 +- src/components/layout.mts | 17 ++++++++++--- src/components/page_layout.mts | 17 +++++++------ src/server.mts | 46 +++++++++++++++++++++++++--------- static/styles.css | 31 +++++++++++++++++++++++ 7 files changed, 104 insertions(+), 32 deletions(-) create mode 100644 static/styles.css diff --git a/.gitignore b/.gitignore index 22fdaef..e2629f1 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ # sources !/src +!/static diff --git a/package-lock.json b/package-lock.json index c701161..b067096 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "dependencies": { - "ren": "github:pleshevskiy/ren" + "ren": "file:../../sandbox/ren" }, "devDependencies": { "@types/node": "^17.0.21", @@ -21,7 +21,6 @@ }, "../../sandbox/ren": { "version": "0.0.1", - "extraneous": true, "license": "MIT", "devDependencies": { "@types/node": "^17.0.21", @@ -1347,9 +1346,8 @@ } }, "node_modules/ren": { - "version": "0.0.1", - "resolved": "git+ssh://git@github.com/pleshevskiy/ren.git#9a783eba321b32fdbbb385fee3277fc08e80cb92", - "license": "MIT" + "resolved": "../../sandbox/ren", + "link": true }, "node_modules/resolve-from": { "version": "4.0.0", @@ -2622,8 +2620,18 @@ "dev": true }, "ren": { - "version": "git+ssh://git@github.com/pleshevskiy/ren.git#9a783eba321b32fdbbb385fee3277fc08e80cb92", - "from": "ren@git+ssh://git@github.com:pleshevskiy/ren.git" + "version": "file:../../sandbox/ren", + "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": { "version": "4.0.0", diff --git a/package.json b/package.json index 9357e0e..af52f61 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,6 @@ "typescript": "^4.6.2" }, "dependencies": { - "ren": "github:pleshevskiy/ren" + "ren": "file:../../sandbox/ren" } } diff --git a/src/components/layout.mts b/src/components/layout.mts index bdeb1bc..c3a53f7 100644 --- a/src/components/layout.mts +++ b/src/components/layout.mts @@ -4,9 +4,18 @@ export async function Layout(page: AnyNode): Promise { return new Elem("html") .withAttr("lang", "ru") .withChild( - new Elem("head") - .withChild(new Elem("meta").withAttr("charset", "utf-8")) - .withChild(new Elem("title").withText("hello world")) + new Elem("head").withChildren([ + new Elem("meta").withAttr("charset", "utf-8"), + 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) + ) + ); } diff --git a/src/components/page_layout.mts b/src/components/page_layout.mts index 4dde09d..178ce06 100644 --- a/src/components/page_layout.mts +++ b/src/components/page_layout.mts @@ -1,12 +1,13 @@ -import { AnyNode, Elem, Frag } from "ren"; +import { AnyNode, Elem } from "ren"; -export async function PageLayout(children: AnyNode[]): Promise { - return new Frag() - .withChild(Header()) - .withChild( - new Elem("div").withAttr("class", "content").withChildren(children) - ) - .withChild(Footer()); +export async function PageLayout(children: AnyNode[]): Promise { + return new Elem("div") + .withAttr("id", "main") + .withChildren([ + Header(), + new Elem("div").withAttr("class", "content").withChildren(children), + Footer(), + ]); } export function Header(): Elem { diff --git a/src/server.mts b/src/server.mts index a2d99e3..923f8b4 100644 --- a/src/server.mts +++ b/src/server.mts @@ -1,4 +1,6 @@ import * as http from "http"; +import * as fs from "fs/promises"; +import * as path from "path"; import { Layout } from "./components/layout.mjs"; import { ServerConfig } from "./config.mjs"; import { debug, info } from "./log.mjs"; @@ -23,19 +25,34 @@ async function handleHttpReq( debug("[server]", { req }); - const ren = new StrRenderer(); - if (/^[/](?:about[/]?)?$/.test(req.url)) { - 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()))); + if (req.url.startsWith("/static")) { + const relFilePath = path.join(process.cwd(), req.url.slice(1)); + const mimeType = mimeTypeByExt.get(path.extname(relFilePath)); + + const fileContent = await fs + .readFile(relFilePath, { encoding: "utf-8" }) + .catch((_e) => null); + + if (fileContent && mimeType) { + httpRes.writeHead(200, { "content-type": mimeType }).end(fileContent); + } else { + httpRes.writeHead(404).end("Not found"); + } } else { - httpRes - .writeHead(404, { "content-type": "text/html" }) - .end(await ren.render(Layout(E404()))); + const ren = new StrRenderer(); + if (/^[/](?:about[/]?)?$/.test(req.url)) { + 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) { if (err instanceof InvalidServerRequest) { @@ -46,6 +63,11 @@ async function handleHttpReq( } } +const mimeTypeByExt = new Map([ + [".html", "text/html"], + [".css", "text/css"], +]); + export function tryIntoAppServerRequest( req: http.IncomingMessage ): ServerRequest { diff --git a/static/styles.css b/static/styles.css new file mode 100644 index 0000000..a867312 --- /dev/null +++ b/static/styles.css @@ -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; +} \ No newline at end of file