🐛 修复潜在的ssg问题

This commit is contained in:
li-chx 2025-10-05 03:01:52 +08:00
parent 51a39d498b
commit 1cefa4c661
7 changed files with 56 additions and 44 deletions

View File

@ -13,13 +13,24 @@ const eraseHeaderMarkdown = computed(() => props.markdown.replace(/^---[\s\S]*?-
const { colorMode } = storeToRefs(useColorModeStore()); const { colorMode } = storeToRefs(useColorModeStore());
const mounted = ref(false);
onMounted(() => {
mounted.value = true;
});
</script> </script>
<template> <template>
<div class="pt-0 bg-old-neutral-200 dark:bg-old-neutral-800 transition-colors duration-500"> <div class="pt-0 bg-old-neutral-200 dark:bg-old-neutral-800 transition-colors duration-500">
<client-only> <MdPreview
<MdPreview :editor-id="editorId" :theme="colorMode" :model-value="eraseHeaderMarkdown" class="transition-all duration-500 max-w-full"/> v-if="mounted"
</client-only> :key="editorId + '-' + colorMode"
:editor-id="editorId"
:theme="colorMode"
:model-value="eraseHeaderMarkdown"
class="transition-all duration-500 max-w-full"
/>
</div> </div>
</template> </template>

View File

@ -64,6 +64,7 @@ const renderChart = () => {
chart: { chart: {
type: 'bar', type: 'bar',
backgroundColor: 'transparent', backgroundColor: 'transparent',
reflow: false,
}, },
credits: { credits: {
enabled: false, enabled: false,
@ -127,7 +128,8 @@ const renderChart = () => {
dataLabels: { dataLabels: {
enabled: true, enabled: true,
style: { style: {
color: '#fff', color: colorMode.value === 'light' ? '#4e4d55' : '#fff',
textOutline: 'none',
}, },
formatter: function () { formatter: function () {
return toPercent(this.y); // return toPercent(this.y); //
@ -178,11 +180,15 @@ const scrollbarOptions = {
}, },
}; };
const mounted = ref(false);
onMounted(() => {
mounted.value = true;
});
</script> </script>
<template> <template>
<div class="h-full"> <div class="h-full">
<div v-if="noDataAvailable" class="flex items-center justify-center h-full p-8"> <div v-if="!mounted||noDataAvailable" class="flex items-center justify-center h-full p-8">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 112.01"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 112.01">
<g id="_图层_1" data-name="图层 1"> <g id="_图层_1" data-name="图层 1">
<polyline <polyline
@ -216,9 +222,7 @@ const scrollbarOptions = {
</svg> </svg>
</div> </div>
<overlay-scrollbars-component v-else class="max-h-full" :options="scrollbarOptions"> <overlay-scrollbars-component v-else class="max-h-full" :options="scrollbarOptions">
<client-only> <div ref="chartRef" class="w-full"/>
<div ref="chartRef" class="w-full"/>
</client-only>
</overlay-scrollbars-component> </overlay-scrollbars-component>
</div> </div>
</template> </template>

View File

@ -61,6 +61,11 @@ useRouter().beforeEach(() => {
useRouter().afterEach(() => { useRouter().afterEach(() => {
isLoading.value = false; isLoading.value = false;
}); });
const mounted = ref(false);
onMounted(() => {
mounted.value = true;
});
</script> </script>
<template> <template>
@ -75,7 +80,7 @@ useRouter().afterEach(() => {
}" }"
@mouseleave="collapsed = true"> @mouseleave="collapsed = true">
<!-- header --> <!-- header -->
<client-only> <div v-if="mounted">
<Transition <Transition
enter-active-class="transition-opacity duration-500 ease-in-out" enter-active-class="transition-opacity duration-500 ease-in-out"
enter-from-class="opacity-0" enter-from-class="opacity-0"
@ -113,7 +118,7 @@ useRouter().afterEach(() => {
class="opacity-20 max-h-[48px] flex w-full h-full fixed bg-[url('/anime-8788959.jpg')] bg-cover bg-center"/> class="opacity-20 max-h-[48px] flex w-full h-full fixed bg-[url('/anime-8788959.jpg')] bg-cover bg-center"/>
</div> </div>
</Transition> </Transition>
</client-only> </div>
<!-- navbar --> <!-- navbar -->
<div <div
class="fixed z-10 w-full transition-all duration-500 dark:bg-gray-800/60 bg-old-neutral-50/40 backdrop-blur-sm dark:backdrop-blur-md"> class="fixed z-10 w-full transition-all duration-500 dark:bg-gray-800/60 bg-old-neutral-50/40 backdrop-blur-sm dark:backdrop-blur-md">
@ -123,13 +128,8 @@ useRouter().afterEach(() => {
</div> </div>
<div <div
class="transition-all duration-500 flex 2xl:w-[1240px] xl:w-[1020px] lg:w-[964px] md:w-[708px] sm:w-[580px] w-10/12"> class="transition-all duration-500 flex 2xl:w-[1240px] xl:w-[1020px] lg:w-[964px] md:w-[708px] sm:w-[580px] w-10/12">
<client-only> <UNavigationMenu v-if="mounted" :items="items" :class="colorMode" class="w-full"/>
<UNavigationMenu :items="items" :class="colorMode" class="w-full"/> <div v-else class="w-full h-12 animate-pulse"></div>
<template #fallback>
<!-- 骨架屏/占位内容 -->
<div class="w-full h-12 animate-pulse"></div>
</template>
</client-only>
</div> </div>
<div class="flex-1 overflow-hidden"> <div class="flex-1 overflow-hidden">
<slot name="navbarRight" :is-scroll-down="isScrollDown"/> <slot name="navbarRight" :is-scroll-down="isScrollDown"/>

View File

@ -33,9 +33,11 @@
"vue-router": "^4.5.1", "vue-router": "^4.5.1",
"word-count": "^0.3.1" "word-count": "^0.3.1"
}, },
"packageManager": "pnpm@10.17.1", "packageManager": "pnpm@10.18.0",
"devDependencies": { "devDependencies": {
"@iconify-json/clarity": "^1.2.4",
"@iconify-json/lucide": "^1.2.68", "@iconify-json/lucide": "^1.2.68",
"@iconify-json/material-symbols": "^1.2.40",
"@stylistic/eslint-plugin": "^5.4.0", "@stylistic/eslint-plugin": "^5.4.0",
"@stylistic/eslint-plugin-jsx": "^4.4.1", "@stylistic/eslint-plugin-jsx": "^4.4.1",
"@vue/eslint-config-typescript": "^14.6.0", "@vue/eslint-config-typescript": "^14.6.0",

View File

@ -2,7 +2,6 @@
import { DataAnomaly, defaultMetaData } from '~/types/PostMetaData'; import { DataAnomaly, defaultMetaData } from '~/types/PostMetaData';
import type { PostMetaData } from '~/types/PostMetaData'; import type { PostMetaData } from '~/types/PostMetaData';
import breakpointsHelper from '~/utils/BreakpointsHelper';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-vue'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-vue';
withDefaults(defineProps<{ withDefaults(defineProps<{
@ -45,6 +44,11 @@ function getCostTime(length: number | DataAnomaly | undefined) {
return `${minutes}分钟`; return `${minutes}分钟`;
} }
} }
const mounted = ref(false);
onMounted(() => {
mounted.value = true;
});
</script> </script>
<template> <template>
@ -94,24 +98,17 @@ function getCostTime(length: number | DataAnomaly | undefined) {
<overlay-scrollbars-component> <overlay-scrollbars-component>
{{ metaData?.description }} {{ metaData?.description }}
</overlay-scrollbars-component> </overlay-scrollbars-component>
<Transition <div v-if="mounted" class="">
enter-active-class="transition-opacity duration-500 ease-in-out" <TechStackCard
enter-from-class="opacity-0" :async-key="'stack:' + metaData?.id"
enter-to-class="opacity-100" :tech-stack="metaData?.tech_stack"
leave-active-class="transition-opacity duration-500 ease-in-out" :tech-stack-icon-names="metaData?.tech_stack_icon_names"
leave-from-class="opacity-100" :tech-stack-theme-colors="metaData?.tech_stack_theme_colors"
leave-to-class="opacity-0" :tech-stack-percent="metaData?.tech_stack_percent"
> class="lg:w-64 w-0 transition-all duration-500"
<TechStackCard />
v-if="breakpointsHelper.greater('lg').value" </div>
:async-key="'stack:' + metaData?.id" <div v-else class="min-w-64"/>
:tech-stack="metaData?.tech_stack"
:tech-stack-icon-names="metaData?.tech_stack_icon_names"
:tech-stack-theme-colors="metaData?.tech_stack_theme_colors"
:tech-stack-percent="metaData?.tech_stack_percent"
class="min-w-64"
/>
</Transition>
</div> </div>
<hr/> <hr/>
<div class="flex mt-2"> <div class="flex mt-2">

View File

@ -1,8 +1,6 @@
// darkVerify.js // darkVerify.js
if ( if (
localStorage.getItem('system-theme-mode') === "dark" || window.matchMedia("(prefers-color-scheme: dark)").matches
(!localStorage.getItem('system-theme-mode') &&
window.matchMedia("(prefers-color-scheme: dark)").matches)
) { ) {
document.querySelector('html').classList.add('dark'); document.querySelector('html').classList.add('dark');
document.querySelector('html').classList.remove('light'); document.querySelector('html').classList.remove('light');

View File

@ -5,12 +5,12 @@ function getInitialMode(): 'light' | 'dark' {
if (document.documentElement.classList.contains('light')) return 'light'; if (document.documentElement.classList.contains('light')) return 'light';
// 其次用 localStorage // 其次用 localStorage
const val = localStorage.getItem('system-theme-mode'); const val = localStorage.getItem('system-theme-mode');
if (!!val || (val !== 'light' && val !== 'dark')) if (val === 'dark') return 'dark';
return 'light'; if (val === 'light') return 'light';
return val; return 'light'; // 默认
} }
return 'light'; // SSR 默认 return 'light'; // SSR 默认
}; }
const useColorModeStore = defineStore('colorMode', { const useColorModeStore = defineStore('colorMode', {
state: () => ({ state: () => ({