feat: Add nav bar

This commit is contained in:
2025-05-16 00:19:24 +08:00
parent 621bc20edd
commit 95d25ee6f0
11 changed files with 612 additions and 73 deletions

196
app.vue
View File

@@ -1,25 +1,177 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import ScrollPanel from "primevue/scrollpanel";
import SparkIcon from "~/assets/icons/spark.svg";
const path = computed(() => {
return useRoute().path;
});
const sProgress = ref(path.value === "/" ? 1 : 0);
const scrollPanel =
useTemplateRef<InstanceType<typeof ScrollPanel>>("scrollPanel");
const sX = ref(0);
const sY = ref(0);
const sWidth = ref(0);
const sHeight = ref(0);
const mounted = ref(false);
const handleScrollOrResize = () => {
if (path.value !== "/") {
sProgress.value = 0;
return;
}
const scrollTop = scrollPanel.value?.lastScrollTop;
const clientHeight = scrollPanel.value?.$el.clientHeight;
sProgress.value = 1 - Math.min(scrollTop / clientHeight, 1);
};
onMounted(() => {
watchEffect(handleScrollOrResize);
watchEffect(() => {
console.log("path changed", path.value);
const navEl = document.querySelector("header nav");
const el = document.querySelector("header .active");
if (el && navEl) {
sX.value = el.getBoundingClientRect().x - navEl.getBoundingClientRect().x;
sY.value = el.getBoundingClientRect().y - navEl.getBoundingClientRect().y;
sWidth.value = el.getBoundingClientRect().width;
sHeight.value = el.getBoundingClientRect().height;
}
});
nextTick(() => {
mounted.value = true;
});
});
</script>
<template>
<header>
<nav>
<NuxtLink to="/">
<img />
<h1>SPARK</h1>
</NuxtLink>
<ul>
<li><NuxtLink to="/">首页</NuxtLink></li>
<li><NuxtLink to="/download">下载</NuxtLink></li>
<li><NuxtLink to="/news">新闻</NuxtLink></li>
<li><NuxtLink to="/faq">帮助</NuxtLink></li>
<li><NuxtLink to="/about">关于</NuxtLink></li>
<li><NuxtLink to="/gxde">GXDE OS</NuxtLink></li>
</ul>
<Button icon="pi pi-sun" aria-label="Save" />
</nav>
</header>
<div>
<NuxtPage />
</div>
<footer></footer>
<ScrollPanel ref="scrollPanel" style="width: 100vw; height: 100vh">
<header
class="fixed w-full z-10 px-12"
:style="{ '--s-progress': sProgress }"
>
<nav
class="relative flex px-8 py-2 items-center"
:class="{ mounted }"
:style="{
'--s-x': sX,
'--s-y': sY,
'--s-width': sWidth,
'--s-height': sHeight,
}"
>
<NuxtLink to="/" class="flex items-center">
<SparkIcon class="w-10 h-10 mr-2 fill-(--p-primary-color)" />
<h1>SPARK</h1>
</NuxtLink>
<div class="grow" />
<NuxtLink to="/" class="nav-link" active-class="active">
首页
</NuxtLink>
<NuxtLink to="/download" class="nav-link" active-class="active">
下载
</NuxtLink>
<NuxtLink to="/news" class="nav-link" active-class="active">
新闻
</NuxtLink>
<NuxtLink to="/faq" class="nav-link" active-class="active">
帮助
</NuxtLink>
<NuxtLink to="/about" class="nav-link" active-class="active">
关于
</NuxtLink>
<NuxtLink to="/gxde" class="nav-link" active-class="active">
GXDE OS
</NuxtLink>
<Button
icon="pi pi-sun"
aria-label="Toggle Dark Mode"
size="small"
class="shrink-0"
rounded
severity="secondary"
/>
</nav>
</header>
<div>
<NuxtPage />
</div>
<footer></footer>
</ScrollPanel>
</template>
<style scoped lang="scss">
header {
transform: translateY(calc(var(--s-progress) * 12 * var(--spacing)));
transition: {
property: transform;
duration: 0.1s;
}
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
transform: translateX(calc(var(--s-progress) * 12 * var(--spacing)));
width: calc(100% - var(--s-progress) * 24 * var(--spacing));
border-radius: calc(var(--s-progress) * 6 * var(--spacing));
height: 100%;
background-color: #fff;
z-index: -1;
transition: {
property: transform, width, border-radius;
duration: 0.1s;
}
}
h1 {
font-family: "KNYuanmo";
font-size: 1.75em;
color: var(--p-surface-500);
}
nav::before {
content: "";
position: absolute;
top: 0;
left: 0;
transform: translate(calc(var(--s-x) * 1px), calc(var(--s-y) * 1px));
width: calc(var(--s-width) * 1px);
height: calc(var(--s-height) * 1px);
background-color: var(--p-primary-200);
border-radius: calc(var(--spacing) * 4.75);
z-index: -1;
}
.nav-link {
margin-right: calc(var(--spacing) * 2);
padding: calc(var(--spacing) * 2) calc(var(--spacing) * 4);
border-radius: calc(var(--spacing) * 4.75);
font-weight: bold;
color: var(--p-surface-600);
&.active {
color: var(--p-primary-600);
background-color: var(--p-primary-200);
}
}
nav.mounted {
&::before {
transition: {
property: width, transform;
duration: 0.3s;
}
}
.nav-link {
background-color: unset;
&:hover {
background-color: rgba(from var(--p-surface-400) r g b / 0.1);
}
}
}
}
</style>