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
!/src
!/static

22
package-lock.json generated
View File

@ -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",

View File

@ -11,6 +11,6 @@
"typescript": "^4.6.2"
},
"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")
.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)
)
);
}

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> {
return new Frag()
.withChild(Header())
.withChild(
new Elem("div").withAttr("class", "content").withChildren(children)
)
.withChild(Footer());
export async function PageLayout(children: AnyNode[]): Promise<Elem> {
return new Elem("div")
.withAttr("id", "main")
.withChildren([
Header(),
new Elem("div").withAttr("class", "content").withChildren(children),
Footer(),
]);
}
export function Header(): Elem {

View File

@ -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 {

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;
}