修改页面风格
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
---
|
||||
import ArticleSidebar from '@/components/ArticleSidebar.astro';
|
||||
import BaseLayout from '@/layouts/BaseLayout.astro';
|
||||
import { getAllPosts } from '@/lib/posts';
|
||||
|
||||
@@ -11,20 +12,93 @@ export function getStaticPaths() {
|
||||
|
||||
const { post } = Astro.props;
|
||||
const { Content } = post;
|
||||
const allPosts = getAllPosts();
|
||||
|
||||
function slugifyHeading(value: string): string {
|
||||
return value
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/<[^>]+>/g, '')
|
||||
.replace(/[`*_~[\]()]/g, '')
|
||||
.replace(/[^\p{Letter}\p{Number}\s-]/gu, '')
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-|-$/g, '');
|
||||
}
|
||||
|
||||
function makeToc(raw: string) {
|
||||
const used = new Map<string, number>();
|
||||
let inFence = false;
|
||||
|
||||
return raw
|
||||
.split(/\r?\n/)
|
||||
.flatMap((line) => {
|
||||
if (/^\s*```/.test(line)) {
|
||||
inFence = !inFence;
|
||||
return [];
|
||||
}
|
||||
|
||||
if (inFence) return [];
|
||||
|
||||
const match = /^(#{1,3})\s+(.+?)\s*#*$/.exec(line);
|
||||
if (!match) return [];
|
||||
|
||||
const text = match[2].replace(/<[^>]+>/g, '').trim();
|
||||
if (!text) return [];
|
||||
|
||||
const baseId = slugifyHeading(text) || 'section';
|
||||
const count = used.get(baseId) ?? 0;
|
||||
used.set(baseId, count + 1);
|
||||
|
||||
return [{
|
||||
depth: match[1].length,
|
||||
text,
|
||||
id: count === 0 ? baseId : `${baseId}-${count}`,
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
const toc = makeToc(post.rawContent?.() ?? '');
|
||||
const relatedPosts = allPosts
|
||||
.filter((item) => item.slug !== post.slug)
|
||||
.filter((item) => item.categories.some((category) => post.categories.includes(category)))
|
||||
.slice(0, 8);
|
||||
---
|
||||
|
||||
<BaseLayout title={post.title} description={post.summary}>
|
||||
<article class="article">
|
||||
<header class="article-header">
|
||||
<time datetime={post.date.toISOString()}>{post.dateText}</time>
|
||||
<h1>{post.title}</h1>
|
||||
<div class="meta-list">
|
||||
{post.categories.map((category) => <a href={`/categories/${encodeURIComponent(category)}/`}>{category}</a>)}
|
||||
{post.tags.map((tag) => <a href={`/tags/${encodeURIComponent(tag)}/`}>#{tag}</a>)}
|
||||
<section class="post-layout">
|
||||
<article class="article post-article">
|
||||
<header class="article-header">
|
||||
<time datetime={post.date.toISOString()}>{post.dateText}</time>
|
||||
<h1>{post.title}</h1>
|
||||
<div class="meta-list">
|
||||
{post.categories.map((category) => <a href={`/categories/${encodeURIComponent(category)}/`}>{category}</a>)}
|
||||
{post.tags.map((tag) => <a href={`/tags/${encodeURIComponent(tag)}/`}>#{tag}</a>)}
|
||||
</div>
|
||||
</header>
|
||||
<div class="prose" data-toc={JSON.stringify(toc)}>
|
||||
<Content />
|
||||
</div>
|
||||
</header>
|
||||
<div class="prose">
|
||||
<Content />
|
||||
</div>
|
||||
</article>
|
||||
</article>
|
||||
<ArticleSidebar post={post} toc={toc} relatedPosts={relatedPosts} />
|
||||
</section>
|
||||
</BaseLayout>
|
||||
|
||||
<script is:inline>
|
||||
(() => {
|
||||
const prose = document.querySelector('.prose[data-toc]');
|
||||
if (!prose) return;
|
||||
|
||||
let toc = [];
|
||||
try {
|
||||
toc = JSON.parse(prose.dataset.toc || '[]');
|
||||
} catch {
|
||||
toc = [];
|
||||
}
|
||||
|
||||
prose.querySelectorAll('h1, h2, h3').forEach((heading, index) => {
|
||||
const item = toc[index];
|
||||
if (item?.id && !heading.id) heading.id = item.id;
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user