mirror of
https://github.com/sergeyyarkov/yarkov.tech.git
synced 2026-10-11 18:39:14 +03:00
181 lines
3.8 KiB
Plaintext
181 lines
3.8 KiB
Plaintext
---
|
|
import type { CollectionEntry } from "astro:content";
|
|
import { Icon } from "astro-icon";
|
|
import { createDateFormatter } from "@root/utils";
|
|
import ArticleCover from "@components/ArticleCover.astro";
|
|
import ArticleComments from "@components/ArticleComments.astro";
|
|
import TranslatedLink from "@components/TranslatedLink.astro";
|
|
import { useTranslation, getLanguageFromURL } from "@i18n/utils";
|
|
import * as utils from "@utils/index";
|
|
|
|
export type Props = {
|
|
article: CollectionEntry<"blog">;
|
|
lang: string;
|
|
};
|
|
|
|
const { article } = Astro.props as Props;
|
|
const pageLang = getLanguageFromURL(Astro.url.pathname);
|
|
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
|
|
const {
|
|
id,
|
|
data: { coverImage, title, author, description, tags, pubDate },
|
|
} = article;
|
|
|
|
const slug = utils.encodeString(id.split("/")[1]);
|
|
const t = useTranslation(Astro);
|
|
---
|
|
|
|
<article itemscope itemtype="http://schema.org/BlogPosting" class="article">
|
|
<header>
|
|
<div>
|
|
{
|
|
tags && (
|
|
<div class="tags">
|
|
<ul itemprop="keywords">
|
|
{tags.map((tag) => (
|
|
<li>
|
|
<TranslatedLink rel="tag" to={`/articles/?tags=${tag}`}>
|
|
{tag}
|
|
</TranslatedLink>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
)
|
|
}
|
|
<div class="views">
|
|
<Icon name="eye" width="21" height="21" />
|
|
<span><span id="views">---</span> {t("article.views")}</span>
|
|
</div>
|
|
</div>
|
|
<div class="heading">
|
|
<h1 itemprop="headline">{title}</h1>
|
|
</div>
|
|
<div class="published">
|
|
<time itemprop="datePublished" datetime={pubDate.toString()}>
|
|
{createDateFormatter(pageLang).format(pubDate)}
|
|
</time>
|
|
<span itemprop="author">{author}</span>
|
|
</div>
|
|
{coverImage && <ArticleCover src={coverImage} alt={title} />}
|
|
<div class="description">
|
|
<p>
|
|
{description}
|
|
</p>
|
|
</div>
|
|
</header>
|
|
<slot />
|
|
<ArticleComments url={canonicalUrl.href} id={slug} />
|
|
</article>
|
|
|
|
<script define:vars={{ slug, IS_DEV: import.meta.env.DEV }}>
|
|
(async () => {
|
|
if (IS_DEV) return;
|
|
const response = await fetch(`/api/views?slug=${slug}`, { method: "POST" });
|
|
if (!response.ok) return;
|
|
const views = await response.text();
|
|
const $views = document.getElementById("views");
|
|
if (isNaN(parseInt(views, 10))) return;
|
|
if ($views) $views.textContent = views;
|
|
})();
|
|
</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;
|
|
& li:not(:last-child)::after {
|
|
content: ",";
|
|
color: var(--color-blue-400);
|
|
}
|
|
}
|
|
}
|
|
|
|
& .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>
|