Skip to content
0

Teek 主题自定义 原创

本博客在默认的 Teek 主题上进行了一些自定义。本文将长期更新,尽可能地记录自定义的细节。

样式

对于样式的修改较为简单,我将其分为两部分:自定义样式覆写样式

  • 自定义样式:存放在 .vitepress/theme/styles/custom.css,自定义样式类,独立于 Teek
  • 覆写样式:存放在 .vitepress/theme/styles/override.css,覆写 Teek 的样式

加载

根据 VitePress 的要求,为使样式生效,需要将样式文件导入 .vitepress/theme/index.ts 中。

ts
import "./styles/custom.css"
import "./styles/override.css"

清单

参考源文件(已详细注释):

配置

teekConfig.mts 中,有一些配置是函数回调的形式,其中可以配置自定义组件 / 数据。

清单

⭐articleTopTip

  • 功能:文章页顶部添加提示
  • 来源:基于 Teek 官方项目二次开发
  • 备注:二次开发修改了一些逻辑,以支持通过 frontmatter 自定义提示内容。
ts
// .vitepress/teekConfig.mts
import { defineTeekConfig } from "vitepress-theme-teek/config";

export const teekConfig = defineTeekConfig({
  // 文章页顶部使用 VitePress 容器添加提示
  articleTopTip: (frontmatter) => {
    // 在每个文章页顶部显示 VitePress 容器添加提示,使用场景如超过半年的文章自动提示文章内容可能已过时
    const tip: Record<string, string> = {
      type: frontmatter.topTip?.type ?? "warning",
      title: frontmatter.topTip?.title ?? "",
      text: frontmatter.topTip?.text ??  "文章发布较早,内容可能过时,阅读注意甄别。",
    };
    // 大于半年,添加提示
    const longTime = 6 * 30 * 24 * 60 * 60 * 1000;
    if (frontmatter.date && Date.now() - new Date(frontmatter.date).getTime() > longTime)
      return tip;
  },
});

⭐articleBottomTip

  • 功能:文章页底部添加版权声明
  • 来源:自制
  • 备注:版权声明需要读取 teekConfig.mts 中配置的默认作者,但回调函数中无法使用外部变量,且无法使用 import 导入 useData,从而无法读取 teekConfig。通过查看 Teek 源码后,将此处配置为传递空函数,从而启用原底部提示的前后插槽,同时由于空函数返回了空内容,原底部提示不会显示。最后,将逻辑转到原底部提示的前后插槽中实现。插槽组件实现参考 ArticleBottomTipBefore

组件

组件的自定义有两种方式:DOM 插入插槽组件

加载

两种方式使用统一的加载方法(参考 Teek 官方项目)。

首先,在 .vitepress/theme/components/ 中创建入口组件 TeekLayoutProvider.vue,并写入代码。

vue
<template>
  <Teek.Layout>
    此行留空,后续向指定插槽添加组件时使用。
  </Teek.Layout>
</template>

<script setup lang="ts">
import Teek from "vitepress-theme-teek";

// 后续向 DOM 插入元素时在这里编写代码。
</script>

<style scoped lang="scss">

</style>

然后,在 .vitepress/theme/index.ts 中导入入口组件。

ts
import Teek from "vitepress-theme-teek";
import TeekLayoutProvider from "./components/TeekLayoutProvider.vue";

export default {
  extends: Teek,
  Layout: TeekLayoutProvider,
};

清单

⭐useRibbon.ts

  • 功能:彩带背景
  • 方式:DOM 插入
  • 来源:基于 Teek 官方项目二次开发
  • 使用:复制 useRibbon.ts.vitepress/theme/composables/ 中,然后在 TeekLayoutProvider.vue 中使用。
  • 备注:二次开发对透明度方面的代码进行了微调。
ts
import { useData } from "vitepress";
import { nextTick, watch } from "vue";
import { useRibbon } from "../composables/useRibbon";

const { frontmatter } = useData();

// 彩带背景
const { start: startRibbon, stop: stopRibbon } = useRibbon({ alpha: 0.4, immediate: false, clickReRender: true, });
const watchRibbon = async (layout: string) => {
  const isHome = layout === "home";
  const isDoc = [undefined, "doc"].includes(layout);
  await nextTick();
  // 博客类风格的首页显示彩带 & 文章页显示彩带
  if (isHome || isDoc) startRibbon();
  else stopRibbon();
};
watch(frontmatter, newVal => setTimeout(() => watchRibbon(newVal.layout), 700), { immediate: true, flush: "post", });

⭐useRuntime.ts

  • 功能:首页页脚显示网站运行时间
  • 方式:DOM 插入
  • 来源:Teek 官方项目
  • 使用:复制 useRuntime.ts.vitepress/theme/composables/ 中,然后在 TeekLayoutProvider.vue 中使用。
ts
import { useData } from "vitepress";
import { nextTick, watch } from "vue";
import { useRuntime } from "../composables/useRuntime";

const { theme, frontmatter } = useData();

