mirror of
https://github.com/10h30/astroplate.git
synced 2026-06-05 15:08:00 +09:00
tags pages added
This commit is contained in:
@@ -12,10 +12,6 @@
|
||||
"logo_text": "Astroplate"
|
||||
},
|
||||
|
||||
"language": {
|
||||
"defaultLang": "en"
|
||||
},
|
||||
|
||||
"settings": {
|
||||
"search": true,
|
||||
"sticky_header": true,
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
{
|
||||
"main": [
|
||||
{
|
||||
"name": "Home",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"name": "About",
|
||||
"url": "/about"
|
||||
},
|
||||
{
|
||||
"name": "Elements",
|
||||
"url": "/elements"
|
||||
},
|
||||
{
|
||||
"name": "Pages",
|
||||
"url": "",
|
||||
"hasChildren": true,
|
||||
"children": [
|
||||
{
|
||||
"name": "Contact",
|
||||
"url": "/contact"
|
||||
},
|
||||
{
|
||||
"name": "Blog",
|
||||
"url": "/blog"
|
||||
},
|
||||
{
|
||||
"name": "Authors",
|
||||
"url": "/authors"
|
||||
},
|
||||
{
|
||||
"name": "Categories",
|
||||
"url": "/categories"
|
||||
},
|
||||
{
|
||||
"name": "Tags",
|
||||
"url": "/tags"
|
||||
},
|
||||
{
|
||||
"name": "404 Page",
|
||||
"url": "/404"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"footer": [
|
||||
{
|
||||
"name": "Elements",
|
||||
"url": "/elements"
|
||||
},
|
||||
{
|
||||
"name": "Privacy Policy",
|
||||
"url": "/privacy-policy"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,19 +1,25 @@
|
||||
---
|
||||
import BlogCard from "@/components/BlogCard.astro";
|
||||
import Share from "@/components/Share.astro";
|
||||
import config from "@/config/config.json";
|
||||
import Disqus from "@/helpers/Disqus";
|
||||
import { getSinglePage } from "@/lib/contentParser.astro";
|
||||
import dateFormat from "@/lib/utils/dateFormat";
|
||||
import similarItems from "@/lib/utils/similarItems";
|
||||
import { humanize, markdownify, slugify } from "@/lib/utils/textConverter";
|
||||
import type { ContentEntryMap } from "astro:content";
|
||||
import { FaRegClock, FaRegFolder, FaRegUserCircle } from "react-icons/fa";
|
||||
import ImageMod from "./components/ImageMod.astro";
|
||||
const { default_language } = config.settings;
|
||||
|
||||
const COLLECTION_FOLDER = "blog";
|
||||
const { post } = Astro.props;
|
||||
const { lang } = Astro.params;
|
||||
|
||||
const posts = await getSinglePage(COLLECTION_FOLDER);
|
||||
const posts = await getSinglePage(
|
||||
COLLECTION_FOLDER,
|
||||
lang as keyof ContentEntryMap,
|
||||
);
|
||||
const similarPosts = similarItems(post, posts);
|
||||
const { Content } = await post.render();
|
||||
const { title, description, author, categories, image, date, tags } = post.data;
|
||||
@@ -40,7 +46,9 @@ const { title, description, author, categories, image, date, tags } = post.data;
|
||||
<h1 set:html={markdownify(title)} class="h2 mb-4" />
|
||||
<ul class="mb-4">
|
||||
<li class="mr-4 inline-block">
|
||||
<a href={`/${lang === "en" ? "authors" + "/" : lang}/authors/${slugify(author)}`} >
|
||||
<a
|
||||
href={`/${lang === default_language ? "authors" + "/" : lang}/authors/${slugify(author)}`}
|
||||
>
|
||||
<FaRegUserCircle className={"mr-2 -mt-1 inline-block"} />
|
||||
{humanize(author)}
|
||||
</a>
|
||||
@@ -50,7 +58,7 @@ const { title, description, author, categories, image, date, tags } = post.data;
|
||||
{
|
||||
categories.map((category: string, index: number) => (
|
||||
<a
|
||||
href={`/${lang === "en" ? "categories" + "/" : lang}/categories/${slugify(category)}`}
|
||||
href={`/${lang === default_language ? "categories" + "/" : lang}/categories/${slugify(category)}`}
|
||||
>
|
||||
{humanize(category)}
|
||||
{index !== categories.length - 1 && ","}
|
||||
|
||||
@@ -3,6 +3,8 @@ import { getLangFromUrl } from "@/lib/utils/i18nUtils";
|
||||
import { plainify } from "@/lib/utils/textConverter";
|
||||
import ImageMod from "./ImageMod.astro";
|
||||
import Social from "./Social.astro";
|
||||
import config from "@/config/config.json";
|
||||
const { default_language } = config.settings;
|
||||
|
||||
const { data } = Astro.props;
|
||||
const { title, image, social } = data.data;
|
||||
@@ -25,7 +27,8 @@ const lang = getLangFromUrl(Astro.url);
|
||||
)
|
||||
}
|
||||
<h4 class="mb-3">
|
||||
<a href={`/${lang === "en" ? "authors" + "/" : lang}/${data.slug}`}
|
||||
<a
|
||||
href={`/${lang === default_language ? "authors" + "/" : lang}/${data.slug}`}
|
||||
>{title}</a
|
||||
>
|
||||
</h4>
|
||||
|
||||
@@ -7,11 +7,9 @@ import type { ContentEntryMap } from "astro:content";
|
||||
import { FaRegFolder, FaRegUserCircle } from "react-icons/fa";
|
||||
import ImageMod from "./ImageMod.astro";
|
||||
|
||||
const {
|
||||
summary_length,
|
||||
blog_folder,
|
||||
}: { summary_length: number; blog_folder: string } = config.settings;
|
||||
const { defaultLang } = config.language;
|
||||
const { summary_length }: { summary_length: number; blog_folder: string } =
|
||||
config.settings;
|
||||
const { default_language } = config.settings;
|
||||
const { data } = Astro.props;
|
||||
const { title, image, date, author, categories } = data.data;
|
||||
|
||||
@@ -34,17 +32,15 @@ const { read_more } = await getTranslations(lang as keyof ContentEntryMap);
|
||||
)
|
||||
}
|
||||
<h4 class="mb-3">
|
||||
<a
|
||||
href={path.includes("/categories")
|
||||
? `${lang === defaultLang ? "" : `/${lang}`}/blog/${data.slug}`
|
||||
: `${lang === defaultLang ? "" : `/${lang}`}/${data.slug}`}
|
||||
>
|
||||
<a href={`${lang === default_language ? "" : `/${lang}`}/${data.slug}`}>
|
||||
{title}
|
||||
</a>
|
||||
</h4>
|
||||
<ul class="mb-4">
|
||||
<li class="mr-4 inline-block">
|
||||
<a href={`/${lang}/authors/${slugify(author)}`}>
|
||||
<a
|
||||
href={`${lang === default_language ? "" : `/${lang}`}/authors/${slugify(author)}`}
|
||||
>
|
||||
<FaRegUserCircle className={"mr-2 -mt-1 inline-block"} />
|
||||
{humanize(author)}
|
||||
</a>
|
||||
@@ -53,7 +49,9 @@ const { read_more } = await getTranslations(lang as keyof ContentEntryMap);
|
||||
<FaRegFolder className={"mr-2 -mt-1 inline-block"} />
|
||||
{
|
||||
categories.map((category: string, index: number) => (
|
||||
<a href={`/${lang}/categories/${slugify(category)}`}>
|
||||
<a
|
||||
href={`${lang === default_language ? "" : `/${lang}`}/categories/${slugify(category)}`}
|
||||
>
|
||||
{humanize(category)}
|
||||
{index !== categories.length - 1 && ","}
|
||||
</a>
|
||||
@@ -65,9 +63,7 @@ const { read_more } = await getTranslations(lang as keyof ContentEntryMap);
|
||||
<p class="mb-6">{plainify(data.body?.slice(0, Number(summary_length)))}</p>
|
||||
<a
|
||||
class="btn btn-outline-primary btn-sm"
|
||||
href={path.includes("/categories")
|
||||
? `${lang === defaultLang ? "" : `/${lang}`}/blog/${data.slug}`
|
||||
: `${lang === defaultLang ? "" : `/${lang}`}/${data.slug}`}
|
||||
href={`${lang === default_language ? "" : `/${lang}`}/${data.slug}`}
|
||||
>
|
||||
{read_more}
|
||||
</a>
|
||||
|
||||
@@ -1,32 +1,42 @@
|
||||
import config from "@/config/config.json";
|
||||
import languages from "@/config/language.json";
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
const LanguageSwitcher = ({ lang, pathname }: { lang: string; pathname: string }) => {
|
||||
const LanguageSwitcher = ({
|
||||
lang,
|
||||
pathname,
|
||||
}: {
|
||||
lang: string;
|
||||
pathname: string;
|
||||
}) => {
|
||||
const { default_language } = config.settings;
|
||||
|
||||
return (
|
||||
<div className="mr-5">
|
||||
<select
|
||||
className="border border-dark py-1 rounded-sm"
|
||||
onChange={(e) => {
|
||||
const selectedLang = e.target.value;
|
||||
const newPath = selectedLang === "en"
|
||||
? pathname.replace(`/${lang}`, "")
|
||||
: `/${selectedLang}${pathname.replace(`/${lang}`, "")}`;
|
||||
window.location.href = newPath;
|
||||
}}
|
||||
value={lang}
|
||||
>
|
||||
{languages.map((language) => (
|
||||
<option
|
||||
key={language.languageCode}
|
||||
value={language.languageCode}
|
||||
>
|
||||
{language.languageName}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className="mr-5">
|
||||
<select
|
||||
className="border border-dark text-dark bg-transparent dark:border-darkmode-primary dark:text-white py-1 rounded-sm dark:bg cursor-pointer"
|
||||
onChange={(e) => {
|
||||
const selectedLang = e.target.value;
|
||||
const newPath =
|
||||
selectedLang === default_language
|
||||
? pathname.replace(`/${lang}`, "")
|
||||
: `/${selectedLang}${pathname.replace(`/${lang}`, "")}`;
|
||||
window.location.href = newPath;
|
||||
}}
|
||||
value={lang}
|
||||
>
|
||||
{languages.map((language) => (
|
||||
<option
|
||||
className="dark:text-dark"
|
||||
key={language.languageCode}
|
||||
value={language.languageCode}
|
||||
>
|
||||
{language.languageName}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LanguageSwitcher;
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
import Logo from "@/components/Logo.astro";
|
||||
import Social from "@/components/Social.astro";
|
||||
import config from "@/config/config.json";
|
||||
import menu from "@/config/menu.json";
|
||||
import social from "@/config/social.json";
|
||||
import { getLangFromUrl } from "@/lib/utils/i18nUtils";
|
||||
import { loadMenu } from "@/lib/utils/loadMenu";
|
||||
import { markdownify } from "@/lib/utils/textConverter";
|
||||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const menu = loadMenu(lang);
|
||||
const { footer }: { footer: { name: string; url: string }[] } = menu;
|
||||
---
|
||||
|
||||
|
||||
@@ -10,17 +10,17 @@ import config from "@/config/config.json";
|
||||
|
||||
export const getSinglePage = async <C extends CollectionKey>(
|
||||
collectionName: C,
|
||||
lang: keyof ContentEntryMap
|
||||
lang: keyof ContentEntryMap,
|
||||
): Promise<CollectionEntry<C>[]> => {
|
||||
const { defaultLang } = config.language;
|
||||
const { default_language } = config.settings;
|
||||
const langCollection: keyof ContentEntryMap = lang as keyof ContentEntryMap;
|
||||
|
||||
// Explicitly define the type of pages to CollectionEntry<C>[]
|
||||
const pages: CollectionEntry<C>[] = (await getCollection(
|
||||
langCollection || defaultLang,
|
||||
langCollection || default_language,
|
||||
({ id }: any) => {
|
||||
return id.startsWith(collectionName) && !id.endsWith("-index.md");
|
||||
}
|
||||
},
|
||||
)) as CollectionEntry<C>[];
|
||||
|
||||
const removeDrafts = pages.filter((data) => !data.data.draft);
|
||||
@@ -29,16 +29,16 @@ export const getSinglePage = async <C extends CollectionKey>(
|
||||
|
||||
export const getListPage = async <C extends CollectionKey>(
|
||||
collectionName: C,
|
||||
lang: keyof ContentEntryMap
|
||||
lang: keyof ContentEntryMap,
|
||||
): Promise<CollectionEntry<C>[]> => {
|
||||
const { defaultLang } = config.language;
|
||||
const { default_language } = config.settings;
|
||||
const langCollection: keyof ContentEntryMap = lang as keyof ContentEntryMap;
|
||||
// Fetch the collection based on the language
|
||||
const pages: CollectionEntry<C>[] = (await getCollection(
|
||||
langCollection || defaultLang,
|
||||
langCollection || default_language,
|
||||
({ id }: any) => {
|
||||
return id.startsWith(collectionName);
|
||||
}
|
||||
},
|
||||
)) as CollectionEntry<C>[];
|
||||
|
||||
return pages;
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
---
|
||||
import config from "@/config/config.json";
|
||||
import { slugify } from "@/lib/utils/textConverter";
|
||||
import type { ContentEntryMap } from "astro:content";
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
// get taxonomy from frontmatter
|
||||
export const getTaxonomy = async (collection: any, name: string) => {
|
||||
// const singlePages = await getSinglePage(collection);
|
||||
const { default_language } = config.settings;
|
||||
const actualCollection =
|
||||
collection !== ("" || undefined) ? collection : default_language;
|
||||
|
||||
const singlePages = await getCollection(
|
||||
collection as keyof ContentEntryMap,
|
||||
actualCollection as keyof ContentEntryMap,
|
||||
({ id }: any) => {
|
||||
return id.startsWith("blog") && !id.endsWith("-index.md");
|
||||
}
|
||||
},
|
||||
);
|
||||
const taxonomyPages = singlePages.map((page: any) => page.data[name]);
|
||||
let taxonomies: string[] = [];
|
||||
@@ -26,12 +30,14 @@ export const getTaxonomy = async (collection: any, name: string) => {
|
||||
|
||||
// get all taxonomies from frontmatter
|
||||
export const getAllTaxonomy = async (collection: any, name: string) => {
|
||||
// const singlePages = await getSinglePage(collection);
|
||||
const { default_language } = config.settings;
|
||||
const actualCollection =
|
||||
collection !== ("" || undefined) ? collection : default_language;
|
||||
const singlePages = await getCollection(
|
||||
collection as keyof ContentEntryMap,
|
||||
actualCollection as keyof ContentEntryMap,
|
||||
({ id }: any) => {
|
||||
return id.startsWith("blog") && !id.endsWith("-index.md");
|
||||
}
|
||||
},
|
||||
);
|
||||
const taxonomyPages = singlePages.map((page: any) => page.data[name]);
|
||||
let taxonomies: string[] = [];
|
||||
|
||||
@@ -2,7 +2,7 @@ import config from "@/config/config.json";
|
||||
import languagesJSON from "@/config/language.json";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
const { defaultLang } = config.language;
|
||||
const { default_language } = config.settings;
|
||||
|
||||
const menusFolderPath = "./src/config";
|
||||
|
||||
@@ -30,12 +30,16 @@ export function getLangFromUrl(url: URL): string {
|
||||
if (locales.hasOwnProperty(lang)) {
|
||||
return lang;
|
||||
}
|
||||
return defaultLang;
|
||||
return default_language;
|
||||
}
|
||||
|
||||
export const getTranslations = async (lang: string) => {
|
||||
const menu = await import(`../../config/menu.${lang || defaultLang}.json`);
|
||||
const dictionary = await import(`../../i18n/${lang || defaultLang}.json`);
|
||||
const menu = await import(
|
||||
`../../config/menu.${lang || default_language}.json`
|
||||
);
|
||||
const dictionary = await import(
|
||||
`../../i18n/${lang || default_language}.json`
|
||||
);
|
||||
return { ...menu, ...dictionary };
|
||||
};
|
||||
|
||||
|
||||
+7
-4
@@ -1,9 +1,12 @@
|
||||
---
|
||||
import config from "@/config/config.json";
|
||||
import Base from "@/layouts/Base.astro";
|
||||
import { getLangFromUrl, getTranslations } from "@/lib/utils/i18nUtils";
|
||||
import {
|
||||
getLangFromUrl,
|
||||
getTranslations,
|
||||
supportedLang,
|
||||
} from "@/lib/utils/i18nUtils";
|
||||
import type { ContentEntryMap } from "astro:content";
|
||||
import { supportedLang } from "@/lib/utils/i18nUtils";
|
||||
|
||||
export function getStaticPaths() {
|
||||
const paths = supportedLang.map((lang) => ({
|
||||
@@ -15,8 +18,8 @@ export function getStaticPaths() {
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const { page_not_found_content, page_not_found, back_to_home } =
|
||||
await getTranslations(lang as keyof ContentEntryMap);
|
||||
const { defaultLang } = config.language;
|
||||
const href = lang && lang !== defaultLang ? `/${lang}/` : "/";
|
||||
const { default_language } = config.settings;
|
||||
const href = lang && lang !== default_language ? `/${lang}/` : "/";
|
||||
---
|
||||
|
||||
<Base title="Page Not Found">
|
||||
|
||||
@@ -4,6 +4,8 @@ import Base from "@/layouts/Base.astro";
|
||||
import { getListPage } from "@/lib/contentParser.astro";
|
||||
import { supportedLang } from "@/lib/utils/i18nUtils";
|
||||
import { markdownify } from "@/lib/utils/textConverter";
|
||||
import type { ContentEntryMap } from "astro:content";
|
||||
import type { ContentCollectionKey } from "astro:content";
|
||||
|
||||
export function getStaticPaths() {
|
||||
const paths = supportedLang.map((lang) => ({
|
||||
@@ -13,7 +15,10 @@ export function getStaticPaths() {
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const about = await getListPage("about", lang);
|
||||
const about: any = await getListPage(
|
||||
"about" as ContentCollectionKey,
|
||||
lang as keyof ContentEntryMap,
|
||||
);
|
||||
|
||||
const { Content } = await about[0].render();
|
||||
const { title, description, meta_title, image } = about[0].data;
|
||||
|
||||
@@ -7,6 +7,7 @@ import { supportedLang } from "@/lib/utils/i18nUtils";
|
||||
import { sortByDate } from "@/lib/utils/sortFunctions";
|
||||
import taxonomyFilter from "@/lib/utils/taxonomyFilter";
|
||||
import PageHeader from "@/partials/PageHeader.astro";
|
||||
import type { ContentEntryMap } from "astro:content";
|
||||
|
||||
// get all static paths for categories
|
||||
export async function getStaticPaths() {
|
||||
@@ -23,7 +24,7 @@ export async function getStaticPaths() {
|
||||
category,
|
||||
},
|
||||
}));
|
||||
})
|
||||
}),
|
||||
);
|
||||
return paths.flat();
|
||||
}
|
||||
@@ -32,7 +33,7 @@ const { category, lang } = Astro.params;
|
||||
|
||||
// get posts by category
|
||||
const BLOG_FOLDER = "blog";
|
||||
const posts = await getSinglePage(BLOG_FOLDER, lang as any);
|
||||
const posts = await getSinglePage(BLOG_FOLDER, lang as keyof ContentEntryMap);
|
||||
const filterByCategories = taxonomyFilter(posts, "categories", category!);
|
||||
const sortedPosts = sortByDate(filterByCategories);
|
||||
---
|
||||
|
||||
@@ -30,7 +30,7 @@ const allCategories = await getAllTaxonomy(langCollection, "categories");
|
||||
return (
|
||||
<li class="m-3 inline-block">
|
||||
<a
|
||||
href={`/${lang === "en" ? "categories" + "/" : lang}/categories/${category}`}
|
||||
href={`/${lang === "" ? "categories" + "/" : lang}/categories/${category}`}
|
||||
class="block rounded bg-theme-light px-4 py-2 text-xl text-dark dark:bg-darkmode-theme-light dark:text-darkmode-dark"
|
||||
>
|
||||
{humanize(category)}{" "}
|
||||
|
||||
@@ -3,15 +3,15 @@ import ImageMod from "@/components/ImageMod.astro";
|
||||
import config from "@/config/config.json";
|
||||
import Base from "@/layouts/Base.astro";
|
||||
import { getListPage } from "@/lib/contentParser.astro";
|
||||
import { supportedLang } from "@/lib/utils/i18nUtils";
|
||||
import { markdownify } from "@/lib/utils/textConverter";
|
||||
import CallToAction from "@/partials/CallToAction.astro";
|
||||
import Testimonial from "@/partials/Testimonial.astro";
|
||||
import type { Button, Feature } from "@/types";
|
||||
import type { ContentEntryMap } from "astro:content";
|
||||
import type { ContentCollectionKey, ContentEntryMap } from "astro:content";
|
||||
import { getCollection } from "astro:content";
|
||||
import { FaCheck } from "react-icons/fa";
|
||||
const { defaultLang } = config.language;
|
||||
import { supportedLang } from "@/lib/utils/i18nUtils";
|
||||
const { default_language } = config.settings;
|
||||
|
||||
interface Homepage {
|
||||
banner: {
|
||||
@@ -31,22 +31,25 @@ export function getStaticPaths() {
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const homepage = await getListPage("homepage", lang);
|
||||
const { banner, features }: Homepage = homepage[0].data;
|
||||
const homepage: any = await getListPage(
|
||||
"homepage" as ContentCollectionKey,
|
||||
lang as keyof ContentEntryMap,
|
||||
);
|
||||
const { banner, features } = homepage[0].data;
|
||||
|
||||
const testimonial = await getCollection(
|
||||
(lang as keyof ContentEntryMap) || defaultLang,
|
||||
(lang as keyof ContentEntryMap) || default_language,
|
||||
({ id }: any) => {
|
||||
return id.startsWith("sections/testimonial") && !id.endsWith("-index.md");
|
||||
}
|
||||
},
|
||||
);
|
||||
const call_to_action = await getCollection(
|
||||
(lang as keyof ContentEntryMap) || defaultLang,
|
||||
(lang as keyof ContentEntryMap) || default_language,
|
||||
({ id }: any) => {
|
||||
return (
|
||||
id.startsWith("sections/call-to-action") && !id.endsWith("-index.md")
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
---
|
||||
|
||||
@@ -96,7 +99,7 @@ const call_to_action = await getCollection(
|
||||
|
||||
<!-- Features -->
|
||||
{
|
||||
features.map((feature, index: number) => (
|
||||
features.map((feature: Feature, index: number) => (
|
||||
<section class={`section-sm ${index % 2 === 0 && "bg-gradient"}`}>
|
||||
<div class="container">
|
||||
<div class="row items-center justify-between">
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
import BlogCard from "@/components/BlogCard.astro";
|
||||
import Base from "@/layouts/Base.astro";
|
||||
import { getSinglePage } from "@/lib/contentParser.astro";
|
||||
import { getTaxonomy } from "@/lib/taxonomyParser.astro";
|
||||
import { supportedLang } from "@/lib/utils/i18nUtils";
|
||||
import { sortByDate } from "@/lib/utils/sortFunctions";
|
||||
import taxonomyFilter from "@/lib/utils/taxonomyFilter";
|
||||
import PageHeader from "@/partials/PageHeader.astro";
|
||||
import type { ContentEntryMap } from "astro:content";
|
||||
|
||||
// get all static paths for categories
|
||||
export async function getStaticPaths() {
|
||||
const paths = await Promise.all(
|
||||
supportedLang.map(async (lang) => {
|
||||
const tags = await getTaxonomy(lang, "tags");
|
||||
|
||||
return tags.map((tag) => ({
|
||||
params: {
|
||||
lang: lang || undefined,
|
||||
tag: tag,
|
||||
},
|
||||
props: {
|
||||
tag,
|
||||
},
|
||||
}));
|
||||
}),
|
||||
);
|
||||
return paths.flat();
|
||||
}
|
||||
|
||||
const { tag, lang } = Astro.params;
|
||||
|
||||
// get posts by tag
|
||||
const BLOG_FOLDER = "blog";
|
||||
const posts = await getSinglePage(BLOG_FOLDER, lang as keyof ContentEntryMap);
|
||||
const filterByTags = taxonomyFilter(posts, "tags", tag!);
|
||||
const sortedPosts = sortByDate(filterByTags);
|
||||
---
|
||||
|
||||
<Base title={tag}>
|
||||
<PageHeader title={tag} />
|
||||
<div class="section-sm pb-0">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{
|
||||
sortedPosts.map((post) => (
|
||||
<div class="mb-14 md:col-6 lg:col-4">
|
||||
<BlogCard data={post} />
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Base>
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
import Base from "@/layouts/Base.astro";
|
||||
import { getAllTaxonomy, getTaxonomy } from "@/lib/taxonomyParser.astro";
|
||||
import { supportedLang } from "@/lib/utils/i18nUtils";
|
||||
import { humanize } from "@/lib/utils/textConverter";
|
||||
import PageHeader from "@/partials/PageHeader.astro";
|
||||
import type { ContentEntryMap } from "astro:content";
|
||||
|
||||
export function getStaticPaths() {
|
||||
const paths = supportedLang.map((lang) => ({
|
||||
params: { lang: lang || undefined },
|
||||
}));
|
||||
return paths;
|
||||
}
|
||||
|
||||
const { lang } = Astro.params;
|
||||
const langCollection: keyof ContentEntryMap = lang as keyof ContentEntryMap;
|
||||
const tags = await getTaxonomy(langCollection, "tags");
|
||||
const allTags = await getAllTaxonomy(langCollection, "tags");
|
||||
---
|
||||
|
||||
<Base title={"Tags"}>
|
||||
<PageHeader title={"Tags"} />
|
||||
<section class="section">
|
||||
<div class="container text-center">
|
||||
<ul>
|
||||
{
|
||||
tags.map((tag: any) => {
|
||||
const count = allTags.filter((c) => c === tag).length;
|
||||
return (
|
||||
<li class="m-3 inline-block">
|
||||
<a
|
||||
href={`/${lang === "" ? "tags" + "/" : lang}/tags/${tag}`}
|
||||
class="block rounded bg-theme-light px-4 py-2 text-xl text-dark dark:bg-darkmode-theme-light dark:text-darkmode-dark"
|
||||
>
|
||||
{humanize(tag)}{" "}
|
||||
<span class="ml-2 rounded bg-body px-2 dark:bg-darkmode-body">
|
||||
{count}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</Base>
|
||||
Reference in New Issue
Block a user