By 水澄ぐみ
833 字
4 分钟
在Fuwari中添加系列栏
封面图来源:かぷりちお(アズレン3人組)🔗
前言系列相当于是对同一分类下的文章进行再细分
当查看某篇文章时,如果它属于某一个系列,在名片栏与分类栏中间会多出一个系列栏,
里面会列出同系列的所有文章
示例
在md
文件上方配置项中添加series
,只要系列名相同就会被归类为同一系列
---title: 在Fuwari中添加系列栏published: 2024-10-23updated: 2025-02-28description: 可以将同一分类下有关联的文章归类为同一个系列image: "https://imagedelivery.net/yqyTMQ7rzpPmnK0CN8a9vA/7aa86014-a0d0-4089-1139-88c8a95dd000/public"tags: [Fuwari, Astro, 博客]category: "前端"draft: falselang: ""series: "改造博客"---
改动点
- 修改
📁i18n
里的文件,增加series
Key
enum I18nKey { // ... series = 'series',}
export default I18nKey
export const en: Translation = { // ... [Key.series]: 'Series',}
export const es: Translation = { // ... [Key.series]: 'Serie',}
export const ja: Translation = { // ... [Key.series]: 'シリーズ',}
export const ko: Translation = { // ... [Key.series]: '시리즈',}
export const ko: Translation = { // ... [Key.series]: 'ชุด',}
export const zh_CN: Translation = { // ... [Key.series]: '系列',}
export const zh_TW: Translation = { // ... [Key.series]: '系列',}
- 在两个
config
文件里增加series
字段
export type BlogPostData = { // ... series?: string prevTitle?: string prevSlug?: string nextTitle?: string nextSlug?: string}
const postsCollection = defineCollection({ schema: z.object({ // ... lang: z.string().optional().default(''), series: z.string().optional(),
/* For internal use */ prevTitle: z.string().default(''), // ... }),})
- 修改
[...slug]
页面,将series
传入MainGridLayout
组件
<MainGridLayout banner={entry.data.image} title={entry.data.title} description={entry.data.description} lang={entry.data.lang} setOGTypeArticle={true} series={entry.data.series}>
</MainGridLayout>
- 修改
MainGridLayout
组件里的三处代码,接收series
并将其传入SideBar
组件
---interface Props { title?: string banner?: string description?: string lang?: string setOGTypeArticle?: boolean; series?: string}
const { title, banner, description, lang, setOGTypeArticle, series } = Astro.props---
<SideBar class="mb-4 row-start-2 row-end-3 col-span-2 lg:row-start-1 lg:row-end-2 lg:col-span-1 lg:max-w-[17.5rem] onload-animation" series={ series }></SideBar>
- 在
content-utils.ts
里添加getPostSeries
方法
export async function getPostSeries( seriesName: string,): Promise<{ body: string; data: BlogPostData; slug: string }[]> { const posts = (await getCollection('posts', ({ data }) => { return ( (import.meta.env.PROD ? data.draft !== true : true) && data.series === seriesName ) })) as unknown as { body: string; data: BlogPostData; slug: string }[]
posts.sort((a, b) => { const dateA = new Date(a.data.published) const dateB = new Date(b.data.published) return dateA > dateB ? 1 : -1 })
return posts}
📁widget
里新增Series
组件
---import I18nKey from '../../i18n/i18nKey'import { i18n } from '../../i18n/translation'import { getPostSeries } from '../../utils/content-utils'import { getPostUrlBySlug } from '../../utils/url-utils'import WidgetLayout from './WidgetLayout.astro'
const COLLAPSED_HEIGHT = '7.5rem'
interface Props { class?: string style?: string series: string}const className = Astro.props.classconst style = Astro.props.styleconst seriesName = Astro.props.series
const series = await getPostSeries(seriesName)
const isCollapsed = series.length >= 10---<WidgetLayout name={i18n(I18nKey.series) + " - " + series[0].data.series} id="series" isCollapsed={isCollapsed} collapsedHeight={COLLAPSED_HEIGHT} class={className} style={style}> <div class="flex flex-col gap-1"> {series.map(t => ( <a href={getPostUrlBySlug(t.slug)} aria-label={t.data.title} class="group btn-plain h-10 w-full rounded-lg hover:text-[initial]" > <!-- dot and line --> <div class="w-[15%] md:w-[10%] relative dash-line h-full flex items-center"> <div class="transition-all mx-auto w-1 h-1 rounded group-hover:h-5 bg-[oklch(0.5_0.05_var(--hue))] group-hover:bg-[var(--primary)] outline outline-4 z-50 outline-[var(--card-bg)] group-hover:outline-[var(--btn-plain-bg-hover)] group-active:outline-[var(--btn-plain-bg-active)] " ></div> </div> <!-- post title --> <div class="w-[85%] text-left font-bold group-hover:translate-x-1 transition-all group-hover:text-[var(--primary)] text-75 pr-15 whitespace-nowrap overflow-ellipsis overflow-hidden" > {t.data.title} </div> </a> ))} </div></WidgetLayout>
- 在
SideBar
组件中导入Series
组件,接收series
并将其出入Series
组件
---import Profile from './Profile.astro'import Tag from './Tags.astro'import Categories from './Categories.astro'import type { MarkdownHeading } from 'astro'import TOC from './TOC.astro'import Series from './Series.astro'
interface Props { class? : string headings? : MarkdownHeading[] series?: string}
const className = Astro.props.classconst headings = Astro.props.headingsconst series = Astro.props.series
---<div id="sidebar" class:list={[className, "w-full"]}> <div class="flex flex-col w-full gap-4 mb-4"> <Profile></Profile> </div> <div id="sidebar-sticky" class="transition-all duration-700 flex flex-col w-full gap-4 top-4 sticky top-4"> <div id="series" class="flex flex-col w-full gap-4"> { series && <Series series={ series }></Series> } </div> <Categories class="onload-animation" style="animation-delay: 150ms"></Categories> <Tag class="onload-animation" style="animation-delay: 200ms"></Tag> </div></div>
- 在 swup 的 containers 配置项里加上
#series
export default defineConfig({ integrations: [ swup({ theme: false, animationClass: "transition-swup-", // see https://swup.js.org/options/#animationselector // the default value `transition-` cause transition delay // when the Tailwind class `transition-all` is used containers: ["main", "#toc", "#series"], smoothScrolling: true, cache: true, preload: true, accessibility: true, updateHead: true, updateBodyClass: false, globalInstance: true, }), ],});