diff --git a/README.md b/README.md index 77583fb..b842bb2 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Personal website created with Astro. - [x] Search articles by title or description - [x] Dark/Light Theme - [x] Multilang web-site +- [x] Table of contents - [x] Content management via [NetlifyCMS](https://www.netlifycms.org/) - [x] Prefetch pages via [Quicklink](https://getquick.link/) - [x] Form handling via [Netlify Forms](https://www.netlify.com/products/forms/) diff --git a/package.json b/package.json index 490749d..31c2c26 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "yarkov.tech", "private": false, - "version": "2.0.0", + "version": "2.1.0", "description": "Personal website created with Astro.", "author": { "name": "Sergey Yarkov", diff --git a/src/components/ArticleContent.astro b/src/components/ArticleContent.astro index ba29de4..cf3ef10 100644 --- a/src/components/ArticleContent.astro +++ b/src/components/ArticleContent.astro @@ -2,6 +2,7 @@ diff --git a/src/components/TableOfContents.astro b/src/components/TableOfContents.astro index fd01af9..ad4bb10 100644 --- a/src/components/TableOfContents.astro +++ b/src/components/TableOfContents.astro @@ -2,22 +2,62 @@ import { buildToc } from "@root/utils"; import type { MarkdownHeading } from "astro"; import TableOfContentsHeading from "./TableOfContentsHeading.astro"; +import { useTranslation } from "@root/i18n/utils"; export interface Props { headings: MarkdownHeading[]; } -const toc = buildToc(Astro.props.headings); +const toc = buildToc(Astro.props.headings, 3); +const t = useTranslation(Astro); --- - - Содержание - - {toc.map((heading) => )} - - + + {t("article.tableOfContents")} + + + + {toc.map((heading) => )} + + + + + + diff --git a/src/i18n/en/ui.ts b/src/i18n/en/ui.ts index 0a7a174..2739b69 100644 --- a/src/i18n/en/ui.ts +++ b/src/i18n/en/ui.ts @@ -4,6 +4,7 @@ export default { "Here I publish articles and tutorials on various IT topics, and I also talk about my projects that I have done over the past few years.", "site.underConstruction": "This web-site is under development...", "article.availableOn": "Available on", + "article.tableOfContents": "Table of contents", "articles.empty": "No articles found...", "articlePost.comments": "Comments", "article.views": "views", diff --git a/src/i18n/ru/ui.ts b/src/i18n/ru/ui.ts index 77f4fa2..78a13bc 100644 --- a/src/i18n/ru/ui.ts +++ b/src/i18n/ru/ui.ts @@ -4,6 +4,7 @@ export default { "Здесь я публикую статьи и туториалы на разные IT темы, а также рассказываю о своих проектах которые я сделал за последние несколько лет.", "site.underConstruction": "Этот веб-сайт находится в разработке...", "article.availableOn": "Доступно на", + "article.tableOfContents": "Оглавление", "articles.empty": "Не найдено ни одной статьи...", "articlePost.comments": "Комментарии", "article.views": "просмотров", diff --git a/src/layouts/article.astro b/src/layouts/article.astro index 1f9a605..ce55910 100644 --- a/src/layouts/article.astro +++ b/src/layouts/article.astro @@ -8,15 +8,18 @@ import ArticleContent from "@components/ArticleContent.astro"; import ArticlePost from "@components/ArticlePost.astro"; import OpenGraph from "@components/OpenGraph.astro"; import TableOfContents from "@root/components/TableOfContents.astro"; +import { useTranslation } from "@root/i18n/utils"; export interface Props { lang?: string | undefined; article: CollectionEntry<"blog">; + availableOnLangs?: CollectionEntry<"blog">[]; headings: MarkdownHeading[]; } const canonicalUrl = new URL(Astro.url.pathname, Astro.site); -const { lang = DEFAULT_LANGUAGE, article, headings } = Astro.props as Props; +const t = useTranslation(Astro); +const { lang = DEFAULT_LANGUAGE, article, headings, availableOnLangs } = Astro.props as Props; const { data: { title, description, coverImage }, } = article; @@ -39,8 +42,8 @@ const { - - + + diff --git a/src/pages/[...blog].astro b/src/pages/[...blog].astro index 79c8d0a..79f2f6d 100644 --- a/src/pages/[...blog].astro +++ b/src/pages/[...blog].astro @@ -3,11 +3,6 @@ import { CollectionEntry, getCollection } from "astro:content"; import ArticleLayout from "@root/layouts/article.astro"; import { createRelativeArticleUrl, removeLanguageCodeFromPath } from "@root/utils"; import { getLanguageFromURL, useTranslation } from "@i18n/utils"; -import { URL_BLOG_PREFIX } from "@root/constants"; -import languages from "@i18n/languages"; - -const t = useTranslation(Astro); -const pageLang = getLanguageFromURL(Astro.url.pathname); /** * Generate articles pages from `blog` collection. @@ -26,7 +21,7 @@ export async function getStaticPaths() { params: { blog: url.slice(1) }, props: { article, - availableOnLang: collection.filter((e) => + availableOnLangs: collection.filter((e) => e.id.includes(removeLanguageCodeFromPath(article.id)) ), }, @@ -34,26 +29,17 @@ export async function getStaticPaths() { }); } -type Props = { article: CollectionEntry<"blog">; availableOnLang: CollectionEntry<"blog">[] }; +type Props = { article: CollectionEntry<"blog">; availableOnLangs: CollectionEntry<"blog">[] }; const { Content, headings } = await Astro.props.article.render(); -const { article, availableOnLang } = Astro.props; +const { article, availableOnLangs } = Astro.props; --- - - { - availableOnLang.length > 1 && ( - - {t("article.availableOn")}:{" "} - {availableOnLang - .filter((a) => !a.id.startsWith(`${pageLang}/`)) - .map(({ id, data: { title, pubDate } }) => ( - {`${ - languages[id.split("/")[0] as LanguageKeys] - }`} - ))} - - ) - } + diff --git a/src/utils/article.ts b/src/utils/article.ts index 7702193..6e05e77 100644 --- a/src/utils/article.ts +++ b/src/utils/article.ts @@ -66,7 +66,7 @@ export function getUniqueTags(articles: CollectionEntry<"blog">[]): string[] { export type MarkdownHeadingToc = MarkdownHeading & { subheadings: MarkdownHeading[] }; -export function buildToc(headings: MarkdownHeading[]) { +export function buildToc(headings: MarkdownHeading[], maxDepth: number = 2) { const toc: MarkdownHeadingToc[] = []; const parentHeadings = new Map(); headings.forEach((h) => { @@ -74,7 +74,7 @@ export function buildToc(headings: MarkdownHeading[]) { parentHeadings.set(heading.depth, heading); if (heading.depth === 1) { toc.push(heading); - } else { + } else if (heading.depth <= maxDepth) { parentHeadings.get(heading.depth - 1).subheadings.push(heading); } });