diff --git a/makefile b/makefile index 62865a5..407cd6d 100644 --- a/makefile +++ b/makefile @@ -1,3 +1,11 @@ +PAR := $(MAKE) -j 128 + + +watch: + $(PAR) hr ts-w + +hr: + deno run -A ~/sandbox/hr/server.ts target static ts-w: npx tsc-watch --onSuccess "node target/scripts/main.mjs" diff --git a/src/components/layout.mts b/src/components/layout.mts index 5ff8587..58cb213 100644 --- a/src/components/layout.mts +++ b/src/components/layout.mts @@ -1,17 +1,29 @@ -import { AnyNode, Elem } from "ren"; +import { AnyNode, E, Ea, Elem } from "ren"; +import { div } from "../utils.mjs"; export function Layout(page: AnyNode): Elem { - return new Elem("html").withAttr("lang", "ru").withChildren( - new Elem("head").withChildren( - new Elem("meta").withAttr("charset", "utf-8"), - new Elem("link").withAttrs({ + return Ea("html", { lang: "ru" }, [ + E("head", [ + Ea("meta", { charset: "utf-8" }), + Ea("meta", { + name: "viewport", + content: "width=device-width, initial-scale=1", + }), + Ea("link", { rel: "stylesheet", href: "/static/styles.css", }), - new Elem("title").withText("hello world") - ), - new Elem("body").withChildren( - new Elem("div").withAttr("id", "root").withChildren(page) - ) - ); + E("title", "hello world"), + ]), + E("body", [ + div({ id: "root" }, page), + E( + "script", + `const ws = new WebSocket("ws://localhost:30001"); + ws.addEventListener("message", (m) => { + if (m.data === "RELOAD") location.reload(); + });` + ), + ]), + ]); } diff --git a/src/components/page_layout.mts b/src/components/page_layout.mts index d05d97e..9eac452 100644 --- a/src/components/page_layout.mts +++ b/src/components/page_layout.mts @@ -1,26 +1,27 @@ -import { AnyNode, Elem } from "ren"; +import { AnyNode, E, Ea, Elem } from "ren"; +import { div } from "../utils.mjs"; export function PageLayout(...children: AnyNode[]): Elem { - return new Elem("div") - .withAttr("id", "main") - .withChildren( - Header(), - new Elem("div").withAttrs({ class: "content" }).withChildren(...children), - Footer() - ); + return Ea("div", { id: "main" }, [ + Header(), + Ea("div", { class: "content" }, children), + Footer(), + ]); } export function Header(): Elem { - return new Elem("header").withChildren(HeaderNav()); + return Ea("header", { class: "header" }, [ + div({ class: "content-width" }, HeaderNav()), + ]); } export function HeaderNav(): Elem { - return new Elem("nav").withChildren( - new Elem("a").withAttr("href", "/").withText("About"), - new Elem("a").withAttr("href", "/works").withText("Works") - ); + return E("nav", [ + Ea("a", { href: "/" }, "Обо мне"), + Ea("a", { href: "/works" }, "Работы"), + ]); } export function Footer(): Elem { - return new Elem("footer").withAttr("class", "footer").withText("footer"); + return Ea("footer", { class: "footer" }, "footer"); } diff --git a/src/server.mts b/src/server.mts index 43869e3..46d23ae 100644 --- a/src/server.mts +++ b/src/server.mts @@ -44,7 +44,7 @@ async function handleHttpReq( httpRes .writeHead(200, { "content-type": "text/html" }) .end(ren.render(Layout(AboutPage()))); - } else if (/^[/]works[/]?/.test(req.url)) { + } else if (/^[/]works[/]?$/.test(req.url)) { httpRes .writeHead(200, { "content-type": "text/html" }) .end(ren.render(Layout(WorksPage()))); diff --git a/src/utils.mts b/src/utils.mts new file mode 100644 index 0000000..267e1f3 --- /dev/null +++ b/src/utils.mts @@ -0,0 +1,9 @@ +import { E, Ea, Et } from "ren"; + +export const p = Et.bind(null, "p"); +export const h2 = Et.bind(null, "h2"); +export const h3 = Et.bind(null, "h3"); + +export const div = Ea.bind(null, "div"); +export const ul = E.bind(null, "ul"); +export const li = E.bind(null, "li"); diff --git a/src/views/about.mts b/src/views/about.mts index 08bcfd4..11df5b2 100644 --- a/src/views/about.mts +++ b/src/views/about.mts @@ -1,6 +1,48 @@ import { PageLayout } from "../components/page_layout.mjs"; -import { AnyNode, Elem } from "ren"; +import { AnyNode } from "ren"; +import { div, h3, li, p, ul } from "../utils.mjs"; export function AboutPage(): AnyNode { - return PageLayout(new Elem("p").withText("Привет мир")); + return PageLayout( + div({ class: "content-width responsive-typography" }, [ + div({}, [ + p("Привет!"), + p("Меня зовут Дмитрий Плешевский."), + p( + "Я ведущий разработчик программного обеспечения, архитектор,", + "руководитель команды, а так же ментор." + ), + p( + "Open-source проекты – моя страсть! Придумываю, экспериментирую,", + "воплощаю, улучшаю проекты в свое свободное время" + ), + p( + "Помимо программирования я люблю готовить и проводить время со своей", + "любимой семьей!" + ), + ]), + div({}, [ + h3("Языки программирования"), + p("Предпочитаю: Rust, TS"), + p("Огромный опыт: Rust, TS, JS, Python"), + p("Ограниченный опыт: Haskell, Java, C#"), + ]), + div({}, [ + h3("Базы данных"), + p("Предпочитаю: Postgres"), + p("Огромный опыт: Postgres, MySQL, Sqlite, mongo"), + ]), + div({}, [ + h3("Создание приложений"), + ul([ + li("Традиционное (SSR + Forms)"), + li("API (REST/GraphQL/WebSocket/EventSource)"), + li("Динамическое (SPA)"), + li("Гибридное (SSR + SPA)"), + li("Консольные"), + li("Кроссплатформенные"), + ]), + ]), + ]) + ); } diff --git a/src/views/e404.mts b/src/views/e404.mts index 8bcd20a..471fd03 100644 --- a/src/views/e404.mts +++ b/src/views/e404.mts @@ -1,6 +1,12 @@ import { PageLayout } from "../components/page_layout.mjs"; -import { AnyNode, Elem } from "ren"; +import { AnyNode, Ea } from "ren"; +import { div } from "../utils.mjs"; export function E404(): AnyNode { - return PageLayout(new Elem("p").withText("Page not found")); + return PageLayout( + div( + { class: "content-width" }, + Ea("h3", { class: "font-h3" }, "Страница не найдена") + ) + ); } diff --git a/src/views/works.mts b/src/views/works.mts index 7d2e96e..fc0905e 100644 --- a/src/views/works.mts +++ b/src/views/works.mts @@ -1,6 +1,7 @@ import { PageLayout } from "../components/page_layout.mjs"; -import { AnyNode, Elem } from "ren"; +import { AnyNode } from "ren"; +import { div, p } from "../utils.mjs"; export function WorksPage(): AnyNode { - return PageLayout(new Elem("p").withText("Works")); + return PageLayout(div({ class: "content-width" }, p("Works"))); } diff --git a/static/styles.css b/static/styles.css index cb26f70..b9fe8dc 100644 --- a/static/styles.css +++ b/static/styles.css @@ -1,15 +1,43 @@ -*, ::before, ::after { +:root { + --min-width: 320px; + --max-width: 1024px; + + --default-color-white: hsl(0, 0, 100%); + --color-blue: #1966df; + + --default-font-size: 16px; + --font-family: system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Roboto,Oxygen-Sans, Ubuntu, Cantarell, "Segoe UI", Verdana, sans-serif; + --font-weight-regular: 400; +} + +*, *::before, *::after { box-sizing: border-box; padding: 0; margin: 0; } html { - background-color: #eee; + background-color: var(--default-color-white); + font-size: var(--default-font-size); + line-height: 1; + -webkit-text-size-adjust: 100%; + -moz-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +body { + font-weight: var(--font-weight-regular); + font-family: var(--font-family); + min-width: var(--min-width); } html, body { height: 100%; + width: 100%; +} + +ul, ol { + list-style: none; } #root { @@ -17,11 +45,78 @@ html, body { align-items: stretch; } -#root, #main { +#root, +#main { display: flex; flex-direction: column; } -#main, .content { +#main, +.content { flex: 1 0; -} \ No newline at end of file +} + +.header { + padding-top: 1.5rem; + padding-bottom: 1.5rem; +} + +.content-width { + width: 100%; + max-width: var(--max-width); + margin-left: auto; + margin-right: auto; +} + +.responsive-typography h3 { + font-size: 24px; +} + +.responsive-typography > div, +.responsive-typography p, +.responsive-typography li { + font-size: 18px; + line-height: 1.5; +} + +.responsive-typography ul, +.responsive-typography ol { + width: 100%; +} + +.responsive-typography ul li, +.responsive-typography ol li { + position: relative; + width: 100%; + min-height: 1.5rem; + padding-left: 1.5rem; +} + +.responsive-typography ul li::before, +.responsive-typography ol li::before { + content: ''; + position: absolute; + top: 0; + left: 0; +} + +.responsive-typography ul > li::before { + background-color: var(--color-blue); + border-radius: 50%; + width: 0.5rem; + height: 0.5rem; + margin-top: 0.5rem; + margin-left: 0.25rem; +} + +.responsive-typography > * + * { + margin-top: 2rem; +} + +.responsive-typography > div + div, +.responsive-typography p + p { + margin-top: 1rem; +} +.responsive-typography li + li { + margin-top: 0.5rem; +}