Merge pull request #99 from prototypa/astro2
Allow post permalink pattern configuration
This commit is contained in:
16
README.md
16
README.md
@ -171,26 +171,26 @@ const CONFIG = {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
postsPerPage: 4,
|
postsPerPage: 4,
|
||||||
|
|
||||||
|
post: {
|
||||||
|
permalink: '/%slug%', // variables: %slug%, %year%, %month%, %day%, %hour%, %minute%, %second%, %category%
|
||||||
|
noindex: false,
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
|
||||||
list: {
|
list: {
|
||||||
pathname: 'blog', // Blog main path, you can change this to "articles" (/articles)
|
pathname: 'blog', // Blog main path, you can change this to "articles" (/articles)
|
||||||
noindex: false,
|
noindex: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
post: {
|
|
||||||
pathname: '', // Empty for /some-post, value for /pathname/some-post
|
|
||||||
noindex: false,
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
category: {
|
category: {
|
||||||
pathname: 'category', // Set empty to change from /category/some-category to /some-category
|
pathname: 'category', // Category main path /category/some-category
|
||||||
noindex: true,
|
noindex: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
tag: {
|
tag: {
|
||||||
pathname: 'tag', // Set empty to change from /tag/some-tag to /some-tag
|
pathname: 'tag', // Tag main path /tag/some-tag
|
||||||
noindex: true,
|
noindex: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
},
|
},
|
||||||
|
@ -38,7 +38,7 @@ const image = await findImage(post.image);
|
|||||||
post.title
|
post.title
|
||||||
) : (
|
) : (
|
||||||
<a
|
<a
|
||||||
href={getPermalink(post.slug, 'post')}
|
href={getPermalink(post.permalink, 'post')}
|
||||||
class="hover:text-primary dark:hover:text-blue-700 transition ease-in duration-200"
|
class="hover:text-primary dark:hover:text-blue-700 transition ease-in duration-200"
|
||||||
>
|
>
|
||||||
{post.title}
|
{post.title}
|
||||||
|
@ -17,7 +17,7 @@ export interface Props {
|
|||||||
const { post } = Astro.props;
|
const { post } = Astro.props;
|
||||||
const image = await findImage(post.image);
|
const image = await findImage(post.image);
|
||||||
|
|
||||||
const link = !BLOG?.post?.disabled ? getPermalink(post.slug, 'post') : '';
|
const link = !BLOG?.post?.disabled ? getPermalink(post.permalink, 'post') : '';
|
||||||
---
|
---
|
||||||
|
|
||||||
<article class={`max-w-md mx-auto md:max-w-none grid gap-6 md:gap-8 ${image ? 'md:grid-cols-2' : ''}`}>
|
<article class={`max-w-md mx-auto md:max-w-none grid gap-6 md:gap-8 ${image ? 'md:grid-cols-2' : ''}`}>
|
||||||
|
@ -31,26 +31,26 @@ const CONFIG = {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
postsPerPage: 4,
|
postsPerPage: 4,
|
||||||
|
|
||||||
list: {
|
post: {
|
||||||
pathname: 'blog', // blog main path, you can change this to "articles" (/articles)
|
permalink: '/%slug%', // Variables: %slug%, %year%, %month%, %day%, %hour%, %minute%, %second%, %category%
|
||||||
noindex: false,
|
noindex: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
post: {
|
list: {
|
||||||
pathname: '', // empty for /some-post, value for /pathname/some-post
|
pathname: 'blog', // Blog main path, you can change this to "articles" (/articles)
|
||||||
noindex: false,
|
noindex: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
category: {
|
category: {
|
||||||
pathname: 'category', // set empty to change from /category/some-category to /some-category
|
pathname: 'category', // Category main path /category/some-category
|
||||||
noindex: true,
|
noindex: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
tag: {
|
tag: {
|
||||||
pathname: 'tag', // set empty to change from /tag/some-tag to /some-tag
|
pathname: 'tag', // Tag main path /tag/some-tag
|
||||||
noindex: true,
|
noindex: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
},
|
},
|
||||||
|
@ -5,7 +5,7 @@ import Layout from '~/layouts/PageLayout.astro';
|
|||||||
import SinglePost from '~/components/blog/SinglePost.astro';
|
import SinglePost from '~/components/blog/SinglePost.astro';
|
||||||
import ToBlogLink from '~/components/blog/ToBlogLink.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 { fetchPosts } from '~/utils/blog';
|
||||||
import { findImage } from '~/utils/images';
|
import { findImage } from '~/utils/images';
|
||||||
|
|
||||||
@ -13,20 +13,19 @@ export async function getStaticPaths() {
|
|||||||
if (BLOG?.disabled || BLOG?.post?.disabled) return [];
|
if (BLOG?.disabled || BLOG?.post?.disabled) return [];
|
||||||
return (await fetchPosts()).map((post) => ({
|
return (await fetchPosts()).map((post) => ({
|
||||||
params: {
|
params: {
|
||||||
slug: post.slug,
|
blog: post.permalink,
|
||||||
blog: POST_BASE || undefined,
|
|
||||||
},
|
},
|
||||||
props: { post },
|
props: { post },
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { post } = Astro.props;
|
const { post } = Astro.props;
|
||||||
const url = getCanonical(getPermalink(post.slug, 'post'));
|
const url = getCanonical(getPermalink(post.permalink, 'post'));
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: post.title,
|
title: post.title,
|
||||||
description: post.description,
|
description: post.description,
|
||||||
canonical: post.canonical || undefined,
|
canonical: post.canonical || url,
|
||||||
image: await findImage(post.image),
|
image: await findImage(post.image),
|
||||||
noindex: BLOG?.post?.noindex,
|
noindex: BLOG?.post?.noindex,
|
||||||
ogType: 'article',
|
ogType: 'article',
|
@ -1,27 +1,60 @@
|
|||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
import type { CollectionEntry } from 'astro:content';
|
import type { CollectionEntry } from 'astro:content';
|
||||||
import type { Post } from '~/types';
|
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<Post> => {
|
const getNormalizedPost = async (post: CollectionEntry<'posts'>): Promise<Post> => {
|
||||||
const { id, slug = '', data } = post;
|
const { id, slug: rawSlug = '', data } = post;
|
||||||
const { Content } = await post.render();
|
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 {
|
return {
|
||||||
id: id,
|
id: id,
|
||||||
slug: cleanSlug(slug.split('/').pop()),
|
slug: slug,
|
||||||
|
|
||||||
publishDate: new Date(publishDate),
|
publishDate: publishDate,
|
||||||
category: cleanSlug(category),
|
category: category,
|
||||||
tags: tags.map((tag: string) => cleanSlug(tag)),
|
tags: tags,
|
||||||
author,
|
author: author,
|
||||||
|
|
||||||
...rest,
|
...rest,
|
||||||
|
|
||||||
Content: Content,
|
Content: Content,
|
||||||
// or 'body' in case you consume from API
|
// or 'body' in case you consume from API
|
||||||
|
|
||||||
|
permalink: await generatePermalink({ id, slug, publishDate, category }),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,10 +20,11 @@ export const cleanSlug = (text = '') =>
|
|||||||
.map((slug) => slugify(slug))
|
.map((slug) => slugify(slug))
|
||||||
.join('/');
|
.join('/');
|
||||||
|
|
||||||
|
export const POST_PERMALINK_PATTERN = trimSlash(BLOG?.post?.permalink || '/%slug%');
|
||||||
|
|
||||||
export const BLOG_BASE = cleanSlug(BLOG?.list?.pathname);
|
export const BLOG_BASE = cleanSlug(BLOG?.list?.pathname);
|
||||||
export const POST_BASE = cleanSlug(BLOG?.post?.pathname);
|
export const CATEGORY_BASE = cleanSlug(BLOG?.category?.pathname || 'category');
|
||||||
export const CATEGORY_BASE = cleanSlug(BLOG?.category?.pathname);
|
export const TAG_BASE = cleanSlug(BLOG?.tag?.pathname) || 'tag';
|
||||||
export const TAG_BASE = cleanSlug(BLOG?.tag?.pathname);
|
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
export const getCanonical = (path = ''): string | URL => new URL(path, SITE.origin);
|
export const getCanonical = (path = ''): string | URL => new URL(path, SITE.origin);
|
||||||
@ -34,15 +35,15 @@ export const getPermalink = (slug = '', type = 'page'): string => {
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'category':
|
case 'category':
|
||||||
permalink = createPath(CATEGORY_BASE, cleanSlug(slug));
|
permalink = createPath(CATEGORY_BASE, trimSlash(slug));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'tag':
|
case 'tag':
|
||||||
permalink = createPath(TAG_BASE, cleanSlug(slug));
|
permalink = createPath(TAG_BASE, trimSlash(slug));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'post':
|
case 'post':
|
||||||
permalink = createPath(POST_BASE, cleanSlug(slug));
|
permalink = createPath(trimSlash(slug));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'page':
|
case 'page':
|
||||||
|
Reference in New Issue
Block a user