From 31a4103f9b5c64e93cf96838dfbfc58b70a53fb2 Mon Sep 17 00:00:00 2001 From: xiaomai Date: Thu, 6 Nov 2025 00:17:34 +0800 Subject: [PATCH] feat(ui): implement dynamic dropdown navigation and refactor project cards Replaced the static navigation with a dynamic, internationalized dropdown menu powered by a new `useNavLinks` composable. The navigation items are now sourced from i18n files. The featured project cards on the homepage have been refactored to use the `` component, and the content schema is updated with `spotlight` and `highlight` options for enhanced display. --- app/composables/NavLinks.ts | 85 ++++++++++++++++++++++++ app/layouts/default.vue | 15 ++++- app/pages/index.vue | 38 ++++++----- app/utils/navLinks.ts | 12 ---- content.config.ts | 114 ++++++++++++--------------------- content/en-US/index.yml | 1 + content/zh-CN/index.yml | 1 + i18n/locales/en-US/common.json | 57 +++++++++++++++++ i18n/locales/zh-CN/common.json | 57 +++++++++++++++++ nuxt.config.ts | 4 +- 10 files changed, 276 insertions(+), 108 deletions(-) create mode 100644 app/composables/NavLinks.ts delete mode 100644 app/utils/navLinks.ts create mode 100644 i18n/locales/en-US/common.json create mode 100644 i18n/locales/zh-CN/common.json diff --git a/app/composables/NavLinks.ts b/app/composables/NavLinks.ts new file mode 100644 index 0000000..10d361a --- /dev/null +++ b/app/composables/NavLinks.ts @@ -0,0 +1,85 @@ +// composables/useNavLinks.ts +import type { NavigationMenuItem } from "@nuxt/ui"; + +export const useNavLinks = () => { + const { t } = useI18n(); + + const navLinks = computed(() => [ + { + label: t("common.header.services.label"), + icon: "mdi:briefcase-outline", + children: [ + { + label: t("common.header.services.children.webDev.label"), + description: t("common.header.services.children.webDev.description"), + icon: "mdi:web", + }, + { + label: t("common.header.services.children.softwareDev.label"), + description: t( + "common.header.services.children.softwareDev.description" + ), + icon: "mdi:tools", + }, + { + label: t("common.header.services.children.eventVisual.label"), + description: t( + "common.header.services.children.eventVisual.description" + ), + icon: "mdi:monitor-dashboard", + }, + { + label: t("common.header.services.children.lab.label"), + description: t("common.header.services.children.lab.description"), + icon: "mdi:test-tube-off", + }, + ], + }, + { + label: t("common.header.projects.label"), + icon: "mdi:lightbulb-group-outline", + children: [ + { + label: t("common.header.projects.children.commercialWebsite.label"), + description: t( + "common.header.projects.children.commercialWebsite.description" + ), + icon: "mdi:web", + }, + { + label: t("common.header.projects.children.gameDev.label"), + description: t("common.header.projects.children.gameDev.description"), + icon: "mdi:gamepad-variant-outline", + }, + { + label: t("common.header.projects.children.tools.label"), + description: t("common.header.projects.children.tools.description"), + icon: "mdi:tools", + }, + { + label: t("common.header.projects.children.special.label"), + description: t("common.header.projects.children.special.description"), + icon: "mdi:star", + }, + ], + }, + { + label: t("common.header.insights.label"), + icon: "mdi:brain", + children: [ + { + label: t("common.header.insights.children.xiaomaiBlog.label"), + description: t( + "common.header.insights.children.xiaomaiBlog.description" + ), + icon: "mdi:pencil-outline", + to: "https://xiaomai.tootaio.com/", + type: "link", + target: "_blank", + }, + ], + }, + ]); + + return navLinks; +}; diff --git a/app/layouts/default.vue b/app/layouts/default.vue index 859188d..b930397 100644 --- a/app/layouts/default.vue +++ b/app/layouts/default.vue @@ -1,9 +1,19 @@