mirror of
https://github.com/sergeyyarkov/yarkov.tech.git
synced 2026-10-11 10:29:21 +03:00
recent articles render
This commit is contained in:
parent
c311050b65
commit
a334a67b03
@ -5,14 +5,15 @@ import { createDateFormatter } from "@root/utils";
|
|||||||
import ArticleCover from "@components/ArticleCover.astro";
|
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 { useTranslation } from "@i18n/utils";
|
import { useTranslation, getLanguageFromURL } from "@i18n/utils";
|
||||||
|
|
||||||
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 } = Astro.props as Props;
|
||||||
|
const pageLang = getLanguageFromURL(Astro.url.pathname);
|
||||||
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 },
|
||||||
@ -50,7 +51,7 @@ const {
|
|||||||
</div>
|
</div>
|
||||||
<div class="published">
|
<div class="published">
|
||||||
<time itemprop="datePublished" datetime={pubDate.toString()}>
|
<time itemprop="datePublished" datetime={pubDate.toString()}>
|
||||||
{createDateFormatter(lang).format(pubDate)}
|
{createDateFormatter(pageLang).format(pubDate)}
|
||||||
</time>
|
</time>
|
||||||
<span itemprop="author">{author}</span>
|
<span itemprop="author">{author}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,19 +3,20 @@ import { SITE_METADATA } from "@root/constants";
|
|||||||
import { Icon } from "astro-icon";
|
import { Icon } from "astro-icon";
|
||||||
import TranslatedLink from "./TranslatedLink.astro";
|
import TranslatedLink from "./TranslatedLink.astro";
|
||||||
import UIString from "./UIString.astro";
|
import UIString from "./UIString.astro";
|
||||||
const date = new Date();
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div>
|
<div>
|
||||||
<i>
|
<i>
|
||||||
Разработка: <TranslatedLink to="/contacts">{SITE_METADATA.author}</TranslatedLink>
|
<UIString key={"footer.developed"} />: <TranslatedLink to="/contacts">
|
||||||
© {date.getFullYear()}
|
{SITE_METADATA.author}
|
||||||
|
</TranslatedLink>
|
||||||
|
© {new Date().getFullYear()}
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="/rss.xml" target="_blank"><UIString key={"rss.feed"} /></a>
|
<a href="/rss.xml" target="_blank"><UIString key={"footer.rssFeed"} /></a>
|
||||||
<span>
|
<span>
|
||||||
<Icon name="rss" width="20" height="20" />
|
<Icon name="rss" width="20" height="20" />
|
||||||
</span>
|
</span>
|
||||||
@ -27,14 +28,18 @@ const date = new Date();
|
|||||||
footer {
|
footer {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-top: 5rem;
|
margin-top: 5rem;
|
||||||
color: var(--color-gray-200);
|
color: var(--color-gray-400);
|
||||||
font-size: var(--font-size-sm);
|
font-size: var(--font-size-sm);
|
||||||
& .container {
|
& .container {
|
||||||
padding: 15px 0 15px 0;
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
border-top: 1px solid var(--border-color);
|
border-top: 1px solid var(--border-color);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
column-gap: 20px;
|
||||||
|
row-gap: 5px;
|
||||||
& div:last-child {
|
& div:last-child {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -1,35 +1,35 @@
|
|||||||
---
|
---
|
||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import siteconfig from "siteconfig.json";
|
import siteconfig from "siteconfig.json";
|
||||||
|
import { getLanguageFromURL } from "@i18n/utils";
|
||||||
|
import * as utils from "@utils/index";
|
||||||
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 UIString from "@components/UIString.astro";
|
import UIString from "@components/UIString.astro";
|
||||||
import TranslatedLink from "@components/TranslatedLink.astro";
|
import TranslatedLink from "@components/TranslatedLink.astro";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
articles: CollectionEntry<"blog">[];
|
articles: CollectionEntry<"blog">[];
|
||||||
length?: number | undefined;
|
length?: number | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { articles, length = siteconfig.articles.recentLimit } = Astro.props as Props;
|
const { articles, length = siteconfig.articles.recentLimit } = Astro.props as Props;
|
||||||
|
const pageLang = getLanguageFromURL(Astro.url.pathname);
|
||||||
|
const filtered = utils.removeDuplicates(articles.slice(0, length), pageLang);
|
||||||
const isEmpty = articles.length === 0;
|
const isEmpty = articles.length === 0;
|
||||||
---
|
---
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div>
|
<div>
|
||||||
<h2><UIString key={"recentArticles.heading"} /></h2>
|
<h2>
|
||||||
|
<UIString key={"recentArticles.heading"} />
|
||||||
|
</h2>
|
||||||
<TranslatedLink to="/articles">
|
<TranslatedLink to="/articles">
|
||||||
<UIString key={"recentArticles.all"} />
|
<UIString key={"recentArticles.all"} />
|
||||||
</TranslatedLink>
|
</TranslatedLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div itemscope itemtype="http://schema.org/Blog">
|
<div itemscope itemtype="http://schema.org/Blog">
|
||||||
{
|
{!isEmpty ? filtered.map((article) => <ArticleItem entry={article} />) : <EmptyList />}
|
||||||
!isEmpty ? (
|
|
||||||
articles.slice(0, length).map((article) => <ArticleItem entry={article} />)
|
|
||||||
) : (
|
|
||||||
<EmptyList />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
---
|
|
||||||
|
|
||||||
...
|
|
||||||
@ -53,6 +53,7 @@ export default {
|
|||||||
"form.contactError": "An error occurred while sending. Please try again later.",
|
"form.contactError": "An error occurred while sending. Please try again later.",
|
||||||
/* Error messages */
|
/* Error messages */
|
||||||
"error.invalidEmail": "Fill in the field in the e-mail format.",
|
"error.invalidEmail": "Fill in the field in the e-mail format.",
|
||||||
/* Other */
|
/* Footer */
|
||||||
"rss.feed": "RSS Feed",
|
"footer.rssFeed": "RSS Feed",
|
||||||
|
"footer.developed": "Developed",
|
||||||
};
|
};
|
||||||
|
|||||||
@ -54,6 +54,7 @@ export default {
|
|||||||
"form.contactError": "При отправке произошла ошибка. Повторите запрос позже.",
|
"form.contactError": "При отправке произошла ошибка. Повторите запрос позже.",
|
||||||
/* Error messages */
|
/* Error messages */
|
||||||
"error.invalidEmail": "Заполните поле в формате e-mail.",
|
"error.invalidEmail": "Заполните поле в формате e-mail.",
|
||||||
/* Other */
|
/* Footer */
|
||||||
"rss.feed": "RSS Лента",
|
"footer.rssFeed": "RSS Лента",
|
||||||
|
"footer.developed": "Разработка",
|
||||||
};
|
};
|
||||||
|
|||||||
33
src/utils/article.ts
Normal file
33
src/utils/article.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import type { CollectionEntry } from "astro:content";
|
||||||
|
import { findDuplicates } from "./string";
|
||||||
|
import { removeLanguageCodeFromPath } from "./url";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there is a translation of an article in the current language of the page,
|
||||||
|
* the remaining articles with other translations should be removed.
|
||||||
|
*
|
||||||
|
* @param entries Array of articles
|
||||||
|
* @param pageLang Current language on page
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function removeDuplicates(
|
||||||
|
entries: CollectionEntry<"blog">[],
|
||||||
|
pageLang: LanguageKeys
|
||||||
|
): CollectionEntry<"blog">[] {
|
||||||
|
const ids = entries.map((a) => a.id) as string[];
|
||||||
|
const duplicates = findDuplicates(ids.map((id) => removeLanguageCodeFromPath(id)));
|
||||||
|
|
||||||
|
duplicates.forEach((id) => {
|
||||||
|
const toDeleteIdxs: number[] = [];
|
||||||
|
if (ids.indexOf(`${pageLang}/${id}`) !== -1) {
|
||||||
|
entries.forEach((a, i) => {
|
||||||
|
if (a.id !== `${pageLang}/${id}` && a.id.includes(id)) {
|
||||||
|
toDeleteIdxs.push(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
toDeleteIdxs.forEach((i) => entries.splice(i, 1));
|
||||||
|
});
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
@ -1,3 +1,5 @@
|
|||||||
export * from "./date";
|
export * from "./date";
|
||||||
export * from "./history";
|
export * from "./history";
|
||||||
export * from "./url";
|
export * from "./url";
|
||||||
|
export * from "./string";
|
||||||
|
export * from "./article";
|
||||||
|
|||||||
@ -7,7 +7,11 @@ export function isEmail(email: string): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isURL(url: string): boolean {
|
export function isURL(url: string): boolean {
|
||||||
return new RegExp(/(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\\/~+#-]*[\w@?^=%&\\/~+#-])/).test(
|
return new RegExp(
|
||||||
url
|
/(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\\/~+#-]*[\w@?^=%&\\/~+#-])/
|
||||||
);
|
).test(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findDuplicates(array: string[]): string[] {
|
||||||
|
return array.filter((item, i) => array.indexOf(item) !== i);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,3 +3,7 @@ export const encode = (data: object) => {
|
|||||||
.map((key) => encodeURIComponent(key) + "=" + encodeURIComponent(data[key]))
|
.map((key) => encodeURIComponent(key) + "=" + encodeURIComponent(data[key]))
|
||||||
.join("&");
|
.join("&");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function removeLanguageCodeFromPath(path: string) {
|
||||||
|
return path.replace(/^[a-zA-Z-]+\/+/, "");
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user