1
0
mirror of https://github.com/sendevia/website.git synced 2026-03-06 07:40:50 +08:00

feat(theme): 使用配置文件提供全局变量

This commit is contained in:
2025-10-09 18:47:58 +08:00
parent b470cebb69
commit 1bd5ed73a5
5 changed files with 32 additions and 34 deletions

View File

@@ -25,7 +25,6 @@ export default defineConfig({
lazyLoading: true,
},
},
head: [
["link", { rel: "preconnect", href: "https://fonts.googleapis.com" }],
["link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossorigin: "" }],
@@ -38,10 +37,16 @@ export default defineConfig({
],
["link", { href: "https://fonts.googleapis.com/css2?family=Josefin+Sans:ital,wght@0,100..700;1,100..700&display=swap", rel: "stylesheet" }],
],
vite: {
define: {
__SITE_VERSION__: JSON.stringify(packageJson.version || "0.0.0"),
__DEFAULT_COLOR__: JSON.stringify("#39c5bb"),
},
},
themeConfig: {
defaultColor: "#39c5bb",
defaultImpression: "/assets/images/116014672_p0.webp",
siteVersion: packageJson.version || "0.0.0",
navSegment: [
{ text: "首页", icon: "home", link: "/" },
{ text: "所有文章", icon: "list", link: "/posts" },
{ text: "Markdown 示例", icon: "counter_1", link: "/posts/markdown-examples" },
{ text: "API 示例", icon: "counter_2", link: "/posts/api-examples" },
{ text: "Markdown it", icon: "counter_3", link: "/posts/markdown-it" },
],
} as any,
});

View File

@@ -1,13 +1,11 @@
<script setup lang="ts">
import { ref } from "vue";
import { useGlobalData } from "../composables/useGlobalData";
const { site, page } = useGlobalData();
// @ts-ignore
const siteVersion = __SITE_VERSION__;
const { site, page, theme } = useGlobalData();
const siteVersion = theme.value.siteVersion;
const buildDate = ref("");
if (typeof window !== "undefined") {
fetch("/index.html", { method: "HEAD" })
.then((res) => {

View File

@@ -1,9 +1,11 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useGlobalData } from "../composables/useGlobalData";
const { frontmatter } = useGlobalData();
const { page, frontmatter, theme } = useGlobalData();
const seed = ref(1);
const defaultImpression = theme.value.defaultImpression;
onMounted(() => {
seed.value = Date.now();
});
@@ -25,14 +27,15 @@ onMounted(() => {
</filter>
</svg>
<div id="header-hero-container">
<span id="header-hero-headline">{{ frontmatter.title }}</span>
<span id="header-hero-headline">{{ frontmatter.title ? frontmatter.title : page.title }}</span>
<span id="header-hero-subtitle">{{ frontmatter.description }}</span>
<div id="header-impression">
<div id="header-impression-noise"></div>
<div
id="header-impression-image"
:style="{ backgroundImage: frontmatter.impression ? `url('${frontmatter.impression}')` : '' }"
:style="{ backgroundImage: frontmatter.impression ? `url('${frontmatter.impression}')` : `url('${defaultImpression}')` }"
:impression-color="frontmatter.color"
loading="lazy"
></div>
</div>
</div>

View File

@@ -1,16 +1,12 @@
<script setup lang="ts">
import { computed } from "vue";
import { useGlobalData } from "../composables/useGlobalData";
const { page } = useGlobalData();
const navItems = computed(() => [
{ text: "首页", icon: "home", link: "/" },
{ text: "所有文章", icon: "list", link: "/posts" },
{ text: "Markdown 示例", icon: "counter_1", link: "/posts/markdown-examples" },
{ text: "API 示例", icon: "counter_2", link: "/posts/api-examples" },
{ text: "Markdown it", icon: "counter_3", link: "/posts/markdown-it" },
]);
const { page, theme } = useGlobalData();
const navSegment = computed(() => {
const items = theme.value.navSegment;
if (Array.isArray(items) && items.length > 0) return items;
});
function isActive(link: string) {
const current = page.value.relativePath.replace(/(\/index)?\.md$/, "");
@@ -25,7 +21,7 @@ function isActive(link: string) {
<span>search</span>
</a>
<ul id="navigation-destinations">
<li v-for="item in navItems" :key="item.link" :class="isActive(item.link) ? 'navigation-segment-active' : 'navigation-segment-inactive'">
<li v-for="item in navSegment" :key="item.link" :class="isActive(item.link) ? 'navigation-segment-active' : 'navigation-segment-inactive'">
<a :href="item.link">
<div class="navigation-destination-accent">
<div class="navigation-segment-icon">

View File

@@ -10,14 +10,15 @@ import { generateColorPalette } from "../utils/colorPalette";
import { onMounted, nextTick } from "vue";
import { useRoute } from "vitepress";
import { useGlobalData } from "../composables/useGlobalData";
const { site, page, frontmatter } = useGlobalData();
const { site, page, frontmatter, theme } = useGlobalData();
/**
* 获取图片主色调(取图片左上角像素点的颜色)
* @param url 图片地址
* @returns Promise<number | null> 返回 ARGB 颜色值,获取失败返回 null
*/
function getImageMainColor(url: string): Promise<number | null> {
async function getImageMainColor(url: string): Promise<number | null> {
return new Promise((resolve) => {
if (!url) return resolve(null);
const img = new window.Image();
@@ -40,17 +41,12 @@ function getImageMainColor(url: string): Promise<number | null> {
/**
* 根据头图动态更新调色板
* 1. 等待 DOM 更新后查找 id="header-impression-image" 的元素
* 2. 如果找不到该元素,则使用默认颜色生成调色板
* 3. 如果元素有 impression-color 属性且为合法的 hex 颜色,则用该颜色生成调色板
* 4. 否则尝试从元素的 backgroundImage 提取图片 URL并获取图片主色调
* 5. 最终调用 generateColorPalette 生成调色板
*/
async function updatePalette() {
await nextTick();
const el = document.getElementById("header-impression-image");
// @ts-ignore
const defaultColor = __DEFAULT_COLOR__;
const defaultColor = theme.value.defaultColor;
if (!el) {
await generateColorPalette(argbFromHex(defaultColor));
return;