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 `<UPageCard>` component, and the content schema is updated with `spotlight` and `highlight` options for enhanced display.
This commit is contained in:
85
app/composables/NavLinks.ts
Normal file
85
app/composables/NavLinks.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
// composables/useNavLinks.ts
|
||||
import type { NavigationMenuItem } from "@nuxt/ui";
|
||||
|
||||
export const useNavLinks = () => {
|
||||
const { t } = useI18n();
|
||||
|
||||
const navLinks = computed<NavigationMenuItem[]>(() => [
|
||||
{
|
||||
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;
|
||||
};
|
||||
@@ -1,9 +1,19 @@
|
||||
<template>
|
||||
<UPage>
|
||||
<UHeader>
|
||||
<UHeader
|
||||
:ui="{
|
||||
left: 'flex items-center gap-1.5',
|
||||
center: 'hidden lg:flex lg:flex-16',
|
||||
right: 'flex items-center justify-end gap-1.5',
|
||||
}"
|
||||
>
|
||||
<template #title> Tootaio Studio </template>
|
||||
<template #default>
|
||||
<UNavigationMenu :items="navLinks" variant="link" />
|
||||
<UNavigationMenu
|
||||
:items="navLinks"
|
||||
variant="link"
|
||||
class="w-full justify-center"
|
||||
/>
|
||||
</template>
|
||||
<template #body>
|
||||
<UNavigationMenu :items="navLinks" orientation="vertical" />
|
||||
@@ -42,6 +52,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
const { setLocale } = useI18n();
|
||||
const navLinks = useNavLinks();
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
||||
@@ -23,26 +23,24 @@
|
||||
:items="page?.featuredProjects.projects"
|
||||
:ui="{ item: 'basis-full sm:basis-1/2 lg:basis-1/3' }"
|
||||
>
|
||||
<UCard class="my-2">
|
||||
<template #header>
|
||||
<h3 class="text-2xl font-bold">{{ item.title }}</h3>
|
||||
</template>
|
||||
<template #default>
|
||||
<img :src="item.image" :alt="item.title" />
|
||||
<p class="mt-2 line-clamp-3">{{ item.description }}</p>
|
||||
</template>
|
||||
<template #footer>
|
||||
<UButton
|
||||
v-if="item.demoLink"
|
||||
:href="item.demoLink"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
size="sm"
|
||||
>
|
||||
{{ $t("index.featuredProjects.viewDemo") }}
|
||||
</UButton>
|
||||
</template>
|
||||
</UCard>
|
||||
<UPageCard
|
||||
class="my-2"
|
||||
:title="item.title"
|
||||
:description="item.description"
|
||||
:highlight="item.highlight"
|
||||
:spotlight="item.spotlight"
|
||||
>
|
||||
<img :src="item.image" :alt="item.title" />
|
||||
<UButton
|
||||
v-if="item.demoLink"
|
||||
:href="item.demoLink"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
size="sm"
|
||||
>
|
||||
{{ $t("index.featuredProjects.viewDemo") }}
|
||||
</UButton>
|
||||
</UPageCard>
|
||||
</UCarousel>
|
||||
</UPageSection>
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import type {NavigationMenuItem} from "@nuxt/ui";
|
||||
|
||||
export const navLinks: NavigationMenuItem[] = [{
|
||||
label: "Services",
|
||||
icon: "mdi:briefcase-outline"
|
||||
}, {
|
||||
label: "Projects",
|
||||
icon: "mdi:lightbulb-group-outline"
|
||||
}, {
|
||||
label: "Insights",
|
||||
icon: "mdi:brain"
|
||||
}]
|
||||
Reference in New Issue
Block a user