// 页脚运行时间
const { start: startRuntime, stop: stopRuntime } = useRuntime(theme.value.docAnalysis.createTime, {
  prefix: `<span style="width: 16px; display: inline-block; vertical-align: -3px; margin-right: 3px;">${clockIcon}</span>小破站已运行 `,
});
const watchRuntime = async (layout: string) => {
  const isHome = layout === "home";
  await nextTick();
  // 博客类风格的首页显示运行时间
  if (isHome) startRuntime();
  else stopRuntime();
};
watch(frontmatter, newVal => setTimeout(() => watchRuntime(newVal.layout), 700), { immediate: true, flush: "post", });

另外,还需要在 teekConfig.mts 中配置运行时间的挂载点。

ts
import { defineTeekConfig } from "vitepress-theme-teek/config";

export const teekConfig = defineTeekConfig({
  // 页脚配置
  footerInfo: {
    // 自定义 HTML 片段
    customHtml: `<span id="runtime"></span>`,
  }
});

⭐useDocBgImage.ts

  • 功能:文章页背景图
  • 方式:DOM 插入
  • 来源:自制
  • 使用:复制 useDocBgImage.ts.vitepress/theme/composables/ 中,然后在 TeekLayoutProvider.vue 中使用。
ts
import { useData } from "vitepress";
import { nextTick, watch } from "vue";
import { useRuntime } from "../composables/useRuntime";

const { frontmatter } = useData();

// 文档页背景图片
const { switchDocBgImage } = useDocBgImage({});
const watchDocBgImage = async (layout: string) => {
  const isDoc = [undefined, "doc"].includes(layout); // 首页 & 文章页
  const showAside = frontmatter.value.aside !== false; // 文档风文章页 & 博客风文章页
  await nextTick();
  // 切换文档页背景图片
  switchDocBgImage(isDoc && showAside && frontmatter.value.coverImg ? frontmatter.value.coverImg : '');
};
watch(frontmatter, newVal => setTimeout(() => watchDocBgImage(newVal.layout), 0), { immediate: true, flush: "post", });

⭐HomeBannerContentAfter

  • 功能:标注首页 Banner 背景图来源
  • 方式:插槽组件
  • 来源:自制
  • 使用:复制 HomeBannerContentAfter.vue.vitepress/theme/components/ 中,然后在 TeekLayoutProvider.vue 中使用。
html
<template>
    <Teek.Layout>
        <template #teek-home-banner-content-after>
            <HomeBannerContentAfter />
        </template>
    </Teek.Layout>
</template>

<script setup lang="ts">
import HomeBannerContentAfter from "./HomeBannerContentAfter.vue";
</script>

⭐ArticleBannerInfoBottom

  • 功能:标注文章页 Banner 背景图来源
  • 方式:插槽组件
  • 来源:自制
  • 使用:复制 ArticleBannerInfoBottom.vue.vitepress/theme/components/ 中,然后在 TeekLayoutProvider.vue 中使用。导入方式同 HomeBannerContentAfter

⭐ArticleBottomTipBefore

  • 功能:文章页底部标注文章版权及背景图来源
  • 方式:插槽组件
  • 来源:自制
  • 使用:复制 ArticleBottomTipBefore.vue.vitepress/theme/components/ 中,然后在 TeekLayoutProvider.vue 中使用。导入方式同 HomeBannerContentAfter
  • 备注:此组件需要考虑文章切换后的参数刷新;另如果直接读取 URL,会存在编译时 SSR 错误。均已解决。

⭐HomeCardMyAvatarBefore

  • 功能:标注首页个人卡片背景图来源
  • 方式:插槽组件
  • 来源:自制
  • 使用:复制 HomeCardMyAvatarBefore.vue.vitepress/theme/components/ 中,然后在 TeekLayoutProvider.vue 中使用。导入方式同 HomeBannerContentAfter

⭐ContributeHeatmapChart

  • 功能:贡献热力图
  • 方式:插槽组件
  • 来源:基于 Teek 官方项目二次开发
  • 使用:
    1. 安装 Echarts 依赖:pnpm add -D echarts
    2. 复制 ContributeHeatmapChart.vue.vitepress/theme/components/
    3. 使用方式参考 ArchivesTopBeforeHomeCardTagAfter
  • 备注:二次开发增加了以下特性:
    1. 根据屏幕宽度动态显示最合适宽度的日期范围(多端适配)
    2. 热力图 Tooltip 适配暗色模式
    3. 组件化,可复用
    4. 其他样式优化

⭐ArchivesTopBefore

  • 功能:归档页贡献热力图
  • 方式:插槽组件
  • 来源:自制
  • 使用:复制 ArchivesTopBefore.vue.vitepress/theme/components/ 中,然后在 TeekLayoutProvider.vue 中使用。
  • 备注:该插槽所用的贡献热力图组件参考 ContributeHeatmapChart

⭐HomeCardTagAfter

  • 功能:首页贡献热力图卡片
  • 方式:插槽组件
  • 来源:自制
  • 使用:复制 HomeCardTagAfter.vue.vitepress/theme/components/ 中,然后在 TeekLayoutProvider.vue 中使用。
  • 备注:该插槽所用的贡献热力图组件参考 ContributeHeatmapChart

⭐NotFound

  • 功能:自定义 404 页面
  • 方式:插槽组件
  • 来源:基于 VitePress 官方项目二次开发
  • 使用:复制 NotFound.vue.vitepress/theme/components/ 中,然后在 TeekLayoutProvider.vue 中使用。导入方式同 HomeBannerContentAfter
最近更新