parent
07ac383798
commit
3fa54d4ac6
27 changed files with 94 additions and 3481 deletions
|
@ -1,12 +0,0 @@
|
|||
|
||||
/*
|
||||
|
||||
!/tsconfig.json
|
||||
|
||||
# node modules
|
||||
!/package.json
|
||||
!/package-lock.json
|
||||
|
||||
# sources
|
||||
!/src
|
||||
!/static
|
|
@ -1,28 +0,0 @@
|
|||
parser: "@typescript-eslint/parser"
|
||||
env:
|
||||
es6: true
|
||||
node: true
|
||||
parserOptions:
|
||||
ecmaVersion: 2020
|
||||
sourceType: "module"
|
||||
extends:
|
||||
- prettier
|
||||
- plugin:prettier/recommended
|
||||
- "plugin:@typescript-eslint/recommended"
|
||||
rules:
|
||||
"@typescript-eslint/no-unused-vars":
|
||||
- error
|
||||
- vars: all
|
||||
args: after-used
|
||||
argsIgnorePattern: ^_
|
||||
varsIgnorePattern: ^_
|
||||
ignoreRestSiblings: true
|
||||
"@typescript-eslint/no-empty-interface": off
|
||||
"@typescript-eslint/no-explicit-any": off
|
||||
"@typescript-eslint/explicit-function-return-type":
|
||||
- warn
|
||||
- allowExpressions: false
|
||||
allowTypedFunctionExpressions: true
|
||||
allowHigherOrderFunctions: true
|
||||
"@typescript-eslint/camelcase": off
|
||||
"@typescript-eslint/no-use-before-define": off
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -9,6 +9,7 @@
|
|||
!/*file
|
||||
!/*.yml
|
||||
!/*.json
|
||||
!/*.nix
|
||||
|
||||
# sources
|
||||
!/src
|
||||
|
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"editor.tabSize": 2
|
||||
}
|
27
Dockerfile
27
Dockerfile
|
@ -1,24 +1,13 @@
|
|||
FROM node:16.14.2-alpine3.14
|
||||
FROM denoland/deno:alpine-1.22.1
|
||||
|
||||
EXPOSE 33334
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apk update \
|
||||
&& apk upgrade \
|
||||
&& apk add --no-cache bash git openssh
|
||||
USER deno
|
||||
|
||||
COPY package*.json ./
|
||||
ADD . .
|
||||
# Compile the main app so that it doesn't need to be compiled each startup/entry.
|
||||
RUN deno cache server.ts
|
||||
|
||||
RUN npm install \
|
||||
&& apk del bash git openssh
|
||||
|
||||
COPY tsconfig.json ./
|
||||
COPY src ./src
|
||||
|
||||
RUN npm run build \
|
||||
&& npm prune --production
|
||||
|
||||
COPY static ./static/
|
||||
|
||||
EXPOSE 30000
|
||||
|
||||
CMD npm run start
|
||||
CMD ["run", "-A", "server.ts"]
|
||||
|
|
6
deno.json
Normal file
6
deno.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["deno.ns", "dom"]
|
||||
},
|
||||
"importMap": "./import_map.json"
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
version: "3.9"
|
||||
|
||||
networks:
|
||||
rp_public:
|
||||
external: true
|
||||
|
||||
services:
|
||||
site:
|
||||
image: pleshevski
|
||||
networks:
|
||||
- rp_public
|
||||
deploy:
|
||||
replicas: 1
|
||||
endpoint_mode: vip
|
||||
update_config:
|
||||
order: start-first
|
||||
rollback_config:
|
||||
order: start-first
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=rp_public
|
||||
- traefik.constraint-label=rp_public
|
||||
- traefik.http.routers.pleshevski_http.rule=Host(`pleshevski.ru`)
|
||||
- traefik.http.routers.pleshevski_http.entrypoints=http
|
||||
- traefik.http.routers.pleshevski_http.middlewares=https_redirect
|
||||
- traefik.http.routers.pleshevski_https.rule=Host(`pleshevski.ru`)
|
||||
- traefik.http.routers.pleshevski_https.entrypoints=https
|
||||
- traefik.http.routers.pleshevski_https.tls=true
|
||||
- traefik.http.routers.pleshevski_https.tls.certresolver=le
|
||||
- traefik.http.services.pleshevski.loadbalancer.server.port=30000
|
||||
|
43
flake.lock
Normal file
43
flake.lock
Normal file
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1654593855,
|
||||
"narHash": "sha256-c+SyXvj7THre87OyIdZfRVR+HhI/g1ZDrQ3VUtTuHkU=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "033bd4fa9a8fbe0c68a88e925d9a884161044b25",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"utils": "utils"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"locked": {
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
22
flake.nix
Normal file
22
flake.nix
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
description = "Pleshevski personal site";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = {self, nixpkgs, utils}:
|
||||
let out = system:
|
||||
let pkgs = nixpkgs.legacyPackages."${system}";
|
||||
in {
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
gnumake
|
||||
nodePackages.sass
|
||||
];
|
||||
};
|
||||
};
|
||||
in with utils.lib; eachSystem defaultSystems out;
|
||||
|
||||
}
|
5
import_map.json
Normal file
5
import_map.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"imports": {
|
||||
"ren/": "https://git.pleshevski.ru/pleshevskiy/ren/raw/branch/main/ren/"
|
||||
}
|
||||
}
|
30
makefile
30
makefile
|
@ -1,10 +1,15 @@
|
|||
PAR := $(MAKE) -j 128
|
||||
DOCKER_NAME := pleshevski
|
||||
DOCKER_TAG := pleshevski
|
||||
|
||||
DOCKER_NAME := recipes
|
||||
DOCKER_TAG := recipes
|
||||
|
||||
watch:
|
||||
$(PAR) hr ts-w
|
||||
${PAR} deno-w sass-w
|
||||
|
||||
deno-w:
|
||||
deno run -A --watch server.ts
|
||||
|
||||
sass-w:
|
||||
sass -w styles/main.scss public/styles/main.css
|
||||
|
||||
docker-restart: docker-stop docker-run
|
||||
|
||||
|
@ -16,20 +21,3 @@ docker-run:
|
|||
|
||||
docker-build:
|
||||
docker build -t ${DOCKER_TAG} .
|
||||
|
||||
build: ts
|
||||
|
||||
start:
|
||||
npm run start
|
||||
|
||||
hr:
|
||||
deno run -A ~/sandbox/hr/server.ts target static
|
||||
|
||||
ts:
|
||||
npm run build
|
||||
|
||||
ts-w:
|
||||
NODE_ENV=develop npx tsc-watch --onSuccess "make start"
|
||||
|
||||
clean:
|
||||
rm -rf target
|
||||
|
|
2849
package-lock.json
generated
2849
package-lock.json
generated
File diff suppressed because it is too large
Load diff
20
package.json
20
package.json
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node target/scripts/main.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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"
|
||||
},
|
||||
"dependencies": {
|
||||
"ren": "github:pleshevskiy/ren"
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
import { AnyNode, E, Ea, Elem } from "ren";
|
||||
import { config } from "../config.mjs";
|
||||
import { div } from "../utils.mjs";
|
||||
|
||||
export function Layout(page: AnyNode): Elem {
|
||||
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",
|
||||
}),
|
||||
E("title", "pleshevski"),
|
||||
]),
|
||||
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();
|
||||
});`
|
||||
);
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
import { AnyNode, Ea, Elem } from "ren";
|
||||
import { Context } from "../context.mjs";
|
||||
import { div } from "../utils.mjs";
|
||||
|
||||
export function PageLayout(ctx: Context, ...children: AnyNode[]): Elem {
|
||||
return Ea("div", { id: "main" }, [
|
||||
Header(ctx.locPath),
|
||||
Ea("div", { class: "content" }, children),
|
||||
// Footer(),
|
||||
]);
|
||||
}
|
||||
|
||||
export function Header(locPath: string): Elem {
|
||||
return Ea("header", { class: "header" }, [
|
||||
div({ class: "content-width" }, HeaderNav(locPath)),
|
||||
]);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
export const config = createConfig();
|
||||
|
||||
export function createConfig(): Config {
|
||||
return {
|
||||
isDev: process.env.NODE_ENV === "develop",
|
||||
server: { port: 30000 },
|
||||
};
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
isDev: boolean;
|
||||
server: ServerConfig;
|
||||
}
|
||||
|
||||
export interface ServerConfig {
|
||||
port: number;
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
export interface Context {
|
||||
locPath: string;
|
||||
}
|
13
src/lang.mts
13
src/lang.mts
|
@ -1,13 +0,0 @@
|
|||
export function isNil<T>(v: Nilable<T>): v is Nil {
|
||||
return v == null;
|
||||
}
|
||||
|
||||
export type Nullable<T> = T | null;
|
||||
|
||||
export type Nilable<T> = T | Nil;
|
||||
|
||||
export type Nil = null | undefined;
|
||||
|
||||
export function isBool(v: unknown): v is boolean {
|
||||
return typeof v === "boolean";
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
export function info(...args: unknown[]): void {
|
||||
console.log("[INFO]", ...args);
|
||||
}
|
||||
|
||||
export function debug(...args: unknown[]): void {
|
||||
console.log("[DEBUG]", ...args);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
import { createServer } from "./server.mjs";
|
||||
|
||||
main();
|
||||
|
||||
function main(): void {
|
||||
createServer();
|
||||
}
|
110
src/server.mts
110
src/server.mts
|
@ -1,110 +0,0 @@
|
|||
import * as http from "http";
|
||||
import * as fs from "fs/promises";
|
||||
import * as path from "path";
|
||||
import { Layout } from "./components/layout.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(): void {
|
||||
const server = http.createServer(handleHttpReq);
|
||||
server.listen(config.server.port, () => {
|
||||
info(
|
||||
"[server]",
|
||||
`Server listening at http://localhost:${config.server.port}`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async function handleHttpReq(
|
||||
httpReq: http.IncomingMessage,
|
||||
httpRes: http.ServerResponse
|
||||
): Promise<void> {
|
||||
try {
|
||||
const req = tryIntoAppServerRequest(httpReq);
|
||||
|
||||
debug("[server]", { req });
|
||||
|
||||
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 {
|
||||
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(ctx))));
|
||||
} else if (/^[/]works[/]?$/.test(req.url)) {
|
||||
httpRes
|
||||
.writeHead(200, { "content-type": "text/html" })
|
||||
.end(ren.render(Layout(WorksPage(ctx))));
|
||||
} else {
|
||||
httpRes
|
||||
.writeHead(404, { "content-type": "text/html" })
|
||||
.end(ren.render(Layout(E404(ctx))));
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof InvalidServerRequest) {
|
||||
httpRes.writeHead(400).end("Bad request");
|
||||
} else if (err instanceof UnsupportedRestMethod) {
|
||||
httpRes.writeHead(405).end("Method not allowed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mimeTypeByExt = new Map([[".css", "text/css"]]);
|
||||
|
||||
export function tryIntoAppServerRequest(
|
||||
req: http.IncomingMessage
|
||||
): ServerRequest {
|
||||
if (!req.method || !req.url) throw new InvalidServerRequest();
|
||||
|
||||
return {
|
||||
method: tryIntoAppRestMethod(req.method),
|
||||
url: req.url,
|
||||
};
|
||||
}
|
||||
|
||||
export interface ServerRequest {
|
||||
method: RestMethod;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export class InvalidServerRequest extends Error {}
|
||||
|
||||
export function tryIntoAppRestMethod(rest: string): RestMethod {
|
||||
switch (rest.toUpperCase()) {
|
||||
case "GET":
|
||||
return RestMethod.Get;
|
||||
default:
|
||||
throw new UnsupportedRestMethod();
|
||||
}
|
||||
}
|
||||
|
||||
export enum RestMethod {
|
||||
Get = "GET",
|
||||
}
|
||||
|
||||
export class UnsupportedRestMethod extends Error {}
|
||||
|
||||
export interface ServerResponse {
|
||||
statusCode?: number;
|
||||
headers?: Headers;
|
||||
body: string;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
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,50 +0,0 @@
|
|||
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(ctx: Context): AnyNode {
|
||||
return PageLayout(
|
||||
ctx,
|
||||
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,14 +0,0 @@
|
|||
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(ctx: Context): AnyNode {
|
||||
return PageLayout(
|
||||
ctx,
|
||||
div(
|
||||
{ class: "content-width" },
|
||||
Ea("h3", { class: "font-h3" }, "Страница не найдена")
|
||||
)
|
||||
);
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
import { PageLayout } from "../components/page_layout.mjs";
|
||||
import { AnyNode, Ea } from "ren";
|
||||
import { div, h3, li, ul } from "../utils.mjs";
|
||||
import { Context } from "../context.mjs";
|
||||
|
||||
export function WorksPage(ctx: Context): AnyNode {
|
||||
return PageLayout(
|
||||
ctx,
|
||||
div({ class: "content-width responsive-typography" }, [
|
||||
h3("Одни из моих последних работ"),
|
||||
ul([
|
||||
li(Ea("a", { href: "https://github.com/pleshevskiy/ren" }, "ren")),
|
||||
li(Ea("a", { href: "https://github.com/pleshevskiy/hwt" }, "hwt")),
|
||||
li(
|
||||
Ea(
|
||||
"a",
|
||||
{ href: "https://github.com/pleshevskiy/sonic-channel" },
|
||||
"sonic-channel"
|
||||
)
|
||||
),
|
||||
li(Ea("a", { href: "https://github.com/pleshevskiy/migra" }, "migra")),
|
||||
li(
|
||||
Ea(
|
||||
"a",
|
||||
{ href: "https://github.com/pleshevskiy/itconfig-rs" },
|
||||
"itconfig-rs"
|
||||
)
|
||||
),
|
||||
]),
|
||||
])
|
||||
);
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
:root {
|
||||
--min-width: 320px;
|
||||
--max-width: 1024px;
|
||||
|
||||
--default-color-white: #ffffff;
|
||||
--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: 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 {
|
||||
min-height: 100vh;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
#root,
|
||||
#main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#main,
|
||||
.content {
|
||||
flex: 1 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding-top: 1.5rem;
|
||||
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);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 1.25rem;
|
||||
padding-right: 1.25rem;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "target/scripts",
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"lib": ["dom", "esnext"],
|
||||
"moduleResolution": "node",
|
||||
"rootDir": "src",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.mts"
|
||||
],
|
||||
}
|
Loading…
Reference in a new issue