diff --git a/old/.dockerignore b/old/.dockerignore deleted file mode 100644 index 9632ce5..0000000 --- a/old/.dockerignore +++ /dev/null @@ -1,13 +0,0 @@ -/* - -!/data -!/public -!/styles -!/translates -!/views -!/uikit -!/modules - -!/*.ts -!/*.json - diff --git a/old/.woodpecker.yml b/old/.woodpecker.yml deleted file mode 100644 index 282bfd5..0000000 --- a/old/.woodpecker.yml +++ /dev/null @@ -1,19 +0,0 @@ -when: - branch: main - -steps: - - name: build-docker-image - image: plugins/docker - settings: - repo: ${ORG_REGISTRY}/${CI_REPO} - tags: - - "${CI_COMMIT_BRANCH}" - - "${CI_COMMIT_SHA:0:8}" - - - name: deploy - image: ${ORG_REGISTRY}/drone_plugins/docker_stack - pull: true - environment: - PLESHEVSKI_IMAGE: ${ORG_REGISTRY}/${CI_REPO}:${CI_COMMIT_SHA:0:8} - settings: - name: pleshevski diff --git a/old/Dockerfile b/old/Dockerfile deleted file mode 100644 index 6fa85e9..0000000 --- a/old/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM denoland/deno:alpine-1.22.1 - -EXPOSE 33334 - -WORKDIR /app - -USER deno - -ADD . . -# Compile the main app so that it doesn't need to be compiled each startup/entry. -RUN deno cache server.ts - -CMD ["run", "-A", "server.ts"] diff --git a/old/context.ts b/old/context.ts deleted file mode 100644 index 4404445..0000000 --- a/old/context.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Translations } from "./translates/rus.ts"; - -export interface Context { - title?: string; - locPath: string; - lang: Lang; - tr: Translations; -} - -export function getLangHref(lang: Lang, url: string): string { - return getLangUrlPrefix(lang) + url; -} - -export function getLangUrlPrefix(lang: Lang): string { - return `/${lang}`; -} - -export function iterLangs(): Lang[] { - return [Lang.Eng, Lang.Rus]; -} - -export enum Lang { - Rus = "rus", - Eng = "eng", -} diff --git a/old/data/about/eng.md b/old/data/about/eng.md deleted file mode 100644 index ffa5e3f..0000000 --- a/old/data/about/eng.md +++ /dev/null @@ -1,105 +0,0 @@ -### - -Always up-to-date link to [resume](https://pleshevski.ru/eng/). - -### Overview - -My name is Dmitriy Pleshevskiy. - -I'm an open source software enthusiast, a lead software developer, architect, -team leader and also mentor. - -### Skills - -Programming Languages: - -- TypeScript (prefer, solid 9-year exp) -- SQL (prefer, solid 8-year exp) -- Rust (prefer, solid 5-year exp) -- Python (solid 9-year exp) -- Haskell -- Bash -- Java -- C# -- C++ - -Databases: - -- PostgreSQL (prefer, solid 7-year exp) -- MySQL -- Sqlite -- MsSQL -- MongoDB -- Reddis - -I also have extensive experience in creating the following applications: - -- Traditional (SSR + Forms) -- API (REST/GraphQL/WebSocket/EventSource) -- Dynamic (SPA) -- Hybrid (SSR + SPA) -- Console -- Crossplatform - -### Stack - -Backend (Rust) - -- axum (prefer, solid 2-year exp) -- async-graphql (prefer, solid 2-year exp) -- shaku (prefer, solid 2-year exp) -- bb8 + postgres-types (prefer, solid 5-year exp) -- diesel (2-year exp) - -Backend (Node.JS) - -- Apollo (solid 5-year exp) -- Express (solid 9-year exp) -- Nest.JS -- Knex.js / Objection.js (solid 5-year exp) -- Sequelize - -Frontend - -- React (solid 8-year exp) -- VueJS (prefer, solid 3-year exp) -- Cypress (prefer, solid 3-year exp) -- JQuery -- Antd / Antdv -- PostCSS (prefer, solid 5-year exp) -- Sass (prefer, solid 8-year exp) -- Less (weak 4-year exp) - -DevOps - -- NixOS / NixOps / Nix dev shell (prefer, solid 2-year exp) -- Docker Swarm (prefer, solid 5-year exp) -- Kubernetes (weak 4-year exp) -- Woodpecker CI (prefer, solid 3-year exp) -- Drone CI (solid 3-year exp) -- Gitlab CI (solid 7-year exp) -- GitHub Actions (3-year exp) - -### Interests - -Open-source projects are my passion! I develop, maintain and improve projects in -my spare time. - -Besides programming, I love to cook and spend time with my beloved family! - -### Contacts - -SimpleX: -[Dmitriy Pleshevskiy](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FSkIkI6EPd2D63F4xFKfHk7I1UGZVNn6k1QWZ5rcyr6w%3D%40smp9.simplex.im%2FLfKyG0YgW5eRO-z8vrEyvnNfV2EKDfBv%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAMRpR3YB10GVzc-asfqY2oIFkipx5RQm4DZRabzjfPHo%253D%26srv%3Djssqzccmrcws6bhmn77vgmhfjmhwlyr3u7puw4erkyoosywgl67slqqd.onion) - -Telegram: [Dmitriy Pleshevskiy](https://telegram.me/da_pranaya) - -Matrix: @pleshevskiy:matrix.org - -Email: dmitriy[at]pleshevski[dot]ru - -### Links - -[My Git Repo](https://git.pleshevski.ru/) - -[My Github (Suspended due to sanctions)](https://github.com/pleshevskiy) diff --git a/old/data/about/rus.md b/old/data/about/rus.md deleted file mode 100644 index c36185d..0000000 --- a/old/data/about/rus.md +++ /dev/null @@ -1,107 +0,0 @@ -### - -Всегда актуальная ссылка на [резюме](https://pleshevski.ru/rus/). - -### Общие сведения - -Меня зовут Дмитрий Плешевский. - -Я энтузиаст программного обеспечения с открытым исходным кодом, ведущий -разработчик програмного обеспечения, архитектор, руководитель команды, а так же -ментор. - -### Умения - -Языки программирования: - -- TypeScript (предпочитаю, твёрдый 9-летний опыт) -- SQL (предпочитаю, твёрдый 8-летний опыт) -- Rust (предпочитаю, 5-летний опыт) -- Python (твёрдый 9-летний опыт) -- Haskell -- Bash -- Java -- C# -- C++ - -Базы данных: - -- PostgreSQL (предпочитаю, твёрдый 7-летний опыт) -- MySQL -- Sqlite -- MsSQL -- MongoDB -- Reddis - -Я так же имею большой опыт в создании следующих типов приложений: - -- Традиционные (SSR + Forms) -- API (REST/GraphQL/WebSocket/EventSource) -- Динамическое (SPA) -- Гибридное (SSR + SPA) -- Консольные -- Кроссплатформенные - -### Stack - -Backend (Rust) - -- axum (предпочитаю, твёрдый 2-летний опыт) -- async-graphql (предпочитаю, твёрдый 2-летний опыт) -- shaku (предпочитаю, твёрдый 2-летний опыт) -- bb8 + postgres-types (предпочитаю, твёрдый 5-летний опыт) -- diesel (2-летний опыт) - -Backend (Node.JS) - -- Apollo (твёрдый 5-летний опыт) -- Express (твёрдый 9-летний опыт) -- Nest.JS -- Knex.js / Objection.js (твёрдый 5-летний опыт) -- Sequelize - -Frontend - -- React (твёрдый 8-летний опыт) -- VueJS (предпочитаю, твёрдый 3-летний опыт) -- Cypress (предпочитаю, твёрдый 3-летний опыт) -- JQuery -- Antd / Antdv -- PostCSS (предпочитаю, твёрдый 5-летний опыт) -- Sass (предпочитаю, твёрдый 8-летний опыт) -- Less (слабый 4-летний опыт) - -DevOps - -- NixOS / NixOps / Nix dev shell (предпочитаю, твёрдый 2-летний опыт) -- Docker Swarm (предпочитаю, твёрдый 5-летний опыт) -- Kubernetes (слабый 4-летний опыт) -- Woodpecker CI (предпочитаю, твёрдый 3-летний опыт) -- Drone CI (твёрдый 3-летний опыт) -- Gitlab CI (твёрдый 7-летний опыт) -- GitHub Actions (3-летний опыт) - -### Интересы - -Open-source проекты - моя страсть! Разрабатываю, поддерживаю и улучшаю проекты в -своё свободное время. - -Помимо программирования я люблю готовить и проводить время со своей любимой -семьей! - -### Контакты - -SimpleX: -[Dmitriy Pleshevskiy](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FSkIkI6EPd2D63F4xFKfHk7I1UGZVNn6k1QWZ5rcyr6w%3D%40smp9.simplex.im%2FLfKyG0YgW5eRO-z8vrEyvnNfV2EKDfBv%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAMRpR3YB10GVzc-asfqY2oIFkipx5RQm4DZRabzjfPHo%253D%26srv%3Djssqzccmrcws6bhmn77vgmhfjmhwlyr3u7puw4erkyoosywgl67slqqd.onion) - -Telegram: [Dmitriy Pleshevskiy](https://telegram.me/da_pranaya) - -Matrix: @pleshevskiy:matrix.org - -Email: dmitriy[at]pleshevski[dot]ru - -### Ссылки - -[My Git Repo](https://git.pleshevski.ru/) - -[My Github (Приостановлен из-за санкций)](https://github.com/pleshevskiy) diff --git a/old/data/works/eng.md b/old/data/works/eng.md deleted file mode 100644 index 7d7c510..0000000 --- a/old/data/works/eng.md +++ /dev/null @@ -1,64 +0,0 @@ -### Highlighted working experience - -#### Binary Management - -- Dates: August 2018 – currently -- Roles: Lead Fullstack Developer, Team Lead, Architect - -Development of a project management tool for interior designers - -- Development of the GraphQL API (Node.JS, Apollo, PostgreSQL, Redis, BullMQ). - Moved database triggers to business logic. Wrote integration tests on 70% api. -- Development of the frontend (React, Antd). Formed uikit, shared components, - redesigned the page generation gathering. Completely changed work with API on - the frontend. Introduced the practice of writing integration tests using - cypress -- Completely ported the project to TypeScript. I have formed isolated modules of - the system. -- As a team leader, I brought the critical chain method, the buffer method, and - the planning method to the project from the end. Helped the team get into a - rhythm to make releases each week in small batches. A couple of times I also - prepared an individual development plan for team members. - -#### Master Progress - -- Dates: May 2018 - currently (Passively maintained) -- Role: Tech Lead - -Development web infrastructure of the educational center Master Progress - -- Development of [the main site](https://masterprogress.ru) (Python, Flask). -- Development of [Student's cabinet](https://cabinet.masterprogress.ru) (Python, - Flask, TypeScript, React). -- Development of [a tool for rosmintrud](https://rosmintrud.masterprogress.ru) - (Deno, Vue, Typescript) -- Created a complete infrastructure on Woodpecker CI and Docker swarm. - -#### Core Spirit - -- Dates: August 2018 - May 2020 -- Role: Lead Fullstack Developer - -Development of Social platform focusing on human and planetary enhancement - -- Development of the REST API (Node.JS, Express, PostgreSQL) for main site and - backoffice. -- Development of an auto poster to various social networks and messengers - (Facebook, LinkedIn, Twitter, Telegram). -- Development of a neural network for automatic categorization of articles. - -#### MERLION - -- Dates: March 2016 – May 2018 -- Role: Senior Fullstack developer - -In this company there were 6 considerable projects I have successfully -completed: - -- optimize the creation of promotional pages (PHP, JavaScript) -- support main traditional site (PHP, JavaScript) -- development of parsing to monitor products for changes in price, - quantity/availability in stock, rating and other fields based on data from 55 - websites (Node.JS, Express) -- work with neural networks for matching of goods -- development face recognition apps for Android (Java) diff --git a/old/data/works/rus.md b/old/data/works/rus.md deleted file mode 100644 index 49c81d4..0000000 --- a/old/data/works/rus.md +++ /dev/null @@ -1,65 +0,0 @@ -### Выделенный опыт работы - -#### Binary Management - -- Даты: Август 2018 – по настоящее время -- Роли: Lead Fullstack Developer, Team Lead, Architect - -Разработка инструмента управления проектами для дизайнеров интерьера - -- Разработка GraphQL API (Node.JS, Apollo, PostgreSQL, Redis, BullMQ). Перенес - триггеры базы данных в бизнес-логику. Написал интеграционные тесты на 70% api. -- Разработка фронтенда (React, Antd). Сформировал uikit и общие компоненты, - оптимизировал сложные и нагруженные компоненты. Полностью изменил работу с API - на фронтенде. Внедрил практику написания интеграционных тестов с помощью - cypress. -- Полностью перенес проект на TypeScript. Сформировал изолированные модули - системы. -- Как руководитель команды, я привнес в проект метод критической цепи, метод - буфера и метод планирования с конца. Помог команде войти в ритм, чтобы - выпускать релизы каждую неделю небольшими партиями. Я также несколько раз - составлял индивидуальный план развития для членов команды. - -#### Master Progress - -- Даты: Май 2018 - по настоящее время (Пассивная поддержка) -- Роль: Tech Lead - -Разработка веб-инфраструктуры образовательного центра Мастер Прогресс - -- Разработка [главного сайта](https://masterprogress.ru) (Python, Flask). -- Разработка [кабинета студента](https://cabinet.masterprogress.ru) (Python, - Flask, TypeScript, React). -- Разработка - [инструмента для работы с rosmintrud](https://rosmintrud.masterprogress.ru) - (Deno, Vue, Typescript) -- Создана полная инфраструктура на Woodpecker CI и Docker swarm. - -#### Core Spirit - -- Даты: Август 2018 - May 2020 -- Роль: Lead Fullstack Developer - -Разработка социальной платформы, сфокусированной на улучшении человека и планеты - -- Разработка REST API (Node.JS, Express, PostgreSQL) для основного сайта и - бэк-офиса. -- Разработка автопостера в различные социальные сети и мессенджеры (Facebook, - LinkedIn, Twitter, Telegram). -- Разработка нейронной сети для автоматической категоризации статей. - -#### MERLION - -- Dates: March 2016 – May 2018 -- Role: Senior Fullstack developer - -В этой компании было 6 значительных проектов, которые я успешно завершил: - -- Оптимизация создания рекламных страниц (PHP, JavaScript) -- Поддержка основного традиционного сайта (PHP, - JavaScript) -- Разработка парсинга для мониторинга товаров на предмет изменения цены, - количества/наличия на складе, рейтинга и других полей на основе данных с 55+ - сайтов (Node.js, Express) -- Работа с нейронными сетями для подбора товаров -- Разработка приложений для распознавания лиц для Android (Java) diff --git a/old/deno.json b/old/deno.json deleted file mode 100644 index f76bf0a..0000000 --- a/old/deno.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "compilerOptions": { - "lib": ["deno.ns", "dom"] - }, - "importMap": "./import_map.json" -} diff --git a/old/deno.lock b/old/deno.lock deleted file mode 100644 index 4a058be..0000000 --- a/old/deno.lock +++ /dev/null @@ -1,13 +0,0 @@ -{ - "version": "2", - "remote": { - "https://git.pleshevski.ru/pleshevskiy/paren/raw/commit/257079305813c4c0a71c16a89164c20bbce1a5e2/core/node.ts": "0857215f4ddbc5ef661af1eef8010376914373b9040d11ac777923651f59db08", - "https://git.pleshevski.ru/pleshevskiy/paren/raw/commit/257079305813c4c0a71c16a89164c20bbce1a5e2/core/utils.ts": "136b4b594befe6f1157741932aaea86f00f5ca6b1f7ee3e84059e9140a87e82d", - "https://git.pleshevski.ru/pleshevskiy/paren/raw/commit/257079305813c4c0a71c16a89164c20bbce1a5e2/par/md.ts": "0d4264ee133a883372664ac4b5e2dcb66a41a10a914de089e96b4ebb6757c641", - "https://git.pleshevski.ru/pleshevskiy/paren/raw/commit/257079305813c4c0a71c16a89164c20bbce1a5e2/par/types.ts": "f114cafde896121b9db754ffb5f2778edb3d414c78e3782ce1fb50a2ec8e2708", - "https://git.pleshevski.ru/pleshevskiy/paren/raw/commit/257079305813c4c0a71c16a89164c20bbce1a5e2/ren/attrs.ts": "a8f118423567bc64fd53ffd472bba4417df7de4df726c122c2ae8f37e921329a", - "https://git.pleshevski.ru/pleshevskiy/paren/raw/commit/257079305813c4c0a71c16a89164c20bbce1a5e2/ren/html_str.ts": "6052fa5b65ae0d8b2d5f6cb82d365e8b9a01f6070d55015db8386175386b8cca", - "https://git.pleshevski.ru/pleshevskiy/paren/raw/commit/257079305813c4c0a71c16a89164c20bbce1a5e2/ren/node.ts": "85d81ee3adc506f7ae90db31ed52336034766430ec8a8d6ae5d9951206f989fc", - "https://git.pleshevski.ru/pleshevskiy/paren/raw/commit/257079305813c4c0a71c16a89164c20bbce1a5e2/ren/types.ts": "f1f561397a8326ddfcfefb00c3c9ea7e4e5467021fa89795628daa656d90727b" - } -} diff --git a/old/docker-compose.yml b/old/docker-compose.yml deleted file mode 100644 index e47b1e8..0000000 --- a/old/docker-compose.yml +++ /dev/null @@ -1,29 +0,0 @@ -version: "3.8" - -networks: - traefik_public: - external: true - -services: - site: - image: $PLESHEVSKI_IMAGE - networks: - - traefik_public - deploy: - replicas: 1 - endpoint_mode: vip - update_config: - order: start-first - rollback_config: - order: start-first - labels: - - traefik.enable=true - - traefik.constraint-label=magenta_public - - traefik.http.routers.to_pleshevski_site.rule=Host(`pleshevski.ru`) - - traefik.http.routers.to_pleshevski_site.entrypoints=https - - traefik.http.routers.to_pleshevski_site.tls=true - - traefik.http.routers.to_pleshevski_site.tls.certresolver=le - - traefik.http.services.pleshevski_site.loadbalancer.server.port=33334 - placement: - constraints: - - node.role == worker diff --git a/old/global.ts b/old/global.ts deleted file mode 100644 index 5ae448c..0000000 --- a/old/global.ts +++ /dev/null @@ -1 +0,0 @@ -export type NonEmptyArray = [T, ...T[]]; diff --git a/old/import_map.json b/old/import_map.json deleted file mode 100644 index ac65af8..0000000 --- a/old/import_map.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "imports": { - "par/": "https://git.pleshevski.ru/pleshevskiy/paren/raw/commit/257079305813c4c0a71c16a89164c20bbce1a5e2/par/", - "ren/": "https://git.pleshevski.ru/pleshevskiy/paren/raw/commit/257079305813c4c0a71c16a89164c20bbce1a5e2/ren/" - } -} diff --git a/old/log.ts b/old/log.ts deleted file mode 100644 index 9735b62..0000000 --- a/old/log.ts +++ /dev/null @@ -1,14 +0,0 @@ -export function error(...args: unknown[]): void { - console.log("[ERROR]", ...args); -} - -export function info(...args: unknown[]): void { - console.log("[INFO]", ...args); -} - -export function debug(...args: unknown[]): void { - // choose better name for this env - if (Deno.env.get("DEBUG") === "1") { - console.log("[DEBUG]", ...args); - } -} diff --git a/old/modules/work/ChronologicalWorksTable/ChronologicalWorksTable.ts b/old/modules/work/ChronologicalWorksTable/ChronologicalWorksTable.ts deleted file mode 100644 index 0c67fb6..0000000 --- a/old/modules/work/ChronologicalWorksTable/ChronologicalWorksTable.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { AnyNode, E } from "ren/node.ts"; -import { WorkLink } from "../mod.ts"; -import { renderDate } from "../../../render.ts"; -import { CHRONOLOGICAL_WORKS } from "../data.ts"; -import { RoleList } from "./RoleList.ts"; -import { TechnologyList } from "./TechnologyList.ts"; - -export type ChronologicalWorksTableTranslations = Readonly< - Record< - | "Name" - | "Description" - | "Role" - | "Technologies" - | "Start" - | "Status_or_End", - string - > ->; - -const tr = E.bind(null, "tr", []); -const td = E.bind(null, "td", []); -const th = E.bind(null, "th", []); - -export const ChronologicalWorksTable = ( - i18n: ChronologicalWorksTableTranslations, -): AnyNode => - E("table", [], [ - E("thead", [], [ - tr([ - th(i18n.Name), - th(i18n.Description), - th(i18n.Role), - th(i18n.Technologies), - th(i18n.Start), - th(i18n.Status_or_End), - ]), - ]), - E( - "tbody", - [], - CHRONOLOGICAL_WORKS.map((work) => - tr([ - td([WorkLink(work)]), - td(work.description), - td([RoleList(work.roles)]), - td([TechnologyList(work.technologies)]), - td(renderDate(work.startDate)), - td( - work.endDate ? renderDate(work.endDate) : work.status, - ), - ]) - ), - ), - ]); diff --git a/old/modules/work/ChronologicalWorksTable/RoleList.ts b/old/modules/work/ChronologicalWorksTable/RoleList.ts deleted file mode 100644 index b3f43f2..0000000 --- a/old/modules/work/ChronologicalWorksTable/RoleList.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { NonEmptyArray } from "../../../global.ts"; -import { Role } from "../domain/mod.ts"; -import { AnyNode, TextNode } from "ren/node.ts"; - -export const RoleList: (roles: NonEmptyArray) => AnyNode = (roles) => - new TextNode(roles.join(", ")); diff --git a/old/modules/work/ChronologicalWorksTable/TechnologyList.ts b/old/modules/work/ChronologicalWorksTable/TechnologyList.ts deleted file mode 100644 index e0c625c..0000000 --- a/old/modules/work/ChronologicalWorksTable/TechnologyList.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { NonEmptyArray } from "../../../global.ts"; -import { Technology } from "../domain/mod.ts"; -import { AnyNode, TextNode } from "ren/node.ts"; - -export const TechnologyList: (techs: NonEmptyArray) => AnyNode = ( - techs, -) => new TextNode(techs.join(", ")); diff --git a/old/modules/work/ChronologicalWorksTable/mod.ts b/old/modules/work/ChronologicalWorksTable/mod.ts deleted file mode 100644 index f4f59df..0000000 --- a/old/modules/work/ChronologicalWorksTable/mod.ts +++ /dev/null @@ -1 +0,0 @@ -export { ChronologicalWorksTable } from "./ChronologicalWorksTable.ts"; diff --git a/old/modules/work/WorkLink.ts b/old/modules/work/WorkLink.ts deleted file mode 100644 index 99a2e7e..0000000 --- a/old/modules/work/WorkLink.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AnyNode } from "ren/node.ts"; -import { Work, work as w } from "./domain/mod.ts"; -import { Link } from "../../uikit/link.ts"; - -export const WorkLink: (work: Work) => AnyNode = (work) => - Link(work.name, { href: w.getExternalLink(work) }); diff --git a/old/modules/work/data.ts b/old/modules/work/data.ts deleted file mode 100644 index 3a9f437..0000000 --- a/old/modules/work/data.ts +++ /dev/null @@ -1,368 +0,0 @@ -import { Role } from "./domain/Role.ts"; -import { Status } from "./domain/Status.ts"; -import { Technology } from "./domain/Technology.ts"; -import { Work } from "./domain/Work.ts"; - -export const CHRONOLOGICAL_WORKS: Work[] = [ - { - name: "picsg", - url: "/pleshevskiy/picsg", - description: - "A tool for steganographing information in a picture encoded using the Vernam cipher.", - roles: [Role.Author], - technologies: [Technology.Haskell], - startDate: new Date("2024-04-13"), - status: Status.AsIs, - }, - { - name: "Mindustry tools", - url: "/pleshevskiy/mindustry-tools", - description: "Tools for the Mindustry game", - roles: [Role.Author], - technologies: [ - Technology.Nix, - Technology.Godot, - ], - startDate: new Date("2024-01-07"), - status: Status.PassivelyMaintained, - }, - { - name: "Master Progress Rosmintrud tools", - url: "https://rosmintrud.masterprogress.ru", - description: - "Internal service to prepare documents for the rosmintrud (SPA)", - roles: [Role.TechLead], - technologies: [ - Technology.Deno, - Technology.Sqlite, - Technology.TypeScript, - Technology.Vue, - Technology.Docker, - Technology.Woodpecker, - Technology.Nix, - ], - startDate: new Date("2023-07-03"), - status: Status.PassivelyMaintained, - }, - { - name: "yandexgpt_tg_bot", - url: "/pleshevskiy/yandexgpt_tg_bot", - description: "The Telegram bot to describe article with link by YandexGPT.", - roles: [Role.Author], - technologies: [Technology.JavaScript, Technology.NodeJS, Technology.Nix], - startDate: new Date("2023-06-27"), - status: Status.PassivelyMaintained, - }, - { - name: "tree-sitter-plpgsql", - url: "/pleshevskiy/tree-sitter-plpgsql", - description: "plpgsql grammar for tree-sitter", - roles: [Role.Author], - technologies: [ - Technology.C, - Technology.JavaScript, - Technology.TreeSitter, - Technology.Nix, - ], - startDate: new Date("2023-01-05"), - status: Status.PassivelyMaintained, - }, - { - name: "wd2", - url: "/pleshevskiy/wd2", - description: - "A wrapper over d2 which allows to use additional configs from d2 file", - roles: [Role.Author], - technologies: [Technology.Bash, Technology.Nix], - startDate: new Date("2022-12-12"), - endDate: new Date("2023-07-31"), - status: Status.AsIs, - }, - { - name: "tree-sitter-d2", - url: "/pleshevskiy/tree-sitter-d2", - description: "d2 grammar for tree-sitter", - roles: [Role.Author], - technologies: [ - Technology.C, - Technology.JavaScript, - Technology.TreeSitter, - Technology.Nix, - ], - startDate: new Date("2022-12-04"), - status: Status.ActiveDeveloped, - }, - { - name: "nix2lua", - url: "/mynix/nix2lua", - description: - "This is a small but functional library that converts your nix configurations into lua format.", - roles: [Role.Author], - technologies: [Technology.Nix, Technology.Lua], - startDate: new Date("2022-11-22"), - status: Status.PassivelyMaintained, - }, - { - name: "vnetod", - url: "/pleshevskiy/vnetod", - description: "Dotenv section switcher", - roles: [Role.Author], - technologies: [Technology.Rust], - startDate: new Date("2022-07-29"), - status: Status.PassivelyMaintained, - }, - { - name: "estring", - url: "/pleshevskiy/estring", - description: "A simple way to parse a string using type annotations.", - roles: [Role.Author], - technologies: [Technology.Rust], - startDate: new Date("2022-07-23"), - status: Status.PassivelyMaintained, - }, - { - name: "enve", - url: "/pleshevskiy/enve", - description: - "It helps you work with environment variables and convert it to any type using only type annotations", - roles: [Role.Author], - technologies: [Technology.Rust], - startDate: new Date("2022-07-18"), - status: Status.PassivelyMaintained, - }, - { - name: "docker stack drone plugin", - url: "/drone_plugins/docker_stack", - description: "Deploy to production using `docker stack deploy`", - roles: [Role.Author], - technologies: [ - Technology.Docker, - Technology.Drone, - Technology.Woodpecker, - ], - startDate: new Date("2022-06-06"), - status: Status.PassivelyMaintained, - }, - { - name: "dexios", - url: "/github/dexios", - description: - "Dexios is a fast, secure, and open source command-line encryption tool.", - roles: [Role.Collaborator], - technologies: [Technology.Rust], - startDate: new Date("2022-06-01"), - endDate: new Date("2023-02-28"), - }, - { - name: "recipes", - url: "/pleshevskiy/recipes", - description: "Site with recipes which cares about privacy", - roles: [Role.Author], - technologies: [Technology.TypeScript, Technology.Deno, Technology.Rust], - startDate: new Date("2022-05-04"), - status: Status.PassivelyMaintained, - }, - { - name: "pleshevski.ru", - url: "/pleshevskiy/pleshevski.ru", - description: "Source code of my personal site", - roles: [Role.Author], - technologies: [ - Technology.TypeScript, - Technology.Deno, - Technology.Docker, - Technology.Woodpecker, - ], - startDate: new Date("2022-03-16"), - status: Status.PassivelyMaintained, - }, - { - name: "paren", - url: "/pleshevskiy/paren", - description: "Library for parsing and rendering information.", - roles: [Role.Author], - technologies: [Technology.TypeScript, Technology.Deno], - startDate: new Date("2022-03-14"), - status: Status.Experimental, - }, - { - name: "hwt", - url: "/pleshevskiy/hwt", - description: - "healthy workaholic timer – A tool that keeps you from breaking your health by working all day.", - roles: [Role.Author], - technologies: [Technology.Rust], - startDate: new Date("2022-02-04"), - status: Status.AsIs, - }, - { - name: "ood_persistence", - url: "/pleshevskiy/ood_persistence", - description: - "Asynchronous and synchronous interfaces and persistence implementations for your OOD architecture ", - roles: [Role.Author], - technologies: [Technology.Rust], - startDate: new Date("2021-10-12"), - status: Status.Deprecated, - }, - { - name: "migra", - url: "/pleshevskiy/migra", - description: "Simple SQL migration manager for your project.", - roles: [Role.Author], - technologies: [Technology.Rust], - startDate: new Date("2021-01-31"), - status: Status.AsIs, - }, - { - name: "espruino-starter", - url: "/pleshevskiy/espruino-starter", - description: - "Quickly start creating your new project on the espruino board or a board based on it.", - roles: [Role.Author], - technologies: [Technology.JavaScript], - startDate: new Date("2021-08-23"), - status: Status.AsIs, - }, - { - name: "react-rest-request", - url: "/pleshevskiy/react-rest-request", - description: "Minimalistic REST API client for React inspired by Apollo.", - roles: [Role.Author], - technologies: [Technology.TypeScript, Technology.React], - startDate: new Date("2020-10-04"), - status: Status.Deprecated, - }, - { - name: "sonic-channel", - url: "/pleshevskiy/sonic-channel", - description: "Rust client for sonic search backend.", - roles: [Role.Author], - technologies: [Technology.Rust], - startDate: new Date("2020-07-18"), - status: Status.PassivelyMaintained, - }, - { - name: "itconfig", - url: "/pleshevskiy/itconfig", - description: - "Easy build a configs from environment variables and use it in globally.", - roles: [Role.Author], - technologies: [Technology.Rust], - startDate: new Date("2019-12-22"), - status: Status.Deprecated, - }, - { - name: "it-fsm", - url: "/pleshevskiy/it-fsm", - description: "Simple full-featured finite state machine for your project", - roles: [Role.Author], - technologies: [Technology.TypeScript, Technology.NodeJS, Technology.Deno], - startDate: new Date("2019"), - status: Status.PassivelyMaintained, - }, - { - name: "Cabinet Master Progress", - url: "https://cabinet.masterprogress.ru", - description: - "Student's cabinet of the educational center Master Progress (SSR + SPA)", - roles: [Role.TechLead], - technologies: [ - Technology.Python, - Technology.Flask, - Technology.Postgresql, - Technology.TypeScript, - Technology.React, - Technology.Docker, - Technology.Woodpecker, - Technology.Nix, - ], - startDate: new Date("2019-09-22"), - status: Status.PassivelyMaintained, - }, - { - name: "genrss", - url: "/pleshevskiy/genrss", - description: "RSS generator for python", - roles: [Role.Author], - technologies: [Technology.Python], - startDate: new Date("2019-07-23"), - status: Status.AsIs, - }, - { - name: "marshmallow_pageinfo", - url: "/pleshevskiy/marshmallow_pageinfo", - description: "Page info marshmallow schema for api", - roles: [Role.Author], - technologies: [Technology.Python], - startDate: new Date("2019-10-05"), - status: Status.AsIs, - }, - { - name: "Binary Management", - url: "https://www.binarymanagement.com", - description: "Project management tool for interior designers", - roles: [Role.Developer, Role.TechLead, Role.TeamLead], - technologies: [ - Technology.TypeScript, - Technology.NodeJS, - Technology.React, - Technology.Antd, - Technology.Docker, - Technology.Drone, - Technology.Rust, - Technology.Nix, - ], - startDate: new Date("2018-09-15"), - status: Status.ActiveDeveloped, - }, - { - name: "Core Spirit", - url: "https://corespirit.com", - description: "Social platform focusing on human and planetary enhancement", - roles: [Role.Developer], - technologies: [ - Technology.TypeScript, - Technology.NodeJS, - Technology.React, - Technology.Docker, - Technology.Drone, - ], - startDate: new Date("2018-09-05"), - endDate: new Date("2019-12-31"), - }, - { - name: "Master Progress", - url: "https://masterprogress.ru", - description: - "Main website of the educational center Master Progress (SSR + Forms)", - roles: [Role.TechLead], - technologies: [ - Technology.Python, - Technology.Flask, - Technology.JavaScript, - Technology.Docker, - Technology.Woodpecker, - ], - startDate: new Date("2018-04-10"), - status: Status.PassivelyMaintained, - }, - { - name: "ictmpl", - url: "/pleshevskiy/ictmpl", - description: "Generate projects from templates", - roles: [Role.Author], - technologies: [Technology.Python], - startDate: new Date("2018-06-30"), - status: Status.AsIs, - }, - { - name: "jjcrypto", - url: "/pleshevskiy/jjcrypto", - description: "Javascript encoder and decoder", - roles: [Role.Author], - technologies: [Technology.Php], - startDate: new Date("2015-11-01"), - status: Status.AsIs, - }, -]; diff --git a/old/modules/work/domain/Role.ts b/old/modules/work/domain/Role.ts deleted file mode 100644 index f124a40..0000000 --- a/old/modules/work/domain/Role.ts +++ /dev/null @@ -1,7 +0,0 @@ -export enum Role { - Collaborator = "collaborator", - Author = "author", - TechLead = "tech lead", - TeamLead = "team lead", - Developer = "developer", -} diff --git a/old/modules/work/domain/Status.ts b/old/modules/work/domain/Status.ts deleted file mode 100644 index 3e3dc64..0000000 --- a/old/modules/work/domain/Status.ts +++ /dev/null @@ -1,25 +0,0 @@ -export enum Status { - // New features are being added and bugs are being fixed. - ActiveDeveloped = "actively-developed", - - // There are no plans for new features, but the maintainer intends to respond - // to issues that get filed. - PassivelyMaintained = "passively-maintained", - - // The package is feature complete, the maintainer does not intend to continue - // working on it or providing support, but it works for the purposes it was - // designed for. - AsIs = "as-is", - - // The author wants to share it with the community but is not intending to - // meet anyone's particular use case. - Experimental = "experimental", - - // The current maintainer would like to transfer the package to someone else. - LookingForMaintainer = "looking-for-maintainer", - - // The maintainer does not recommend using this package (the description of the - // package can describe why, there could be a better solution available or - // there could be problems with the package that the author does not want to fix). - Deprecated = "deprecated", -} diff --git a/old/modules/work/domain/Technology.ts b/old/modules/work/domain/Technology.ts deleted file mode 100644 index 3f9b25c..0000000 --- a/old/modules/work/domain/Technology.ts +++ /dev/null @@ -1,25 +0,0 @@ -export enum Technology { - C = "C", - JavaScript = "JS", - TypeScript = "TS", - Rust = "Rust", - Python = "Python", - Php = "PHP", - Deno = "Deno", - NodeJS = "NodeJS", - Flask = "Flask", - React = "React", - Antd = "Antd", - Postgresql = "PostgreSQL", - Docker = "Docker", - Drone = "Drone CI", - Woodpecker = "Woodpecker CI", - Bash = "Bash", - TreeSitter = "TreeSitter", - Nix = "Nix", - Lua = "Lua", - Sqlite = "Sqlite", - Vue = "Vue", - Godot = "Godot", - Haskell = "Haskell", -} diff --git a/old/modules/work/domain/Work.ts b/old/modules/work/domain/Work.ts deleted file mode 100644 index 0e03500..0000000 --- a/old/modules/work/domain/Work.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { NonEmptyArray } from "../../../global.ts"; -import { Role } from "./Role.ts"; -import { Status } from "./Status.ts"; -import { Technology } from "./Technology.ts"; - -export interface Work { - name: string; - url: string; - description: string; - roles: NonEmptyArray; - technologies: NonEmptyArray; - startDate: Date; - endDate?: Date; - status?: Status; -} - -export const getExternalLink: (work: Pick) => string = (work) => - work.url.startsWith("https://") - ? work.url - : new URL(work.url, "https://git.pleshevski.ru").toString(); diff --git a/old/modules/work/domain/mod.ts b/old/modules/work/domain/mod.ts deleted file mode 100644 index cf8937a..0000000 --- a/old/modules/work/domain/mod.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { Role } from "./Role.ts"; -export { Status } from "./Status.ts"; -export { Technology } from "./Technology.ts"; -export type { Work } from "./Work.ts"; -export * as work from "./Work.ts"; diff --git a/old/modules/work/mod.ts b/old/modules/work/mod.ts deleted file mode 100644 index 6d8bead..0000000 --- a/old/modules/work/mod.ts +++ /dev/null @@ -1 +0,0 @@ -export { WorkLink } from "./WorkLink.ts"; diff --git a/old/public/styles/main.css b/old/public/styles/main.css deleted file mode 100644 index f14a31f..0000000 --- a/old/public/styles/main.css +++ /dev/null @@ -1,570 +0,0 @@ -@charset "UTF-8"; -:root { - --default-color-black: #000000; - --default-color-black-0: hsla(0, 0%, 0%, 0); - --default-color-black-0x15: hsla(0, 0%, 0%, 0.15); - --default-color-black-0x6: hsla(0, 0%, 0%, 0.6); - --default-color-white: #ffffff; - --default-color-warning: #ffee58; - --default-color-error: #b00008; - --default-color-success: #417505; - --color-brand-blue: #1966df; - --color-brand-faded-blue: #f5f5ff; - --color-graphite: #212121; - --color-warm-gray: #757575; - --color-pale: #b6b6b6; - --color-faded: #e0e0e0; - --max-content-width: 1440px; - --min-content-width: 320px; - --rad-std-half: 0.125rem; - --rad-std: 0.25rem; - --rad-std-x2: 0.5rem; - --rad-std-x3: 0.75rem; - --default-font-size: 16px; - --f-family: system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Roboto,Oxygen-Sans, Ubuntu, Cantarell, "Segoe UI", Verdana, sans-serif; - --f-wei-thin: 100; - --f-wei-reg: 400; - --f-wei-bold: 700; - --f-wei-black: 800; - --z-ind-background: -100; - --z-ind-backward: -1; - --z-ind-select: 50; - --z-ind-tooltip: 75; - --z-ind-high: 100; - --z-ind-overlay: 500; -} - -*, -::before, -::after { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -html { - background-color: var(--default-color-white); - font-size: var(--default-font-size); - line-height: 1; - height: 100%; - -webkit-text-size-adjust: 100%; - -moz-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} - -body { - color: var(--color-graphite); - font-weight: var(--f-wei-regular); - font-family: var(--f-family); - min-width: var(--min-content-width); - width: 100%; - height: 100%; -} - -article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section { - display: block; -} - -details > summary { - cursor: pointer; - list-style: none; -} -details > summary::before, details > summary::-webkit-details-marker { - display: none; -} - -audio, canvas, progress, video { - display: inline-block; - vertical-align: baseline; -} - -audio:not([controls]) { - display: none; - height: 0; -} - -address, caption, cite, code, dfn, strong, th, var { - font-style: normal; - font-weight: var(--f-wei-regular); -} - -h1, h2, h3, h4, h5, h6 { - font-weight: var(--f-wei-bold); - line-height: 1; -} - -b, strong, optgroup { - font-weight: var(--f-wei-bold); -} - -dfn, em, i { - font-style: italic; -} - -iframe, abbr, acronym, img { - border: 0; - outline: 0; -} - -mark { - background: var(--default-color-warning); - color: var(--default-color-black); -} - -small { - font-size: 80%; -} - -sub, sup { - font-size: 80%; - vertical-align: baseline; - line-height: 0; - position: relative; -} - -sup { - top: -0.25em; -} - -sub { - bottom: -0.25em; -} - -q::before, q::after { - content: ""; -} - -hr { - box-sizing: content-box; - height: 0; - overflow: visible; -} - -code, kbd, pre, samp { - font-family: monospace; - font-size: 1em; -} - -pre { - overflow: auto; -} - -figure { - margin: 0; -} - -fieldset { - border: 1px solid var(--color-pale); - padding: 0.25rem 0.75rem; -} - -legend { - border: 0; - color: inherit; - display: table; - word-spacing: normal; - max-width: 100%; -} - -button, input, optgroup, select, textarea { - color: inherit; - font: inherit; -} - -button, input { - overflow: visible; -} - -button, select { - text-transform: none; -} - -input { - line-height: 1; -} - -button::-moz-focus-inner, -[type=button]::-moz-focus-inner, -[type=reset]::-moz-focus-inner, -[type=submit]::-moz-focus-inner { - border-style: none; - padding: 0; -} - -button:-moz-focusring, -[type=button]:-moz-focusring, -[type=reset]:-moz-focusring, -[type=submit]:-moz-focusring { - outline: 1px dotted ButtonText; -} - -input, input:focus, -button, textarea, -select, a:focus { - outline: 0; - border: 0; -} - -input::-webkit-input-placeholder, -input:-moz-placeholder, -textarea::-webkit-input-placeholder, -textarea:-moz-placeholder { - color: var(--color-pale); -} - -input[type=number]::-webkit-inner-spin-button, -input[type=number]::-webkit-outer-spin-button { - height: auto; -} - -input[type=search] { - -webkit-appearance: textfield; - outline-offset: -2px; -} - -input[type=search]::-webkit-search-cancel-button, -input[type=search]::-webkit-search-decoration { - -webkit-appearance: none; -} - -::-webkit-file-upload-button { - -webkit-appearance: button; - color: inherit; -} - -button, -input[type=button], -input[type=reset], -input[type=submit] { - -webkit-appearance: button; - cursor: pointer; -} - -button[disabled], input[disabled] { - cursor: no-drop; -} - -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - outline: 0; -} - -textarea { - overflow: auto; - resize: none; -} - -a { - cursor: pointer; - text-decoration: none; - color: var(--color-brand-blue); - border-bottom: dashed 1px var(--color-brand-blue); -} -a:hover, a:focus { - border-bottom-style: solid; -} - -table { - border-collapse: collapse; - border-spacing: 0; - table-layout: fixed; -} - -ul, ol { - list-style: none; - margin: 0; - padding: 0; -} - -[hidden], template { - display: none; -} - -svg:not(:root) { - overflow: hidden; -} - -::selection { - background-color: var(--default-color-black); - color: var(--default-color-white); -} - -.footer { - border-top: 1px solid var(--color-faded); -} - -.maw-100p { - max-width: 100%; -} - -.maw-content, .content-width { - max-width: var(--max-content-width); -} - -.miw-content, #main { - min-width: var(--min-content-width); -} - -.w-100p, .responsive-typography ul li, .responsive-typography ol li, .responsive-typography ul, .responsive-typography ol, #root, #main, .content, .content-width { - width: 100%; -} - -.mah-100p { - max-height: 100%; -} - -.mah-100vh { - max-height: 100vh; -} - -.mih-100vh, #root { - min-height: 100vh; -} - -.mar-ha, .content-width { - margin-left: auto; - margin-right: auto; -} - -.pad-0x5, .main-menu > a, .responsive-typography th, .responsive-typography td { - padding: 0.5rem; -} - -.pad-h-1x25, .content-width { - padding-right: 1.25rem; - padding-left: 1.25rem; -} - -.pad-v-1, .header, .footer { - padding-top: 1rem; - padding-bottom: 1rem; -} - -.gap-v-1x5 > :not([hidden]):not(.hidden-input) + :not([hidden]):not(.hidden-input), #main > :not([hidden]):not(.hidden-input) + :not([hidden]):not(.hidden-input) { - margin-top: 1.5rem; -} - -.gap-h-0x5 > :not(:last-child):not(:only-child) { - margin-right: 0.5rem; -} - -.gap-h-1 > :not(:last-child):not(:only-child), .main-menu > :not(:last-child):not(:only-child) { - margin-right: 1rem; -} - -.row-sta-sta, .main-menu { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-pack: start; - -ms-flex-pack: start; - justify-content: flex-start; - -webkit-box-align: start; - -ms-flex-align: start; - align-items: flex-start; -} - -.row-sta-bet { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; - -webkit-box-align: start; - -ms-flex-align: start; - align-items: flex-start; -} - -.col-sta-sta { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: start; - -ms-flex-pack: start; - justify-content: flex-start; - -webkit-box-align: start; - -ms-flex-align: start; - align-items: flex-start; -} - -.col-str-sta, #root, #main { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: start; - -ms-flex-pack: start; - justify-content: flex-start; - -webkit-box-align: stretch; - -ms-flex-align: stretch; - align-items: stretch; -} - -.flex-1, #main, .content { - -webkit-box-flex: 1 0; - -ms-flex: 1 0; - flex: 1 0; -} - -.responsive-typography h3 { - font-size: 24px; - margin: 1.5rem 0; -} -.responsive-typography > div, .responsive-typography p, .responsive-typography li { - font-size: 18px; - line-height: 1.5; -} -.responsive-typography ul li, .responsive-typography ol li { - position: relative; - 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, .responsive-typography ol > li::before { - background-color: var(--color-brand-blue); - border-radius: 50%; - width: 0.5rem; - height: 0.5rem; - margin-top: 0.5rem; - margin-left: 0.25rem; -} -.responsive-typography ul > * + *, .responsive-typography ol > * + * { - margin-top: 2rem; -} -.responsive-typography p + ul, -.responsive-typography ul + p, -.responsive-typography p + p { - margin-top: 1rem; -} -.responsive-typography li + li { - margin-top: 0.5rem; -} -.responsive-typography table { - table-layout: fixed; - border-collapse: collapse; - line-height: 1.5; -} -.responsive-typography thead { - background-color: var(--color-brand-faded-blue); -} -.responsive-typography tbody tr { - border-top: solid 1px var(--color-pale); -} -.responsive-typography th, .responsive-typography td { - text-align: initial; -} -.responsive-typography th:not(:first-of-type), .responsive-typography td:not(:first-of-type) { - border-left: solid 1px var(--color-pale); -} -.responsive-typography td:nth-child(n+3) { - color: var(--color-warm-gray); -} - -.anim, .main-menu > a, a, .anim::before, .main-menu > a::before, a::before, .anim::after, .main-menu > a::after, a::after { - transition: all 0.2s ease-in-out; -} - -.main-menu > a { - color: var(--color-brand-blue); - border-radius: 6px; - border: 1px solid var(--color-brand-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-brand-blue); -} - -/* dropdown - * Source: https://codepen.io/markcaron/pen/wdVmpB - * - * TODO: change styles - * */ -.dropdown { - position: relative; - display: inline-block; -} -.dropdown > input[type=checkbox] { - position: absolute; - left: -100vw; -} -.dropdown > label { - display: inline-block; - padding: 6px 15px; - color: #333; - line-height: 1.5em; - text-decoration: none; - border: 1px solid #8c8c8c; - cursor: pointer; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} -.dropdown > label:hover { - border-color: #333; -} -.dropdown > label:after { - content: "▲"; - font-size: 10px; - display: inline-block; - margin-left: 6px; - vertical-align: top; -} -.dropdown > ul { - position: absolute; - z-index: 999; - display: block; - left: -100vw; - bottom: calc(1.5em + 14px); - border: 1px solid #8c8c8c; - background: #fff; - padding: 6px 0; - margin: 0; - list-style: none; - width: 100%; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - -webkit-box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15); - -moz-box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15); - box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15); -} -.dropdown > ul a { - display: block; - padding: 6px 15px; - text-decoration: none; - color: #333; -} -.dropdown > ul a:hover, .dropdown > ul a:focus { - background: #ececec; -} -.dropdown > input[type=checkbox]:checked ~ ul { - left: 0; -} -.dropdown > input[type=checkbox]:checked + label:after { - content: "▼"; -} - -/*# sourceMappingURL=main.css.map */ diff --git a/old/public/styles/main.css.map b/old/public/styles/main.css.map deleted file mode 100644 index 0a88c23..0000000 --- a/old/public/styles/main.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sourceRoot":"","sources":["../../styles/base/reset.scss","../../styles/base/layout.scss","../../styles/atoms/sizes.scss","../../styles/atoms/white-spaces.scss","../../styles/mixins/white-spaces.scss","../../styles/atoms/flex.scss","../../styles/mixins/flex.scss","../../styles/atoms/typography.scss","../../styles/atoms/misc.scss","../../styles/uikit/main-menu.scss","../../styles/uikit/dropdown.scss"],"names":[],"mappings":";AAEA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;;AAGF;AAAA;AAAA;EAGE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAKF;EACE;EACA;;AAEA;EAEE;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;AAAA;AAAA;AAAA;EAIE;EACA;;;AAGF;AAAA;AAAA;AAAA;EAIE;;;AAGF;AAAA;AAAA;EAGE;EACA;;;AAGF;AAAA;AAAA;AAAA;EAIE;;;AAGF;AAAA;EAEE;;;AAGF;EACE;EACA;;;AAGF;AAAA;EAEE;;;AAGF;EACE;EACA;;;AAGF;AAAA;AAAA;AAAA;EAIE;EACA;;;AAGF;EACE;;;AAGF;AAAA;EAEE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;AAKA;EACE;;;AAIJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;;ACzSF;EAEE;;;ACTF;EAAe;;;AACf;EAAe;;;AACf;EAAe;;;AACf;EAAU;;;AAEV;EAAa;;;AACb;EAAa;;;AACb;EAAa;;;ACPb;ECQgB;EAAmB;;;ADNnC;ECQmB;;;ADPnB;ECWqB;EAEA;;;ADZrB;ECSqB;EAEA;;;AAInB;EAfmB;;;AAmBnB;EAlBmB;;;AAkBnB;EAlBmB;;;ACLrB;ECCE;EACA;EACA;EAWA;EACA;EACA;EACA;EA4CA;EACA;EACA;EAoCA;EACA;EACA;;;ADpGF;ECAE;EACA;EACA;EAWA;EACA;EACA;EACA;EAmEA;EACA;EACA;EAaA;EACA;EACA;;;ADnGF;ECDE;EACA;EACA;EAmBA;EACA;EACA;EACA;EAoCA;EACA;EACA;EAoCA;EACA;EACA;;;ADlGF;ECFE;EACA;EACA;EAmBA;EACA;EACA;EACA;EAoCA;EACA;EACA;EAsDA;EACA;EACA;;;ADlHF;ECuCE,kBDvCsB;ECwCtB,UDxCsB;ECyCtB,MDzCsB;;;AEHtB;EACE;EACA;;AAGF;EACE;EACA;;AAMA;EAGE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAIJ;AAAA;AAAA;EAGE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAGF;EAEE;;AAEA;EACE;;AAIJ;EACE;;;AC9EJ;EACE;;;ACGA;EAIE;EACA;EACA;EACA;;AAEA;EAEE;EACA;;;ACfN;AAAA;AAAA;AAAA;AAAA;AAMA;EACE;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAMJ;EACE;;AAGF;EACE","file":"main.css"} \ No newline at end of file diff --git a/old/render.ts b/old/render.ts deleted file mode 100644 index 8d64623..0000000 --- a/old/render.ts +++ /dev/null @@ -1,7 +0,0 @@ -export function renderDate(date: Date): string { - return date.toLocaleDateString(undefined, { - year: "numeric", - month: "2-digit", - day: "2-digit", - }); -} diff --git a/old/server.ts b/old/server.ts deleted file mode 100644 index dcae727..0000000 --- a/old/server.ts +++ /dev/null @@ -1,246 +0,0 @@ -import { MarkdownParser } from "par/md.ts"; -import { HtmlStrRenderer } from "ren/html_str.ts"; -import * as log from "./log.ts"; -import rusTranslates from "./translates/rus.ts"; -import type { Translations } from "./translates/rus.ts"; -import { Context, getLangHref, getLangUrlPrefix, Lang } from "./context.ts"; -import { E404Page } from "./views/pages/e404.ts"; -import { E500Page } from "./views/pages/e500.ts"; -import { WorksPage } from "./views/pages/works.ts"; -import { Layout } from "./views/comp/layout.ts"; -import { ContentPage } from "./views/pages/content.ts"; - -if (import.meta.main) { - await main(); -} - -async function main() { - await startServer({ port: 33334 }); -} - -async function startServer(cfg: ServerConfig) { - const srv = Deno.listen({ hostname: "0.0.0.0", port: cfg.port }); - log.info(`Server listening at http://localhost:${cfg.port}`); - - for await (const conn of srv) { - serveHttp(conn); - } -} - -interface ServerConfig { - port: number; -} - -async function serveHttp(conn: Deno.Conn) { - const httpConn = Deno.serveHttp(conn); - - for await (const reqEvt of httpConn) { - const res = await handleRequest(reqEvt.request); - reqEvt.respondWith(res); - } -} - -async function handleRequest(req: Request): Promise { - log.info({ method: req.method, url: req.url }); - - if (req.method === "GET") { - return await handleGet(req); - } else { - return new Response("Method Not Allowed", { status: 405 }); - } -} - -async function handleGet(req: Request) { - const restCtx = createRestContextFromRequest(req); - - try { - const res = await tryCreateFileResponse(restCtx.locPath); - return res; - } catch (_) { - if (restCtx.lang == null && restCtx.newLang) { - return new Response(null, { - status: 301, - headers: { - location: getLangUrlPrefix(restCtx.newLang) + restCtx.locPath, - }, - }); - } - - const ctx = intoAppContext(restCtx); - - if (restCtx.lang !== Lang.Rus) { - await loadAndUpdateTranslations(ctx); - } - log.debug({ context: restCtx }); - - const par = new MarkdownParser(); - const ren = new HtmlStrRenderer({ - wrapNode: Layout.bind(null, ctx), - onVisitAttr: ([key, value]) => { - if (key === "lhref" && typeof value === "string") { - return ["href", getLangHref(ctx.lang, value)]; - } else { - return [key, value]; - } - }, - }); - - try { - if (restCtx.locPath === "/" || restCtx.locPath === "/about") { - const res = par.parse( - await readMarkdownFile("data/about", ctx.lang), - ); - return createHtmlResponse(ren.render(ContentPage(ctx, res))); - } else if (restCtx.locPath === "/works") { - const res = par.parse( - await readMarkdownFile("data/works", ctx.lang), - ); - return createHtmlResponse(ren.render(WorksPage(ctx, res))); - } else { - return createHtmlResponse(ren.render(E404Page(ctx)), 404); - } - } catch (e) { - log.error(e); - return createHtmlResponse(ren.render(E500Page(ctx)), 500); - } - } -} - -async function readMarkdownFile(dirPath: string, lang: Lang): Promise { - return await Deno.readTextFile(`${dirPath}/${lang}.md`) - .catch((_) => Deno.readTextFile(`${dirPath}/${Lang.Rus}.md`)); -} - -async function loadAndUpdateTranslations(ctx: Context) { - try { - const translates = await import(`./translates/${ctx.lang}.ts`); - ctx.tr = Object.entries(translates.default as Partial) - .reduce( - (acc, [key, val]) => ({ - ...acc, - [key as keyof Translations]: val, - }), - { ...ctx.tr } as Translations, - ); - } catch (err) { - log.debug({ err }); - /* ignore */ - } -} - -function intoAppContext(restCtx: RestContext): Context { - return { - locPath: restCtx.locPath, - lang: restCtx.lang || Lang.Rus, - tr: restCtx.tr, - }; -} - -function createRestContextFromRequest(req: Request): RestContext { - log.debug(req.headers); - - const locUrl = new URL(req.url); - const lang = tryIntoAppLangFromUrl(locUrl); - - return { - lang, - newLang: getPreferRequestLang(req.headers) ?? Lang.Rus, - locPath: stripPrefix(`/${lang}`, locUrl.pathname), - tr: rusTranslates, - }; -} - -interface RestContext { - locPath: string; - lang: Lang | null; - newLang: Lang; - tr: Translations; -} - -function getPreferRequestLang(headers: Headers): Lang | null { - const acceptLanguageHeader = headers.get("accept-language"); - if (!acceptLanguageHeader) return null; - - const acceptLanguages = acceptLanguageHeader - .split(/,\s*/) - .map((part) => part.split(";q=")[0]) - .map(tryIntoAppLangFromAcceptLangCode) - .filter((lang): lang is Lang => !!lang); - return acceptLanguages[0] ?? null; -} - -function tryIntoAppLangFromAcceptLangCode(lang: string): Lang | null { - return lang === "*" - ? Lang.Rus - : lang.startsWith("en") - ? Lang.Eng - : lang.startsWith("ru") - ? Lang.Rus - : null; -} - -function tryIntoAppLangFromUrl(url: URL): Lang | null { - return url.pathname.startsWith("/eng/") - ? Lang.Eng - : url.pathname.startsWith("/rus/") - ? Lang.Rus - : null; -} - -function stripPrefix(prefix: string, val: string): string { - return val.startsWith(prefix) ? val.slice(prefix.length) : val; -} - -function createHtmlResponse(body: string, status = 200): Response { - return new Response(body, { - status, - headers: getContentTypeHeader("html"), - }); -} - -async function tryCreateFileResponse(urlPath: string): Promise { - const filePath = extractFilePath(urlPath); - log.debug({ filePath }); - if (!filePath) throw new SkipFile(); - - const content = await Deno.readTextFile(filePath).catch(() => { - throw new SkipFile(); - }); - - return createFileResponse(content, getFileExt(filePath)); -} - -class SkipFile extends Error {} - -function createFileResponse(content: string, fileExt: string): Response { - return new Response(content, { - headers: getContentTypeHeader(fileExt), - }); -} - -function extractFilePath(urlPath: string): string | null { - const relPath = urlPath.slice(1); - if (relPath.startsWith("styles/")) { - return `public/${relPath}`; - } - return null; -} - -function getContentTypeHeader(fileExt: string): Record { - return { "content-type": getContentTypeByExt(fileExt) }; -} - -function getContentTypeByExt(fileExt: string): string { - switch (fileExt) { - case "html": - return "text/html"; - case "css": - return "text/css"; - default: - return "text/plain"; - } -} - -function getFileExt(filePath: string): string { - return filePath.slice((filePath.lastIndexOf(".") - 1 >>> 0) + 2); -} diff --git a/old/styles/atoms/flex.scss b/old/styles/atoms/flex.scss deleted file mode 100644 index 968a8a1..0000000 --- a/old/styles/atoms/flex.scss +++ /dev/null @@ -1,6 +0,0 @@ -.row-sta-sta { @include flex-layout(row, sta, sta) } -.row-sta-bet { @include flex-layout(row, sta, bet) } -.col-sta-sta { @include flex-layout(col, sta, sta) } -.col-str-sta { @include flex-layout(col, str, sta) } - -.flex-1 { @include flex(1 0) } diff --git a/old/styles/atoms/misc.scss b/old/styles/atoms/misc.scss deleted file mode 100644 index 8b8987e..0000000 --- a/old/styles/atoms/misc.scss +++ /dev/null @@ -1,3 +0,0 @@ -.anim, .anim::before, .anim::after { - transition: all 0.2s ease-in-out; -} diff --git a/old/styles/atoms/mod.scss b/old/styles/atoms/mod.scss deleted file mode 100644 index 172a120..0000000 --- a/old/styles/atoms/mod.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import 'sizes'; -@import 'white-spaces'; -@import 'flex'; -@import 'typography'; -@import 'misc'; diff --git a/old/styles/atoms/sizes.scss b/old/styles/atoms/sizes.scss deleted file mode 100644 index f8c5060..0000000 --- a/old/styles/atoms/sizes.scss +++ /dev/null @@ -1,9 +0,0 @@ -.maw-100p { max-width: 100% } -.maw-content { max-width: var(--max-content-width) } -.miw-content { min-width: var(--min-content-width) } -.w-100p { width: 100% } - -.mah-100p { max-height: 100% } -.mah-100vh { max-height: 100vh } -.mih-100vh { min-height: 100vh } - diff --git a/old/styles/atoms/typography.scss b/old/styles/atoms/typography.scss deleted file mode 100644 index 1e8d797..0000000 --- a/old/styles/atoms/typography.scss +++ /dev/null @@ -1,86 +0,0 @@ -.responsive-typography { - - h3 { - font-size: 24px; - margin: 1.5rem 0; - } - - > div, p, li { - font-size: 18px; - line-height: 1.5; - } - - ul, ol { - @extend .w-100p; - - li { - @extend .w-100p; - - position: relative; - min-height: 1.5rem; - padding-left: 1.5rem; - - &::before { - content: ''; - position: absolute; - top: 0; - left: 0; - } - } - - > li::before { - background-color: var(--color-brand-blue); - border-radius: 50%; - width: 0.5rem; - height: 0.5rem; - margin-top: 0.5rem; - margin-left: 0.25rem; - } - - > * + * { - margin-top: 2rem; - } - } - - p + ul, - ul + p, - p + p { - margin-top: 1rem; - } - - li + li { - margin-top: 0.5rem; - } - - table { - table-layout: fixed; - border-collapse: collapse; - line-height: 1.5; - } - - thead { - background-color: var(--color-brand-faded-blue); - } - - tbody tr { - border-top: solid 1px var(--color-pale); - } - - th, td { - @extend .pad-0x5; - text-align: initial; - - &:not(:first-of-type) { - border-left: solid 1px var(--color-pale); - } - } - - td:nth-child(n+3) { - color: var(--color-warm-gray) - } - -} - - - - diff --git a/old/styles/atoms/white-spaces.scss b/old/styles/atoms/white-spaces.scss deleted file mode 100644 index be309bf..0000000 --- a/old/styles/atoms/white-spaces.scss +++ /dev/null @@ -1,11 +0,0 @@ -.mar-ha { @include mar-ha } - -.pad-0x5 { @include pad(0.5) } -.pad-h-1x25 { @include pad-h(1.25) } -.pad-v-1 { @include pad-v(1) } - -.gap-v-1x5 { @include gap-v(1.5) } - -.gap-h-0x5 { @include gap-h(0.5) } -.gap-h-1 { @include gap-h(1) } - diff --git a/old/styles/base/layout.scss b/old/styles/base/layout.scss deleted file mode 100644 index 749785c..0000000 --- a/old/styles/base/layout.scss +++ /dev/null @@ -1,11 +0,0 @@ -#root { @extend .col-str-sta, .w-100p, .mih-100vh } -#main { @extend .col-str-sta, .flex-1, .miw-content, .w-100p, .gap-v-1x5 } -.content { @extend .flex-1, .w-100p } -.content-width { @extend .maw-content, .w-100p, .mar-ha, .pad-h-1x25 } - -.header { @extend .pad-v-1 } - -.footer { - @extend .pad-v-1; - border-top: 1px solid var(--color-faded); -} diff --git a/old/styles/base/reset.scss b/old/styles/base/reset.scss deleted file mode 100644 index 7ce99f3..0000000 --- a/old/styles/base/reset.scss +++ /dev/null @@ -1,307 +0,0 @@ -@use "sass:math"; - -:root { - // Default Colors - --default-color-black: #000000; - --default-color-black-0: hsla(0, 0%, 0%, 0); - --default-color-black-0x15: hsla(0, 0%, 0%, 0.15); - --default-color-black-0x6: hsla(0, 0%, 0%, 0.6); - --default-color-white: #ffffff; - --default-color-warning: #ffee58; - --default-color-error: #b00008; - --default-color-success: #417505; - // Project Colors - --color-brand-blue: #1966df; - --color-brand-faded-blue: #f5f5ff; - --color-graphite: #212121; - --color-warm-gray: #757575; - --color-pale: #b6b6b6; - --color-faded: #e0e0e0; - // Layout - --max-content-width: #{$page-max-width + px}; - --min-content-width: #{$page-min-width + px}; - // Borders - --rad-std-half: #{math.div($radius, 2)}; - --rad-std: #{$radius}; - --rad-std-x2: #{$radius * 2}; - --rad-std-x3: #{$radius * 3}; - // Font - --default-font-size: 16px; - --f-family: system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Roboto,Oxygen-Sans, Ubuntu, Cantarell, "Segoe UI", Verdana, sans-serif; - --f-wei-thin: 100; - --f-wei-reg: 400; // Normal = Regular - --f-wei-bold: 700; - --f-wei-black: 800; // Extra Bold = Black - // Z-index - --z-ind-background: -100; - --z-ind-backward: -1; - --z-ind-select: 50; - --z-ind-tooltip: 75; - --z-ind-high: 100; - --z-ind-overlay: 500; -} - -*, -::before, -::after { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -html { - background-color: var(--default-color-white); - font-size: var(--default-font-size); - line-height: 1; - height: 100%; - -webkit-text-size-adjust: 100%; - -moz-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} - -body { - color: var(--color-graphite); - font-weight: var(--f-wei-regular); - font-family: var(--f-family); - min-width: var(--min-content-width); - width: 100%; - height: 100%; -} - -article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section { - display: block; -} - -summary {} - -details > summary { - cursor: pointer; - list-style: none; - - &::before, - &::-webkit-details-marker { - display: none; - } -} - -audio, canvas, progress, video { - display: inline-block; - vertical-align: baseline; -} - -audio:not([controls]) { - display: none; - height: 0; -} - -address, caption, cite, code, dfn, strong, th, var { - font-style: normal; - font-weight: var(--f-wei-regular); -} - -h1, h2, h3, h4, h5, h6 { - font-weight: var(--f-wei-bold); - line-height: 1; -} - -b, strong, optgroup { - font-weight: var(--f-wei-bold); -} - -dfn, em, i { - font-style: italic; -} - -iframe, abbr, acronym, img { - border: 0; - outline: 0; -} - -mark { - background: var(--default-color-warning); - color: var(--default-color-black); -} - -small { - font-size: 80%; -} - -sub, sup { - font-size: 80%; - vertical-align: baseline; - line-height: 0; - position: relative; -} - -sup { - top: -0.25em; -} - -sub { - bottom: -0.25em; -} - -q::before, q::after { - content: ''; -} - -hr { - box-sizing: content-box; - height: 0; - overflow: visible; -} - -code, kbd, pre, samp { - font-family: monospace; - font-size: 1em; -} - -pre { - overflow: auto; -} - -figure { - margin: 0; -} - -fieldset { - border: 1px solid var(--color-pale); - padding: 0.25rem 0.75rem; -} - -legend { - border: 0; - color: inherit; - display: table; - word-spacing: normal; - max-width: 100%; -} - -button, input, optgroup, select, textarea { - color: inherit; - font: inherit; -} - -button, input { - overflow: visible; -} - -button, select { - text-transform: none; -} - -input { - line-height: 1; -} - -button::-moz-focus-inner, -[type='button']::-moz-focus-inner, -[type='reset']::-moz-focus-inner, -[type='submit']::-moz-focus-inner { - border-style: none; - padding: 0; -} - -button:-moz-focusring, -[type='button']:-moz-focusring, -[type='reset']:-moz-focusring, -[type='submit']:-moz-focusring { - outline: 1px dotted ButtonText; -} - -input, input:focus, -button, textarea, -select, a:focus { - outline: 0; - border: 0; -} - -input::-webkit-input-placeholder, -input:-moz-placeholder, -textarea::-webkit-input-placeholder, -textarea:-moz-placeholder { - color: var(--color-pale); -} - -input[type='number']::-webkit-inner-spin-button, -input[type='number']::-webkit-outer-spin-button { - height: auto; -} - -input[type='search'] { - -webkit-appearance: textfield; - outline-offset: -2px; -} - -input[type='search']::-webkit-search-cancel-button, -input[type='search']::-webkit-search-decoration { - -webkit-appearance: none; -} - -::-webkit-file-upload-button { - -webkit-appearance: button; - color: inherit; -} - -button, -input[type='button'], -input[type='reset'], -input[type='submit'] { - -webkit-appearance: button; - cursor: pointer; -} - -button[disabled], input[disabled] { - cursor: no-drop; -} - -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - outline: 0; -} - -textarea { - overflow: auto; - resize: none; -} - -a { - cursor: pointer; - text-decoration: none; - color: var(--color-brand-blue); - border-bottom: dashed 1px var(--color-brand-blue); - - // TODO: move to other place - @extend .anim; - - &:hover, &:focus { - border-bottom-style: solid; - } -} - -table { - border-collapse: collapse; - border-spacing: 0; - table-layout: fixed; -} - -ul, ol { - list-style: none; - margin: 0; - padding: 0; -} - -[hidden], template { - display: none; -} - -svg:not(:root) { - overflow: hidden; -} - -::selection { - background-color: var(--default-color-black); - color: var(--default-color-white); -} - diff --git a/old/styles/main.scss b/old/styles/main.scss deleted file mode 100644 index a539986..0000000 --- a/old/styles/main.scss +++ /dev/null @@ -1,6 +0,0 @@ -@import 'variables'; -@import 'mixins/mod'; -@import 'base/reset'; -@import 'base/layout'; -@import 'atoms/mod'; -@import 'uikit/mod'; diff --git a/old/styles/mixins/flex.scss b/old/styles/mixins/flex.scss deleted file mode 100644 index 0b8f923..0000000 --- a/old/styles/mixins/flex.scss +++ /dev/null @@ -1,165 +0,0 @@ -@mixin dis-flex { - display: -webkit-box; - display: -ms-flexbox; - display: flex; -} - -@mixin dis-inl-flex { - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; -} - -@mixin flex-dir-row { - @include dis-flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; -} - -@mixin flex-dir-col { - @include dis-flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; -} - -@mixin flex-dir($val) { - @if $val == row {@include flex-dir-row;} - @else if $val == col {@include flex-dir-col;} - @else {@error 'unknown flex-direction: #{$val}';} -} - -@mixin flex-wrap($val: wrap) { - -ms-flex-wrap: $val; - flex-wrap: $val; -} - -@mixin flex-nowrap { - @include flex-wrap(nowrap); -} - -@mixin flex($val) { - -webkit-box-flex: $val; - -ms-flex: $val; - flex: $val; -} - -@mixin flex-shrink($val) { - -ms-flex-negative: $val; - flex-shrink: $val; -} - -@mixin ord($val) { - -webkit-box-ordinal-group: $val + 1; - -ms-flex-order: $val; - order: $val; -} - -@mixin flex-jus-sta { - -webkit-box-pack: start; - -ms-flex-pack: start; - justify-content: flex-start; -} - -@mixin flex-jus-cen { - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; -} - -@mixin flex-jus-end { - -webkit-box-pack: end; - -ms-flex-pack: end; - justify-content: flex-end; -} - -@mixin flex-jus-aro { - -ms-flex-pack: distribute; - justify-content: space-around; -} - -@mixin flex-jus-bet { - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; -} - -@mixin flex-jus($val) { - @if $val == sta {@include flex-jus-sta;} - @else if $val == cen {@include flex-jus-cen;} - @else if $val == end {@include flex-jus-end;} - @else if $val == aro {@include flex-jus-aro;} - @else if $val == bet {@include flex-jus-bet;} - @else {@error 'unknown flex-jus (justify-content) property: #{$val}';} -} - -@mixin flex-ali-sta { - -webkit-box-align: start; - -ms-flex-align: start; - align-items: flex-start; -} - -@mixin flex-ali-cen { - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - -@mixin flex-ali-end { - -webkit-box-align: end; - -ms-flex-align: end; - align-items: flex-end; -} - -@mixin flex-ali-str { - -webkit-box-align: stretch; - -ms-flex-align: stretch; - align-items: stretch; -} - -@mixin flex-ali($val) { - @if $val == sta {@include flex-ali-sta;} - @else if $val == cen {@include flex-ali-cen;} - @else if $val == end {@include flex-ali-end;} - @else if $val == str {@include flex-ali-str;} - @else {@error 'unknown flex-ali (align-items) property: #{$val}';} -} - -@mixin ali-self-sta { - -ms-flex-item-align: start; - align-self: flex-start; -} - -@mixin ali-self-cen { - -ms-flex-item-align: center; - -ms-grid-row-align: center; - align-self: center; -} - -@mixin ali-self-end { - -ms-flex-item-align: end; - align-self: flex-end; -} - -@mixin ali-self-str { - -ms-flex-item-align: stretch; - -ms-grid-row-align: stretch; - align-self: stretch; -} - -@mixin ali-self($val) { - @if $val == sta {@include ali-self-sta;} - @else if $val == cen {@include ali-self-cen;} - @else if $val == end {@include ali-self-end;} - @else if $val == str {@include ali-self-str;} - @else {@error 'unknown ali-self (align-self) property: #{$val}';} -} - -@mixin flex-layout($dir: none, $ali: none, $jus: none) { - @if $dir != none {@include flex-dir($dir);} - @if $jus != none {@include flex-jus($jus);} - @if $ali != none {@include flex-ali($ali);} -} diff --git a/old/styles/mixins/mod.scss b/old/styles/mixins/mod.scss deleted file mode 100644 index 276fb85..0000000 --- a/old/styles/mixins/mod.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'flex'; -@import 'white-spaces'; diff --git a/old/styles/mixins/white-spaces.scss b/old/styles/mixins/white-spaces.scss deleted file mode 100644 index fbfd577..0000000 --- a/old/styles/mixins/white-spaces.scss +++ /dev/null @@ -1,29 +0,0 @@ - -@mixin mar($val) { margin: #{$val}rem } -@mixin mar-v($val) { @include mar-t($val); @include mar-b($val) } -@mixin mar-h($val) { @include mar-r($val); @include mar-l($val) } -@mixin mar-t($val) { margin-top: #{$val}rem } -@mixin mar-r($val) { margin-right: #{$val}rem } -@mixin mar-b($val) { margin-bottom: #{$val}rem } -@mixin mar-l($val) { margin-left: #{$val}rem } -@mixin mar-ha { margin-left: auto; margin-right: auto } - -@mixin pad($val) { padding: #{$val}rem } -@mixin pad-v($val) { @include pad-t($val); @include pad-b($val) } -@mixin pad-h($val) { @include pad-r($val); @include pad-l($val) } -@mixin pad-t($val) { padding-top: #{$val}rem } -@mixin pad-r($val) { padding-right: #{$val}rem } -@mixin pad-b($val) { padding-bottom: #{$val}rem } -@mixin pad-l($val) { padding-left: #{$val}rem } - -@mixin gap-v($val) { - > :not([hidden]):not(.hidden-input) + :not([hidden]):not(.hidden-input) { @include mar-t($val) } -} - -@mixin gap-h($val) { - > :not(:last-child):not(:only-child) { @include mar-r($val) } -} - -@mixin gap-h-l($val) { - > :not([hidden]):not(.hidden-input) + :not([hidden]):not(.hidden-input) { @include mar-l($val) } -} diff --git a/old/styles/uikit/dropdown.scss b/old/styles/uikit/dropdown.scss deleted file mode 100644 index 4ce34b3..0000000 --- a/old/styles/uikit/dropdown.scss +++ /dev/null @@ -1,83 +0,0 @@ - -/* dropdown - * Source: https://codepen.io/markcaron/pen/wdVmpB - * - * TODO: change styles - * */ - -.dropdown { - position: relative; - display: inline-block; - - & > input[type="checkbox"] { - position: absolute; - left: -100vw; - } - - & > label { - display: inline-block; - padding: 6px 15px; - color: #333; - line-height: 1.5em; - text-decoration: none; - border: 1px solid #8c8c8c; - cursor: pointer; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - - &:hover { - border-color: #333; - } - - &:after { - content: "▲"; - font-size: 10px; - display: inline-block; - margin-left: 6px; - vertical-align: top; - } - } - - & > ul { - position: absolute; - z-index: 999; - display: block; - left: -100vw; - bottom: calc(1.5em + 14px); - border: 1px solid #8c8c8c; - background: #fff; - padding: 6px 0; - margin: 0; - list-style: none; - width: 100%; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - -webkit-box-shadow: 0 3px 8px rgba(0,0,0,.15); - -moz-box-shadow: 0 3px 8px rgba(0,0,0,.15); - box-shadow: 0 3px 8px rgba(0,0,0,.15); - - a { - display: block; - padding: 6px 15px; - text-decoration: none; - color: #333; - - &:hover, &:focus { - background: #ececec; - } - } - } - - & > input[type="checkbox"]:checked { - & ~ ul { - left: 0; - } - - & + label:after { - content: "▼"; - } - } -} - diff --git a/old/styles/uikit/main-menu.scss b/old/styles/uikit/main-menu.scss deleted file mode 100644 index d26d52b..0000000 --- a/old/styles/uikit/main-menu.scss +++ /dev/null @@ -1,21 +0,0 @@ - -.main-menu { - @extend .row-sta-sta, .gap-h-1; - - > a { - @extend .pad-0x5, .anim; - - // TODO: move to atoms - color: var(--color-brand-blue); - border-radius: 6px; - border: 1px solid var(--color-brand-blue); - text-decoration: none; - - &:hover, - &[aria-current]:not([aria-current=""]) { - color: var(--default-color-white); - background-color: var(--color-brand-blue); - } - } -} - diff --git a/old/styles/uikit/mod.scss b/old/styles/uikit/mod.scss deleted file mode 100644 index 4de409d..0000000 --- a/old/styles/uikit/mod.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'main-menu'; -@import 'dropdown'; diff --git a/old/styles/variables.scss b/old/styles/variables.scss deleted file mode 100644 index cc38d60..0000000 --- a/old/styles/variables.scss +++ /dev/null @@ -1,9 +0,0 @@ -@use "sass:math"; - -$radius: 0.25rem; -$col: 12; -$col-gutter: 24; -$page-max-width: 1440; -$page-min-width: 320; -$content-width: $page-max-width - ($col-gutter * 2); -$col-width: math.div($content-width - $col-gutter * $col - 1, $col); diff --git a/old/translates/eng.ts b/old/translates/eng.ts deleted file mode 100644 index 384d1bc..0000000 --- a/old/translates/eng.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Translations } from "./rus.ts"; - -export default { - About: "About", - Works: "Works", - Chronological: "Chronological", - Source_code: "Source code", - Page_not_found: "Page not found", - Internal_server_error: "Internal server error", - Name: "Name", - Description: "Description", - Role: "Role", - Technologies: "Technologies", - Start: "Start", - Status_or_End: "Status/End", -} as Translations; diff --git a/old/translates/rus.ts b/old/translates/rus.ts deleted file mode 100644 index fdbd1b3..0000000 --- a/old/translates/rus.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const rus = { - About: "Обо мне", - Works: "Работы", - Chronological: "Хронология", - Source_code: "Исходный код", - Page_not_found: "Страница не найдена", - Internal_server_error: "Внутренняя ошибка сервера", - Name: "Название", - Description: "Описание", - Role: "Роль", - Technologies: "Технологии", - Start: "Начало", - Status_or_End: "Статус/Окончание", -}; - -export default rus; - -export type Translations = typeof rus; diff --git a/old/uikit/link.ts b/old/uikit/link.ts deleted file mode 100644 index d51894b..0000000 --- a/old/uikit/link.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { AnyNode, Attrs, E } from "ren/node.ts"; - -export function Link( - text: string, - sourceAttrs: Attrs | Attrs[], -): AnyNode { - const attrs = Array.isArray(sourceAttrs) ? sourceAttrs : [sourceAttrs]; - const isExternal = attrs.some((attr) => - typeof attr.href === "string" && attr.href?.startsWith("http") - ); - - if (isExternal) { - attrs.push({ - target: "_blank", - rel: "external nofollow noopener noreferrer", - }); - } - - return E("a", attrs, text); -} diff --git a/old/uikit/typo.ts b/old/uikit/typo.ts deleted file mode 100644 index 5f95691..0000000 --- a/old/uikit/typo.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { classNames } from "ren/attrs.ts"; -import { E, Elem } from "ren/node.ts"; - -export function H3(text: string): Elem { - return E("h3", classNames("font-h3"), text); -} diff --git a/old/views/comp/layout.ts b/old/views/comp/layout.ts deleted file mode 100644 index c7ab48a..0000000 --- a/old/views/comp/layout.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { AnyNode, E } from "ren/node.ts"; -import { Context } from "../../context.ts"; - -export function Layout(ctx: Context, page: AnyNode): AnyNode { - return E("html", { lang: ctx.lang }, [ - E("head", [], [ - E("meta", { charset: "utf-8" }), - E("meta", { - name: "viewport", - content: "width=device-width, initial-scale=1", - }), - E("link", { rel: "stylesheet", href: "/styles/main.css" }), - E("title", [], ctx.title ?? "Pleshevski"), - ]), - E("body", [], [ - E("div", { id: "root" }, [page]), - ]), - ]); -} diff --git a/old/views/comp/page_layout.ts b/old/views/comp/page_layout.ts deleted file mode 100644 index e9088f4..0000000 --- a/old/views/comp/page_layout.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { AnyNode, Attrs, E, Elem } from "ren/node.ts"; -import { classNames } from "ren/attrs.ts"; -import { Context, getLangHref, iterLangs, Lang } from "../../context.ts"; -import { Link } from "../../uikit/link.ts"; -import { renderDate } from "../../render.ts"; - -const SITE_UPDATED_AT = new Date(); - -export function PageLayout(ctx: Context, children: AnyNode[]): Elem { - return E("div", { id: "main" }, [ - Header(ctx), - E("div", classNames("content"), children), - Footer(ctx), - ]); -} - -export function Header(ctx: Context): AnyNode { - return E("header", classNames("header gap-v-1x5"), [ - E("div", classNames("content-width"), [HeaderNav(ctx)]), - ]); -} - -export function HeaderNav(ctx: Context): AnyNode { - return E("nav", classNames("main-menu"), [ - Link(ctx.tr.About, navLink("/", ctx)), - Link(ctx.tr.Works, navLink("/works", ctx)), - ]); -} - -function navLink(lhref: string, ctx?: Context): Attrs { - const attrs: Attrs = { lhref }; - if (ctx?.locPath === lhref) attrs["aria-current"] = "true"; - return attrs; -} - -export function Footer(ctx: Context): AnyNode { - return E("footer", classNames("footer"), [ - E("div", classNames("content-width row-sta-bet"), [ - E("div", classNames("gap-v-1x5"), [ - E("div", [], [ - E("b", [], "Updated At:"), - renderDate(SITE_UPDATED_AT), - ]), - E("div", [], [ - Link(ctx.tr.Source_code, { - href: "https://git.pleshevski.ru/pleshevskiy/pleshevski.ru", - }), - ]), - ]), - ChangeLang(ctx), - ]), - ]); -} - -export function ChangeLang(ctx: Context): AnyNode { - const dropdownId = "change_langs"; - return E("div", classNames("dropdown"), [ - E("input", { id: dropdownId, type: "checkbox" }), - E("label", { for: dropdownId }, ctx.lang), - E( - "ul", - [], - iterLangs().filter((l) => l !== ctx.lang).map((l) => - ChangeLangBtn(ctx, l) - ), - ), - ]); -} - -export function ChangeLangBtn(ctx: Context, lang: Lang): AnyNode { - return Link(lang, { "href": getLangHref(lang, ctx.locPath) }); -} diff --git a/old/views/pages/content.ts b/old/views/pages/content.ts deleted file mode 100644 index de41e61..0000000 --- a/old/views/pages/content.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PageLayout } from "../comp/page_layout.ts"; -import { AnyNode, E } from "ren/node.ts"; -import { classNames } from "ren/attrs.ts"; -import { Context } from "../../context.ts"; - -export function ContentPage(ctx: Context, content: AnyNode): AnyNode { - ctx.title = "About | Pleshevski"; - - return PageLayout(ctx, [ - E("div", classNames("content-width responsive-typography"), [content]), - ]); -} diff --git a/old/views/pages/e404.ts b/old/views/pages/e404.ts deleted file mode 100644 index ee98334..0000000 --- a/old/views/pages/e404.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PageLayout } from "../comp/page_layout.ts"; -import { AnyNode, E } from "ren/node.ts"; -import { classNames } from "ren/attrs.ts"; -import { Context } from "../../context.ts"; -import { H3 } from "../../uikit/typo.ts"; - -export function E404Page(ctx: Context): AnyNode { - ctx.title = "Not Found - 404 | Pleshevski"; - - return PageLayout(ctx, [E404(ctx)]); -} - -export function E404(ctx: Context): AnyNode { - return E("div", classNames("content-width gap-v-1x5"), [ - H3(ctx.tr.Page_not_found), - ]); -} diff --git a/old/views/pages/e500.ts b/old/views/pages/e500.ts deleted file mode 100644 index b0c58e6..0000000 --- a/old/views/pages/e500.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PageLayout } from "../comp/page_layout.ts"; -import { AnyNode, E } from "ren/node.ts"; -import { classNames } from "ren/attrs.ts"; -import { Context } from "../../context.ts"; -import { H3 } from "../../uikit/typo.ts"; - -export function E500Page(ctx: Context): AnyNode { - ctx.title = "Internal Server Error - 500 | Pleshevski"; - - return PageLayout(ctx, [E500(ctx)]); -} - -export function E500(ctx: Context): AnyNode { - return E("div", classNames("content-width gap-v-1x5"), [ - H3(ctx.tr.Internal_server_error), - ]); -} diff --git a/old/views/pages/works.ts b/old/views/pages/works.ts deleted file mode 100644 index 3ceb0b9..0000000 --- a/old/views/pages/works.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { PageLayout } from "../comp/page_layout.ts"; -import { AnyNode, E } from "ren/node.ts"; -import { classNames } from "ren/attrs.ts"; -import { Context } from "../../context.ts"; -import { ChronologicalWorksTable } from "../../modules/work/ChronologicalWorksTable/mod.ts"; -import { H3 } from "../../uikit/typo.ts"; - -export function WorksPage(ctx: Context, content: AnyNode): AnyNode { - ctx.title = "Works | Pleshevski"; - - return PageLayout(ctx, [ - E("div", classNames("content-width gap-v-1x5 responsive-typography"), [ - content, - H3(ctx.tr.Chronological), - ChronologicalWorksTable(ctx.tr), - ]), - ]); -}