feat: add context and env

This commit is contained in:
Dmitriy Pleshevskiy 2022-03-21 22:50:07 +03:00
parent 1c4fb5fb44
commit 58c0f976af
11 changed files with 89 additions and 37 deletions

View file

@ -8,7 +8,7 @@ hr:
deno run -A ~/sandbox/hr/server.ts target static
ts-w:
npx tsc-watch --onSuccess "node target/scripts/main.mjs"
NODE_ENV=develop npx tsc-watch --onSuccess "node target/scripts/main.mjs"
clean:
rm -rf target

View file

@ -1,4 +1,5 @@
import { AnyNode, E, Ea, Elem } from "ren";
import { config } from "../config.mjs";
import { div } from "../utils.mjs";
export function Layout(page: AnyNode): Elem {
@ -15,15 +16,16 @@ export function Layout(page: AnyNode): Elem {
}),
E("title", "hello world"),
]),
E("body", [
div({ id: "root" }, page),
E(
E("body", [div({ id: "root" }, page), config.isDev && HotReloadScript()]),
]);
}
function HotReloadScript(): Elem {
return E(
"script",
`const ws = new WebSocket("ws://localhost:30001");
ws.addEventListener("message", (m) => {
if (m.data === "RELOAD") location.reload();
});`
),
]),
]);
);
}

View file

@ -1,27 +1,34 @@
import { AnyNode, E, Ea, Elem } from "ren";
import { AnyNode, Ea, Elem } from "ren";
import { Context } from "../context.mjs";
import { div } from "../utils.mjs";
export function PageLayout(...children: AnyNode[]): Elem {
export function PageLayout(ctx: Context, ...children: AnyNode[]): Elem {
return Ea("div", { id: "main" }, [
Header(),
Header(ctx.locPath),
Ea("div", { class: "content" }, children),
Footer(),
// Footer(),
]);
}
export function Header(): Elem {
export function Header(locPath: string): Elem {
return Ea("header", { class: "header" }, [
div({ class: "content-width" }, HeaderNav()),
div({ class: "content-width" }, HeaderNav(locPath)),
]);
}
export function HeaderNav(): Elem {
return E("nav", [
Ea("a", { href: "/" }, "Обо мне"),
Ea("a", { href: "/works" }, "Работы"),
export function HeaderNav(locPath: string): Elem {
return Ea("nav", { class: "main-menu" }, [
NavLink(locPath, "/", "Обо мне"),
NavLink(locPath, "/works", "Работы"),
]);
}
export function NavLink(locPath: string, href: string, text: string): Elem {
const attrs = { href };
if (locPath === href) attrs["aria-current"] = "true";
return Ea("a", attrs, text);
}
export function Footer(): Elem {
return Ea("footer", { class: "footer" }, "footer");
}

View file

@ -1,8 +1,14 @@
export const config = createConfig();
export function createConfig(): Config {
return { server: { port: 30000 } };
return {
isDev: process.env.NODE_ENV === "develop",
server: { port: 30000 },
};
}
export interface Config {
isDev: boolean;
server: ServerConfig;
}

3
src/context.mts Normal file
View file

@ -0,0 +1,3 @@
export interface Context {
locPath: string;
}

View file

@ -1,9 +1,7 @@
import { createConfig } from "./config.mjs";
import { createServer } from "./server.mjs";
main();
function main(): void {
const config = createConfig();
createServer(config.server);
createServer();
}

View file

@ -2,17 +2,21 @@ 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 { config } from "./config.mjs";
import { debug, info } from "./log.mjs";
import { StrRenderer } from "ren";
import { AboutPage } from "./views/about.mjs";
import { E404 } from "./views/e404.mjs";
import { WorksPage } from "./views/works.mjs";
import { Context } from "./context.mjs";
export function createServer(cfg: ServerConfig): void {
export function createServer(): void {
const server = http.createServer(handleHttpReq);
server.listen(cfg.port, () => {
info("[server]", `Server listening at http://localhost:${cfg.port}`);
server.listen(config.server.port, () => {
info(
"[server]",
`Server listening at http://localhost:${config.server.port}`
);
});
}
@ -39,19 +43,20 @@ async function handleHttpReq(
httpRes.writeHead(404).end("Not found");
}
} else {
const ctx: Context = { locPath: req.url };
const ren = new StrRenderer();
if (/^[/](?:about[/]?)?$/.test(req.url)) {
httpRes
.writeHead(200, { "content-type": "text/html" })
.end(ren.render(Layout(AboutPage())));
.end(ren.render(Layout(AboutPage(ctx))));
} else if (/^[/]works[/]?$/.test(req.url)) {
httpRes
.writeHead(200, { "content-type": "text/html" })
.end(ren.render(Layout(WorksPage())));
.end(ren.render(Layout(WorksPage(ctx))));
} else {
httpRes
.writeHead(404, { "content-type": "text/html" })
.end(ren.render(Layout(E404())));
.end(ren.render(Layout(E404(ctx))));
}
}
} catch (err) {

View file

@ -1,9 +1,11 @@
import { PageLayout } from "../components/page_layout.mjs";
import { AnyNode } from "ren";
import { div, h3, li, p, ul } from "../utils.mjs";
import { Context } from "../context.mjs";
export function AboutPage(): AnyNode {
export function AboutPage(ctx: Context): AnyNode {
return PageLayout(
ctx,
div({ class: "content-width responsive-typography" }, [
div({}, [
p("Привет!"),

View file

@ -1,9 +1,11 @@
import { PageLayout } from "../components/page_layout.mjs";
import { AnyNode, Ea } from "ren";
import { div } from "../utils.mjs";
import { Context } from "../context.mjs";
export function E404(): AnyNode {
export function E404(ctx: Context): AnyNode {
return PageLayout(
ctx,
div(
{ class: "content-width" },
Ea("h3", { class: "font-h3" }, "Страница не найдена")

View file

@ -1,7 +1,8 @@
import { PageLayout } from "../components/page_layout.mjs";
import { AnyNode } from "ren";
import { div, p } from "../utils.mjs";
import { Context } from "../context.mjs";
export function WorksPage(): AnyNode {
return PageLayout(div({ class: "content-width" }, p("Works")));
export function WorksPage(ctx: Context): AnyNode {
return PageLayout(ctx, div({ class: "content-width" }, p("Works")));
}

View file

@ -2,7 +2,7 @@
--min-width: 320px;
--max-width: 1024px;
--default-color-white: hsl(0, 0, 100%);
--default-color-white: #ffffff;
--color-blue: #1966df;
--default-font-size: 16px;
@ -61,6 +61,32 @@ ul, ol {
padding-bottom: 1.5rem;
}
.main-menu {
display: flex;
flex-direction: row;
}
// anim
.main-menu > a {
transition: all .2s ease-in-out;
}
.main-menu > a {
color: var(--color-blue);
padding: 0.5rem;
border-radius: 6px;
border: 1px solid var(--color-blue);
text-decoration: none;
}
.main-menu > a:hover,
.main-menu > a[aria-current]:not([aria-current=""]) {
color: var(--default-color-white);
background-color: var(--color-blue);
}
.main-menu > a:not(:last-child) {
margin-right: 1rem;
}
.content-width {
width: 100%;
max-width: var(--max-width);