评论区 侧边栏
This commit is contained in:
1 parent
ebaf187d89
commit
ce4a201508
6 files changed
+368
-7
No files matched your search
@@ -7,6 +7,11 @@ type TocItem = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
type TocSection = {
|
||||
heading: TocItem;
|
||||
children: TocItem[];
|
||||
};
|
||||
|
||||
interface Props {
|
||||
post: BlogPost;
|
||||
toc: TocItem[];
|
||||
@@ -15,6 +20,16 @@ interface Props {
|
||||
|
||||
const { post, toc, relatedPosts } = Astro.props;
|
||||
const avatar = 'https://free.picui.cn/free/2025/08/10/689845496a283.png';
|
||||
const topDepth = toc.length > 0 ? Math.min(...toc.map((item) => item.depth)) : 1;
|
||||
const tocSections = toc.reduce<TocSection[]>((sections, item) => {
|
||||
if (item.depth <= topDepth || sections.length === 0) {
|
||||
sections.push({ heading: item, children: [] });
|
||||
} else {
|
||||
sections[sections.length - 1].children.push(item);
|
||||
}
|
||||
|
||||
return sections;
|
||||
}, []);
|
||||
---
|
||||
|
||||
<aside class="article-sidebar" aria-label="文章侧边栏">
|
||||
@@ -27,6 +42,21 @@ const avatar = 'https://free.picui.cn/free/2025/08/10/689845496a283.png';
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{post.tags.length > 0 && (
|
||||
<section class="sidebar-card article-tags-card">
|
||||
<h2>
|
||||
<span aria-hidden="true">#</span>
|
||||
文章标签
|
||||
<em>{post.tags.length}</em>
|
||||
</h2>
|
||||
<div class="article-tag-list" aria-label="文章标签">
|
||||
{post.tags.map((tag) => (
|
||||
<a href={`/tags/${encodeURIComponent(tag)}/`}>#{tag}</a>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{toc.length > 0 && (
|
||||
<section class="sidebar-card toc-card">
|
||||
<h2>
|
||||
@@ -34,9 +64,23 @@ const avatar = 'https://free.picui.cn/free/2025/08/10/689845496a283.png';
|
||||
文章目录
|
||||
<em>{toc.length}</em>
|
||||
</h2>
|
||||
<nav class="toc-list" aria-label="文章目录">
|
||||
{toc.map((item) => (
|
||||
<a class={`toc-depth-${item.depth}`} href={`#${item.id}`}>{item.text}</a>
|
||||
<nav class="toc-list toc-tree" aria-label="文章目录" data-toc-tree>
|
||||
{tocSections.map((section, index) => (
|
||||
<div class:list={['toc-group', index === 0 && 'is-open']} data-toc-group data-heading-id={section.heading.id}>
|
||||
<a class="toc-link toc-link-main" href={`#${section.heading.id}`} data-toc-link data-toc-top>
|
||||
<span class="toc-marker" aria-hidden="true"></span>
|
||||
<span>{section.heading.text}</span>
|
||||
</a>
|
||||
{section.children.length > 0 && (
|
||||
<div class="toc-children" data-toc-children>
|
||||
{section.children.map((item) => (
|
||||
<a class={`toc-link toc-link-child toc-depth-${item.depth}`} href={`#${item.id}`} data-toc-link>
|
||||
<span>{item.text}</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
interface Props {
|
||||
envId: string;
|
||||
path: string;
|
||||
title: string;
|
||||
region?: string;
|
||||
}
|
||||
|
||||
const { envId, path, title, region = '' } = Astro.props;
|
||||
---
|
||||
|
||||
<section
|
||||
id="post-comment"
|
||||
class="twikoo-comments"
|
||||
aria-label="Comments"
|
||||
data-env-id={envId}
|
||||
data-region={region}
|
||||
data-path={path}
|
||||
>
|
||||
<div class="twikoo-comments-head">
|
||||
<span class="twikoo-comments-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M21 12a8 8 0 0 1-8 8H7l-4 3v-5a8 8 0 1 1 18-6Z" />
|
||||
</svg>
|
||||
</span>
|
||||
<div>
|
||||
<h2>Comments</h2>
|
||||
<p>{title}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="twikoo-wrap" class="twikoo-wrap"></div>
|
||||
</section>
|
||||
|
||||
<script is:inline>
|
||||
(() => {
|
||||
const root = document.getElementById('post-comment');
|
||||
const wrap = document.getElementById('twikoo-wrap');
|
||||
if (!root || !wrap || root.dataset.twikooLoaded === 'true') return;
|
||||
|
||||
const envId = root.dataset.envId;
|
||||
const path = root.dataset.path || window.location.pathname;
|
||||
const region = root.dataset.region || undefined;
|
||||
if (!envId) return;
|
||||
|
||||
root.dataset.twikooLoaded = 'true';
|
||||
|
||||
const initTwikoo = () => {
|
||||
if (!window.twikoo || typeof window.twikoo.init !== 'function') return;
|
||||
|
||||
window.twikoo.init({
|
||||
el: wrap,
|
||||
envId,
|
||||
region,
|
||||
path,
|
||||
});
|
||||
};
|
||||
|
||||
if (window.twikoo) {
|
||||
initTwikoo();
|
||||
return;
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://cdn.jsdelivr.net/npm/twikoo@1.7.7/dist/twikoo.min.js';
|
||||
script.defer = true;
|
||||
script.onload = initTwikoo;
|
||||
script.onerror = () => {
|
||||
root.dataset.twikooLoaded = 'false';
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
})();
|
||||
</script>
|
||||
@@ -19,6 +19,7 @@ const currentYear = new Date().getFullYear();
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content={description} />
|
||||
<link rel="icon" href="/images/Bi.ico" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/instantsearch.css/themes/reset-min.css" />
|
||||
<title>{pageTitle}</title>
|
||||
</head>
|
||||
<body>
|
||||
@@ -31,6 +32,13 @@ const currentYear = new Date().getFullYear();
|
||||
<a href="/tags/">标签</a>
|
||||
<a href="/about/">关于</a>
|
||||
<a href="/link/">友链</a>
|
||||
<button class="nav-search search-typesense-trigger" type="button" aria-label="搜索" title="搜索">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24">
|
||||
<path d="m21 21-4.3-4.3" />
|
||||
<circle cx="11" cy="11" r="7" />
|
||||
</svg>
|
||||
<span>搜索</span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
@@ -92,6 +100,9 @@ const currentYear = new Date().getFullYear();
|
||||
</section>
|
||||
</div>
|
||||
</footer>
|
||||
<script is:inline src="https://cdn.jsdmirror.com/npm/instantsearch.js@4.56.0"></script>
|
||||
<script is:inline src="https://cdn.jsdmirror.com/npm/typesense-instantsearch-adapter@2.7.0/dist/typesense-instantsearch-adapter.min.js"></script>
|
||||
<script is:inline src="/js/search/typesense-search.js"></script>
|
||||
<script is:inline>
|
||||
(() => {
|
||||
const runtime = document.getElementById('site-runtime');
|
||||
|
||||
Loaded 3 of 6 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user