mirror of
https://github.com/sergeyyarkov/yarkov.tech.git
synced 2026-10-11 02:19:08 +03:00
feat: added dynamin article page
This commit is contained in:
parent
73ee879952
commit
d935483507
@ -1,5 +1,4 @@
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
import solid from '@astrojs/solid-js';
|
||||
|
||||
// https://astro.build/config
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
if (window.theme) {
|
||||
/* the {theme} in the path will be dynamically changed */
|
||||
const PATH = `assets/css/code-highlight-{theme}.min.css`;
|
||||
const PATH = `/assets/css/code-highlight-{theme}.min.css`;
|
||||
const $head = document.getElementsByTagName('head')[0];
|
||||
const getPath = (theme) => PATH.replace(`{theme}`, theme);
|
||||
const createLink = (theme, media) => {
|
||||
|
||||
@ -9,7 +9,7 @@ export type ArticleItemProps = {
|
||||
export const ArticleItem: Component<ArticleItemProps> = (props) => {
|
||||
return (
|
||||
<article class="article-item">
|
||||
<a href="#">
|
||||
<a href={`/${new Date(props.data.published_at).toLocaleDateString('en-CA')}/${props.data.slug}`}>
|
||||
<h3>{props.data.title}</h3>
|
||||
<p>
|
||||
<time datetime={props.data.published_at.toString()}>{DateFormatter.format(new Date(props.data.published_at))}</time>
|
||||
|
||||
@ -16,7 +16,7 @@ const { title, tags, author, published_at } = data;
|
||||
<ul class='list-links'>
|
||||
{tags.map((tag) => (
|
||||
<li>
|
||||
<a class="btn-link" href={`/articles?tags=${tag}`}>
|
||||
<a class="btn-link" href={`/articles?tags=${tag.toLocaleLowerCase()}`}>
|
||||
{tag}
|
||||
</a>
|
||||
</li>
|
||||
@ -32,10 +32,7 @@ const { title, tags, author, published_at } = data;
|
||||
</div>
|
||||
<div>
|
||||
<figure>
|
||||
<img
|
||||
src='https://img.freepik.com/premium-photo/beautiful-emerald-lake-yoho-national-park-british-columbia-canada_131985-177.jpg?w=1920'
|
||||
alt='Article Image'
|
||||
/>
|
||||
<img src='https://picsum.photos/1920/1080' alt='Article Image' />
|
||||
</figure>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@ -1,18 +1,17 @@
|
||||
---
|
||||
import { SITE_METADATA } from '@root/config';
|
||||
import { SITE_METADATA } from '@root/config';
|
||||
|
||||
export interface Props {
|
||||
title?: string | undefined;
|
||||
description?: string | undefined;
|
||||
}
|
||||
export interface Props {
|
||||
title?: string | undefined;
|
||||
description?: string | undefined;
|
||||
}
|
||||
|
||||
const { title = SITE_METADATA.title, description } = Astro.props as Props;
|
||||
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' />
|
||||
<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' />
|
||||
@ -21,5 +20,5 @@
|
||||
</title>
|
||||
<meta name='title' content={title} />
|
||||
<meta name='description' content={description || SITE_METADATA.description} />
|
||||
<script is:inline src='assets/js/detect-theme.min.js' />
|
||||
<slot></slot>
|
||||
<script is:inline src='/assets/js/detect-theme.min.js' />
|
||||
<slot></slot>
|
||||
|
||||
17
src/components/Counter/Counter.tsx
Normal file
17
src/components/Counter/Counter.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import type { Component } from 'solid-js';
|
||||
|
||||
import { createSignal, createEffect } from 'solid-js';
|
||||
|
||||
const Counter: Component = () => {
|
||||
const [count, setCount] = createSignal<number>(0);
|
||||
|
||||
createEffect(() => {
|
||||
setInterval(() => {
|
||||
setCount(count() + 1);
|
||||
}, 500);
|
||||
});
|
||||
|
||||
return <div>{count()}</div>;
|
||||
};
|
||||
|
||||
export default Counter;
|
||||
1
src/components/Counter/index.ts
Normal file
1
src/components/Counter/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './Counter';
|
||||
@ -18,9 +18,7 @@ const { lang = 'ru', content } = Astro.props as Props;
|
||||
<html lang={lang}>
|
||||
<head>
|
||||
<BaseHead title={content.title} description={content.description}>
|
||||
<script is:inline defer src='assets/js/load-code-highlight.js'>
|
||||
|
||||
</script>
|
||||
<script is:inline defer src='/assets/js/load-code-highlight.js' />
|
||||
</BaseHead>
|
||||
</head>
|
||||
|
||||
|
||||
22
src/pages/[...slug].astro
Normal file
22
src/pages/[...slug].astro
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
import type { MarkdownInstance } from 'astro';
|
||||
|
||||
import ArticleLayout from '@root/layouts/article.astro';
|
||||
|
||||
// TODO: generate pages based on user language
|
||||
export async function getStaticPaths() {
|
||||
const data = await Astro.glob<ArticleType>('../../content/articles/**/*.md');
|
||||
return data.map((article) => {
|
||||
const published_at = new Date(article.frontmatter.published_at).toLocaleDateString('en-CA');
|
||||
const slug = `${published_at}/${article.frontmatter.slug}`;
|
||||
const props = { Content: article.Content, frontmatter: article.frontmatter };
|
||||
return { params: { slug }, props };
|
||||
});
|
||||
}
|
||||
|
||||
const { Content, frontmatter: data } = Astro.props as MarkdownInstance<ArticleType>;
|
||||
---
|
||||
|
||||
<ArticleLayout content={data}>
|
||||
<Content />
|
||||
</ArticleLayout>
|
||||
@ -1,80 +0,0 @@
|
||||
---
|
||||
import ArticleLayout from '@root/layouts/article.astro';
|
||||
import { Markdown } from 'astro/components';
|
||||
|
||||
export function getStaticPaths() {
|
||||
return [{ params: { article: 'article' } }];
|
||||
}
|
||||
---
|
||||
|
||||
<ArticleLayout
|
||||
content={{
|
||||
title: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
description: 'description1',
|
||||
author: 'Sergey Yarkov',
|
||||
tags: ['AVR', 'JavaScript', 'NodeJS'],
|
||||
published_at: new Date().toISOString(),
|
||||
}}
|
||||
>
|
||||
<Markdown>
|
||||
## Introduction
|
||||
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
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
|
||||
nisi, ac posuere leo.
|
||||
|
||||
### Another Heading
|
||||
|
||||
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.
|
||||
|
||||
- `Nam metus lacus`: porttitor eu mauris a, [blandit ultrices](#) nibh.
|
||||
- `Class aptent`: taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
|
||||
- `Sed nec ante`: dictum sem condimentum [ullamcorper quis](#) venenatis nisi.
|
||||
|
||||
```typescript
|
||||
import type { APIContext } from 'astro';
|
||||
|
||||
export async function get({ params, request }: APIContext) {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
path: new URL(request.url).pathname,
|
||||
}),
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu turpis molestie, dictum est a, mattis tellus.
|
||||
Sed dignissim.
|
||||
|
||||
<figure>
|
||||
<img src="https://wallpaperaccess.com/full/138733.jpg" alt="test" />
|
||||
<figcaption>This is a test image!</figcaption>
|
||||
</figure>
|
||||
|
||||
<blockquote>
|
||||
<p>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.
|
||||
</p>
|
||||
<p>— <a href="#">Metus Nec</a></p>
|
||||
</blockquote>
|
||||
|
||||
## Conclusion
|
||||
|
||||
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.
|
||||
</Markdown>
|
||||
</ArticleLayout>
|
||||
@ -1,16 +1,24 @@
|
||||
---
|
||||
import PageLayout from '@layouts/default.astro';
|
||||
import ArticlesList from '@components/ArticlesList';
|
||||
import { transformArticles, formatToArticleBlocks } from '@utils/articles';
|
||||
import PageLayout from '@layouts/default.astro';
|
||||
import ArticlesList from '@components/ArticlesList';
|
||||
import { transformArticles, formatToArticleBlocks } from '@utils/articles';
|
||||
|
||||
const articles = await Astro.glob<ArticleType>('../../content/articles/**/*.md');
|
||||
const tags = new Set(articles.map((article) => article.frontmatter.tags).flat());
|
||||
const articles = await Astro.glob<ArticleType>('../../content/articles/**/*.md');
|
||||
const tags = new Set(articles.map((article) => article.frontmatter.tags).flat());
|
||||
---
|
||||
|
||||
<PageLayout title='Статьи'
|
||||
description='Технические статьи, туториалы и различные справочные материалы которые связаны с IT тематикой находятся здесь.'>
|
||||
<PageLayout
|
||||
title='Статьи'
|
||||
description='Технические статьи, туториалы и различные справочные материалы которые связаны с IT тематикой находятся здесь.'
|
||||
>
|
||||
<section>
|
||||
<ArticlesList client:load data={{ articles: formatToArticleBlocks(transformArticles(articles)), tags: [...tags], }}
|
||||
emptyPlaceholder='Не найдено ни одной статьи...' />
|
||||
<ArticlesList
|
||||
client:load
|
||||
data={{
|
||||
articles: formatToArticleBlocks(transformArticles(articles)),
|
||||
tags: [...tags],
|
||||
}}
|
||||
emptyPlaceholder='Не найдено ни одной статьи...'
|
||||
/>
|
||||
</section>
|
||||
</PageLayout>
|
||||
</PageLayout>
|
||||
|
||||
1
src/types/main.d.ts
vendored
1
src/types/main.d.ts
vendored
@ -11,6 +11,7 @@ declare global {
|
||||
}
|
||||
|
||||
type ArticleType = {
|
||||
slug: string;
|
||||
title: string;
|
||||
description: string;
|
||||
author: string;
|
||||
|
||||
@ -2,6 +2,7 @@ import { MarkdownInstance } from 'astro';
|
||||
|
||||
export const transformArticles = (articles: MarkdownInstance<ArticleType>[]): ArticleType[] =>
|
||||
articles.map((article) => ({
|
||||
slug: article.frontmatter.slug,
|
||||
title: article.frontmatter.title,
|
||||
description: article.frontmatter.description,
|
||||
author: article.frontmatter.author,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user