feat: added mobile header
22
.eslintrc.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:solid/typescript"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "latest",
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"@typescript-eslint",
|
||||||
|
"solid"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
}
|
||||||
|
}
|
||||||
8
.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 150,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"useTabs": true
|
||||||
|
}
|
||||||
2059
package-lock.json
generated
@ -17,8 +17,12 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/solid-js": "^0.2.1",
|
"@astrojs/solid-js": "^0.2.1",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.30.6",
|
||||||
|
"@typescript-eslint/parser": "^5.30.6",
|
||||||
"astro": "^1.0.0-beta.63",
|
"astro": "^1.0.0-beta.63",
|
||||||
"astro-icon": "^0.7.1",
|
"astro-icon": "^0.7.1",
|
||||||
|
"eslint": "^8.19.0",
|
||||||
|
"eslint-plugin-solid": "^0.7.1",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"prettier-plugin-astro": "^0.1.1",
|
"prettier-plugin-astro": "^0.1.1",
|
||||||
"sass": "^1.53.0",
|
"sass": "^1.53.0",
|
||||||
|
|||||||
@ -1,31 +1,42 @@
|
|||||||
.article-item {
|
.article-item {
|
||||||
border-radius: var(--border-radius-md);
|
border-radius: var(--border-radius-md);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
& a {
|
& a {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
column-gap: 10px;
|
column-gap: 10px;
|
||||||
color: var(--font-color);
|
row-gap: 5px;
|
||||||
padding: 8px 15px;
|
color: var(--font-color);
|
||||||
& h3 {
|
padding: 8px 15px;
|
||||||
font-size: var(--font-size-md);
|
& h3 {
|
||||||
font-weight: normal;
|
font-size: var(--font-size-md);
|
||||||
margin: 0;
|
font-weight: normal;
|
||||||
}
|
margin: 0;
|
||||||
& p {
|
}
|
||||||
font-size: var(--font-size-xs);
|
& p {
|
||||||
font-family: monospace;
|
font-size: var(--font-size-xs);
|
||||||
color: var(--font-color-gray);
|
font-family: monospace;
|
||||||
text-transform: uppercase;
|
color: var(--font-color-gray);
|
||||||
margin: 0;
|
text-transform: uppercase;
|
||||||
text-align: right;
|
margin: 0;
|
||||||
}
|
text-align: right;
|
||||||
&:hover {
|
white-space: nowrap;
|
||||||
text-decoration: none;
|
}
|
||||||
}
|
&:hover {
|
||||||
}
|
text-decoration: none;
|
||||||
&:hover {
|
}
|
||||||
background-color: var(--background-color-hover);
|
}
|
||||||
}
|
&:hover {
|
||||||
|
background-color: var(--background-color-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 560px) {
|
||||||
|
.article-item {
|
||||||
|
& a {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,22 @@
|
|||||||
|
import type { IArticle } from '@root/interfaces';
|
||||||
|
|
||||||
import './ArticleItem.scss';
|
import './ArticleItem.scss';
|
||||||
import { Component } from 'solid-js';
|
import { Component } from 'solid-js';
|
||||||
import type { IArticle } from '@root/interfaces';
|
|
||||||
import { DateFormatter } from '@utils/date';
|
import { DateFormatter } from '@utils/date';
|
||||||
|
|
||||||
export type ArticleItemProps = {
|
export type ArticleItemProps = {
|
||||||
data: IArticle;
|
data: IArticle;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ArticleItem: Component<ArticleItemProps> = ({ data }) => (
|
export const ArticleItem: Component<ArticleItemProps> = (props) => {
|
||||||
<article class='article-item'>
|
return (
|
||||||
<a href='#'>
|
<article class="article-item">
|
||||||
<h3>{data.title}</h3>
|
<a href="#">
|
||||||
<p>
|
<h3>{props.data.title}</h3>
|
||||||
<time datetime={data.published_at.toString()}>
|
<p>
|
||||||
{DateFormatter.format(new Date(data.published_at))}
|
<time datetime={props.data.published_at.toString()}>{DateFormatter.format(new Date(props.data.published_at))}</time>
|
||||||
</time>
|
</p>
|
||||||
</p>
|
</a>
|
||||||
</a>
|
</article>
|
||||||
</article>
|
);
|
||||||
);
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import "./ArticlesList.scss";
|
import "./ArticlesList.scss";
|
||||||
import { Component, createSignal, Show } from "solid-js";
|
import { Component, createSignal, Show, For } from "solid-js";
|
||||||
import { PageHeading } from "@components/PageHeading";
|
import { PageHeading } from "@components/PageHeading";
|
||||||
import type { IArticle } from "@root/interfaces";
|
import type { IArticle } from "@root/interfaces";
|
||||||
import * as utils from "@root/utils/articles";
|
import * as utils from "@root/utils/articles";
|
||||||
@ -10,8 +10,8 @@ export type ArticlesListProps = {
|
|||||||
tags: string[];
|
tags: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ArticlesList: Component<ArticlesListProps> = ({ data, tags }) => {
|
export const ArticlesList: Component<ArticlesListProps> = (props) => {
|
||||||
const [articles, setArticles] = createSignal(utils.filterArticlesByYear(data));
|
const [articles, setArticles] = createSignal(utils.filterArticlesByYear(props.data));
|
||||||
const [selectedTags, setSelectedTags] = createSignal<string[]>([]);
|
const [selectedTags, setSelectedTags] = createSignal<string[]>([]);
|
||||||
const [filteredArticles, setFilteredArticles] = createSignal<IArticle[]>([]);
|
const [filteredArticles, setFilteredArticles] = createSignal<IArticle[]>([]);
|
||||||
|
|
||||||
@ -32,41 +32,43 @@ export const ArticlesList: Component<ArticlesListProps> = ({ data, tags }) => {
|
|||||||
d="M10.6026 3.60001C11.8798 3.59993 13.1316 3.94283 14.2172 4.5901C15.3028 5.23736 16.179 6.16331 16.7472 7.26368C17.3154 8.36405 17.5531 9.59517 17.4334 10.8184C17.3137 12.0417 16.8415 13.2085 16.0699 14.1876L21.2427 19.164C21.4085 19.3248 21.5053 19.5399 21.5135 19.7662C21.5218 19.9926 21.4411 20.2137 21.2874 20.3853C21.1337 20.5569 20.9184 20.6665 20.6845 20.6921C20.4505 20.7178 20.2151 20.6576 20.0253 20.5236L19.9205 20.436L14.7476 15.4596C13.8802 16.0922 12.8687 16.5172 11.7968 16.6994C10.7248 16.8815 9.62324 16.8157 8.58298 16.5074C7.54272 16.199 6.59366 15.6569 5.81422 14.9259C5.03478 14.1949 4.44733 13.296 4.10042 12.3034C3.7535 11.3108 3.65708 10.2531 3.81911 9.21757C3.98114 8.18204 4.39698 7.19847 5.03226 6.34812C5.66755 5.49778 6.50404 4.80506 7.47263 4.32721C8.44122 3.84936 9.51411 3.60009 10.6026 3.60001V3.60001ZM10.6026 5.40001C9.27934 5.40001 8.01025 5.90572 7.07454 6.80589C6.13884 7.70607 5.61316 8.92697 5.61316 10.2C5.61316 11.473 6.13884 12.6939 7.07454 13.5941C8.01025 14.4943 9.27934 15 10.6026 15C11.9259 15 13.195 14.4943 14.1307 13.5941C15.0664 12.6939 15.5921 11.473 15.5921 10.2C15.5921 8.92697 15.0664 7.70607 14.1307 6.80589C13.195 5.90572 11.9259 5.40001 10.6026 5.40001Z"></path>
|
d="M10.6026 3.60001C11.8798 3.59993 13.1316 3.94283 14.2172 4.5901C15.3028 5.23736 16.179 6.16331 16.7472 7.26368C17.3154 8.36405 17.5531 9.59517 17.4334 10.8184C17.3137 12.0417 16.8415 13.2085 16.0699 14.1876L21.2427 19.164C21.4085 19.3248 21.5053 19.5399 21.5135 19.7662C21.5218 19.9926 21.4411 20.2137 21.2874 20.3853C21.1337 20.5569 20.9184 20.6665 20.6845 20.6921C20.4505 20.7178 20.2151 20.6576 20.0253 20.5236L19.9205 20.436L14.7476 15.4596C13.8802 16.0922 12.8687 16.5172 11.7968 16.6994C10.7248 16.8815 9.62324 16.8157 8.58298 16.5074C7.54272 16.199 6.59366 15.6569 5.81422 14.9259C5.03478 14.1949 4.44733 13.296 4.10042 12.3034C3.7535 11.3108 3.65708 10.2531 3.81911 9.21757C3.98114 8.18204 4.39698 7.19847 5.03226 6.34812C5.66755 5.49778 6.50404 4.80506 7.47263 4.32721C8.44122 3.84936 9.51411 3.60009 10.6026 3.60001V3.60001ZM10.6026 5.40001C9.27934 5.40001 8.01025 5.90572 7.07454 6.80589C6.13884 7.70607 5.61316 8.92697 5.61316 10.2C5.61316 11.473 6.13884 12.6939 7.07454 13.5941C8.01025 14.4943 9.27934 15 10.6026 15C11.9259 15 13.195 14.4943 14.1307 13.5941C15.0664 12.6939 15.5921 11.473 15.5921 10.2C15.5921 8.92697 15.0664 7.70607 14.1307 6.80589C13.195 5.90572 11.9259 5.40001 10.6026 5.40001Z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
<input type="text" placeholder="поиск по названию или описанию..." />
|
<input type="text" placeholder="поиск по названию или описанию..." />
|
||||||
<span>{data.length}</span>
|
<span>{props.data.length}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="articles-tags">
|
<div class="articles-tags">
|
||||||
<nav>
|
<nav>
|
||||||
<ul class='list-links'>
|
<ul class='list-links'>
|
||||||
{tags.map((tag) => (
|
<For each={props.tags}>
|
||||||
<li
|
{(tag) => (
|
||||||
style={
|
<li
|
||||||
selectedTags().includes(tag) &&
|
style={
|
||||||
"border-color: var(--border-color-hover);"
|
selectedTags().includes(tag) &&
|
||||||
}
|
"border-color: var(--border-color-hover);"
|
||||||
class="btn-link"
|
|
||||||
onClick={() => {
|
|
||||||
if (selectedTags().includes(tag)) {
|
|
||||||
setSelectedTags(
|
|
||||||
selectedTags().filter(
|
|
||||||
(selectedTag) => selectedTag !== tag
|
|
||||||
)
|
|
||||||
);
|
|
||||||
setFilteredArticles(
|
|
||||||
filteredArticles().filter((a) => !a.tags.includes(tag))
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
setSelectedTags([...selectedTags(), tag]);
|
class="btn-link"
|
||||||
data.forEach((article) => {
|
onClick={() => {
|
||||||
if (article.tags.includes(tag)) {
|
if (selectedTags().includes(tag)) {
|
||||||
setFilteredArticles([...filteredArticles(), article]);
|
setSelectedTags(
|
||||||
|
selectedTags().filter(
|
||||||
|
(selectedTag) => selectedTag !== tag
|
||||||
|
)
|
||||||
|
);
|
||||||
|
setFilteredArticles(
|
||||||
|
filteredArticles().filter((a) => !a.tags.includes(tag))
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
setSelectedTags([...selectedTags(), tag]);
|
||||||
}}
|
props.data.forEach((article) => {
|
||||||
data-tag={tag.toLocaleLowerCase()}>
|
if (article.tags.includes(tag)) {
|
||||||
{tag}
|
setFilteredArticles([...filteredArticles(), article]);
|
||||||
</li>
|
}
|
||||||
))}
|
});
|
||||||
|
}}
|
||||||
|
data-tag={tag.toLocaleLowerCase()}>
|
||||||
|
{tag}
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
22
src/components/BaseHead.astro
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
import { SITE_METADATA } from '@root/config';
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
title?: string | undefined;
|
||||||
|
description?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title = SITE_METADATA.title, description } = Astro.props as Props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<link rel='preconnect' href='https://fonts.googleapis.com' />
|
||||||
|
<link rel='preconnect' href='https://fonts.gstatic.com' crossorigin />
|
||||||
|
<link href='https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap' rel='stylesheet' />
|
||||||
|
|
||||||
|
<meta charset='utf-8' />
|
||||||
|
<meta name='viewport' content='width=device-width, initial-scale=1' />
|
||||||
|
<title>
|
||||||
|
{title}
|
||||||
|
</title>
|
||||||
|
<meta name='title' content={title} />
|
||||||
|
{description && <meta name="description" content={description} />}
|
||||||
13
src/components/BaseLayout/BaseLayout.astro
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
import './BaseLayout.scss'
|
||||||
|
import Header from '@components/Header'
|
||||||
|
import Footer from '@components/Footer'
|
||||||
|
---
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<Header />
|
||||||
|
<main class='site-content'>
|
||||||
|
<slot></slot>
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
5
src/components/BaseLayout/BaseLayout.scss
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.site-content {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 5rem;
|
||||||
|
}
|
||||||
1
src/components/BaseLayout/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './BaseLayout.astro';
|
||||||
@ -2,36 +2,44 @@
|
|||||||
import './Header.scss';
|
import './Header.scss';
|
||||||
import { SITE_METADATA } from '@root/config';
|
import { SITE_METADATA } from '@root/config';
|
||||||
import ThemeSwitcher from '@components/ThemeSwticher';
|
import ThemeSwitcher from '@components/ThemeSwticher';
|
||||||
import {Icon} from 'astro-icon'
|
import { Icon } from 'astro-icon';
|
||||||
|
import { NavToggle } from './NavToggle/NavToggle.tsx';
|
||||||
|
|
||||||
|
const { name, nav, contacts } = SITE_METADATA;
|
||||||
|
const { pathname } = Astro.canonicalURL;
|
||||||
---
|
---
|
||||||
|
|
||||||
<header class='header'>
|
<header class='header'>
|
||||||
<div class='container'>
|
<div class='container'>
|
||||||
<div class='header__logo'>
|
<div class='header__logo'>
|
||||||
<a href='/'>{SITE_METADATA.name}</a>
|
<a href='/'>{name}</a>
|
||||||
</div>
|
</div>
|
||||||
<nav class='header__nav'>
|
<nav class='header__nav'>
|
||||||
<ul class='header__nav-links'>
|
<ul class='header__nav-links'>
|
||||||
<li><a href='/articles'>статьи</a></li>
|
{nav.map((link) => (
|
||||||
<li><a href='/projects'>проекты</a></li>
|
<li>
|
||||||
<li><a href='/about'>обо мне</a></li>
|
<a class={pathname.includes(link.url) && 'active'} href={link.url}>
|
||||||
<li><a href='/contacts'>контакты</a></li>
|
{link.name}
|
||||||
</ul>
|
</a>
|
||||||
<div class='header__nav-contacts'>
|
</li>
|
||||||
<a href={'mailto:' + SITE_METADATA.contacts.email}>
|
))}
|
||||||
Почта
|
</ul>
|
||||||
<Icon name='email' width='18' height='18' />
|
<div class='header__nav-contacts'>
|
||||||
</a>
|
<a href={'mailto:' + contacts.email}>
|
||||||
<a href={SITE_METADATA.contacts.githubUrl}>
|
Почта
|
||||||
Github
|
<Icon name='email' width='18' height='18' />
|
||||||
<Icon name='github_filled' width='18' height='18' />
|
</a>
|
||||||
</a>
|
<a href={contacts.githubUrl}>
|
||||||
<a href={SITE_METADATA.contacts.telegramUrl}>
|
Github
|
||||||
Телеграм
|
<Icon name='github_filled' width='18' height='18' />
|
||||||
<Icon name='telegram' width='18' height='18' />
|
</a>
|
||||||
</a>
|
<a href={contacts.telegramUrl}>
|
||||||
</div>
|
Телеграм
|
||||||
<ThemeSwitcher />
|
<Icon name='telegram' width='18' height='18' />
|
||||||
</nav>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<ThemeSwitcher />
|
||||||
|
</nav>
|
||||||
|
<NavToggle client:idle />
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@ -1,59 +1,175 @@
|
|||||||
.header {
|
.header {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
background-color: var(--background-header-color);
|
background-color: var(--background-header-color);
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
padding-bottom: 15px;
|
padding-bottom: 15px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
& .container {
|
& .container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__logo a {
|
&__logo a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: var(--font-size-lg);
|
font-size: var(--font-size-lg);
|
||||||
color: var(--font-color);
|
color: var(--font-color);
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
text-decoration-thickness: 2px;
|
text-decoration-thickness: 2px;
|
||||||
text-underline-offset: 5px;
|
text-underline-offset: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__nav {
|
&__nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
& ul {
|
& ul {
|
||||||
display: flex;
|
display: flex;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
column-gap: 20px;
|
column-gap: 20px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-right: 35px;
|
margin-right: 35px;
|
||||||
& li a {
|
& li a {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--font-color);
|
color: var(--font-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
&:hover {
|
text-transform: lowercase;
|
||||||
color: var(--color-blue-500);
|
&:hover,
|
||||||
text-decoration: underline;
|
&.active {
|
||||||
}
|
color: var(--color-blue-500);
|
||||||
}
|
text-decoration: underline;
|
||||||
}
|
text-decoration-thickness: 2px;
|
||||||
&-contacts {
|
text-underline-offset: 4px;
|
||||||
display: flex;
|
}
|
||||||
align-items: center;
|
}
|
||||||
column-gap: 10px;
|
}
|
||||||
margin-right: 40px;
|
&-contacts {
|
||||||
& a {
|
display: flex;
|
||||||
text-decoration: none;
|
align-items: center;
|
||||||
font-size: 0;
|
column-gap: 10px;
|
||||||
}
|
margin-right: 40px;
|
||||||
}
|
& a {
|
||||||
}
|
text-decoration: none;
|
||||||
|
font-size: 0;
|
||||||
|
&:hover {
|
||||||
|
opacity: var(--opacity-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__button {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 30px;
|
||||||
|
height: 21px;
|
||||||
|
position: relative;
|
||||||
|
transform: rotate(0deg);
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
&:hover {
|
||||||
|
border: none;
|
||||||
|
opacity: var(--opacity-hover);
|
||||||
|
}
|
||||||
|
& span {
|
||||||
|
pointer-events: none;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
height: 3px;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--color-black);
|
||||||
|
border-radius: 7px;
|
||||||
|
opacity: 1;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
& span:nth-child(1) {
|
||||||
|
top: 2px;
|
||||||
|
transform-origin: left center;
|
||||||
|
}
|
||||||
|
& span:nth-child(2) {
|
||||||
|
top: 9px;
|
||||||
|
transform-origin: left center;
|
||||||
|
}
|
||||||
|
& span:nth-child(3) {
|
||||||
|
top: 16px;
|
||||||
|
transform-origin: left center;
|
||||||
|
}
|
||||||
|
&[aria-pressed='true'] {
|
||||||
|
& span:nth-child(1) {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
top: -1px;
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
& span:nth-child(2) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
& span:nth-child(3) {
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
top: 20px;
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.header {
|
||||||
|
&__nav {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-is-mobile-open='true'] {
|
||||||
|
& .header {
|
||||||
|
background-color: var(--color-white);
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 9999;
|
||||||
|
& .container {
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: 2.5rem;
|
||||||
|
}
|
||||||
|
&__nav {
|
||||||
|
display: block;
|
||||||
|
&-links {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
& li {
|
||||||
|
margin-bottom: 1.2rem;
|
||||||
|
& a {
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-contacts {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-top: 2rem;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__button {
|
||||||
|
position: absolute;
|
||||||
|
right: var(--content-padding);
|
||||||
|
}
|
||||||
|
& .theme-switcher {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 45px;
|
||||||
|
right: var(--content-padding);
|
||||||
|
& svg {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
src/components/Header/NavToggle/NavToggle.scss
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@media screen and (min-width: 769px) {
|
||||||
|
#nav-toggle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/components/Header/NavToggle/NavToggle.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import './NavToggle.scss';
|
||||||
|
import { Component, createSignal, createEffect } from 'solid-js';
|
||||||
|
|
||||||
|
export const NavToggle: Component = () => {
|
||||||
|
const [isNavShown, setIsNavShown] = createSignal<boolean>(false);
|
||||||
|
|
||||||
|
const toggleNav = () => setIsNavShown(!isNavShown());
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
const body = document.body;
|
||||||
|
|
||||||
|
if (isNavShown()) {
|
||||||
|
body.setAttribute('data-is-mobile-open', 'true');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.removeAttribute('data-is-mobile-open');
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button id="nav-toggle" class="header__button" onClick={toggleNav} type="button" aria-pressed={isNavShown() ? 'true' : 'false'}>
|
||||||
|
<span />
|
||||||
|
<span />
|
||||||
|
<span />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,10 +0,0 @@
|
|||||||
import { Component, JSX } from 'solid-js';
|
|
||||||
|
|
||||||
export type PageContentComposition = {
|
|
||||||
Heading?: Component;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PageContent: Component<{ children: JSX.Element }> &
|
|
||||||
PageContentComposition = (props) => {
|
|
||||||
return <section>{props.children}</section>;
|
|
||||||
};
|
|
||||||
@ -6,18 +6,15 @@ export type PageHeadingProps = {
|
|||||||
description?: string | undefined;
|
description?: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PageHeading: Component<PageHeadingProps> = ({
|
export const PageHeading: Component<PageHeadingProps> = (props) => {
|
||||||
heading,
|
|
||||||
description,
|
|
||||||
}) => {
|
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
<h1
|
<h1
|
||||||
class={styles.PageHeading}
|
class={styles.PageHeading}
|
||||||
style={!description && 'margin-bottom: 2.5rem;'}>
|
style={!props.description && 'margin-bottom: 2.5rem;'}>
|
||||||
{heading}
|
{props.heading}
|
||||||
</h1>
|
</h1>
|
||||||
{description && <p class={styles.PageDescription}>{description}</p>}
|
{props.description && <p class={styles.PageDescription}>{props.description}</p>}
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
35
src/components/RecentArticles/RecentArticles.astro
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
import type { IArticle } from '@root/interfaces';
|
||||||
|
|
||||||
|
import './RecentArticles.scss';
|
||||||
|
import { ArticleItem } from '@components/ArticleItem';
|
||||||
|
import { sortArtcilesByDate } from '@utils/articles';
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
articles: IArticle[];
|
||||||
|
length?: number | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { articles, length = 5 } = Astro.props as Props;
|
||||||
|
|
||||||
|
const recent = sortArtcilesByDate(articles);
|
||||||
|
---
|
||||||
|
|
||||||
|
<section class='recent'>
|
||||||
|
<div class='container'>
|
||||||
|
<div class='recent-heading'>
|
||||||
|
<h2>недавние публикации</h2>
|
||||||
|
<a href='/articles'>смотреть все</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='recent-list container'>
|
||||||
|
{recent.length !== 0 ? (
|
||||||
|
recent.slice(0, length).map((article) => <ArticleItem data={article} />)
|
||||||
|
) : (
|
||||||
|
<div style="text-align: center;margin:2.5rem 0;">
|
||||||
|
<p style="color:var(--font-color-gray);user-select: none;">Пока что здесь ничего нет...</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
21
src/components/RecentArticles/RecentArticles.scss
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.recent {
|
||||||
|
&-heading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 15px;
|
||||||
|
row-gap: 5px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
padding-bottom: 10px;
|
||||||
|
|
||||||
|
& h2 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-list {
|
||||||
|
margin-top: 10px;
|
||||||
|
max-width: calc(var(--content-width) + (var(--content-padding) * 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/components/RecentArticles/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './RecentArticles.astro';
|
||||||
@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
import './ThemeSwitcher.scss';
|
import './ThemeSwitcher.scss';
|
||||||
// import { MoonIcon } from '@components/icons';
|
import { Icon } from 'astro-icon'
|
||||||
---
|
---
|
||||||
|
|
||||||
<button class='theme-switcher'>
|
<button class='theme-switcher'>
|
||||||
<!-- <MoonIcon /> -->
|
<Icon name='moon' width='21' height='21' />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
.theme-switcher {
|
.theme-switcher {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
&:hover {
|
||||||
|
opacity: var(--opacity-hover);
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,18 @@
|
|||||||
export const SITE_METADATA = {
|
export const SITE_METADATA = {
|
||||||
name: 'yarkov.tech',
|
title: 'Sergey Yarkov',
|
||||||
author: 'Sergey Yarkov',
|
name: 'yarkov.tech',
|
||||||
contacts: {
|
author: 'Sergey Yarkov',
|
||||||
email: 'serzh.yarkov@gmail.com',
|
contacts: {
|
||||||
githubUrl: 'https://github.com/sergeyyarkov',
|
email: 'serzh.yarkov@gmail.com',
|
||||||
telegramUrl: 'https://t.me/sergeyyarkov',
|
githubUrl: 'https://github.com/sergeyyarkov',
|
||||||
},
|
telegramUrl: 'https://t.me/sergeyyarkov',
|
||||||
projects: [],
|
},
|
||||||
skills: []
|
nav: [
|
||||||
|
{ name: 'Статьи', url: '/articles' },
|
||||||
|
{ name: 'Проекты', url: '/projects' },
|
||||||
|
{ name: 'Обо мне', url: '/about' },
|
||||||
|
{ name: 'Контакты', url: '/contacts' },
|
||||||
|
],
|
||||||
|
projects: [],
|
||||||
|
skills: [],
|
||||||
};
|
};
|
||||||
|
|||||||
4
src/icons/chat.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M3.33317 15.5H4.99984V18.9008L9.25067 15.5H13.3332C14.2523 15.5 14.9998 14.7525 14.9998 13.8333V7.16667C14.9998 6.2475 14.2523 5.5 13.3332 5.5H3.33317C2.414 5.5 1.6665 6.2475 1.6665 7.16667V13.8333C1.6665 14.7525 2.414 15.5 3.33317 15.5Z" fill="black"/>
|
||||||
|
<path d="M16.6667 2.16669H6.66667C5.7475 2.16669 5 2.91419 5 3.83335H15C15.9192 3.83335 16.6667 4.58085 16.6667 5.50002V12.1667C17.5858 12.1667 18.3333 11.4192 18.3333 10.5V3.83335C18.3333 2.91419 17.5858 2.16669 16.6667 2.16669Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 612 B |
4
src/icons/chip.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.5 8H12.5V13H7.5V8Z" fill="black"/>
|
||||||
|
<path d="M16.6665 5.50002C16.6665 4.58085 15.919 3.83335 14.9998 3.83335H13.3332V2.16669H11.6665V3.83335H8.33317V2.16669H6.6665V3.83335H4.99984C4.08067 3.83335 3.33317 4.58085 3.33317 5.50002V7.16669H1.6665V8.83335H3.33317V12.1667H1.6665V13.8334H3.33317V15.5C3.33317 16.4192 4.08067 17.1667 4.99984 17.1667H6.6665V18.8334H8.33317V17.1667H11.6665V18.8334H13.3332V17.1667H14.9998C15.919 17.1667 16.6665 16.4192 16.6665 15.5V13.8334H18.3332V12.1667H16.6665V8.83335H18.3332V7.16669H16.6665V5.50002ZM4.99984 15.5V5.50002H14.9998L15.0015 15.5H4.99984Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 712 B |
3
src/icons/link-out.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.4375 6.5625L13.125 1.875M10 1.875H13.125V5M13.125 8.75V11.875C13.125 12.2065 12.9933 12.5245 12.7589 12.7589C12.5245 12.9933 12.2065 13.125 11.875 13.125H3.125C2.79348 13.125 2.47554 12.9933 2.24112 12.7589C2.0067 12.5245 1.875 12.2065 1.875 11.875V3.125C1.875 2.79348 2.0067 2.47554 2.24112 2.24112C2.47554 2.0067 2.79348 1.875 3.125 1.875H6.25" stroke="#21262D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 545 B |
3
src/icons/moon.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.4998 10.3311C9.39883 9.22975 8.64906 7.82674 8.34521 6.29939C8.04136 4.77203 8.19707 3.18889 8.79266 1.75C7.09451 2.08429 5.53468 2.91752 4.31266 4.14313C0.895781 7.56 0.895781 13.1005 4.31266 16.5174C7.73041 19.9351 13.27 19.9342 16.6878 16.5174C17.9131 15.2955 18.7462 13.736 19.0809 12.0382C17.642 12.6337 16.0589 12.7894 14.5316 12.4855C13.0042 12.1817 11.6012 11.432 10.4998 10.3311Z" fill="#010409"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 523 B |
3
src/icons/round-school.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M4.99979 13.18V15.99C4.99979 16.72 5.39979 17.4 6.03979 17.75L11.0398 20.48C11.6398 20.81 12.3598 20.81 12.9598 20.48L17.9598 17.75C18.5998 17.4 18.9998 16.72 18.9998 15.99V13.18L12.9598 16.48C12.3598 16.81 11.6398 16.81 11.0398 16.48L4.99979 13.18ZM11.0398 3.52L2.60979 8.12C1.91979 8.5 1.91979 9.5 2.60979 9.88L11.0398 14.48C11.6398 14.81 12.3598 14.81 12.9598 14.48L20.9998 10.09V16C20.9998 16.55 21.4498 17 21.9998 17C22.5498 17 22.9998 16.55 22.9998 16V9.59C22.9998 9.22 22.7998 8.89 22.4798 8.71L12.9598 3.52C12.6643 3.36242 12.3346 3.28 11.9998 3.28C11.6649 3.28 11.3352 3.36242 11.0398 3.52Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 728 B |
3
src/icons/round-shop-two.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1.66634 7.50001C1.20801 7.50001 0.833008 7.87501 0.833008 8.33334V16.6667C0.833008 17.5833 1.58301 18.3333 2.49967 18.3333H14.1663C15.0913 18.3333 15.833 17.5917 15.833 16.6667H3.33301C2.87467 16.6667 2.49967 16.2917 2.49967 15.8333V8.33334C2.49967 7.87501 2.12467 7.50001 1.66634 7.50001ZM14.9997 4.16668V2.50001C14.9997 1.58334 14.2497 0.833344 13.333 0.833344H9.99967C9.08301 0.833344 8.33301 1.58334 8.33301 2.50001V4.16668H5.83301C4.91634 4.16668 4.16634 4.91668 4.16634 5.83334V13.3333C4.16634 14.25 4.91634 15 5.83301 15H17.4997C18.4163 15 19.1663 14.25 19.1663 13.3333V5.83334C19.1663 4.91668 18.4163 4.16668 17.4997 4.16668H14.9997ZM9.99967 2.50001H13.333V4.16668H9.99967V2.50001ZM9.99967 11.6833V7.36668C9.99967 7.05001 10.3413 6.85001 10.6163 7.00001L14.008 8.85001C14.2747 9.00001 14.2997 9.37501 14.0497 9.55001L10.658 12.0167C10.383 12.2167 9.99967 12.025 9.99967 11.6833Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1016 B |
3
src/icons/search.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.6026 3.60001C11.8798 3.59993 13.1316 3.94283 14.2172 4.5901C15.3028 5.23736 16.179 6.16331 16.7472 7.26368C17.3154 8.36405 17.5531 9.59517 17.4334 10.8184C17.3137 12.0417 16.8415 13.2085 16.0699 14.1876L21.2427 19.164C21.4085 19.3248 21.5053 19.5399 21.5135 19.7662C21.5218 19.9926 21.4411 20.2137 21.2874 20.3853C21.1337 20.5569 20.9184 20.6665 20.6845 20.6921C20.4505 20.7178 20.2151 20.6576 20.0253 20.5236L19.9205 20.436L14.7476 15.4596C13.8802 16.0922 12.8687 16.5172 11.7968 16.6994C10.7248 16.8815 9.62324 16.8157 8.58298 16.5074C7.54272 16.199 6.59366 15.6569 5.81422 14.9259C5.03478 14.1949 4.44733 13.296 4.10042 12.3034C3.7535 11.3108 3.65708 10.2531 3.81911 9.21757C3.98114 8.18204 4.39698 7.19847 5.03226 6.34812C5.66755 5.49778 6.50404 4.80506 7.47263 4.32721C8.44123 3.84936 9.51411 3.60009 10.6026 3.60001ZM10.6026 5.40001C9.27934 5.40001 8.01025 5.90572 7.07454 6.80589C6.13884 7.70607 5.61316 8.92697 5.61316 10.2C5.61316 11.473 6.13884 12.6939 7.07454 13.5941C8.01025 14.4943 9.27934 15 10.6026 15C11.9259 15 13.195 14.4943 14.1307 13.5941C15.0664 12.6939 15.5921 11.473 15.5921 10.2C15.5921 8.92697 15.0664 7.70607 14.1307 6.80589C13.195 5.90572 11.9259 5.40001 10.6026 5.40001Z" fill="#21262D"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
3
src/icons/sun.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.12062 10.5C6.12062 12.9159 8.08587 14.8811 10.5017 14.8811C12.9176 14.8811 14.8829 12.9159 14.8829 10.5C14.8829 8.08413 12.9176 6.11888 10.5017 6.11888C8.08587 6.11888 6.12062 8.08413 6.12062 10.5ZM9.625 16.625H11.375V19.25H9.625V16.625ZM9.625 1.75H11.375V4.375H9.625V1.75ZM1.75 9.625H4.375V11.375H1.75V9.625ZM16.625 9.625H19.25V11.375H16.625V9.625ZM4.93238 17.3057L3.69513 16.0685L5.551 14.2126L6.78825 15.4499L4.93238 17.3057ZM14.2118 5.551L16.0685 3.69425L17.3057 4.9315L15.449 6.78825L14.2118 5.551ZM5.551 6.78912L3.69513 4.93238L4.93325 3.69513L6.78825 5.55187L5.551 6.78912ZM17.3057 16.0685L16.0685 17.3057L14.2118 15.449L15.449 14.2118L17.3057 16.0685Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 791 B |
3
src/icons/triangle_filled.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.2208 14.5116C8.99268 15.7027 11.0064 15.7032 11.7789 14.5122L18.4977 4.15437C19.2439 3.00368 18.2646 1.59375 16.7183 1.59375L3.2858 1.59375C1.74018 1.59375 0.760803 3.00315 1.50705 4.15384L8.2208 14.5116Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 336 B |
@ -1,7 +1,6 @@
|
|||||||
export interface IArticle {
|
export interface IArticle {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
author: string;
|
||||||
author: string;
|
tags: Array<string>;
|
||||||
tags: Array<string>;
|
published_at: number;
|
||||||
published_at: number;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
---
|
|
||||||
import '@styles/global.scss';
|
|
||||||
import Header from '@components/Header';
|
|
||||||
import Footer from '@components/Footer';
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
title?: string | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { title = 'Sergey Yarkov' } = Astro.props as Props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<html lang='en'>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset='utf-8' />
|
|
||||||
<meta name='viewport' content='width=device-width, initial-scale=1' />
|
|
||||||
<title>{title}</title>
|
|
||||||
<link rel="stylesheet" href="/styles/prism/prism-one-light.css">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<Header />
|
|
||||||
<main class='site-content'>
|
|
||||||
<slot></slot>
|
|
||||||
</main>
|
|
||||||
<Footer />
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
24
src/layouts/default.astro
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
import type { Props as BaseHeadProps } from '@root/components/BaseHead.astro';
|
||||||
|
|
||||||
|
import '@styles/global.scss';
|
||||||
|
import BaseHead from '@root/components/BaseHead.astro';
|
||||||
|
import BaseLayout from '@components/BaseLayout';
|
||||||
|
import { SITE_METADATA } from '@root/config';
|
||||||
|
|
||||||
|
export interface Props extends BaseHeadProps {
|
||||||
|
lang?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title = SITE_METADATA.title, description, lang = 'ru' } = Astro.props as Props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<html lang={lang}>
|
||||||
|
<head>
|
||||||
|
<BaseHead title={title} description={description} />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<BaseLayout>
|
||||||
|
<slot></slot>
|
||||||
|
</BaseLayout>
|
||||||
|
</html>
|
||||||
@ -1,173 +1,181 @@
|
|||||||
---
|
---
|
||||||
import Page from "@root/layouts/Page.astro";
|
import '../styles/prism-one-light.css';
|
||||||
import { Markdown } from "astro/components";
|
import PageLayout from '@root/layouts/default.astro';
|
||||||
|
import { Markdown } from 'astro/components';
|
||||||
|
|
||||||
export function getStaticPaths() {
|
export function getStaticPaths() {
|
||||||
return [
|
return [{ params: { article: 'article' } }];
|
||||||
{ params: { article: 'article' } },
|
}
|
||||||
]
|
|
||||||
}
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Page title="Article">
|
<PageLayout title='Article'>
|
||||||
<article class="article container">
|
<article class='article container'>
|
||||||
<header>
|
<header>
|
||||||
<div class="meta">
|
<div class='meta'>
|
||||||
<ul class="list-links">
|
<ul class='list-links'>
|
||||||
<li><a class="btn-link" href="#">JavaScript</a></li>
|
<li><a class='btn-link' href='#'>JavaScript</a></li>
|
||||||
<li><a class="btn-link" href="#">Docker</a></li>
|
<li><a class='btn-link' href='#'>Docker</a></li>
|
||||||
<li><a class="btn-link" href="#">Node.js</a></li>
|
<li><a class='btn-link' href='#'>Node.js</a></li>
|
||||||
<li><a class="btn-link" href="#">AVR</a></li>
|
<li><a class='btn-link' href='#'>AVR</a></li>
|
||||||
<li><a class="btn-link" href="#">GraphQL</a></li>
|
<li><a class='btn-link' href='#'>GraphQL</a></li>
|
||||||
<li><a class="btn-link" href="#">Web-development</a></li>
|
<li><a class='btn-link' href='#'>Web-development</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div>
|
<div>
|
||||||
<time datetime='2022-01-01'>
|
<time datetime='2022-01-01'> 19 ЯНВ, 2022</time>
|
||||||
19 ЯНВ, 2022
|
<span>Опубликовал <b>Sergey Yarkov</b></span>
|
||||||
</time>
|
</div>
|
||||||
<span>Опубликовал <b>Sergey Yarkov</b></span>
|
</div>
|
||||||
</div>
|
<div class='heading'>
|
||||||
</div>
|
<h1>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h1>
|
||||||
<div class="heading">
|
</div>
|
||||||
<h1>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </h1>
|
<div>
|
||||||
</div>
|
<figure>
|
||||||
<div>
|
<img
|
||||||
<figure>
|
src='https://img.freepik.com/premium-photo/beautiful-emerald-lake-yoho-national-park-british-columbia-canada_131985-177.jpg?w=1920'
|
||||||
<img
|
alt='Article Image'
|
||||||
src="https://img.freepik.com/premium-photo/beautiful-emerald-lake-yoho-national-park-british-columbia-canada_131985-177.jpg?w=1920"
|
/>
|
||||||
alt="Article Image">
|
</figure>
|
||||||
</figure>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
</header>
|
<div class='article-content'>
|
||||||
<div class="article-content">
|
<Markdown>
|
||||||
<Markdown>
|
## Introduction
|
||||||
## Introduction
|
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
|
||||||
Sed dignissim, metus nec fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus elit sed risus.
|
Sed dignissim, metus nec fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus elit sed risus.
|
||||||
Maecenas eget condimentum velit, sit amet feugiat lectus. Class aptent taciti sociosqu ad litora torquent per
|
Maecenas eget condimentum velit, sit amet feugiat lectus. Class aptent taciti sociosqu ad litora torquent per
|
||||||
conubia nostra, per inceptos himenaeos. [Praesent auctor](#) purus luctus enim egestas, ac scelerisque ante pulvinar.
|
conubia nostra, per inceptos himenaeos. [Praesent auctor](#) purus luctus enim egestas, ac scelerisque ante
|
||||||
Donec ut rhoncus ex. Suspendisse ac rhoncus nisl, eu tempor urna. Curabitur vel bibendum lorem. Morbi convallis
|
pulvinar.
|
||||||
convallis diam sit amet [lacinia](#). Aliquam in elementum
|
Donec ut rhoncus ex. Suspendisse ac rhoncus nisl, eu tempor urna. Curabitur vel bibendum lorem. Morbi convallis
|
||||||
|
convallis diam sit amet [lacinia](#). Aliquam in elementum
|
||||||
|
|
||||||
Curabitur tempor quis eros tempus lacinia. Nam bibendum pellentesque quam a convallis. Sed ut vulputate nisi.
|
Curabitur tempor quis eros tempus lacinia. Nam bibendum pellentesque quam a convallis. Sed ut vulputate nisi.
|
||||||
Integer in felis sed leo vestibulum venenatis. Suspendisse quis arcu sem. Aenean feugiat ex eu vestibulum
|
Integer in felis sed leo vestibulum venenatis. Suspendisse quis arcu sem. Aenean feugiat ex eu vestibulum
|
||||||
vestibulum. Morbi a eleifend magna. Nam metus lacus, porttitor eu mauris a, blandit ultrices nibh. Mauris sit
|
vestibulum. Morbi a eleifend magna. Nam metus lacus, porttitor eu mauris a, blandit ultrices nibh. Mauris sit
|
||||||
amet magna non ligula vestibulum eleifend. Nulla varius volutpat turpis sed lacinia. Nam eget mi in purus
|
amet magna non ligula vestibulum eleifend. Nulla varius volutpat turpis sed lacinia. Nam eget mi in purus
|
||||||
lobortis eleifend. Sed nec ante dictum sem condimentum ullamcorper quis venenatis nisi. Proin vitae facilisis
|
lobortis eleifend. Sed nec ante dictum sem condimentum ullamcorper quis venenatis nisi. Proin vitae facilisis
|
||||||
nisi, ac posuere leo.
|
nisi, ac posuere leo.
|
||||||
|
|
||||||
### Another Heading
|
### Another Heading
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
|
||||||
Sed dignissim, metus nec fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus elit sed risus.
|
Sed dignissim, metus nec fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus elit sed risus.
|
||||||
|
|
||||||
- `Nam metus lacus`: porttitor eu mauris a, [blandit ultrices](#) nibh.
|
- `Nam metus lacus`: porttitor eu mauris a, [blandit ultrices](#) nibh.
|
||||||
- `Class aptent`: taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
|
- `Class aptent`: taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
|
||||||
- `Sed nec ante`: dictum sem condimentum [ullamcorper quis](#) venenatis nisi.
|
- `Sed nec ante`: dictum sem condimentum [ullamcorper quis](#) venenatis nisi.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import type { APIContext } from 'astro';
|
import type { APIContext } from 'astro';
|
||||||
|
|
||||||
export async function get({ params, request }: APIContext) {
|
export async function get({ params, request }: APIContext) {
|
||||||
return {
|
return {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
path: new URL(request.url).pathname
|
path: new URL(request.url).pathname,
|
||||||
})
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
|
||||||
Sed dignissim.
|
Sed dignissim.
|
||||||
|
|
||||||
<figure>
|
<figure>
|
||||||
<img src="https://wallpaperaccess.com/full/138733.jpg" alt="test">
|
<img src="https://wallpaperaccess.com/full/138733.jpg" alt="test" />
|
||||||
<figcaption>This is a test image!</figcaption>
|
<figcaption>This is a test image!</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis
|
||||||
Sed dignissim, metus nec fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus elit sed risus.
|
tellus.
|
||||||
</p>
|
Sed dignissim, metus nec fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus elit sed
|
||||||
<p>— <a href="#">Metus Nec</a></p>
|
risus.
|
||||||
</blockquote>
|
</p>
|
||||||
|
<p>— <a href="#">Metus Nec</a></p>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
## Conclusion
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
|
Sed dignissim, metus nec fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus elit sed risus.
|
||||||
Sed dignissim, metus nec fringilla accumsan, risus sem sollicitudin lacus, ut interdum tellus elit sed risus.
|
</Markdown>
|
||||||
|
</div>
|
||||||
|
<footer>
|
||||||
|
<h2>Comments</h2>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
<style lang='scss'>
|
||||||
|
.article {
|
||||||
|
& header {
|
||||||
|
& .meta {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
column-gap: 5px;
|
||||||
|
row-gap: 1.2rem;
|
||||||
|
|
||||||
</Markdown>
|
& ul {
|
||||||
</div>
|
max-width: 350px;
|
||||||
<footer>
|
}
|
||||||
<h2>Comments</h2>
|
|
||||||
</footer>
|
|
||||||
</article>
|
|
||||||
<style lang="scss">
|
|
||||||
.article {
|
|
||||||
& header {
|
|
||||||
& .meta {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: flex-start;
|
|
||||||
column-gap: 5px;
|
|
||||||
row-gap: 1.2rem;
|
|
||||||
|
|
||||||
& ul {
|
& div {
|
||||||
max-width: 350px;
|
display: flex;
|
||||||
}
|
flex-direction: column;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
& div {
|
& .heading {
|
||||||
display: flex;
|
margin-top: 2rem;
|
||||||
flex-direction: column;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .heading {
|
& h1 {
|
||||||
margin-top: 2rem;
|
font-weight: 600;
|
||||||
|
font-size: 2.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
& h1 {
|
& p {
|
||||||
font-weight: 600;
|
font-size: 1.125rem;
|
||||||
font-size: 2.25rem;
|
line-height: var(--line-height-base);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
& p {
|
& figure {
|
||||||
font-size: 1.125rem;
|
margin: 0;
|
||||||
line-height: var(--line-height-base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& figure {
|
& img {
|
||||||
margin: 0;
|
border-radius: var(--border-radius-md);
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
& img {
|
& footer {
|
||||||
border-radius: var(--border-radius-md);
|
margin-top: 5rem;
|
||||||
display: block;
|
}
|
||||||
margin: 0 auto;
|
}
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& footer {
|
@media screen and (max-width: 560px) {
|
||||||
margin-top: 5rem;
|
.article {
|
||||||
}
|
& header {
|
||||||
}
|
& .heading h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 560px) {
|
& .meta {
|
||||||
.article header .meta {
|
flex-direction: column-reverse;
|
||||||
flex-direction: column-reverse;
|
|
||||||
|
|
||||||
& ul {
|
& ul {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
& div {
|
& div {
|
||||||
align-self: flex-end;
|
align-self: flex-end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
}
|
||||||
</Page>
|
}
|
||||||
|
</style>
|
||||||
|
</PageLayout>
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
---
|
---
|
||||||
import Page from '@layouts/Page.astro';
|
import PageLayout from '@layouts/default.astro';
|
||||||
import { Markdown } from 'astro/components';
|
import { Markdown } from 'astro/components';
|
||||||
import { PageHeading } from '@root/components/PageHeading';
|
import { PageHeading } from '@root/components/PageHeading';
|
||||||
import { Icon } from 'astro-icon'
|
import { Icon } from 'astro-icon'
|
||||||
|
|
||||||
// TODO: import content based on user ui language
|
// TODO: import content based on user ui language
|
||||||
import * as aboutContent from '../../content/about/ru/index.md';
|
import * as aboutContent from '../../content/about/ru/index.md';
|
||||||
---
|
---
|
||||||
|
|
||||||
<Page title='Обо мне | Sergey Yarkov'>
|
<PageLayout title='Обо мне | Sergey Yarkov'>
|
||||||
<section class='about container'>
|
<section class='about container'>
|
||||||
<PageHeading heading='Обо мне' />
|
<PageHeading heading='Обо мне' />
|
||||||
<div class='article-content'>
|
<div class='article-content'>
|
||||||
@ -152,16 +152,19 @@ import * as aboutContent from '../../content/about/ru/index.md';
|
|||||||
column-gap: 40px;
|
column-gap: 40px;
|
||||||
row-gap: 30px;
|
row-gap: 30px;
|
||||||
margin-top: 5rem;
|
margin-top: 5rem;
|
||||||
|
|
||||||
& .skills-list {
|
& .skills-list {
|
||||||
& h3 {
|
& h3 {
|
||||||
font-size: var(--font-size-md);
|
font-size: var(--font-size-md);
|
||||||
color: var(--font-color-grayer);
|
color: var(--font-color-grayer);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
& ul {
|
& ul {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
|
||||||
& li {
|
& li {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
@ -174,14 +177,17 @@ import * as aboutContent from '../../content/about/ru/index.md';
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 500px) {
|
@media screen and (max-width: 500px) {
|
||||||
.about-skills {
|
.about-skills {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
& .skills-list {
|
& .skills-list {
|
||||||
& h3 {
|
& h3 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
& ul {
|
& ul {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -191,4 +197,4 @@ import * as aboutContent from '../../content/about/ru/index.md';
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</Page>
|
</PageLayout>
|
||||||
@ -1,19 +1,15 @@
|
|||||||
---
|
---
|
||||||
import Page from '@layouts/Page.astro';
|
import PageLayout from '@layouts/default.astro';
|
||||||
import { ArticlesList } from '@components/ArticlesList';
|
import { ArticlesList } from '@components/ArticlesList';
|
||||||
import { IArticle } from '@root/interfaces';
|
import { IArticle } from '@root/interfaces';
|
||||||
import * as utils from '@utils/index';
|
import * as utils from '@utils/index';
|
||||||
|
|
||||||
const articles = await Astro.glob<IArticle>('../../content/articles/**/*.md');
|
const articles = await Astro.glob<IArticle>('../../content/articles/**/*.md');
|
||||||
const tags = new Set(
|
const tags = new Set(
|
||||||
articles.map((article) => article.frontmatter.tags).flat()
|
articles.map((article) => article.frontmatter.tags).flat()
|
||||||
);
|
);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Page title='Статьи | Sergey Yarkov'>
|
<PageLayout title='Статьи | Sergey Yarkov'>
|
||||||
<ArticlesList
|
<ArticlesList client:load data={utils.transformArticles(articles)} tags={[...tags]} />
|
||||||
client:load
|
</PageLayout>
|
||||||
data={utils.transformArticles(articles)}
|
|
||||||
tags={[...tags]}
|
|
||||||
/>
|
|
||||||
</Page>
|
|
||||||
@ -1,58 +1,78 @@
|
|||||||
---
|
---
|
||||||
import Page from '@layouts/Page.astro';
|
import PageLayout from '@layouts/default.astro';
|
||||||
import { PageHeading } from '@root/components/PageHeading';
|
import { PageHeading } from '@root/components/PageHeading';
|
||||||
import { Icon } from 'astro-icon'
|
import { Icon } from 'astro-icon';
|
||||||
import { SITE_METADATA } from '@root/config'
|
import { SITE_METADATA } from '@root/config';
|
||||||
---
|
---
|
||||||
|
|
||||||
<Page title='Контакты | Sergey Yarkov'>
|
<PageLayout title='Контакты | Sergey Yarkov'>
|
||||||
<section class="contacts container">
|
<section class='contacts container'>
|
||||||
<PageHeading heading='Контакты' description='Воспользуйтесь формой обратной связи или напишите мне в социальные сети.' />
|
<PageHeading heading='Контакты' description='Воспользуйтесь формой обратной связи или напишите мне в социальные сети.' />
|
||||||
<div class="contacts-form">
|
<div class='contacts-form'>
|
||||||
<form name="contact" method="POST" data-netlify="true">
|
<form name='contact' method='POST' data-netlify='true'>
|
||||||
<div>
|
<div>
|
||||||
<input name="name" placeholder="Ваше имя" type="text">
|
<input name='name' placeholder='Ваше имя' type='text' />
|
||||||
<input name="email" placeholder="example@email.com" type="text">
|
<input name='email' placeholder='example@email.com' type='text' />
|
||||||
</div>
|
</div>
|
||||||
<input name="subject" placeholder="Тема сообщения" type="text">
|
<input name='subject' placeholder='Тема сообщения' type='text' />
|
||||||
<textarea name="message" placeholder="Ваше сообщение..." id="message" cols={30} rows={10}></textarea>
|
<textarea name='message' placeholder='Ваше сообщение...' id='message' cols={30} rows={10}></textarea>
|
||||||
<div>
|
<div>
|
||||||
<button type="submit">Отправить</button>
|
<button type='submit'>Отправить</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="contacts-link">
|
<div class='contacts-link'>
|
||||||
<a href={'mailto:' + SITE_METADATA.contacts.email}>Email <Icon name='arrow-up-right' width='15' height='15' /></a>
|
<a href={'mailto:' + SITE_METADATA.contacts.email}
|
||||||
<a href={SITE_METADATA.contacts.githubUrl} target='_blank'>Github <Icon name='arrow-up-right' width='15' height='15' /></a>
|
>Email
|
||||||
<a href={SITE_METADATA.contacts.telegramUrl} target='_blank'>Telegram <Icon name='arrow-up-right' width='15' height='15' /></a>
|
<Icon name='arrow-up-right' width='15' height='15' />
|
||||||
</div>
|
</a>
|
||||||
</section>
|
<a href={SITE_METADATA.contacts.githubUrl} target='_blank'
|
||||||
<style lang='scss'>
|
>Github
|
||||||
.contacts {
|
<Icon name='arrow-up-right' width='15' height='15' />
|
||||||
& form {
|
</a>
|
||||||
display: flex;
|
<a href={SITE_METADATA.contacts.telegramUrl} target='_blank'
|
||||||
flex-direction: column;
|
>Telegram
|
||||||
row-gap: 7px;
|
<Icon name='arrow-up-right' width='15' height='15' />
|
||||||
margin-bottom: 3.125rem;
|
</a>
|
||||||
& div:first-of-type {
|
</div>
|
||||||
display: flex;
|
</section>
|
||||||
column-gap: 10px;
|
<style lang='scss'>
|
||||||
}
|
.contacts {
|
||||||
& div:last-of-type {
|
& form {
|
||||||
text-align: center;
|
display: flex;
|
||||||
margin-top: 15px;
|
flex-direction: column;
|
||||||
}
|
row-gap: 7px;
|
||||||
}
|
margin-bottom: 3.125rem;
|
||||||
&-link {
|
|
||||||
display: flex;
|
& div:first-of-type {
|
||||||
flex-wrap: wrap;
|
display: flex;
|
||||||
column-gap: 40px;
|
column-gap: 10px;
|
||||||
row-gap: 30px;
|
}
|
||||||
& a {
|
|
||||||
display: flex;
|
& div:last-of-type {
|
||||||
column-gap: 5px;
|
text-align: center;
|
||||||
}
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
</Page>
|
&-link {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
column-gap: 40px;
|
||||||
|
row-gap: 30px;
|
||||||
|
|
||||||
|
& a {
|
||||||
|
display: flex;
|
||||||
|
column-gap: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 500px) {
|
||||||
|
.contacts form div:first-of-type {
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</PageLayout>
|
||||||
|
|||||||
@ -1,115 +1,90 @@
|
|||||||
---
|
---
|
||||||
import Page from '@layouts/Page.astro';
|
import type { IArticle } from '@root/interfaces';
|
||||||
import { IArticle } from '@root/interfaces';
|
|
||||||
import { ArticleItem } from '@components/ArticleItem';
|
import PageLayout from '@layouts/default.astro';
|
||||||
import { Icon } from 'astro-icon';
|
import { Icon } from 'astro-icon';
|
||||||
import * as utils from '@utils/index';
|
import * as utils from '@utils/index';
|
||||||
|
import RecentArticles from '@root/components/RecentArticles';
|
||||||
|
|
||||||
const data = await Astro.glob<IArticle>('../../content/articles/**/*.md');
|
const data = await Astro.glob<IArticle>('../../content/articles/**/*.md');
|
||||||
const recent = utils.sortArtcilesByDate(utils.transformArticles(data));
|
const articles = utils.transformArticles(data);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Page title='Sergey Yarkov'>
|
<PageLayout>
|
||||||
<section class='welcome container'>
|
<section class='welcome container'>
|
||||||
<header class='welcome-heading'>
|
<header class='welcome-heading'>
|
||||||
<hgroup class='welcome-heading__title'>
|
<hgroup class='welcome-heading__title'>
|
||||||
<h1>Hello, I'am Sergey</h1>
|
<h1>Hello, I'am Sergey</h1>
|
||||||
<h2>Fullstack <b>web-developer</b> and <b>freelancer</b></h2>
|
<h2>Fullstack <b>web-developer</b> & <b>freelancer</b></h2>
|
||||||
</hgroup>
|
</hgroup>
|
||||||
<p class='welcome-heading__description'>
|
<p class='welcome-heading__description'>
|
||||||
Я занимаюсь разработкой веб-сайтов и веб-приложений разной сложности, а
|
Я занимаюсь разработкой веб-сайтов и веб-приложений разной сложности, а также публикую различные статьи и туториалы на разные IT темы.
|
||||||
также публикую различные статьи и туториалы на разные IT темы.
|
</p>
|
||||||
</p>
|
</header>
|
||||||
</header>
|
<nav class='welcome-links'>
|
||||||
<nav class='welcome-links'>
|
<div class='welcome-links__link'>
|
||||||
<div class='welcome-links__link'>
|
<Icon name='information' width='18' height='18' />
|
||||||
<Icon name='information' width='18' height='18' />
|
<a href='/about'> обо мне</a>
|
||||||
<a href='/about'> обо мне</a>
|
</div>
|
||||||
</div>
|
<div class='welcome-links__link'>
|
||||||
<div class='welcome-links__link'>
|
<Icon name='email_filled' width='18' height='18' />
|
||||||
<Icon name='email_filled' width='18' height='18' />
|
<a href='/contacts'> написать мне</a>
|
||||||
<a href='/contacts'> написать мне</a>
|
</div>
|
||||||
</div>
|
</nav>
|
||||||
</nav>
|
</section>
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class='publications'>
|
<RecentArticles articles={articles} length={4} />
|
||||||
<div class='container'>
|
|
||||||
<div class='publications-heading'>
|
|
||||||
<h2>недавние публикации</h2>
|
|
||||||
<a href='/articles'>смотреть все</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class='publications-list container'>
|
|
||||||
{recent.slice(0, 5).map((article) => <ArticleItem data={article} />)}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<style lang='scss'>
|
<style lang='scss'>
|
||||||
.welcome {
|
.welcome {
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
margin-bottom: 150px;
|
margin-bottom: 150px;
|
||||||
&-heading {
|
|
||||||
&__title {
|
|
||||||
& h1 {
|
|
||||||
font-size: var(--font-size-5xl);
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
& h2 {
|
|
||||||
font-size: var(--font-size-xl);
|
|
||||||
margin-bottom: 1.25rem;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__description {
|
|
||||||
font-size: var(--font-size-lg);
|
|
||||||
max-width: 570px;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&-links {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
column-gap: 20px;
|
|
||||||
&__link {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
column-gap: 5px;
|
|
||||||
& a {
|
|
||||||
color: var(--font-color-gray);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
&-heading {
|
||||||
}
|
&__title {
|
||||||
}
|
& h1 {
|
||||||
|
font-size: var(--font-size-5xl);
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.publications {
|
& h2 {
|
||||||
&-heading {
|
font-size: var(--font-size-xl);
|
||||||
display: flex;
|
margin-bottom: 1.25rem;
|
||||||
align-items: center;
|
font-weight: normal;
|
||||||
column-gap: 15px;
|
}
|
||||||
row-gap: 5px;
|
}
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
padding-bottom: 10px;
|
|
||||||
& h2 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&-list {
|
|
||||||
margin-top: 10px;
|
|
||||||
max-width: calc(var(--content-width) + (var(--content-padding) * 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[astro-icon="information"] {
|
&__description {
|
||||||
fill: var(--color-gray-600)
|
font-size: var(--font-size-lg);
|
||||||
}
|
max-width: 570px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[astro-icon="email_filled"] {
|
&-links {
|
||||||
fill: var(--color-gray-600)
|
display: flex;
|
||||||
}
|
align-items: center;
|
||||||
</style>
|
column-gap: 20px;
|
||||||
</Page>
|
|
||||||
|
&__link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 5px;
|
||||||
|
|
||||||
|
& a {
|
||||||
|
color: var(--font-color-gray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[astro-icon='information'] {
|
||||||
|
fill: var(--color-gray-600);
|
||||||
|
}
|
||||||
|
|
||||||
|
[astro-icon='email_filled'] {
|
||||||
|
fill: var(--color-gray-600);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</PageLayout>
|
||||||
|
|||||||
@ -1,36 +1,24 @@
|
|||||||
---
|
---
|
||||||
import Page from '@layouts/Page.astro';
|
import PageLayout from '@layouts/default.astro';
|
||||||
import { PageHeading } from '@root/components/PageHeading';
|
import { PageHeading } from '@root/components/PageHeading';
|
||||||
import { SITE_METADATA } from '@root/config';
|
import { SITE_METADATA } from '@root/config';
|
||||||
|
import { Icon } from 'astro-icon'
|
||||||
---
|
---
|
||||||
|
|
||||||
<Page title='Проекты | Sergey Yarkov'>
|
<PageLayout title='Проекты | Sergey Yarkov'>
|
||||||
<section class='projects container'>
|
<section class='projects container'>
|
||||||
<PageHeading
|
<PageHeading heading='Проекты'
|
||||||
heading='Проекты'
|
description='Несколько моих основных проектов которые были разработаны и выложены в открытый доступ.' />
|
||||||
description='Несколько моих основных проектов которые были разработаны и выложены в открытый доступ.'
|
|
||||||
/>
|
|
||||||
<div class='projects-heading'>
|
<div class='projects-heading'>
|
||||||
<a href={SITE_METADATA.contacts.githubUrl} target='_blank'
|
<a href={SITE_METADATA.contacts.githubUrl + '?tab=repositories' } target='_blank'>
|
||||||
>смотреть все
|
смотреть все
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class='projects-list'>
|
<div class='projects-list'>
|
||||||
<div class='project-item'>
|
<div class='project-item'>
|
||||||
<div class='project-item__heading'>
|
<div class='project-item__heading'>
|
||||||
<h2>
|
<h2>
|
||||||
<svg
|
<Icon name='nodejs' width='20' height='20' />
|
||||||
width='20'
|
|
||||||
height='21'
|
|
||||||
viewBox='0 0 20 21'
|
|
||||||
fill='none'
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d='M9.99983 18.8208C9.77066 18.8208 9.5565 18.7592 9.3565 18.6525L7.324 17.4458C7.01983 17.2767 7.17233 17.215 7.264 17.1842C7.67733 17.0467 7.754 17.0167 8.1815 16.7733C8.22816 16.7425 8.289 16.7567 8.33566 16.7875L9.894 17.7208C9.95566 17.7508 10.0323 17.7508 10.0782 17.7208L16.1773 14.19C16.239 14.16 16.269 14.0983 16.269 14.0217V6.97334C16.269 6.89751 16.239 6.83584 16.1773 6.80584L10.0782 3.29001C10.0173 3.25917 9.94066 3.25917 9.894 3.29001L3.79316 6.80501C3.73233 6.83501 3.7015 6.91251 3.7015 6.97251V14.02C3.7015 14.0808 3.73233 14.1583 3.79316 14.1883L5.45983 15.1525C6.3615 15.6092 6.92816 15.0733 6.92816 14.54V7.58501C6.92816 7.49334 7.004 7.40084 7.1115 7.40084H7.8915C7.9815 7.40084 8.07483 7.47751 8.07483 7.58501V14.5408C8.07483 15.7483 7.41816 16.4525 6.2715 16.4525C5.91983 16.4525 5.64483 16.4525 4.86483 16.0692L3.26066 15.1533C3.06521 15.0397 2.90301 14.8768 2.79026 14.6808C2.67751 14.4849 2.61817 14.2628 2.61816 14.0367V6.98834C2.61816 6.53001 2.86233 6.10167 3.26066 5.87251L9.35733 2.34167C9.55525 2.23583 9.77622 2.18045 10.0007 2.18045C10.2251 2.18045 10.4461 2.23583 10.644 2.34167L16.7415 5.87251C17.1407 6.10084 17.384 6.53001 17.384 6.98834V14.0367C17.384 14.4942 17.1398 14.9225 16.7415 15.1533L10.644 18.6833C10.4432 18.775 10.214 18.8208 9.99983 18.8208ZM11.8798 13.9742C9.20483 13.9742 8.65483 12.7508 8.65483 11.7125C8.65483 11.6208 8.7315 11.5283 8.83816 11.5283H9.63316C9.72483 11.5283 9.80066 11.5892 9.80066 11.6817C9.92316 12.4908 10.274 12.8892 11.8957 12.8892C13.179 12.8892 13.7307 12.5975 13.7307 11.91C13.7307 11.5125 13.5765 11.2225 11.5748 11.0242C9.909 10.8575 8.86983 10.4883 8.86983 9.15917C8.86983 7.92167 9.909 7.18751 11.6523 7.18751C13.6082 7.18751 14.5715 7.86167 14.6932 9.32751C14.6917 9.37698 14.6755 9.42487 14.6465 9.46501C14.6157 9.49501 14.5707 9.52584 14.5248 9.52584H13.7307C13.6914 9.52501 13.6535 9.51112 13.6231 9.48637C13.5926 9.46162 13.5712 9.42742 13.5623 9.38917C13.3782 8.54584 12.9048 8.27251 11.6523 8.27251C10.2448 8.27251 10.0765 8.76167 10.0765 9.12834C10.0765 9.57084 10.274 9.70834 12.1715 9.95334C14.0515 10.1975 14.9382 10.5492 14.9382 11.865C14.9215 13.2108 13.8223 13.9742 11.8798 13.9742Z'
|
|
||||||
fill='black'></path>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
yarkov.tech
|
yarkov.tech
|
||||||
</h2>
|
</h2>
|
||||||
<span>2022</span>
|
<span>2022</span>
|
||||||
@ -42,38 +30,16 @@ import { SITE_METADATA } from '@root/config';
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class='project-item__links'>
|
<div class='project-item__links'>
|
||||||
<a class='btn-link' href='#'
|
<a class='btn-link' href='#'>
|
||||||
>Исходник <svg
|
Исходник
|
||||||
width='15'
|
<Icon name='link-out' width='15' height='15' />
|
||||||
height='15'
|
|
||||||
viewBox='0 0 15 15'
|
|
||||||
fill='none'
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d='M8.4375 6.5625L13.125 1.875M10 1.875H13.125V5M13.125 8.75V11.875C13.125 12.2065 12.9933 12.5245 12.7589 12.7589C12.5245 12.9933 12.2065 13.125 11.875 13.125H3.125C2.79348 13.125 2.47554 12.9933 2.24112 12.7589C2.0067 12.5245 1.875 12.2065 1.875 11.875V3.125C1.875 2.79348 2.0067 2.47554 2.24112 2.24112C2.47554 2.0067 2.79348 1.875 3.125 1.875H6.25'
|
|
||||||
stroke='#21262D'
|
|
||||||
stroke-width='2'
|
|
||||||
stroke-linecap='round'
|
|
||||||
stroke-linejoin='round'></path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='project-item'>
|
<div class='project-item'>
|
||||||
<div class='project-item__heading'>
|
<div class='project-item__heading'>
|
||||||
<h2>
|
<h2>
|
||||||
<svg
|
<Icon name='triangle_filled' width='20' height='20' />
|
||||||
width='20'
|
|
||||||
height='17'
|
|
||||||
viewBox='0 0 20 17'
|
|
||||||
fill='none'
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d='M8.2208 14.5116C8.99268 15.7027 11.0064 15.7032 11.7789 14.5122L18.4977 4.15437C19.2439 3.00368 18.2646 1.59375 16.7183 1.59375L3.2858 1.59375C1.74018 1.59375 0.760803 3.00315 1.50705 4.15384L8.2208 14.5116Z'
|
|
||||||
fill='black'></path>
|
|
||||||
</svg>
|
|
||||||
devthread
|
devthread
|
||||||
</h2>
|
</h2>
|
||||||
<span>2021</span>
|
<span>2021</span>
|
||||||
@ -85,22 +51,12 @@ import { SITE_METADATA } from '@root/config';
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class='project-item__links'>
|
<div class='project-item__links'>
|
||||||
<a class='btn-link' href='#'>Статья</a>
|
<a class='btn-link' href='#'>
|
||||||
<a class='btn-link' href='#'
|
Статья
|
||||||
>Исходник <svg
|
</a>
|
||||||
width='15'
|
<a class='btn-link' href='#'>
|
||||||
height='15'
|
Исходник
|
||||||
viewBox='0 0 15 15'
|
<Icon name='link-out' width='15' height='15' />
|
||||||
fill='none'
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d='M8.4375 6.5625L13.125 1.875M10 1.875H13.125V5M13.125 8.75V11.875C13.125 12.2065 12.9933 12.5245 12.7589 12.7589C12.5245 12.9933 12.2065 13.125 11.875 13.125H3.125C2.79348 13.125 2.47554 12.9933 2.24112 12.7589C2.0067 12.5245 1.875 12.2065 1.875 11.875V3.125C1.875 2.79348 2.0067 2.47554 2.24112 2.24112C2.47554 2.0067 2.79348 1.875 3.125 1.875H6.25'
|
|
||||||
stroke='#21262D'
|
|
||||||
stroke-width='2'
|
|
||||||
stroke-linecap='round'
|
|
||||||
stroke-linejoin='round'></path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -112,19 +68,23 @@ import { SITE_METADATA } from '@root/config';
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .projects-list {
|
& .projects-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|
||||||
& .project-item {
|
& .project-item {
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
border-radius: var(--border-radius-lg);
|
border-radius: var(--border-radius-lg);
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
|
|
||||||
&__heading {
|
&__heading {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
& h2 {
|
& h2 {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -134,14 +94,17 @@ import { SITE_METADATA } from '@root/config';
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
& span {
|
& span {
|
||||||
font-size: var(--font-size-sm);
|
font-size: var(--font-size-sm);
|
||||||
color: var(--font-color-gray);
|
color: var(--font-color-gray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__description {
|
&__description {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__links {
|
&__links {
|
||||||
display: flex;
|
display: flex;
|
||||||
column-gap: 5px;
|
column-gap: 5px;
|
||||||
@ -150,4 +113,4 @@ import { SITE_METADATA } from '@root/config';
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</Page>
|
</PageLayout>
|
||||||
@ -1,289 +1,290 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap');
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
/* Fonts */
|
/* Fonts */
|
||||||
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Arial,
|
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
||||||
sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
--font-family-base: 'Rubik', var(--font-fallback);
|
||||||
--font-family-base: 'Rubik', var(--font-fallback);
|
--font-color: var(--color-black);
|
||||||
--font-color: var(--color-black);
|
--font-color-gray: var(--color-gray-500);
|
||||||
--font-color-gray: var(--color-gray-500);
|
--font-color-grayer: var(--color-gray-700);
|
||||||
--font-color-grayer: var(--color-gray-700);
|
--font-size-xs: 0.75rem;
|
||||||
--font-size-xs: 0.75rem;
|
--font-size-sm: 0.875rem;
|
||||||
--font-size-sm: 0.875rem;
|
--font-size-md: 1rem;
|
||||||
--font-size-md: 1rem;
|
--font-size-lg: 1.125rem;
|
||||||
--font-size-lg: 1.125rem;
|
--font-size-xl: 1.25rem;
|
||||||
--font-size-xl: 1.25rem;
|
--font-size-2xl: 1.5rem;
|
||||||
--font-size-2xl: 1.5rem;
|
--font-size-3xl: 1.875rem;
|
||||||
--font-size-3xl: 1.875rem;
|
--font-size-4xl: 2.25rem;
|
||||||
--font-size-4xl: 2.25rem;
|
--font-size-5xl: 3rem;
|
||||||
--font-size-5xl: 3rem;
|
--font-size-6xl: 3.75rem;
|
||||||
--font-size-6xl: 3.75rem;
|
--font-size-7xl: 4.5rem;
|
||||||
--font-size-7xl: 4.5rem;
|
--font-size-8xl: 6rem;
|
||||||
--font-size-8xl: 6rem;
|
--font-size-9xl: 8rem;
|
||||||
--font-size-9xl: 8rem;
|
|
||||||
|
|
||||||
/* Line heights */
|
/* Line heights */
|
||||||
--line-height-normal: 'normal';
|
--line-height-normal: 'normal';
|
||||||
--line-height-none: 1;
|
--line-height-none: 1;
|
||||||
--line-height-shorter: 1.25;
|
--line-height-shorter: 1.25;
|
||||||
--line-height-short: 1.375;
|
--line-height-short: 1.375;
|
||||||
--line-height-base: 1.5;
|
--line-height-base: 1.5;
|
||||||
--line-height-tall: 1.625;
|
--line-height-tall: 1.625;
|
||||||
|
|
||||||
/* Colors */
|
/* Colors */
|
||||||
--color-white: #ffffff;
|
--color-white: #ffffff;
|
||||||
--color-black: #010409;
|
--color-black: #010409;
|
||||||
|
|
||||||
--color-blue-50: #cae8ff;
|
--color-blue-50: #cae8ff;
|
||||||
--color-blue-100: #a5d6ff;
|
--color-blue-100: #a5d6ff;
|
||||||
--color-blue-200: #79c0ff;
|
--color-blue-200: #79c0ff;
|
||||||
--color-blue-300: #58a6ff;
|
--color-blue-300: #58a6ff;
|
||||||
--color-blue-400: #388bfd;
|
--color-blue-400: #388bfd;
|
||||||
--color-blue-500: #1f6feb;
|
--color-blue-500: #1f6feb;
|
||||||
--color-blue-600: #1158c7;
|
--color-blue-600: #1158c7;
|
||||||
--color-blue-700: #0d419d;
|
--color-blue-700: #0d419d;
|
||||||
--color-blue-800: #0c2d6b;
|
--color-blue-800: #0c2d6b;
|
||||||
--color-blue-900: #051d4d;
|
--color-blue-900: #051d4d;
|
||||||
|
|
||||||
--color-gray-50: #f0f6fc;
|
--color-gray-50: #f0f6fc;
|
||||||
--color-gray-100: #c9d1d9;
|
--color-gray-100: #c9d1d9;
|
||||||
--color-gray-200: #b1bac4;
|
--color-gray-200: #b1bac4;
|
||||||
--color-gray-300: #8b949e;
|
--color-gray-300: #8b949e;
|
||||||
--color-gray-400: #6e7681;
|
--color-gray-400: #6e7681;
|
||||||
--color-gray-500: #484f58;
|
--color-gray-500: #484f58;
|
||||||
--color-gray-600: #30363d;
|
--color-gray-600: #30363d;
|
||||||
--color-gray-700: #21262d;
|
--color-gray-700: #21262d;
|
||||||
--color-gray-800: #161b22;
|
--color-gray-800: #161b22;
|
||||||
--color-gray-900: #0d1117;
|
--color-gray-900: #0d1117;
|
||||||
|
|
||||||
--color-orange-50: #ffdfb6;
|
--color-orange-50: #ffdfb6;
|
||||||
--color-orange-100: #ffc680;
|
--color-orange-100: #ffc680;
|
||||||
--color-orange-200: #ffa657;
|
--color-orange-200: #ffa657;
|
||||||
--color-orange-300: #f0883e;
|
--color-orange-300: #f0883e;
|
||||||
--color-orange-400: #db6d28;
|
--color-orange-400: #db6d28;
|
||||||
--color-orange-500: #bd561d;
|
--color-orange-500: #bd561d;
|
||||||
--color-orange-600: #9b4215;
|
--color-orange-600: #9b4215;
|
||||||
--color-orange-700: #762d0a;
|
--color-orange-700: #762d0a;
|
||||||
--color-orange-800: #5a1e02;
|
--color-orange-800: #5a1e02;
|
||||||
--color-orange-900: #3d1300;
|
--color-orange-900: #3d1300;
|
||||||
|
|
||||||
--color-yellow-50: #f8e3a1;
|
--color-yellow-50: #f8e3a1;
|
||||||
--color-yellow-100: #f2cc60;
|
--color-yellow-100: #f2cc60;
|
||||||
--color-yellow-200: #e3b341;
|
--color-yellow-200: #e3b341;
|
||||||
--color-yellow-300: #d29922;
|
--color-yellow-300: #d29922;
|
||||||
--color-yellow-400: #bb8009;
|
--color-yellow-400: #bb8009;
|
||||||
--color-yellow-500: #9e6a03;
|
--color-yellow-500: #9e6a03;
|
||||||
--color-yellow-600: #845306;
|
--color-yellow-600: #845306;
|
||||||
--color-yellow-700: #693e00;
|
--color-yellow-700: #693e00;
|
||||||
--color-yellow-800: #4b2900;
|
--color-yellow-800: #4b2900;
|
||||||
--color-yellow-900: #341a00;
|
--color-yellow-900: #341a00;
|
||||||
|
|
||||||
--background-color-hover: var(--color-gray-50);
|
--background-color-hover: var(--color-gray-50);
|
||||||
|
|
||||||
/* Border */
|
/* Border */
|
||||||
--border-color: var(--color-gray-100);
|
--border-color: var(--color-gray-100);
|
||||||
--border-color-hover: var(--color-gray-400);
|
--border-color-hover: var(--color-gray-400);
|
||||||
--border-radius-md: 3px;
|
--border-radius-md: 3px;
|
||||||
--border-radius-lg: 5px;
|
--border-radius-lg: 5px;
|
||||||
|
|
||||||
/* Sizes */
|
/* Sizes */
|
||||||
--content-width: 760px;
|
--content-width: 760px;
|
||||||
--content-padding: 15px;
|
--content-padding: 15px;
|
||||||
|
|
||||||
/* Elements */
|
/* Elements */
|
||||||
--background-body-color: var(--color-white);
|
--background-body-color: var(--color-white);
|
||||||
--background-header-color: var(--color-white);
|
--background-header-color: var(--color-white);
|
||||||
--background-scrollbar-track-color: #EFF1F5;
|
--background-scrollbar-track-color: #eff1f5;
|
||||||
--background-scrollbar-thumb-color: var(--color-gray-100);
|
--background-scrollbar-thumb-color: var(--color-gray-100);
|
||||||
--background-inline-code: rgba(0,0,0,0.05);
|
--background-inline-code: rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
--opacity-hover: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Text selection */
|
/* Text selection */
|
||||||
::selection {
|
::selection {
|
||||||
background: var(--color-yellow-100);
|
background: var(--color-yellow-100);
|
||||||
color: var(--color-black);
|
color: var(--color-black);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Scrollbar */
|
/* Scrollbar */
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
::-webkit-scrollbar-track {
|
||||||
background: var(--background-scrollbar-track-color);
|
background: var(--background-scrollbar-track-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
background: var(--background-scrollbar-thumb-color)
|
background: var(--background-scrollbar-thumb-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
*, *:before, *:after {
|
body[data-is-mobile-open='true'] {
|
||||||
box-sizing: inherit;
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after {
|
||||||
|
box-sizing: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-kerning: normal;
|
font-kerning: normal;
|
||||||
font-family: var(--font-family-base);
|
font-family: var(--font-family-base);
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: var(--font-color);
|
color: var(--font-color);
|
||||||
background-color: var(--background-body-color);
|
background-color: var(--background-body-color);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.site-content {
|
|
||||||
flex: 1 0 auto;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-width: var(--content-width);
|
max-width: var(--content-width);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0 var(--content-padding);
|
padding: 0 var(--content-padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-links {
|
.list-links {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Buttons */
|
/* Buttons */
|
||||||
.btn-link {
|
.btn-link {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
column-gap: 5px;
|
column-gap: 5px;
|
||||||
padding: 3px 10px;
|
padding: 3px 10px;
|
||||||
border-radius: var(--border-radius-md);
|
border-radius: var(--border-radius-md);
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--font-color);
|
color: var(--font-color);
|
||||||
font-size: var(--font-size-sm);
|
font-size: var(--font-size-sm);
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
border-color: var(--border-color-hover);
|
border-color: var(--border-color-hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-content {
|
.article-content {
|
||||||
& p,
|
& p,
|
||||||
& em,
|
& em,
|
||||||
& q {
|
& q {
|
||||||
line-height: var(--line-height-base);
|
line-height: var(--line-height-base);
|
||||||
font-size: var(--font-size-lg);
|
font-size: var(--font-size-lg);
|
||||||
}
|
}
|
||||||
|
|
||||||
& ul {
|
& ul {
|
||||||
padding-left: 1.5rem;
|
padding-left: 1.5rem;
|
||||||
line-height: var(--line-height-base);
|
line-height: var(--line-height-base);
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
& li {
|
& li {
|
||||||
font-size: var(--font-size-lg);
|
font-size: var(--font-size-lg);
|
||||||
line-height: var(--line-height-base);
|
line-height: var(--line-height-base);
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
padding-left: 0.25rem;
|
padding-left: 0.25rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& q {
|
& q {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
quotes: "«" "»";
|
quotes: '«' '»';
|
||||||
}
|
}
|
||||||
|
|
||||||
& h1,
|
& h1,
|
||||||
& h2,
|
& h2,
|
||||||
& h3,
|
& h3,
|
||||||
& h4 {
|
& h4 {
|
||||||
margin-top: 3rem;
|
margin-top: 3rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
padding-bottom: 0.35rem;
|
padding-bottom: 0.35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
& h1:not(:first-child),
|
& h1:not(:first-child),
|
||||||
& h2:not(:first-child),
|
& h2:not(:first-child),
|
||||||
& h3:not(:first-child),
|
& h3:not(:first-child),
|
||||||
& h4:not(:first-child) {
|
& h4:not(:first-child) {
|
||||||
margin-top: 3rem;
|
margin-top: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
& h2 {
|
& h2 {
|
||||||
font-size: var(--font-size-3xl);
|
font-size: var(--font-size-3xl);
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
& h3 {
|
& h3 {
|
||||||
font-size: var(--font-size-2xl);
|
font-size: var(--font-size-2xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
& a {
|
& h4 {
|
||||||
color: var(--color-blue-500);
|
font-size: var(--font-size-xl);
|
||||||
text-underline-offset: 2.5px;
|
}
|
||||||
text-decoration-color: var(--color-blue-500);
|
|
||||||
font-weight: 500;
|
|
||||||
&:hover {
|
|
||||||
color: var(--color-blue-500);
|
|
||||||
text-decoration-thickness: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& figure {
|
& a {
|
||||||
margin: 0 0 1em;
|
color: var(--color-blue-500);
|
||||||
}
|
text-underline-offset: 2.5px;
|
||||||
|
text-decoration-color: var(--color-blue-500);
|
||||||
|
font-weight: 500;
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-blue-500);
|
||||||
|
text-decoration-thickness: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
& figcaption {
|
& figure {
|
||||||
font-size: 1em;
|
margin: 0 0 1em;
|
||||||
text-align: center;
|
}
|
||||||
margin: 0.7rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& img {
|
& figcaption {
|
||||||
display: block;
|
font-style: italic;
|
||||||
border-radius: var(--border-radius-md);
|
font-size: 1em;
|
||||||
max-width: 100%;
|
text-align: center;
|
||||||
margin: 0 auto;
|
margin: 0.7rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& img {
|
||||||
|
display: block;
|
||||||
|
border-radius: var(--border-radius-md);
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
li::marker {
|
li::marker {
|
||||||
color: var(--color-blue-500);
|
color: var(--color-blue-500);
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
line-height: var(--line-height-none);
|
line-height: var(--line-height-none);
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
background-color: var(--border-color);
|
background-color: var(--border-color);
|
||||||
margin: 40px 0;
|
margin: 40px 0;
|
||||||
border: none;
|
border: none;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
@ -291,69 +292,70 @@ h2,
|
|||||||
h3,
|
h3,
|
||||||
h4,
|
h4,
|
||||||
h5 {
|
h5 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
input, textarea {
|
input,
|
||||||
font-family: var(--font-family-base);
|
textarea {
|
||||||
padding: 8px 15px;
|
font-family: var(--font-family-base);
|
||||||
border: 1px solid var(--border-color);
|
padding: 8px 15px;
|
||||||
border-radius: var(--border-radius-md);
|
border: 1px solid var(--border-color);
|
||||||
font-size: var(--font-size-sm);
|
border-radius: var(--border-radius-md);
|
||||||
width: 100%;
|
font-size: var(--font-size-sm);
|
||||||
outline-color: var(--color-blue-500);
|
width: 100%;
|
||||||
resize: vertical;
|
outline-color: var(--color-blue-500);
|
||||||
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-family: var(--font-family-base);
|
font-family: var(--font-family-base);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: var(--font-size-sm);
|
font-size: var(--font-size-sm);
|
||||||
padding: 4px 15px;
|
padding: 4px 15px;
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
border-radius: var(--border-radius-md);
|
border-radius: var(--border-radius-md);
|
||||||
background: none;
|
background: none;
|
||||||
&:hover {
|
&:hover {
|
||||||
border: 1px solid var(--border-color-hover);
|
border: 1px solid var(--border-color-hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
margin: 1.5rem 0;
|
margin: 1.5rem 0;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
border-left: 0.25rem solid var(--border-color);
|
border-left: 0.25rem solid var(--border-color);
|
||||||
padding-left: 1rem;
|
padding-left: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
:not(pre)>code {
|
:not(pre) > code {
|
||||||
-webkit-font-smoothing: subpixel-antialiased;
|
-webkit-font-smoothing: subpixel-antialiased;
|
||||||
background: var(--background-inline-code);
|
background: var(--background-inline-code);
|
||||||
border-radius: var(--border-radius-lg);
|
border-radius: var(--border-radius-lg);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 0.2rem 0.3rem;
|
padding: 0.2rem 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
font-size: var(--font-size-sm);
|
font-size: var(--font-size-sm);
|
||||||
border-radius: var(--border-radius-md);
|
border-radius: var(--border-radius-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--color-blue-500);
|
color: var(--color-blue-500);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: var(--color-blue-500);
|
color: var(--color-blue-500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pre[class*=language-]:before {
|
// pre[class*=language-]:before {
|
||||||
@ -371,7 +373,6 @@ a {
|
|||||||
// padding: 0.25rem 0.5rem;
|
// padding: 0.25rem 0.5rem;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
// pre[class*=language-typescript]:before {
|
// pre[class*=language-typescript]:before {
|
||||||
// content: "ts";
|
// content: "ts";
|
||||||
// background: #007acc;
|
// background: #007acc;
|
||||||
|
|||||||
@ -1,36 +1,29 @@
|
|||||||
import type { IArticle } from '@root/interfaces';
|
import type { IArticle } from '@root/interfaces';
|
||||||
|
|
||||||
import { MarkdownInstance } from 'astro';
|
import { MarkdownInstance } from 'astro';
|
||||||
|
|
||||||
export const transformArticles = (
|
export const transformArticles = (articles: MarkdownInstance<IArticle>[]): IArticle[] =>
|
||||||
articles: MarkdownInstance<IArticle>[]
|
articles.map((article) => ({
|
||||||
): IArticle[] => articles.map((article) => ({
|
title: article.frontmatter.title,
|
||||||
title: article.frontmatter.title,
|
author: article.frontmatter.author,
|
||||||
description: article.frontmatter.description,
|
tags: article.frontmatter.tags,
|
||||||
author: article.frontmatter.author,
|
published_at: article.frontmatter.published_at,
|
||||||
tags: article.frontmatter.tags,
|
}));
|
||||||
published_at: article.frontmatter.published_at,
|
|
||||||
}))
|
|
||||||
;
|
|
||||||
|
|
||||||
export const sortArtcilesByDate = (articles: IArticle[]): IArticle[] => {
|
export const sortArtcilesByDate = (articles: IArticle[]): IArticle[] => {
|
||||||
return articles.sort(
|
return articles.sort((a, b) => new Date(b.published_at).valueOf() - new Date(a.published_at).valueOf());
|
||||||
(a, b) =>
|
|
||||||
new Date(b.published_at).valueOf() - new Date(a.published_at).valueOf()
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filterArticlesByYear = (
|
export const filterArticlesByYear = (articles: IArticle[]): { [year: number]: IArticle[] } => {
|
||||||
articles: IArticle[]
|
const filtered = {};
|
||||||
): { [year: number]: IArticle[] } => {
|
|
||||||
const filtered = {};
|
|
||||||
|
|
||||||
for (const article of articles) {
|
for (const article of articles) {
|
||||||
const year = new Date(article.published_at).getFullYear();
|
const year = new Date(article.published_at).getFullYear();
|
||||||
|
|
||||||
if (!filtered[year]) filtered[year] = [];
|
if (!filtered[year]) filtered[year] = [];
|
||||||
|
|
||||||
filtered[year].push(article);
|
filtered[year].push(article);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filtered;
|
return filtered;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
export const DateFormatter = new Intl.DateTimeFormat(undefined, {
|
export const DateFormatter = new Intl.DateTimeFormat(undefined, {
|
||||||
timeZone: 'UTC',
|
timeZone: 'UTC',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
});
|
});
|
||||||
|
|||||||