diff --git a/README.md b/README.md index 7a201e3..3d7c3c4 100644 --- a/README.md +++ b/README.md @@ -171,26 +171,26 @@ const CONFIG = { disabled: false, postsPerPage: 4, + post: { + permalink: '/%slug%', // variables: %slug%, %year%, %month%, %day%, %hour%, %minute%, %second%, %category% + noindex: false, + disabled: false, + }, + list: { pathname: 'blog', // Blog main path, you can change this to "articles" (/articles) noindex: false, disabled: false, }, - post: { - pathname: '', // Empty for /some-post, value for /pathname/some-post - noindex: false, - disabled: false, - }, - category: { - pathname: 'category', // Set empty to change from /category/some-category to /some-category + pathname: 'category', // Category main path /category/some-category noindex: true, disabled: false, }, tag: { - pathname: 'tag', // Set empty to change from /tag/some-tag to /some-tag + pathname: 'tag', // Tag main path /tag/some-tag noindex: true, disabled: false, }, diff --git a/src/components/blog/GridItem.astro b/src/components/blog/GridItem.astro index a873018..a8cd924 100644 --- a/src/components/blog/GridItem.astro +++ b/src/components/blog/GridItem.astro @@ -38,7 +38,7 @@ const image = await findImage(post.image); post.title ) : ( {post.title} diff --git a/src/components/blog/ListItem.astro b/src/components/blog/ListItem.astro index 20ce0b7..7acf199 100644 --- a/src/components/blog/ListItem.astro +++ b/src/components/blog/ListItem.astro @@ -17,7 +17,7 @@ export interface Props { const { post } = Astro.props; const image = await findImage(post.image); -const link = !BLOG?.post?.disabled ? getPermalink(post.slug, 'post') : ''; +const link = !BLOG?.post?.disabled ? getPermalink(post.permalink, 'post') : ''; ---
diff --git a/src/config.mjs b/src/config.mjs index 2ff79fc..f31628e 100644 --- a/src/config.mjs +++ b/src/config.mjs @@ -31,26 +31,26 @@ const CONFIG = { disabled: false, postsPerPage: 4, - list: { - pathname: 'blog', // blog main path, you can change this to "articles" (/articles) + post: { + permalink: '/%slug%', // Variables: %slug%, %year%, %month%, %day%, %hour%, %minute%, %second%, %category% noindex: false, disabled: false, }, - post: { - pathname: '', // empty for /some-post, value for /pathname/some-post + list: { + pathname: 'blog', // Blog main path, you can change this to "articles" (/articles) noindex: false, disabled: false, }, category: { - pathname: 'category', // set empty to change from /category/some-category to /some-category + pathname: 'category', // Category main path /category/some-category noindex: true, disabled: false, }, tag: { - pathname: 'tag', // set empty to change from /tag/some-tag to /some-tag + pathname: 'tag', // Tag main path /tag/some-tag noindex: true, disabled: false, }, diff --git a/src/pages/[...blog]/[slug].astro b/src/pages/[...blog]/index.astro similarity index 77% rename from src/pages/[...blog]/[slug].astro rename to src/pages/[...blog]/index.astro index bf5de85..43141e7 100644 --- a/src/pages/[...blog]/[slug].astro +++ b/src/pages/[...blog]/index.astro @@ -5,7 +5,7 @@ import Layout from '~/layouts/PageLayout.astro'; import SinglePost from '~/components/blog/SinglePost.astro'; import ToBlogLink from '~/components/blog/ToBlogLink.astro'; -import { getCanonical, getPermalink, POST_BASE } from '~/utils/permalinks'; +import { getCanonical, getPermalink } from '~/utils/permalinks'; import { fetchPosts } from '~/utils/blog'; import { findImage } from '~/utils/images'; @@ -13,20 +13,19 @@ export async function getStaticPaths() { if (BLOG?.disabled || BLOG?.post?.disabled) return []; return (await fetchPosts()).map((post) => ({ params: { - slug: post.slug, - blog: POST_BASE || undefined, + blog: post.permalink, }, props: { post }, })); } const { post } = Astro.props; -const url = getCanonical(getPermalink(post.slug, 'post')); +const url = getCanonical(getPermalink(post.permalink, 'post')); const meta = { title: post.title, description: post.description, - canonical: post.canonical || undefined, + canonical: post.canonical || url, image: await findImage(post.image), noindex: BLOG?.post?.noindex, ogType: 'article', diff --git a/src/utils/blog.ts b/src/utils/blog.ts index 2396f8c..cfd5b3d 100644 --- a/src/utils/blog.ts +++ b/src/utils/blog.ts @@ -1,27 +1,60 @@ import { getCollection } from 'astro:content'; import type { CollectionEntry } from 'astro:content'; import type { Post } from '~/types'; -import { cleanSlug } from './permalinks'; +import { cleanSlug, POST_PERMALINK_PATTERN } from './permalinks'; + +const generatePermalink = async ({ id, slug, publishDate, category }) => { + const year = String(publishDate.getFullYear()).padStart(4, '0'); + const month = String(publishDate.getMonth() + 1).padStart(2, '0'); + const day = String(publishDate.getDate()).padStart(2, '0'); + const hour = String(publishDate.getHours()).padStart(2, '0'); + const minute = String(publishDate.getMinutes()).padStart(2, '0'); + const second = String(publishDate.getSeconds()).padStart(2, '0'); + + return POST_PERMALINK_PATTERN + .replace('%slug%', slug) + .replace('%id%', id) + .replace('%category%', category) + .replace('%year%', year) + .replace('%month%', month) + .replace('%day%', day) + .replace('%hour%', hour) + .replace('%minute%', minute) + .replace('%second%', second); +}; const getNormalizedPost = async (post: CollectionEntry<'posts'>): Promise => { - const { id, slug = '', data } = post; + const { id, slug: rawSlug = '', data } = post; const { Content } = await post.render(); - const { tags = [], category = 'default', author = 'Anonymous', publishDate = new Date(), ...rest } = data; + const { + tags: rawTags = [], + category: rawCategory = 'default', + author = 'Anonymous', + publishDate: rawPublishDate = new Date(), + ...rest + } = data; + + const slug = cleanSlug(rawSlug.split('/').pop()); + const publishDate = new Date(rawPublishDate); + const category = cleanSlug(rawCategory); + const tags = rawTags.map((tag: string) => cleanSlug(tag)); return { id: id, - slug: cleanSlug(slug.split('/').pop()), + slug: slug, - publishDate: new Date(publishDate), - category: cleanSlug(category), - tags: tags.map((tag: string) => cleanSlug(tag)), - author, + publishDate: publishDate, + category: category, + tags: tags, + author: author, ...rest, Content: Content, // or 'body' in case you consume from API + + permalink: await generatePermalink({ id, slug, publishDate, category }), }; }; diff --git a/src/utils/permalinks.ts b/src/utils/permalinks.ts index c5999a6..aec0c56 100644 --- a/src/utils/permalinks.ts +++ b/src/utils/permalinks.ts @@ -20,10 +20,11 @@ export const cleanSlug = (text = '') => .map((slug) => slugify(slug)) .join('/'); +export const POST_PERMALINK_PATTERN = trimSlash(BLOG?.post?.permalink || '/%slug%'); + export const BLOG_BASE = cleanSlug(BLOG?.list?.pathname); -export const POST_BASE = cleanSlug(BLOG?.post?.pathname); -export const CATEGORY_BASE = cleanSlug(BLOG?.category?.pathname); -export const TAG_BASE = cleanSlug(BLOG?.tag?.pathname); +export const CATEGORY_BASE = cleanSlug(BLOG?.category?.pathname || 'category'); +export const TAG_BASE = cleanSlug(BLOG?.tag?.pathname) || 'tag'; /** */ export const getCanonical = (path = ''): string | URL => new URL(path, SITE.origin); @@ -34,15 +35,15 @@ export const getPermalink = (slug = '', type = 'page'): string => { switch (type) { case 'category': - permalink = createPath(CATEGORY_BASE, cleanSlug(slug)); + permalink = createPath(CATEGORY_BASE, trimSlash(slug)); break; case 'tag': - permalink = createPath(TAG_BASE, cleanSlug(slug)); + permalink = createPath(TAG_BASE, trimSlash(slug)); break; case 'post': - permalink = createPath(POST_BASE, cleanSlug(slug)); + permalink = createPath(trimSlash(slug)); break; case 'page':