feat: create styles, update ren
This commit is contained in:
parent
eb506f1f40
commit
1c4fb5fb44
9 changed files with 211 additions and 37 deletions
8
makefile
8
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:
|
ts-w:
|
||||||
npx tsc-watch --onSuccess "node target/scripts/main.mjs"
|
npx tsc-watch --onSuccess "node target/scripts/main.mjs"
|
||||||
|
|
|
@ -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 {
|
export function Layout(page: AnyNode): Elem {
|
||||||
return new Elem("html").withAttr("lang", "ru").withChildren(
|
return Ea("html", { lang: "ru" }, [
|
||||||
new Elem("head").withChildren(
|
E("head", [
|
||||||
new Elem("meta").withAttr("charset", "utf-8"),
|
Ea("meta", { charset: "utf-8" }),
|
||||||
new Elem("link").withAttrs({
|
Ea("meta", {
|
||||||
|
name: "viewport",
|
||||||
|
content: "width=device-width, initial-scale=1",
|
||||||
|
}),
|
||||||
|
Ea("link", {
|
||||||
rel: "stylesheet",
|
rel: "stylesheet",
|
||||||
href: "/static/styles.css",
|
href: "/static/styles.css",
|
||||||
}),
|
}),
|
||||||
new Elem("title").withText("hello world")
|
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();
|
||||||
|
});`
|
||||||
),
|
),
|
||||||
new Elem("body").withChildren(
|
]),
|
||||||
new Elem("div").withAttr("id", "root").withChildren(page)
|
]);
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
export function PageLayout(...children: AnyNode[]): Elem {
|
||||||
return new Elem("div")
|
return Ea("div", { id: "main" }, [
|
||||||
.withAttr("id", "main")
|
|
||||||
.withChildren(
|
|
||||||
Header(),
|
Header(),
|
||||||
new Elem("div").withAttrs({ class: "content" }).withChildren(...children),
|
Ea("div", { class: "content" }, children),
|
||||||
Footer()
|
Footer(),
|
||||||
);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Header(): Elem {
|
export function Header(): Elem {
|
||||||
return new Elem("header").withChildren(HeaderNav());
|
return Ea("header", { class: "header" }, [
|
||||||
|
div({ class: "content-width" }, HeaderNav()),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HeaderNav(): Elem {
|
export function HeaderNav(): Elem {
|
||||||
return new Elem("nav").withChildren(
|
return E("nav", [
|
||||||
new Elem("a").withAttr("href", "/").withText("About"),
|
Ea("a", { href: "/" }, "Обо мне"),
|
||||||
new Elem("a").withAttr("href", "/works").withText("Works")
|
Ea("a", { href: "/works" }, "Работы"),
|
||||||
);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Footer(): Elem {
|
export function Footer(): Elem {
|
||||||
return new Elem("footer").withAttr("class", "footer").withText("footer");
|
return Ea("footer", { class: "footer" }, "footer");
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ async function handleHttpReq(
|
||||||
httpRes
|
httpRes
|
||||||
.writeHead(200, { "content-type": "text/html" })
|
.writeHead(200, { "content-type": "text/html" })
|
||||||
.end(ren.render(Layout(AboutPage())));
|
.end(ren.render(Layout(AboutPage())));
|
||||||
} else if (/^[/]works[/]?/.test(req.url)) {
|
} else if (/^[/]works[/]?$/.test(req.url)) {
|
||||||
httpRes
|
httpRes
|
||||||
.writeHead(200, { "content-type": "text/html" })
|
.writeHead(200, { "content-type": "text/html" })
|
||||||
.end(ren.render(Layout(WorksPage())));
|
.end(ren.render(Layout(WorksPage())));
|
||||||
|
|
9
src/utils.mts
Normal file
9
src/utils.mts
Normal file
|
@ -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");
|
|
@ -1,6 +1,48 @@
|
||||||
import { PageLayout } from "../components/page_layout.mjs";
|
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 {
|
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("Кроссплатформенные"),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
import { PageLayout } from "../components/page_layout.mjs";
|
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 {
|
export function E404(): AnyNode {
|
||||||
return PageLayout(new Elem("p").withText("Page not found"));
|
return PageLayout(
|
||||||
|
div(
|
||||||
|
{ class: "content-width" },
|
||||||
|
Ea("h3", { class: "font-h3" }, "Страница не найдена")
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { PageLayout } from "../components/page_layout.mjs";
|
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 {
|
export function WorksPage(): AnyNode {
|
||||||
return PageLayout(new Elem("p").withText("Works"));
|
return PageLayout(div({ class: "content-width" }, p("Works")));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
box-sizing: border-box;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
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 {
|
html, body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul, ol {
|
||||||
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#root {
|
#root {
|
||||||
|
@ -17,11 +45,78 @@ html, body {
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
#root, #main {
|
#root,
|
||||||
|
#main {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main, .content {
|
#main,
|
||||||
|
.content {
|
||||||
flex: 1 0;
|
flex: 1 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue