mirror of
https://github.com/sergeyyarkov/yarkov.tech.git
synced 2026-10-11 10:29:21 +03:00
refactor 0_0
This commit is contained in:
parent
001e8eba08
commit
943a074058
@ -3,7 +3,6 @@ import { defineConfig } from "astro/config";
|
|||||||
/**
|
/**
|
||||||
* Integrations
|
* Integrations
|
||||||
*/
|
*/
|
||||||
// import mdx from "@astrojs/mdx";
|
|
||||||
import sitemap from "@astrojs/sitemap";
|
import sitemap from "@astrojs/sitemap";
|
||||||
import solidJs from "@astrojs/solid-js";
|
import solidJs from "@astrojs/solid-js";
|
||||||
import image from "@astrojs/image";
|
import image from "@astrojs/image";
|
||||||
@ -65,28 +64,31 @@ export default defineConfig({
|
|||||||
* Articles
|
* Articles
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
name: "posts",
|
name: "articles",
|
||||||
label: "Публикации",
|
label: "Публикации",
|
||||||
label_singular: "публикацию",
|
label_singular: "публикацию",
|
||||||
description:
|
description:
|
||||||
"Технические статьи, туториалы и различные справочные материалы которые связаны с IT тематикой",
|
"Технические статьи, туториалы и различные справочные материалы которые связаны с IT тематикой",
|
||||||
folder: "src/content/blog",
|
folder: "src/content/blog",
|
||||||
slug: "{{year}}-{{month}}-{{day}}_{{slug}}",
|
slug: "{{slug}}",
|
||||||
create: true,
|
create: true,
|
||||||
delete: true,
|
delete: true,
|
||||||
|
i18n: true,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: "coverImage",
|
name: "coverImage",
|
||||||
widget: "image",
|
widget: "image",
|
||||||
label: "Постер",
|
label: "Постер",
|
||||||
|
required: false,
|
||||||
|
i18n: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "draft",
|
name: "draft",
|
||||||
label: "В черновике",
|
label: "В черновике",
|
||||||
widget: "boolean",
|
widget: "boolean",
|
||||||
required: true,
|
|
||||||
default: true,
|
|
||||||
hint: "Опубликована ли статья",
|
hint: "Опубликована ли статья",
|
||||||
|
i18n: true,
|
||||||
|
required: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "author",
|
name: "author",
|
||||||
@ -95,19 +97,19 @@ export default defineConfig({
|
|||||||
search_fields: ["firstName", "lastName"],
|
search_fields: ["firstName", "lastName"],
|
||||||
collection: "authors",
|
collection: "authors",
|
||||||
label: "Автор",
|
label: "Автор",
|
||||||
required: true,
|
i18n: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "title",
|
name: "title",
|
||||||
widget: "string",
|
widget: "string",
|
||||||
label: "Заголовок",
|
label: "Заголовок",
|
||||||
required: true,
|
i18n: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "description",
|
name: "description",
|
||||||
widget: "string",
|
widget: "string",
|
||||||
label: "Описание",
|
label: "Описание",
|
||||||
required: true,
|
i18n: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "tags",
|
name: "tags",
|
||||||
@ -117,25 +119,27 @@ export default defineConfig({
|
|||||||
multiple: true,
|
multiple: true,
|
||||||
value_field: "title",
|
value_field: "title",
|
||||||
search_fields: ["title"],
|
search_fields: ["title"],
|
||||||
|
i18n: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pubDate",
|
name: "pubDate",
|
||||||
widget: "datetime",
|
widget: "datetime",
|
||||||
label: "Дата публикации",
|
label: "Дата публикации",
|
||||||
required: true,
|
|
||||||
picker_utc: true,
|
picker_utc: true,
|
||||||
|
i18n: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "updatedDate",
|
name: "updatedDate",
|
||||||
widget: "datetime",
|
widget: "datetime",
|
||||||
label: "Дата обновления",
|
label: "Дата обновления",
|
||||||
required: true,
|
|
||||||
picker_utc: true,
|
picker_utc: true,
|
||||||
|
i18n: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "body",
|
name: "body",
|
||||||
widget: "markdown",
|
widget: "markdown",
|
||||||
label: "Содержание",
|
label: "Содержание",
|
||||||
|
i18n: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -171,24 +175,28 @@ export default defineConfig({
|
|||||||
folder: "src/content/authors",
|
folder: "src/content/authors",
|
||||||
create: true,
|
create: true,
|
||||||
delete: true,
|
delete: true,
|
||||||
|
i18n: true,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
label: "Имя",
|
label: "Имя",
|
||||||
name: "firstName",
|
name: "firstName",
|
||||||
widget: "string",
|
widget: "string",
|
||||||
required: true,
|
required: true,
|
||||||
|
i18n: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Фамилия",
|
label: "Фамилия",
|
||||||
name: "lastName",
|
name: "lastName",
|
||||||
widget: "string",
|
widget: "string",
|
||||||
required: true,
|
required: true,
|
||||||
|
i18n: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Об авторе",
|
label: "Об авторе",
|
||||||
name: "body",
|
name: "body",
|
||||||
widget: "markdown",
|
widget: "markdown",
|
||||||
required: false,
|
required: false,
|
||||||
|
i18n: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -199,6 +207,7 @@ export default defineConfig({
|
|||||||
name: "projects",
|
name: "projects",
|
||||||
label: "Проекты",
|
label: "Проекты",
|
||||||
label_singular: "проект",
|
label_singular: "проект",
|
||||||
|
description: "Основные проекты, которые были разработаны в выложены в открытый доступ",
|
||||||
folder: "src/content/projects",
|
folder: "src/content/projects",
|
||||||
create: true,
|
create: true,
|
||||||
delete: true,
|
delete: true,
|
||||||
@ -211,18 +220,9 @@ export default defineConfig({
|
|||||||
required: true,
|
required: true,
|
||||||
i18n: true,
|
i18n: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "draft",
|
|
||||||
label: "В черновике",
|
|
||||||
widget: "boolean",
|
|
||||||
required: true,
|
|
||||||
i18n: true,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "title",
|
name: "title",
|
||||||
label: "Название",
|
label: "Название",
|
||||||
default: "my-project",
|
|
||||||
widget: "string",
|
widget: "string",
|
||||||
required: true,
|
required: true,
|
||||||
i18n: true,
|
i18n: true,
|
||||||
@ -231,7 +231,6 @@ export default defineConfig({
|
|||||||
name: "year",
|
name: "year",
|
||||||
label: "В каком году разработал",
|
label: "В каком году разработал",
|
||||||
widget: "number",
|
widget: "number",
|
||||||
default: 2023,
|
|
||||||
required: true,
|
required: true,
|
||||||
i18n: true,
|
i18n: true,
|
||||||
},
|
},
|
||||||
@ -308,9 +307,9 @@ export default defineConfig({
|
|||||||
label: "Настройки",
|
label: "Настройки",
|
||||||
files: [
|
files: [
|
||||||
{
|
{
|
||||||
name: "site-settings",
|
name: "siteconfig",
|
||||||
label: "Настройки веб-сайта",
|
label: "Настройки веб-сайта",
|
||||||
file: "src/content/site-settings.md",
|
file: "siteconfig.json",
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
label: "Глобальный заголовок",
|
label: "Глобальный заголовок",
|
||||||
@ -320,8 +319,9 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "В разработке",
|
label: "В разработке",
|
||||||
name: "isUnderConstruction",
|
name: "isSiteUnderConstruction",
|
||||||
widget: "boolean",
|
widget: "boolean",
|
||||||
|
required: false,
|
||||||
default: false,
|
default: false,
|
||||||
hint: "Отображает баннер на всех старницах о том, что веб-сайт находится в разработке",
|
hint: "Отображает баннер на всех старницах о том, что веб-сайт находится в разработке",
|
||||||
},
|
},
|
||||||
|
|||||||
1178
package-lock.json
generated
1178
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -19,11 +19,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/image": "^0.14.1",
|
"@astrojs/image": "^0.14.1",
|
||||||
"@astrojs/mdx": "^0.16.0",
|
|
||||||
"@astrojs/rss": "^2.1.0",
|
"@astrojs/rss": "^2.1.0",
|
||||||
"@astrojs/sitemap": "^1.0.1",
|
"@astrojs/sitemap": "^1.0.1",
|
||||||
"@astrojs/solid-js": "^2.0.2",
|
"@astrojs/solid-js": "^2.0.2",
|
||||||
"@netlify/functions": "^1.4.0",
|
"@netlify/functions": "^1.4.0",
|
||||||
|
"@sindresorhus/slugify": "^2.2.0",
|
||||||
"astro": "^2.0.10",
|
"astro": "^2.0.10",
|
||||||
"astro-icon": "^0.8.0",
|
"astro-icon": "^0.8.0",
|
||||||
"astro-netlify-cms": "^0.5.3",
|
"astro-netlify-cms": "^0.5.3",
|
||||||
|
|||||||
7
siteconfig.json
Normal file
7
siteconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"globalTitle": "Sergey Yarkov",
|
||||||
|
"articles": {
|
||||||
|
"recentLimit": 5
|
||||||
|
},
|
||||||
|
"isSiteUnderConstruction": false
|
||||||
|
}
|
||||||
@ -38,6 +38,10 @@ const { url, id } = Astro.props as Props;
|
|||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
"onthemetoggled",
|
"onthemetoggled",
|
||||||
() =>
|
() =>
|
||||||
document.readyState == "complete" && setTimeout(() => DISQUS.reset({ reload: true, config: disqus_config }), 100)
|
document.readyState == "complete" &&
|
||||||
|
setTimeout(
|
||||||
|
() => "DISQUS" in window && DISQUS.reset({ reload: true, config: disqus_config }),
|
||||||
|
100
|
||||||
|
)
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
225
src/components/ArticleContent.astro
Normal file
225
src/components/ArticleContent.astro
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
<div itemprop="articleBody" class="article-content"><slot /></div>
|
||||||
|
|
||||||
|
<style lang="scss" is:global>
|
||||||
|
.article-content {
|
||||||
|
& h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
margin-top: 3rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& p,
|
||||||
|
em,
|
||||||
|
q {
|
||||||
|
line-height: var(--line-height-base);
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
& p {
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& ul,
|
||||||
|
ol {
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
line-height: var(--line-height-base);
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
& li {
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
line-height: var(--line-height-base);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
padding-left: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& q {
|
||||||
|
font-style: italic;
|
||||||
|
quotes: "« " " »";
|
||||||
|
}
|
||||||
|
|
||||||
|
& a {
|
||||||
|
color: var(--font-color);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: var(--color-blue-500);
|
||||||
|
text-underline-offset: 2.2px;
|
||||||
|
text-decoration-thickness: 2px;
|
||||||
|
font-weight: 500;
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-blue-500);
|
||||||
|
text-decoration-thickness: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& figure {
|
||||||
|
margin: 0 0 1em;
|
||||||
|
& figcaption {
|
||||||
|
color: var(--color-gray-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& hr {
|
||||||
|
background-color: var(--border-color);
|
||||||
|
margin: 40px 0;
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& pre {
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
border-radius: var(--border-radius-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
& :not(pre) > code {
|
||||||
|
-webkit-font-smoothing: subpixel-antialiased;
|
||||||
|
background: var(--background-inline-code);
|
||||||
|
border-radius: var(--border-radius-lg);
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: "IBM Plex Mono", monospace;
|
||||||
|
padding: 0.2rem 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& figcaption {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 1em;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0.7rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .table-wrapper {
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& table {
|
||||||
|
display: table;
|
||||||
|
border-radius: var(--border-radius-md);
|
||||||
|
min-width: 100%;
|
||||||
|
font-size: var(--font-size-md);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
margin: 5px 0;
|
||||||
|
& thead th {
|
||||||
|
background-color: var(--background-card);
|
||||||
|
border-top-left-radius: var(--border-radius-md);
|
||||||
|
border-top-right-radius: var(--border-radius-md);
|
||||||
|
}
|
||||||
|
& td,
|
||||||
|
th {
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
padding: 0.5rem;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
& tbody tr:last-child td {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& li {
|
||||||
|
list-style: disc;
|
||||||
|
& li {
|
||||||
|
list-style-type: circle;
|
||||||
|
}
|
||||||
|
&::marker {
|
||||||
|
color: var(--color-blue-500);
|
||||||
|
font-size: 1.3rem;
|
||||||
|
line-height: var(--line-height-none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& blockquote {
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
font-style: italic;
|
||||||
|
border-left: 0.25rem solid var(--border-color);
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .heading-wrapper {
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
margin: 3rem 0 1rem 0;
|
||||||
|
padding-bottom: 0.35rem;
|
||||||
|
|
||||||
|
& h2 {
|
||||||
|
font-size: var(--font-size-2xl);
|
||||||
|
}
|
||||||
|
|
||||||
|
& h3 {
|
||||||
|
font-size: var(--font-size-xl);
|
||||||
|
}
|
||||||
|
|
||||||
|
& h4 {
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
& h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .heading-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-inline-start: 1px;
|
||||||
|
& .anchor-link {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
text-decoration: none;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
opacity: 0;
|
||||||
|
& .anchor-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: -25px;
|
||||||
|
top: -13px;
|
||||||
|
}
|
||||||
|
& svg {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& .anchor-label {
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
& .anchor-link {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& .languages-available {
|
||||||
|
margin: 25px 0;
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 800px) {
|
||||||
|
.article-content {
|
||||||
|
& .heading-wrapper {
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
& .anchor-link {
|
||||||
|
& .anchor-icon {
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
import "./ArticleContent.scss";
|
|
||||||
---
|
|
||||||
|
|
||||||
<div itemprop="articleBody" class="article-content"><slot /></div>
|
|
||||||
@ -1,221 +0,0 @@
|
|||||||
.article-content {
|
|
||||||
& h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
margin-top: 3rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
& p,
|
|
||||||
em,
|
|
||||||
q {
|
|
||||||
line-height: var(--line-height-base);
|
|
||||||
font-size: var(--font-size-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
& p {
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& ul,
|
|
||||||
ol {
|
|
||||||
padding-left: 1.5rem;
|
|
||||||
line-height: var(--line-height-base);
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
& li {
|
|
||||||
font-size: var(--font-size-lg);
|
|
||||||
line-height: var(--line-height-base);
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
padding-left: 0.25rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& q {
|
|
||||||
font-style: italic;
|
|
||||||
quotes: "« " " »";
|
|
||||||
}
|
|
||||||
|
|
||||||
& a {
|
|
||||||
color: var(--font-color);
|
|
||||||
text-decoration: underline;
|
|
||||||
text-decoration-color: var(--color-blue-500);
|
|
||||||
text-underline-offset: 2.2px;
|
|
||||||
text-decoration-thickness: 2px;
|
|
||||||
font-weight: 500;
|
|
||||||
&:hover {
|
|
||||||
color: var(--color-blue-500);
|
|
||||||
text-decoration-thickness: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& figure {
|
|
||||||
margin: 0 0 1em;
|
|
||||||
& figcaption {
|
|
||||||
color: var(--color-gray-400);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& hr {
|
|
||||||
background-color: var(--border-color);
|
|
||||||
margin: 40px 0;
|
|
||||||
border: none;
|
|
||||||
height: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
& pre {
|
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
border-radius: var(--border-radius-md);
|
|
||||||
}
|
|
||||||
|
|
||||||
& :not(pre) > code {
|
|
||||||
-webkit-font-smoothing: subpixel-antialiased;
|
|
||||||
background: var(--background-inline-code);
|
|
||||||
border-radius: var(--border-radius-lg);
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 500;
|
|
||||||
font-family: "IBM Plex Mono", monospace;
|
|
||||||
padding: 0.2rem 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
& figcaption {
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 1em;
|
|
||||||
text-align: center;
|
|
||||||
margin: 0.7rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .table-wrapper {
|
|
||||||
overflow-x: auto;
|
|
||||||
margin-bottom: 1.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
& table {
|
|
||||||
display: table;
|
|
||||||
border-radius: var(--border-radius-md);
|
|
||||||
min-width: 100%;
|
|
||||||
font-size: var(--font-size-md);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-collapse: separate;
|
|
||||||
border-spacing: 0;
|
|
||||||
margin: 5px 0;
|
|
||||||
& thead th {
|
|
||||||
background-color: var(--background-card);
|
|
||||||
border-top-left-radius: var(--border-radius-md);
|
|
||||||
border-top-right-radius: var(--border-radius-md);
|
|
||||||
}
|
|
||||||
& td,
|
|
||||||
th {
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
padding: 0.5rem;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
& tbody tr:last-child td {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& li {
|
|
||||||
list-style: disc;
|
|
||||||
& li {
|
|
||||||
list-style-type: circle;
|
|
||||||
}
|
|
||||||
&::marker {
|
|
||||||
color: var(--color-blue-500);
|
|
||||||
font-size: 1.3rem;
|
|
||||||
line-height: var(--line-height-none);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& blockquote {
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
font-style: italic;
|
|
||||||
border-left: 0.25rem solid var(--border-color);
|
|
||||||
padding-left: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .heading-wrapper {
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
margin: 3rem 0 1rem 0;
|
|
||||||
padding-bottom: 0.35rem;
|
|
||||||
|
|
||||||
& h2 {
|
|
||||||
font-size: var(--font-size-2xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
& h3 {
|
|
||||||
font-size: var(--font-size-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
& h4 {
|
|
||||||
font-size: var(--font-size-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
& h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .heading-wrapper {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
justify-content: flex-end;
|
|
||||||
margin-inline-start: 1px;
|
|
||||||
& .anchor-link {
|
|
||||||
position: relative;
|
|
||||||
display: inline-flex;
|
|
||||||
text-decoration: none;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
opacity: 0;
|
|
||||||
& .anchor-icon {
|
|
||||||
position: absolute;
|
|
||||||
left: -25px;
|
|
||||||
top: -13px;
|
|
||||||
}
|
|
||||||
& svg {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .anchor-label {
|
|
||||||
position: absolute;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
& .anchor-link {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .languages-available {
|
|
||||||
margin: 25px 0;
|
|
||||||
font-size: var(--font-size-lg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 800px) {
|
|
||||||
.article-content {
|
|
||||||
& .heading-wrapper {
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
& .anchor-link {
|
|
||||||
& .anchor-icon {
|
|
||||||
left: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
34
src/components/ArticleCover.astro
Normal file
34
src/components/ArticleCover.astro
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
import { Picture } from "@astrojs/image/components";
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
src: string;
|
||||||
|
alt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { src, alt } = Astro.props as Props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="cover">
|
||||||
|
<figure>
|
||||||
|
<Picture
|
||||||
|
itemprop="image"
|
||||||
|
src={src}
|
||||||
|
sizes="(max-width: 450px) 450px, 700px"
|
||||||
|
widths={[450, 700]}
|
||||||
|
formats={["webp"]}
|
||||||
|
aspectRatio={"16:9"}
|
||||||
|
alt={alt ? alt : ""}
|
||||||
|
background={"chocolate"}
|
||||||
|
/>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.cover {
|
||||||
|
margin: 20px 0;
|
||||||
|
& figure {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,29 +1,44 @@
|
|||||||
---
|
---
|
||||||
import { getLanguageFromURL } from "@i18n/utils";
|
import type { CollectionEntry } from "astro:content";
|
||||||
|
import slugify from "@sindresorhus/slugify";
|
||||||
|
import { URL_BLOG_PREFIX } from "@root/pages/[...blog].astro";
|
||||||
import { DEFAULT_LANGUAGE } from "@root/constants";
|
import { DEFAULT_LANGUAGE } from "@root/constants";
|
||||||
|
import { getLanguageFromURL } from "@i18n/utils";
|
||||||
import { createDateFormatter } from "@root/utils";
|
import { createDateFormatter } from "@root/utils";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
href: string;
|
entry: CollectionEntry<"blog">;
|
||||||
title: string;
|
|
||||||
date: Date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const lang = getLanguageFromURL(Astro.url.pathname);
|
const pageLang = getLanguageFromURL(Astro.url.pathname);
|
||||||
// const isNonDefaultLanguage = DEFAULT_LANGUAGE !== lang;
|
const {
|
||||||
|
entry: {
|
||||||
const { href, title, date } = Astro.props as Props;
|
id,
|
||||||
|
data: { title, pubDate },
|
||||||
|
},
|
||||||
|
} = Astro.props as Props;
|
||||||
|
const slug = slugify(title, { lowercase: true });
|
||||||
|
const articleLang = id.split("/")[0];
|
||||||
---
|
---
|
||||||
|
|
||||||
<article itemprop="blogPosts" itemscope itemtype="http://schema.org/BlogPosting" class="article-item">
|
<article
|
||||||
<a href={href}>
|
itemprop="blogPosts"
|
||||||
|
itemscope
|
||||||
|
itemtype="http://schema.org/BlogPosting"
|
||||||
|
class="article-item"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={articleLang === DEFAULT_LANGUAGE
|
||||||
|
? `/${URL_BLOG_PREFIX}/${pubDate.toISOString().split("T")[0]}/${slug}`
|
||||||
|
: `/${articleLang}/${URL_BLOG_PREFIX}/${pubDate.toISOString().split("T")[0]}/${slug}`}
|
||||||
|
>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<h3 itemprop="headline">{title}</h3>
|
<h3 itemprop="headline">{title}</h3>
|
||||||
<!-- {isNonDefaultLanguage && <sup>{lang.toLocaleUpperCase()}</sup>} -->
|
{articleLang !== pageLang && <sup>{articleLang.toLocaleUpperCase()}</sup>}
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
<time datetime={date.toString()}>
|
<time datetime={pubDate.toISOString()}>
|
||||||
{createDateFormatter(lang).format(date)}
|
{createDateFormatter(pageLang).format(pubDate)}
|
||||||
</time>
|
</time>
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@ -1,23 +1,24 @@
|
|||||||
---
|
---
|
||||||
import { Picture } from "@astrojs/image/components";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import { Icon } from "astro-icon";
|
import { Icon } from "astro-icon";
|
||||||
import { createDateFormatter } from "@root/utils";
|
import { createDateFormatter } from "@root/utils";
|
||||||
// import { isURL } from "@utils/string";
|
import ArticleCover from "@components/ArticleCover.astro";
|
||||||
import ArticleComments from "@components/ArticleComments.astro";
|
import ArticleComments from "@components/ArticleComments.astro";
|
||||||
// import TranslatedLink from "../TranslatedLink";
|
// import TranslatedLink from "../TranslatedLink";
|
||||||
import type { CollectionEntry } from "astro:content";
|
// import { useTranslation } from "@i18n/utils";
|
||||||
// import { useTranslation } from "@root/i18n/utils";
|
|
||||||
import "./ArticlePost.scss";
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
article: CollectionEntry<"blog">;
|
article: CollectionEntry<"blog">;
|
||||||
lang: string;
|
lang: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { article, lang } = Astro.props as Props;
|
const { article, lang } = Astro.props as Props;
|
||||||
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
|
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
|
||||||
const {
|
const {
|
||||||
data: { coverImage, title, author, description, tags, pubDate },
|
data: { coverImage, title, author, description, tags, pubDate },
|
||||||
slug,
|
slug,
|
||||||
} = article;
|
} = article;
|
||||||
|
|
||||||
// const t = useTranslation(Astro);
|
// const t = useTranslation(Astro);
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -53,24 +54,7 @@ const {
|
|||||||
>
|
>
|
||||||
<span itemprop="author">{author}</span>
|
<span itemprop="author">{author}</span>
|
||||||
</div>
|
</div>
|
||||||
{
|
{coverImage && <ArticleCover src={coverImage} alt={title} />}
|
||||||
coverImage && (
|
|
||||||
<div class="cover">
|
|
||||||
<figure>
|
|
||||||
<Picture
|
|
||||||
itemprop="image"
|
|
||||||
src={coverImage}
|
|
||||||
sizes="(max-width: 450px) 450px, 700px"
|
|
||||||
widths={[450, 700]}
|
|
||||||
formats={["webp"]}
|
|
||||||
aspectRatio={"16:9"}
|
|
||||||
alt={title}
|
|
||||||
background={"chocolate"}
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<p>
|
<p>
|
||||||
{description}
|
{description}
|
||||||
@ -81,8 +65,9 @@ const {
|
|||||||
<ArticleComments url={canonicalUrl.href} id={slug} />
|
<ArticleComments url={canonicalUrl.href} id={slug} />
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<script define:vars={{ slug }}>
|
<script define:vars={{ slug, IS_DEV: import.meta.env.DEV }}>
|
||||||
(async () => {
|
(async () => {
|
||||||
|
if (IS_DEV) return;
|
||||||
const response = await fetch(`/api/views?slug=${slug}`, { method: "POST" });
|
const response = await fetch(`/api/views?slug=${slug}`, { method: "POST" });
|
||||||
if (!response.ok) return;
|
if (!response.ok) return;
|
||||||
const views = await response.text();
|
const views = await response.text();
|
||||||
@ -91,3 +76,98 @@ const {
|
|||||||
if ($views) $views.textContent = views;
|
if ($views) $views.textContent = views;
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" is:global>
|
||||||
|
.article {
|
||||||
|
& header {
|
||||||
|
& div:nth-child(1) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
& .views {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
& span {
|
||||||
|
margin-left: 3.5px;
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
color: var(--font-color-grayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& .heading {
|
||||||
|
margin-top: 1.125rem;
|
||||||
|
|
||||||
|
& h1 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 2.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& p {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: var(--line-height-base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .tags {
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
text-transform: uppercase;
|
||||||
|
& ul {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
column-gap: 7px;
|
||||||
|
row-gap: 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .published {
|
||||||
|
margin-bottom: 1.25em;
|
||||||
|
color: var(--font-color-gray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .cover {
|
||||||
|
margin: 20px 0;
|
||||||
|
& figure {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .description p {
|
||||||
|
line-height: var(--line-height-base);
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
& footer {
|
||||||
|
margin-top: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& img {
|
||||||
|
border-radius: var(--border-radius-lg);
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
&:not([src*=".svg"]) {
|
||||||
|
filter: var(--image-filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 560px) {
|
||||||
|
.article {
|
||||||
|
& header {
|
||||||
|
& div:nth-child(1) {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
& .tags {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& .heading h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,92 +0,0 @@
|
|||||||
.article {
|
|
||||||
& header {
|
|
||||||
& div:nth-child(1) {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
& .views {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
& span {
|
|
||||||
margin-left: 3.5px;
|
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
color: var(--font-color-grayer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .heading {
|
|
||||||
margin-top: 1.125rem;
|
|
||||||
|
|
||||||
& h1 {
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 2.125rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
& p {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
line-height: var(--line-height-base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .tags {
|
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
text-transform: uppercase;
|
|
||||||
& ul {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
column-gap: 7px;
|
|
||||||
row-gap: 7px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .published {
|
|
||||||
margin-bottom: 1.25em;
|
|
||||||
color: var(--font-color-gray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .cover {
|
|
||||||
margin: 20px 0;
|
|
||||||
& figure {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .description p {
|
|
||||||
line-height: var(--line-height-base);
|
|
||||||
font-size: var(--font-size-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
& footer {
|
|
||||||
margin-top: 5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
& img {
|
|
||||||
border-radius: var(--border-radius-lg);
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
|
|
||||||
&:not([src*=".svg"]) {
|
|
||||||
filter: var(--image-filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 560px) {
|
|
||||||
.article {
|
|
||||||
& header {
|
|
||||||
& div:nth-child(1) {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
& .tags {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .heading h1 {
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -9,7 +9,6 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
||||||
|
|
||||||
const { title, description } = Astro.props;
|
const { title, description } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,12 @@
|
|||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import ArticleItem from "@components/ArticleItem.astro";
|
import ArticleItem from "@components/ArticleItem.astro";
|
||||||
import EmptyList from "@components/EmptyList.astro";
|
import EmptyList from "@components/EmptyList.astro";
|
||||||
|
import siteconfig from "siteconfig.json";
|
||||||
export interface Props {
|
export interface Props {
|
||||||
articles: CollectionEntry<"blog">[];
|
articles: CollectionEntry<"blog">[];
|
||||||
length?: number | undefined;
|
length?: number | undefined;
|
||||||
}
|
}
|
||||||
const { articles, length = 5 } = Astro.props as Props;
|
const { articles, length = siteconfig.articles.recentLimit } = Astro.props as Props;
|
||||||
const isEmpty = articles.length === 0;
|
const isEmpty = articles.length === 0;
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -19,11 +20,7 @@ const isEmpty = articles.length === 0;
|
|||||||
<div itemscope itemtype="http://schema.org/Blog">
|
<div itemscope itemtype="http://schema.org/Blog">
|
||||||
{
|
{
|
||||||
!isEmpty ? (
|
!isEmpty ? (
|
||||||
articles
|
articles.slice(0, length).map((article) => <ArticleItem entry={article} />)
|
||||||
.slice(0, length)
|
|
||||||
.map((article) => (
|
|
||||||
<ArticleItem href={`/articles/${article.slug}`} title={article.data.title} date={article.data.pubDate} />
|
|
||||||
))
|
|
||||||
) : (
|
) : (
|
||||||
<EmptyList />
|
<EmptyList />
|
||||||
)
|
)
|
||||||
|
|||||||
69
src/components/SkillsBlock.astro
Normal file
69
src/components/SkillsBlock.astro
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
import { Icon } from "astro-icon";
|
||||||
|
import type { CollectionEntry } from "astro:content";
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
data: CollectionEntry<"skills">["data"];
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { title, list },
|
||||||
|
} = Astro.props as Props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="skills-block">
|
||||||
|
<div>
|
||||||
|
<h3>{title}</h3>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
{
|
||||||
|
list.map((entry) => (
|
||||||
|
<li>
|
||||||
|
{entry.icon && <Icon name={entry.icon} width="20" height="20" />}
|
||||||
|
{entry.title}
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.skills-block {
|
||||||
|
& h3 {
|
||||||
|
font-size: var(--font-size-md);
|
||||||
|
color: var(--font-color-grayer);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
& ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
& li {
|
||||||
|
font-weight: 400;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 500px) {
|
||||||
|
.skills-block {
|
||||||
|
& h3 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
& ul {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
20
src/components/SkillsList.astro
Normal file
20
src/components/SkillsList.astro
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="skills-list"><slot /></div>
|
||||||
|
<style lang="scss">
|
||||||
|
.skills-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
|
column-gap: 40px;
|
||||||
|
row-gap: 30px;
|
||||||
|
margin-top: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 500px) {
|
||||||
|
.skills-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,13 +1,10 @@
|
|||||||
|
import siteconfig from "../siteconfig.json";
|
||||||
|
|
||||||
export const DEFAULT_LANGUAGE: LanguageKeys = "ru";
|
export const DEFAULT_LANGUAGE: LanguageKeys = "ru";
|
||||||
|
export const IS_SITE_UNDER_CONSTRUCTION = siteconfig.isSiteUnderConstruction;
|
||||||
/* Show banner about website development */
|
|
||||||
export const IS_SITE_UNDER_CONSTRUCTION =
|
|
||||||
import.meta.env.IS_SITE_UNDER_CONSTRUCTION === "true" ? true : false;
|
|
||||||
|
|
||||||
export const SUPPORTED_LANGUAGES: SupportedLanguages = ["ru", "en"];
|
export const SUPPORTED_LANGUAGES: SupportedLanguages = ["ru", "en"];
|
||||||
|
|
||||||
export const SITE_METADATA: SiteMetadataType = {
|
export const SITE_METADATA: SiteMetadataType = {
|
||||||
title: "Sergey Yarkov",
|
title: siteconfig.globalTitle,
|
||||||
name: "yarkov.tech",
|
name: "yarkov.tech",
|
||||||
author: "Sergey Yarkov",
|
author: "Sergey Yarkov",
|
||||||
themeColor: "#1e2327",
|
themeColor: "#1e2327",
|
||||||
|
|||||||
24
src/content/authors/en/сергей-ярков.md
Normal file
24
src/content/authors/en/сергей-ярков.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
firstName: Sergey
|
||||||
|
lastName: Yarkov
|
||||||
|
---
|
||||||
|
My name is Sergey and I am a web developer. My main activity is creating web sites. I am interested in areas such as programming, embedded systems, and electronics.
|
||||||
|
I started making web sites in 2017, starting with simple HTML pages, and in 2019 I started learning programming. At present, I have experience in **full-stack** web development of client-server applications that solve a wide range of tasks.
|
||||||
|
Some of my personal [projects](/projects/) I put in public access on [Github](https://github.com/sergeyyarkov).
|
||||||
|
|
||||||
|
## Purpose of this site
|
||||||
|
|
||||||
|
I originally created this website for myself, to consolidate my knowledge by writing articles.
|
||||||
|
Since 2022, I have been posting materials on this website, and now at any time I can return to any topic and learn it again.
|
||||||
|
My articles can also help someone with mastering a particular topic. The main direction of this site is IT,
|
||||||
|
and [here](/articles/) I publish materials on topics that interest me, as well as talk about my [projects](/projects/).
|
||||||
|
I am absolutely calm about any criticism and I do not claim to be the best programmer in the world,
|
||||||
|
so do not judge the materials of this resource harshly.
|
||||||
|
|
||||||
|
## Skills
|
||||||
|
|
||||||
|
This list shows the skills and technologies that I have used/use in my projects.
|
||||||
|
For creating web projects, I use **Node.js** and the **Adonis.js** framework for the server-side.
|
||||||
|
For the client-side, I develop using **React.js** or **Alpine.js**.
|
||||||
|
|
||||||
|
<q>this website is made using the [**Astro.js**](https://astro.build) framework and [**Solid.js**](https://www.solidjs.com/) library.</q>
|
||||||
28
src/content/authors/ru/сергей-ярков.md
Normal file
28
src/content/authors/ru/сергей-ярков.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
firstName: Сергей
|
||||||
|
lastName: Ярков
|
||||||
|
---
|
||||||
|
Мое имя **Сергей** я являюсь веб-разработчиком. Основной деятельностью моей работы является создание веб-сайтов.
|
||||||
|
Мне интересны такие сферы как программирование, встраиваемые системы и электроника.
|
||||||
|
Веб-сайты я начал делать с 2017 года начиная с верстки простых HTML страничек и с 2019 года я начал
|
||||||
|
обучаться программированием и на сегодняшний момент я имею опыт в **full-stack** веб-разработке клиент-серверных приложений,
|
||||||
|
которые решают самые разные задачи.
|
||||||
|
Некоторые из своих личных [проектов](/projects/) я выкладываю в общий доступ на [Github](https://github.com/sergeyyarkov).
|
||||||
|
|
||||||
|
## Зачем этот сайт
|
||||||
|
|
||||||
|
Первоначально я создал этот сайт для себя, чтобы закреплять свои знания путем написания статей. С 2022 года я начал
|
||||||
|
выкладывать материалы на этот сайт и сейчас в любой момент я могу вернуться к какой-либо теме и еще раз её усвоить.
|
||||||
|
Мои статьи также смогут кому-то помочь с освоением какой-либо темы.
|
||||||
|
Главным направлением этого сайта является IT, и [здесь](/articles/) я публикую материалы на темы, которые меня интересуют,
|
||||||
|
а также рассказываю о своих [проектах](/projects/).
|
||||||
|
Я отношусь абсолютно спокойно к любой критике и я не претендую на звание лучшего программиста в мире, поэтому
|
||||||
|
не судите строго материалы этого ресурса.
|
||||||
|
|
||||||
|
## Навыки
|
||||||
|
|
||||||
|
Этот список показывает имеющиеся у меня навыки и технологии которые я когда-либо использовал/использую в своих проектах.
|
||||||
|
Для создания веб-проектов в качестве серверной части я использую **Node.js** и фреймворк **Adonis.js**.
|
||||||
|
Клиентскую часть я разрабатываю на **React.js** или **Alpine.js**.
|
||||||
|
|
||||||
|
<q>этот веб-сайт сделан с помощью фреймворка **[Astro.js](https://astro.build)** и библиотеки **[Solid.js](https://www.solidjs.com/)**</q>
|
||||||
@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
firstName: Sergey
|
|
||||||
lastName: Yarkov
|
|
||||||
---
|
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
coverImage: /media/serial-port.jpg
|
||||||
|
draft: false
|
||||||
|
author: Sergey Yarkov
|
||||||
|
title: Using the WebSerial API to communicate with the microcontroller
|
||||||
|
description: We will talk about what is WebSerial API, how it can be used in a
|
||||||
|
browser to read and write data to a serial device and where it can be applied.
|
||||||
|
tags:
|
||||||
|
- JavaScript
|
||||||
|
- AVR
|
||||||
|
- WebSerial API
|
||||||
|
- Tutorial
|
||||||
|
pubDate: 2022-11-04T21:00:00.000Z
|
||||||
|
updatedDate: 2023-02-13T16:34:23.326Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# ...
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
coverImage: null
|
||||||
|
draft: false
|
||||||
|
author: Sergey Yarkov
|
||||||
|
title: 74HC595 shift register control by microcontroller
|
||||||
|
description: This tutorial shows how to control the shift register of the
|
||||||
|
74HC595 in conjunction with the AVR microcontroller.
|
||||||
|
tags:
|
||||||
|
- AVR
|
||||||
|
- Digital Electronics
|
||||||
|
- Tutorial
|
||||||
|
pubDate: 2023-02-14T19:23:55.622Z
|
||||||
|
updatedDate: 2023-02-14T19:23:55.646Z
|
||||||
|
---
|
||||||
|
|
||||||
|
...
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
draft: false
|
||||||
|
author: Sergey Yarkov
|
||||||
|
title: Управление сдвиговым регистром 74HC595 микрокотнороллером
|
||||||
|
description: В этом туториале рассматривается то, как управлять сдвиговым
|
||||||
|
регистром 74HC595 в связке с микроконтроллером AVR.
|
||||||
|
tags:
|
||||||
|
- AVR
|
||||||
|
- Digital Electronics
|
||||||
|
- Tutorial
|
||||||
|
pubDate: 2023-02-14T19:23:55.622Z
|
||||||
|
updatedDate: 2023-02-14T19:23:55.646Z
|
||||||
|
---
|
||||||
|
|
||||||
|
...
|
||||||
@ -3,7 +3,8 @@ import { defineCollection, z } from "astro:content";
|
|||||||
const blog = defineCollection({
|
const blog = defineCollection({
|
||||||
schema: z.object({
|
schema: z.object({
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
coverImage: z.string().optional(),
|
draft: z.boolean().optional(),
|
||||||
|
coverImage: z.string().nullable().optional(),
|
||||||
author: z.string(),
|
author: z.string(),
|
||||||
tags: z.string().array().optional(),
|
tags: z.string().array().optional(),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
@ -16,7 +17,6 @@ const blog = defineCollection({
|
|||||||
.or(z.date())
|
.or(z.date())
|
||||||
.optional()
|
.optional()
|
||||||
.transform((str) => (str ? new Date(str) : undefined)),
|
.transform((str) => (str ? new Date(str) : undefined)),
|
||||||
draft: z.boolean(),
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -42,7 +42,6 @@ const projects = defineCollection({
|
|||||||
sourceUrl: z.string(),
|
sourceUrl: z.string(),
|
||||||
demoUrl: z.string().nullable().optional(),
|
demoUrl: z.string().nullable().optional(),
|
||||||
articleUrl: z.string().nullable().optional(),
|
articleUrl: z.string().nullable().optional(),
|
||||||
draft: z.boolean(),
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: triangle_filled
|
icon: triangle_filled
|
||||||
draft: false
|
|
||||||
title: devthread
|
title: devthread
|
||||||
year: 2021
|
year: 2021
|
||||||
description: Static website for publishing various articles, developed with
|
description: Static website for publishing various articles, developed with
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: round-shop-two
|
icon: round-shop-two
|
||||||
draft: false
|
|
||||||
title: digital-store
|
title: digital-store
|
||||||
year: 2019
|
year: 2019
|
||||||
description: Customizable online store with control panel for selling digital goods
|
description: Customizable online store with control panel for selling digital goods
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: round-school
|
icon: round-school
|
||||||
draft: false
|
|
||||||
title: educt
|
title: educt
|
||||||
year: 2022
|
year: 2022
|
||||||
description: Learning Management System (LMS) to publish your courses, lectures, lessons
|
description: Learning Management System (LMS) to publish your courses, lectures, lessons
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: chip
|
icon: chip
|
||||||
draft: false
|
|
||||||
title: memory-led-game
|
title: memory-led-game
|
||||||
year: 2022
|
year: 2022
|
||||||
description: Analogue of the popular game "Simon says" on the AVR microcontroller
|
description: Analogue of the popular game "Simon says" on the AVR microcontroller
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: nodejs
|
icon: nodejs
|
||||||
draft: false
|
|
||||||
title: node-docker-example
|
title: node-docker-example
|
||||||
year: 2022
|
year: 2022
|
||||||
description: An example of using Docker to deploy a Node.js application
|
description: An example of using Docker to deploy a Node.js application
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: chat
|
icon: chat
|
||||||
draft: false
|
|
||||||
title: react-chat-app
|
title: react-chat-app
|
||||||
year: 2021
|
year: 2021
|
||||||
description: Client-server web chat application developed with Node.js and Socket.io
|
description: Client-server web chat application developed with Node.js and Socket.io
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: serial
|
icon: serial
|
||||||
draft: false
|
|
||||||
title: web-serial-example
|
title: web-serial-example
|
||||||
year: 2022
|
year: 2022
|
||||||
description: An example of using the Web Serial API to interact with the
|
description: An example of using the Web Serial API to interact with the
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: book
|
icon: book
|
||||||
draft: false
|
|
||||||
title: yarkov.tech
|
title: yarkov.tech
|
||||||
year: 2023
|
year: 2023
|
||||||
description: My personal website where you can find information about me and a
|
description: My personal website where you can find information about me and a
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: triangle_filled
|
icon: triangle_filled
|
||||||
draft: false
|
|
||||||
title: devthread
|
title: devthread
|
||||||
year: 2021
|
year: 2021
|
||||||
description: Статический веб-сайт для публикации различных статей, разработанный
|
description: Статический веб-сайт для публикации различных статей, разработанный
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: round-shop-two
|
icon: round-shop-two
|
||||||
draft: false
|
|
||||||
title: digital-store
|
title: digital-store
|
||||||
year: 2019
|
year: 2019
|
||||||
description: Настраиваемый интернет-магазин с панелью управления для продажи
|
description: Настраиваемый интернет-магазин с панелью управления для продажи
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: round-school
|
icon: round-school
|
||||||
draft: false
|
|
||||||
title: educt
|
title: educt
|
||||||
year: 2022
|
year: 2022
|
||||||
description: Система управления обучением (LMS) для публикации ваших курсов, лекций, уроков
|
description: Система управления обучением (LMS) для публикации ваших курсов, лекций, уроков
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: chip
|
icon: chip
|
||||||
draft: false
|
|
||||||
title: memory-led-game
|
title: memory-led-game
|
||||||
year: 2022
|
year: 2022
|
||||||
description: Аналог популярной игры "Саймон говорит" на AVR микроконтроллере
|
description: Аналог популярной игры "Саймон говорит" на AVR микроконтроллере
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: nodejs
|
icon: nodejs
|
||||||
draft: false
|
|
||||||
title: node-docker-example
|
title: node-docker-example
|
||||||
year: 2022
|
year: 2022
|
||||||
description: Пример использования Docker для развертывания Node.js приложения
|
description: Пример использования Docker для развертывания Node.js приложения
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: chat
|
icon: chat
|
||||||
draft: false
|
|
||||||
title: react-chat-app
|
title: react-chat-app
|
||||||
year: 2021
|
year: 2021
|
||||||
description: Клиент-серверное веб приложение чата разработанное при помощи
|
description: Клиент-серверное веб приложение чата разработанное при помощи
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: serial
|
icon: serial
|
||||||
draft: false
|
|
||||||
title: web-serial-example
|
title: web-serial-example
|
||||||
year: 2022
|
year: 2022
|
||||||
description: Пример использования Web Serial API для взаимодействия с
|
description: Пример использования Web Serial API для взаимодействия с
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
icon: book
|
icon: book
|
||||||
draft: false
|
|
||||||
title: yarkov.tech
|
title: yarkov.tech
|
||||||
year: 2023
|
year: 2023
|
||||||
description: Мой персональный веб-сайт где находятся информация обо мне и список
|
description: Мой персональный веб-сайт где находятся информация обо мне и список
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
globalTitle: yarkov.tech
|
|
||||||
articles:
|
|
||||||
recentLimit: 5
|
|
||||||
---
|
|
||||||
@ -3,8 +3,8 @@ import type { CollectionEntry } from "astro:content";
|
|||||||
import { DEFAULT_LANGUAGE, SITE_METADATA } from "@root/constants";
|
import { DEFAULT_LANGUAGE, SITE_METADATA } from "@root/constants";
|
||||||
import BaseHead from "@components/BaseHead.astro";
|
import BaseHead from "@components/BaseHead.astro";
|
||||||
import BaseLayout from "@components/BaseLayout.astro";
|
import BaseLayout from "@components/BaseLayout.astro";
|
||||||
import ArticleContent from "@components/ArticleContent/ArticleContent.astro";
|
import ArticleContent from "@components/ArticleContent.astro";
|
||||||
import ArticlePost from "@components/ArticlePost/ArticlePost.astro";
|
import ArticlePost from "@components/ArticlePost.astro";
|
||||||
import OpenGraph from "@components/OpenGraph.astro";
|
import OpenGraph from "@components/OpenGraph.astro";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
|||||||
36
src/pages/[...blog].astro
Normal file
36
src/pages/[...blog].astro
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
import { CollectionEntry, getCollection } from "astro:content";
|
||||||
|
import ArticleLayout from "@root/layouts/article.astro";
|
||||||
|
import { DEFAULT_LANGUAGE } from "@root/constants";
|
||||||
|
import slugify from "@sindresorhus/slugify";
|
||||||
|
|
||||||
|
export const URL_BLOG_PREFIX = "blog";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate articles pages from `blog` collection.
|
||||||
|
* The final url will be `http://website.com/blog/2023-01-01/my-article` with default language
|
||||||
|
* and `http://website.com/{language-code}/blog/2023-01-01/my-article` with other languages.
|
||||||
|
*/
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const collection = await getCollection("blog", (e) => !e.data.draft);
|
||||||
|
return collection.map((article) => {
|
||||||
|
const [languageCode] = article.slug.split("/");
|
||||||
|
const slug = slugify(article.data.title, { lowercase: true });
|
||||||
|
const pubDate = article.data.pubDate.toISOString().split("T")[0];
|
||||||
|
const url =
|
||||||
|
DEFAULT_LANGUAGE !== languageCode
|
||||||
|
? `${languageCode}/${URL_BLOG_PREFIX}/${pubDate}/${slug}`
|
||||||
|
: `${URL_BLOG_PREFIX}/${pubDate}/${slug}`;
|
||||||
|
|
||||||
|
return { params: { blog: url }, props: { article } };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = { article: CollectionEntry<"blog"> };
|
||||||
|
|
||||||
|
const { Content } = await Astro.props.article.render();
|
||||||
|
---
|
||||||
|
|
||||||
|
<ArticleLayout article={Astro.props.article}>
|
||||||
|
<Content />
|
||||||
|
</ArticleLayout>
|
||||||
@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
import { CollectionEntry, getCollection } from "astro:content";
|
|
||||||
import ArticleLayout from "@root/layouts/article.astro";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
|
||||||
const articles = await getCollection("blog");
|
|
||||||
return articles
|
|
||||||
.filter((a) => !a.data.draft)
|
|
||||||
.map((article) => ({
|
|
||||||
params: { slug: `articles/${article.slug}` },
|
|
||||||
props: { article },
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = { article: CollectionEntry<"blog"> };
|
|
||||||
|
|
||||||
const { Content } = await Astro.props.article.render();
|
|
||||||
---
|
|
||||||
|
|
||||||
<ArticleLayout article={Astro.props.article}>
|
|
||||||
<Content />
|
|
||||||
</ArticleLayout>
|
|
||||||
@ -3,6 +3,7 @@ import { getLanguageKeys } from "@i18n/utils";
|
|||||||
import { DEFAULT_LANGUAGE } from "@root/constants";
|
import { DEFAULT_LANGUAGE } from "@root/constants";
|
||||||
import About from "@templates/About.astro";
|
import About from "@templates/About.astro";
|
||||||
|
|
||||||
|
// TODO: do not generate pages without required data
|
||||||
export function getStaticPaths() {
|
export function getStaticPaths() {
|
||||||
return getLanguageKeys()
|
return getLanguageKeys()
|
||||||
.filter((lang) => lang !== DEFAULT_LANGUAGE)
|
.filter((lang) => lang !== DEFAULT_LANGUAGE)
|
||||||
|
|||||||
@ -1,26 +1,28 @@
|
|||||||
---
|
---
|
||||||
import PageLayout from "@layouts/default.astro";
|
import { getCollection, getEntryBySlug } from "astro:content";
|
||||||
import { getLanguageFromURL } from "@i18n/utils";
|
import { getLanguageFromURL } from "@i18n/utils";
|
||||||
// import { useTranslation } from "@i18n/utils";
|
import PageLayout from "@layouts/default.astro";
|
||||||
// import * as API from "@root/lib/api";
|
|
||||||
import PageHeading from "@components/PageHeading.astro";
|
import PageHeading from "@components/PageHeading.astro";
|
||||||
// import SkillsList from "@components/SkillsList";
|
import SkillsList from "@components/SkillsList.astro";
|
||||||
// import SkillsBlock from "@components/SkillsBlock";
|
import SkillsBlock from "@components/SkillsBlock.astro";
|
||||||
// import ArticleContent from "@components/ArticleContent";
|
import ArticleContent from "@components/ArticleContent.astro";
|
||||||
const lang = getLanguageFromURL(Astro.url.pathname);
|
|
||||||
|
const pageLang = getLanguageFromURL(Astro.url.pathname);
|
||||||
|
const skills = await getCollection("skills", (e) => e.id.startsWith(`${pageLang}/`));
|
||||||
|
const about = await getEntryBySlug("authors", `${pageLang}/сергей-ярков`);
|
||||||
|
const data = await about?.render();
|
||||||
|
|
||||||
// const t = useTranslation(Astro);
|
// const t = useTranslation(Astro);
|
||||||
// const data = await API.fetchAboutMe(Astro);
|
|
||||||
// const { skills } = SITE_METADATA;
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<PageLayout noIndex lang={lang} title={"Обо мне"}>
|
<PageLayout noIndex lang={pageLang} title={"Обо мне"}>
|
||||||
<PageHeading heading={"Обо мне"} />
|
<PageHeading heading={"Обо мне"} />
|
||||||
<section>
|
<section>
|
||||||
<!-- <ArticleContent>
|
<ArticleContent>
|
||||||
{data && <data.Content />}
|
{data && <data.Content />}
|
||||||
</ArticleContent> -->
|
</ArticleContent>
|
||||||
<!-- <SkillsList>
|
<SkillsList>
|
||||||
{skills.map((block) => <SkillsBlock data={block} />)}
|
{skills.map((block) => <SkillsBlock data={block.data} />)}
|
||||||
</SkillsList> -->
|
</SkillsList>
|
||||||
</section>
|
</section>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
---
|
---
|
||||||
|
import { getCollection } from "astro:content";
|
||||||
import PageLayout from "@layouts/default.astro";
|
import PageLayout from "@layouts/default.astro";
|
||||||
import Splash from "@components/Splash/Splash.astro";
|
import Splash from "@components/Splash/Splash.astro";
|
||||||
import SplashHeading from "@root/components/Splash/SplashHeading.astro";
|
import SplashHeading from "@root/components/Splash/SplashHeading.astro";
|
||||||
import SplashLinks from "@root/components/Splash/SplashLinks.astro";
|
import SplashLinks from "@root/components/Splash/SplashLinks.astro";
|
||||||
import SplashLink from "@root/components/Splash/SplashLink.astro";
|
import SplashLink from "@root/components/Splash/SplashLink.astro";
|
||||||
import { getCollection } from "astro:content";
|
|
||||||
import RecentArticles from "@root/components/RecentArticles.astro";
|
import RecentArticles from "@root/components/RecentArticles.astro";
|
||||||
|
|
||||||
const articles = (await getCollection("blog"))
|
const articles = (await getCollection("blog", (e) => !e.data.draft)).sort(
|
||||||
.filter((p) => !p.data.draft)
|
(a, b) => a.data.pubDate.valueOf() - b.data.pubDate.valueOf()
|
||||||
.sort((a, b) => a.data.pubDate.valueOf() - b.data.pubDate.valueOf());
|
);
|
||||||
---
|
---
|
||||||
|
|
||||||
<PageLayout description="Home page" lang={"ru"}>
|
<PageLayout description="Home page" lang={"ru"}>
|
||||||
|
|||||||
@ -8,6 +8,6 @@ const lang = getLanguageFromURL(Astro.url.pathname);
|
|||||||
<PageLayout lang={lang}>
|
<PageLayout lang={lang}>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 style="font-size:var(--font-size-5xl);">404</h1>
|
<h1 style="font-size:var(--font-size-5xl);">404</h1>
|
||||||
<p>{"Страница не найдена"}</p>
|
<p>{"Страницу которую вы пытаетесь найти не существует."}</p>
|
||||||
</div>
|
</div>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user