-
+
+
+ Author: Lichx
-
-
-
{{ data.name }}
-
{{ data.count }}
-
-
-
-
-
{{ countGroup.filter((x) => x.type === showType)[0].name }}
-
-
-
{{ countGroup.filter((x) => x.type === showType)[0].count }}
-
-
-
-
-
+ Contact me:
+
+
-
-
diff --git a/components/ReadonlyMdEditor.vue b/components/ReadonlyMdEditor.vue
index ac39d9e..a1b6e6b 100644
--- a/components/ReadonlyMdEditor.vue
+++ b/components/ReadonlyMdEditor.vue
@@ -9,7 +9,6 @@ const props = withDefaults(defineProps<{
}>(), {
markdown: () => '## Hello World!',
});
-console.log(props.markdown);
const eraseHeaderMarkdown = computed(() => props.markdown.replace(/^---[\s\S]*?---\n?/, ''));
const { colorMode } = storeToRefs(useColorModeStore());
@@ -18,7 +17,9 @@ const { colorMode } = storeToRefs(useColorModeStore());
-
+
+
+
diff --git a/components/TechStackCard.vue b/components/TechStackCard.vue
index 900feff..8b51a3e 100644
--- a/components/TechStackCard.vue
+++ b/components/TechStackCard.vue
@@ -54,7 +54,7 @@ const renderChart = () => {
const techStackPercent = props.techStackPercent as number[];
if (!chartRef.value) return;
const sum = techStackPercent.reduce((acc, val) => acc + val, 0);
- const fullArr: [string, number, string, string, string][] = techStack.map((name, index) => [name, techStackPercent[index] / sum, techStackLightIconSVG.value[index] || '', techStackDarkIconSVG.value[index] || '', props.techStackThemeColors[index]] as [string, number, string, string, string]).sort((a, b) => b[1] - a[1]);
+ const fullArr: [string, number, string, string, string][] = techStack.map((name, index) => [name, techStackPercent[index]! / sum, techStackLightIconSVG.value[index] || '', techStackDarkIconSVG.value[index] || '', props.techStackThemeColors[index]] as [string, number, string, string, string]).sort((a, b) => b[1] - a[1]);
const dataArr: [string, number][] = fullArr.map((x) => [x[0], x[1]]);
const barHeight = 20;
const gap = 10;
@@ -83,8 +83,8 @@ const renderChart = () => {
labels: {
useHTML: true,
formatter: function () {
- return `
- ${colorMode.value === 'light' ? fullArr[this.pos][2] : fullArr[this.pos][3]}
+ return `
+ ${colorMode.value === 'light' ? fullArr[this.pos]![2] : fullArr[this.pos]![3]}
`;
},
},
@@ -114,7 +114,7 @@ const renderChart = () => {
],
tooltip: {
formatter: function () {
- return `${fullArr[this.x][0]} ${toPercent(this.y)}`;
+ return `${fullArr[this.x]![0]} ${toPercent(this.y)}`;
},
},
plotOptions: {
@@ -216,7 +216,9 @@ const scrollbarOptions = {
-
+
+
+
diff --git a/layouts/UserLayout.vue b/layouts/UserLayout.vue
index ed3fbdf..1e1e264 100644
--- a/layouts/UserLayout.vue
+++ b/layouts/UserLayout.vue
@@ -4,6 +4,9 @@ import useColorModeStore from '~/stores/colorModeStore';
import { useWindowScroll } from '@vueuse/core';
const { colorMode } = storeToRefs(useColorModeStore());
+watch(colorMode, () => {
+ console.log('colorMode changed:', colorMode.value);
+});
const isHome = computed(() => useRoute().path === '/');
const items = ref([
{
@@ -41,7 +44,6 @@ onMounted(() => {
});
const scrollY = useWindowScroll().y;
const isScrollDown = ref(false);
-// gsap.registerPlugin(ScrollTrigger);
watch(scrollY, (newY) => {
if (newY > 0 && !collapsed.value) {
@@ -73,43 +75,45 @@ useRouter().afterEach(() => {
}"
@mouseleave="collapsed = true">
-
-
-
-
-
-
-
-
-
-
-
+
+
+ class="flex h-full w-full absolute bg-[url('/79d52228c770808810a310115567e6790380823a.png')] bg-cover bg-top ">
+
+
-
-
+ class="flex h-full w-full absolute bg-[url('/anime-8788959.jpg')] bg-cover bg-center">
+
+
+
+
+
+
+
+
@@ -119,7 +123,13 @@ useRouter().afterEach(() => {
diff --git a/nuxt.config.ts b/nuxt.config.ts
index 6b5ed83..a5ba676 100644
--- a/nuxt.config.ts
+++ b/nuxt.config.ts
@@ -2,7 +2,6 @@
import tailwindcss from '@tailwindcss/vite';
export default defineNuxtConfig({
- ssr: false,
compatibilityDate: '2025-05-15',
devtools: { enabled: false },
vite: {
@@ -19,6 +18,7 @@ export default defineNuxtConfig({
css: ['~/assets/css/main.css'],
ui: {
colorMode: false,
+ fonts: false,
},
app: {
head: {
@@ -32,8 +32,8 @@ export default defineNuxtConfig({
script: [{ src: '/darkVerify.js' }],
},
},
- sourcemap: {
- server: true,
- client: true,
- },
+ // sourcemap: {
+ // server: true,
+ // client: true,
+ // },
});
diff --git a/package.json b/package.json
index 1a97b0a..14d1cb6 100644
--- a/package.json
+++ b/package.json
@@ -10,38 +10,40 @@
"postinstall": "nuxt prepare"
},
"dependencies": {
- "@nuxt/content": "^3.6.3",
- "@nuxt/eslint": "1.5.2",
- "@nuxt/icon": "^1.15.0",
- "@nuxt/ui": "3.2.0",
- "@pinia/nuxt": "^0.11.1",
+ "@nuxt/content": "^3.7.1",
+ "@nuxt/eslint": "1.9.0",
+ "@nuxt/icon": "^2.0.0",
+ "@nuxt/ui": "4.0.0",
+ "@pinia/nuxt": "^0.11.2",
"@tailwindcss/vite": "^4.1.11",
"@vue/eslint-config-prettier": "^10.2.0",
- "@vueuse/core": "^13.6.0",
- "better-sqlite3": "^12.2.0",
- "eslint": "^9.0.0",
+ "@vueuse/core": "^13.9.0",
+ "better-sqlite3": "^12.4.1",
+ "eslint": "^9.36.0",
"gsap": "^3.13.0",
- "highcharts": "^12.3.0",
- "md-editor-v3": "^5.8.4",
- "nuxt": "^3.17.6",
+ "highcharts": "^12.4.0",
+ "md-editor-v3": "^6.0.1",
+ "nuxt": "^4.1.2",
"overlayscrollbars-vue": "^0.5.9",
+ "pinia": "^3.0.3",
"tailwind-scrollbar": "^4.0.2",
"tailwindcss": "^4.1.11",
"typescript": "^5.6.3",
- "vue": "^3.5.17",
+ "vue": "^3.5.21",
"vue-router": "^4.5.1",
"word-count": "^0.3.1"
},
- "packageManager": "pnpm@10.15.0",
+ "packageManager": "pnpm@10.17.1",
"devDependencies": {
- "@stylistic/eslint-plugin": "^5.1.0",
+ "@iconify-json/lucide": "^1.2.68",
+ "@stylistic/eslint-plugin": "^5.4.0",
"@stylistic/eslint-plugin-jsx": "^4.4.1",
"@vue/eslint-config-typescript": "^14.6.0",
- "eslint-plugin-vue": "^10.3.0",
- "globals": "^16.3.0",
- "less": "^4.4.0",
- "overlayscrollbars": "^2.11.5",
- "typescript-eslint": "^8.35.1",
+ "eslint-plugin-vue": "^10.5.0",
+ "globals": "^16.4.0",
+ "less": "^4.4.1",
+ "overlayscrollbars": "^2.12.0",
+ "typescript-eslint": "^8.44.1",
"vue-eslint-parser": "^10.2.0"
}
}
diff --git a/pages/index/about/index.vue b/pages/index/about/index.vue
new file mode 100644
index 0000000..96c0baf
--- /dev/null
+++ b/pages/index/about/index.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/index/components/ArticleCard.vue b/pages/index/components/ArticleCard.vue
index bd49628..7aecb0f 100644
--- a/pages/index/components/ArticleCard.vue
+++ b/pages/index/components/ArticleCard.vue
@@ -3,6 +3,7 @@
import { DataAnomaly, defaultMetaData } from '~/types/PostMetaData';
import type { PostMetaData } from '~/types/PostMetaData';
import breakpointsHelper from '~/utils/BreakpointsHelper';
+import { OverlayScrollbarsComponent } from 'overlayscrollbars-vue';
withDefaults(defineProps<{
metaData?: PostMetaData;
@@ -90,9 +91,9 @@ function getCostTime(length: number | DataAnomaly | undefined) {
-
- {{ metaData?.description }}
-
+
+ {{ metaData?.description }}
+
-
@@ -137,7 +137,6 @@ function getCostTime(length: number | DataAnomaly | undefined) {
-
diff --git a/pages/index/components/SimpleCard.vue b/pages/index/components/SimpleCard.vue
index aaea593..eb8c5dd 100644
--- a/pages/index/components/SimpleCard.vue
+++ b/pages/index/components/SimpleCard.vue
@@ -12,12 +12,15 @@ const props = withDefaults(defineProps<{
});
const { data: rawbody } = useAsyncData('simpleCard:' + props.metaData.id, async () => (await queryCollection('content').where('id', '=', props.metaData.id).first())?.rawbody);
const collapsed = ref(true);
-const typeChinese = new Map
([
+const typeChinese = new Map([
['rambling', '絮语'],
['announcement', '公告'],
]);
-function dateFormat(date: Date | DataAnomaly) {
+function dateFormat(date: Date | DataAnomaly | undefined) {
+ if (!date) {
+ return 'date undefined';
+ }
if (date === DataAnomaly.DataNotFound || date === DataAnomaly.Invalid) {
return date;
}
@@ -102,7 +105,7 @@ onUnmounted(() => {
class="p-5 light:bg-old-neutral-200 dark:bg-old-neutral-800 min-h-64 transition-all duration-500"
@click="reverseCollapsed">
- {{ (typeChinese.get(metaData.type) || 'unknown Type') + ':' }}{{ props.metaData.title }}
+ {{ (typeChinese.get(metaData?.type) || 'unknown Type') + ':' }}{{ props.metaData.title }}
@@ -134,7 +137,7 @@ onUnmounted(() => {
-
+
置顶
@@ -168,7 +171,7 @@ onUnmounted(() => {
- {{ dateFormat(props.metaData.updated_at[props.metaData.updated_at.length - 1]) }}
+ {{ dateFormat(props.metaData?.updated_at[props.metaData.updated_at.length - 1]) }}
diff --git a/pages/index/friends/index.vue b/pages/index/friends/index.vue
new file mode 100644
index 0000000..96c0baf
--- /dev/null
+++ b/pages/index/friends/index.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/index/index.vue b/pages/index/index.vue
index 078d569..a134fbe 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -5,35 +5,39 @@ import type { PostMetaData } from '~/types/PostMetaData';
import SimpleCard from '~/pages/index/components/SimpleCard.vue';
import ArticleCard from '~/pages/index/components/ArticleCard.vue';
-const { data: srcPostsMetaData } = useAsyncData(async () => sortMetaData((await queryCollection('content').all()).map((x) => toMetaDataType(x)), 'published_at', true));
+const srcPostsMetaData = ref([]);
const postsMetaData = ref([]);
+
+async function loadPostsMetaData() {
+ srcPostsMetaData.value = sortMetaData((await queryCollection('content').all()).map((x) => toMetaDataType(x)), 'published_at', true) || [];
+ postsMetaData.value = srcPostsMetaData.value;
+}
+
+await loadPostsMetaData();
+
function toArticlePage(article: PostMetaData) {
navigateTo(`/article/${encodeURIComponent(article.id)}`);
}
+
watch(srcPostsMetaData, () => {
postsMetaData.value = srcPostsMetaData.value || [];
});
-//
-// async function loadMetaData() {
-//
-// }
-function filterRuleChange(rule: string) {
- if (rule === '')
- postsMetaData.value = srcPostsMetaData.value || [];
- else
- postsMetaData.value = (srcPostsMetaData.value || []).filter((post) => post.type === rule);
+function filterRuleChange(rule: (data: PostMetaData) => boolean) {
+ postsMetaData.value = (srcPostsMetaData.value || []).filter(rule);
}
-
+
diff --git a/stores/colorModeStore.ts b/stores/colorModeStore.ts
index 3cede63..11a3196 100644
--- a/stores/colorModeStore.ts
+++ b/stores/colorModeStore.ts
@@ -1,10 +1,13 @@
-const getInitialMode = () => {
+function getInitialMode(): 'light' | 'dark' {
if (typeof window !== 'undefined') {
// 优先用 html 的 class
if (document.documentElement.classList.contains('dark')) return 'dark';
if (document.documentElement.classList.contains('light')) return 'light';
// 其次用 localStorage
- return localStorage.getItem('system-theme-mode') || 'light';
+ const val = localStorage.getItem('system-theme-mode');
+ if (!!val || (val !== 'light' && val !== 'dark'))
+ return 'light';
+ return val;
}
return 'light'; // SSR 默认
};
diff --git a/tailwind.config.js b/tailwind.config.js
index 68cbdd6..f48de1e 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -7,12 +7,6 @@ export default {
mode: 'jit',
darkMode: 'class',
theme: {
- extend: {
- colors: {},
- letterSpacing: {
- doublewidest: '.2em',
- },
- },
screens: breakpoints,
},
plugins: [