mirror of
https://github.com/sergeyyarkov/yarkov.tech.git
synced 2026-10-11 02:19:08 +03:00
feat: added rss feed for articles
This commit is contained in:
parent
2550e807d3
commit
e2c3cd4779
@ -14,6 +14,7 @@ Personal website created with Astro.
|
||||
- [x] Multilang web-site
|
||||
- [x] Form handling via [Netlify Forms](https://www.netlify.com/products/forms/)
|
||||
- [x] Comment system via [utterances](https://utteranc.es/)
|
||||
- [x] RSS Feed for articles
|
||||
- [ ] SEO optimized
|
||||
|
||||
## License
|
||||
|
||||
52
package-lock.json
generated
52
package-lock.json
generated
@ -8,6 +8,9 @@
|
||||
"name": "yarkov.tech",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@astrojs/rss": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/image": "^0.3.4",
|
||||
"@astrojs/mdx": "^0.10.0",
|
||||
@ -183,6 +186,14 @@
|
||||
"node": "^14.18.0 || >=16.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/rss": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-1.0.0.tgz",
|
||||
"integrity": "sha512-vOPocf/SC0TfHsCwQXupvLGm0y3oIwpRCnnF2igDP3gFSxQEOk4nmsuVTEU2N87hYyX1/5uxbjJhixuSV/L8Cw==",
|
||||
"dependencies": {
|
||||
"fast-xml-parser": "^4.0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/solid-js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/solid-js/-/solid-js-1.0.0.tgz",
|
||||
@ -3558,6 +3569,21 @@
|
||||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.9.tgz",
|
||||
"integrity": "sha512-4G8EzDg2Nb1Qurs3f7BpFV4+jpMVsdgLVuG1Uv8O2OHJfVCg7gcA53obuKbmVqzd4Y7YXVBK05oJG7hzGIdyzg==",
|
||||
"dependencies": {
|
||||
"strnum": "^1.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"fxparser": "src/cli/cli.js"
|
||||
},
|
||||
"funding": {
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/naturalintelligence"
|
||||
}
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
|
||||
@ -8146,6 +8172,11 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/strnum": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
|
||||
"integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA=="
|
||||
},
|
||||
"node_modules/style-to-object": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz",
|
||||
@ -9335,6 +9366,14 @@
|
||||
"prismjs": "^1.28.0"
|
||||
}
|
||||
},
|
||||
"@astrojs/rss": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-1.0.0.tgz",
|
||||
"integrity": "sha512-vOPocf/SC0TfHsCwQXupvLGm0y3oIwpRCnnF2igDP3gFSxQEOk4nmsuVTEU2N87hYyX1/5uxbjJhixuSV/L8Cw==",
|
||||
"requires": {
|
||||
"fast-xml-parser": "^4.0.8"
|
||||
}
|
||||
},
|
||||
"@astrojs/solid-js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/solid-js/-/solid-js-1.0.0.tgz",
|
||||
@ -11761,6 +11800,14 @@
|
||||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-xml-parser": {
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.9.tgz",
|
||||
"integrity": "sha512-4G8EzDg2Nb1Qurs3f7BpFV4+jpMVsdgLVuG1Uv8O2OHJfVCg7gcA53obuKbmVqzd4Y7YXVBK05oJG7hzGIdyzg==",
|
||||
"requires": {
|
||||
"strnum": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"fastq": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
|
||||
@ -14979,6 +15026,11 @@
|
||||
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
||||
"dev": true
|
||||
},
|
||||
"strnum": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
|
||||
"integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA=="
|
||||
},
|
||||
"style-to-object": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz",
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
"devDependencies": {
|
||||
"@astrojs/image": "^0.3.4",
|
||||
"@astrojs/mdx": "^0.10.0",
|
||||
"@astrojs/rss": "^1.0.0",
|
||||
"@astrojs/solid-js": "^1.0.0",
|
||||
"@types/mdx": "^2.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
|
||||
@ -3,11 +3,10 @@ import * as utils from "@utils/url";
|
||||
import { DEFAULT_LANGUAGE } from "@root/config";
|
||||
import languages from "./languages";
|
||||
|
||||
export function getTranslatedArticles(Astro: Readonly<AstroGlobal>): MDXInstance<ArticleType>[] {
|
||||
const data = import.meta.glob<MDXInstance<ArticleType>>("../../content/articles/**/*.mdx", { eager: true });
|
||||
const modules: Record<string, Record<string, MDXInstance<ArticleType>>> = {};
|
||||
const siteLang = utils.getLanguageFromURL(Astro.url.pathname);
|
||||
const articles: MDXInstance<ArticleType>[] = [];
|
||||
type TranslatedArticlesType = Record<string, Record<LanguageKeys, MDXInstance<ArticleType>> | Record<string, never>>;
|
||||
|
||||
export function formatArticlesByLangs(data: Record<string, MDXInstance<ArticleType>>): TranslatedArticlesType {
|
||||
const modules: TranslatedArticlesType = {};
|
||||
|
||||
for (const module of Object.values(data)) {
|
||||
const splitted = module.file.split("/");
|
||||
@ -17,6 +16,15 @@ export function getTranslatedArticles(Astro: Readonly<AstroGlobal>): MDXInstance
|
||||
modules[name][lang] = module;
|
||||
}
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
export function getTranslatedArticles(Astro: Readonly<AstroGlobal>): MDXInstance<ArticleType>[] {
|
||||
const data = import.meta.glob<MDXInstance<ArticleType>>("../../content/articles/**/*.mdx", { eager: true });
|
||||
const modules = formatArticlesByLangs(data);
|
||||
const siteLang = utils.getLanguageFromURL(Astro.url.pathname);
|
||||
const articles: MDXInstance<ArticleType>[] = [];
|
||||
|
||||
for (const key of Object.keys(modules)) {
|
||||
const langs = Object.keys(modules[key]);
|
||||
for (const articleLang of langs) {
|
||||
@ -53,11 +61,13 @@ function transformExports<T>(modules: Record<string, { default: T }>) {
|
||||
|
||||
const translations = transformExports<UIDictionaryKeys>(import.meta.glob("./*/ui.ts", { eager: true }));
|
||||
|
||||
export function useTranslation(Astro: Readonly<AstroGlobal>): (key: UIDictionaryKeys) => string | undefined {
|
||||
const lang = utils.getLanguageFromURL(Astro.url.pathname);
|
||||
return function translate(key: UIDictionaryKeys): string | undefined {
|
||||
const string: string | undefined = translations[lang]?.[key] || translations[DEFAULT_LANGUAGE][key];
|
||||
if (string === undefined) console.log(`Cannot find any string for translation key "${key}" on "${Astro.url.pathname}" page.`);
|
||||
return string;
|
||||
};
|
||||
export function translate(key: UIDictionaryKeys, lang: LanguageKeys): string | undefined {
|
||||
const string: string | undefined = translations[lang]?.[key] || translations[DEFAULT_LANGUAGE][key];
|
||||
if (string === undefined) console.log(`Cannot find any string for translation key "${key}".`);
|
||||
return string;
|
||||
}
|
||||
|
||||
export function useTranslation(Astro: Readonly<AstroGlobal>): (key: UIDictionaryKeys) => string | undefined {
|
||||
const lang: LanguageKeys = utils.getLanguageFromURL(Astro.url.pathname) as LanguageKeys;
|
||||
return (key: UIDictionaryKeys) => translate(key, lang);
|
||||
}
|
||||
|
||||
35
src/pages/rss.xml.ts
Normal file
35
src/pages/rss.xml.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import type { MDXInstance } from "astro";
|
||||
|
||||
import rss from "@astrojs/rss";
|
||||
import { DEFAULT_LANGUAGE, SITE_METADATA } from "@root/config";
|
||||
import * as utils from "@i18n/utils";
|
||||
|
||||
const data = import.meta.glob<MDXInstance<ArticleType>>("../../content/articles/**/*.mdx", { eager: true });
|
||||
const articles = Object.values(utils.formatArticlesByLangs(data));
|
||||
const items = [];
|
||||
|
||||
for (const key of Object.keys(articles)) {
|
||||
const article: Record<string, MDXInstance<ArticleType>> = articles[key];
|
||||
for (const lang of Object.keys(article)) {
|
||||
const { title, description, slug, published_at, coverImage } = article[lang].frontmatter;
|
||||
items.push({
|
||||
link:
|
||||
`${import.meta.env.SITE}blog/` +
|
||||
new Date(published_at).toLocaleDateString("en-CA") +
|
||||
`${lang !== DEFAULT_LANGUAGE ? "/" + lang : ""}` +
|
||||
`/${slug}/`,
|
||||
title,
|
||||
description: `${description}${coverImage !== undefined ? `<img src="${coverImage}" alt="${title}">` : ""}`,
|
||||
pubDate: published_at,
|
||||
customData: `<language>${lang}</language>`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const get = () =>
|
||||
rss({
|
||||
title: SITE_METADATA.name,
|
||||
description: utils.translate("site.description", "ru"),
|
||||
site: import.meta.env.SITE,
|
||||
items,
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user