diff --git a/app/components/main/hero.vue b/app/components/main/hero.vue
index 0fcea42..ab1417e 100644
--- a/app/components/main/hero.vue
+++ b/app/components/main/hero.vue
@@ -3,9 +3,21 @@ import siteConfig from "~/config";
import SocialLinks from "./SocialLinks.vue";
import Typed from "typed.js";
-const descriptions = siteConfig.hero.description;
+// Normalize `siteConfig.hero.description` to a string[] to satisfy TypeScript
+const rawDescription = siteConfig.hero?.description;
+let descriptions: string[] = [];
+if (Array.isArray(rawDescription)) {
+ descriptions = rawDescription.filter((d) => typeof d === "string" && d.length > 0) as string[];
+} else if (typeof rawDescription === "string" && rawDescription.length > 0) {
+ descriptions = [rawDescription];
+} else if (typeof siteConfig.hero?.title === "string" && siteConfig.hero.title.length > 0) {
+ descriptions = [siteConfig.hero.title];
+} else {
+ descriptions = [""];
+}
+
const typedElement = ref(null);
-const randomDescription = ref(descriptions[0]);
+const randomDescription = ref(descriptions[0] || "");
let typed: Typed | null = null;
onMounted(() => {
@@ -18,7 +30,7 @@ onMounted(() => {
backDelay: siteConfig.hero.typed.backDelay || 2000,
});
} else {
- randomDescription.value = descriptions[Math.floor(Math.random() * descriptions.length)];
+ randomDescription.value = descriptions[Math.floor(Math.random() * descriptions.length)] || "";
}
});
@@ -42,6 +54,8 @@ onUnmounted(() => {
:src="siteConfig.profile.avatar"
alt="avatar"
class="relative h-full w-full object-cover rounded-full border-4 border-white/80 dark:border-slate-800/80 shadow-2xl transition-transform duration-500 group-hover:scale-105"
+ width="160px"
+ height="160px"
loading="eager" />
diff --git a/app/components/main/recent.vue b/app/components/main/recent.vue
index 833dd2b..c9d6cfa 100644
--- a/app/components/main/recent.vue
+++ b/app/components/main/recent.vue
@@ -32,7 +32,7 @@ const formattedData = computed(() => {
path: articles.path,
title: articles.title || "no-title available",
description: articles.description || "no-description available",
- image: articles.image || getRandomFallbackImage(),
+ image: articles.image || getRandomFallbackImage(articles.path),
alt: articles.alt || "no alter data available",
date: articles.date || "not-date-available",
tags: articles.tags || [],
diff --git a/app/pages/categories/[category].vue b/app/pages/categories/[category].vue
index 73897dc..5d16541 100644
--- a/app/pages/categories/[category].vue
+++ b/app/pages/categories/[category].vue
@@ -27,7 +27,7 @@ const formattedData = computed(() => {
path: articles.path,
title: articles.title || "no-title available",
description: articles.description || "no-description available",
- image: articles.image || getRandomFallbackImage(),
+ image: articles.image || getRandomFallbackImage(articles.path),
alt: articles.alt || "no alter data available",
date: articles.date || "not-date-available",
tags: articles.tags || [],
diff --git a/app/pages/tags/[tag].vue b/app/pages/tags/[tag].vue
index d9ac054..649981b 100644
--- a/app/pages/tags/[tag].vue
+++ b/app/pages/tags/[tag].vue
@@ -29,7 +29,7 @@ const formattedData = computed(() => {
path: articles.path,
title: articles.title || "no-title available",
description: articles.description || "no-description available",
- image: articles.image || getRandomFallbackImage(),
+ image: articles.image || getRandomFallbackImage(articles.path),
alt: articles.alt || "no alter data available",
date: formatDate(articles.date) || "not-date-available",
tags: articles.tags || [],
diff --git a/app/utils/helper.ts b/app/utils/helper.ts
index 1e6eb78..1624bb3 100644
--- a/app/utils/helper.ts
+++ b/app/utils/helper.ts
@@ -29,7 +29,7 @@ export function formatDate(dateString: string): string {
* Gets a random 404 image from the /public/404/ directory
* @returns A random image path from /public/404/
*/
-export function getRandomFallbackImage(): string {
+export function getRandomFallbackImage(seed?: string): string {
const fallbackImages: string[] = [
"/404/1.webp",
"/404/2.webp",
@@ -42,11 +42,17 @@ export function getRandomFallbackImage(): string {
"/404/9.webp",
];
- if (import.meta.server) {
- // 在服务器端返回第一张图片以保证 SSR 一致性
- return fallbackImages[0]!;
+ // If a seed is provided, choose a deterministic image based on the seed.
+ if (seed) {
+ let hash = 0;
+ for (let i = 0; i < seed.length; i++) {
+ hash = (hash << 5) - hash + seed.charCodeAt(i);
+ hash |= 0;
+ }
+ const idx = Math.abs(hash) % fallbackImages.length;
+ return fallbackImages[idx]!;
}
- const randomIndex = Math.floor(Math.random() * fallbackImages.length);
- return fallbackImages[randomIndex]!;
+ // No seed: return the first image to keep SSR/client consistent.
+ return fallbackImages[0]!;
}