feat: 添加导航栏移动端适配

This commit is contained in:
2025-09-15 18:50:37 +08:00
parent 823232f9fb
commit f873621eff
2 changed files with 130 additions and 82 deletions

85
app.vue
View File

@@ -9,6 +9,7 @@ const path = computed(() => {
});
const sProgress = ref(1);
const scrollPanel = useTemplateRef<ComponentPublicInstance>("scrollPanel");
const header = useTemplateRef<HTMLElement>("header");
const sX = ref(0);
const sY = ref(0);
const sWidth = ref(0);
@@ -40,6 +41,16 @@ const handleScrollOrResize = () => {
sProgress.value = 1 - range(0, 1, scrollTop / clientHeight);
};
const handleHeaderFocus = () => {
mounted.value = false;
setTimeout(() => {
handleScrollOrResize();
nextTick(() => {
mounted.value = true;
});
}, 300);
};
onMounted(() => {
addEventListener("resize", handleScrollOrResize);
watchEffect(handleScrollOrResize);
@@ -200,11 +211,15 @@ provide("latestRelease", latestRelease);
}"
>
<header
class="fixed w-full z-10 px-12"
tabindex="0"
class="fixed w-full h-15 z-10 px-4 sm:px-8 lg:px-12 translate-y-[calc(var(--s-progress)*4*var(--spacing))] sm:translate-y-[calc(var(--s-progress)*8*var(--spacing))] lg:translate-y-[calc(var(--s-progress)*12*var(--spacing))] before:translate-x-[calc(var(--s-progress)*4*var(--spacing))] sm:before:translate-x-[calc(var(--s-progress)*8*var(--spacing))] lg:before:translate-x-[calc(var(--s-progress)*12*var(--spacing))] before:w-[calc(100%-var(--s-progress)*8*var(--spacing))] sm:before:w-[calc(100%-var(--s-progress)*16*var(--spacing))] lg:before:w-[calc(100%-var(--s-progress)*24*var(--spacing))] sm:h-auto focus-within:h-auto before:h-15 focus-within:before:h-82.5 sm:before:h-full focus-within:sm:before:h-full overflow-hidden focus-within:overflow-visible transition-discrete group"
ref="header"
:style="{ '--s-progress': sProgress }"
@click="if (!header?.matches(':focus-within')) header?.focus();"
@focus="handleHeaderFocus"
>
<nav
class="relative flex px-8 h-15 items-center"
class="relative flex px-2.5 md:px-4 lg:px-8 items-center flex-col md:flex-row before:opacity-0 group-focus-within:before:opacity-100 sm:before:opacity-100 before:origin-top before:scale-0 group-focus-within:before:scale-100 sm:before:scale-100 before:translate-x-[calc(50vw-14.5*var(--spacing))] before:translate-y-15 group-focus-within:before:translate-x-[calc(var(--s-x)*1px)] group-focus-within:before:translate-y-[calc(var(--s-y)*1px)] sm:before:translate-x-[calc(var(--s-x)*1px)] sm:before:translate-y-[calc(var(--s-y)*1px)]"
:class="{ mounted }"
:style="{
'--s-x': sX,
@@ -213,15 +228,36 @@ provide("latestRelease", latestRelease);
'--s-height': sHeight,
}"
>
<NuxtLink to="/" class="flex items-center">
<div
class="flex h-15 w-full sm:w-auto px-2 justify-between items-center"
>
<NuxtLink class="flex items-center">
<Icon
name="sp:spark"
class="text-4xl mr-2 s-color-primary-color"
class="text-4xl sm:mr-2 s-color-primary-color"
mode="svg"
/>
<h1 class="font-(family-name:--s-title-font)">SPARK</h1>
</NuxtLink>
<div class="grow" />
<NuxtLink class="flex items-center">
<h1 class="font-(family-name:--s-title-font) text-surface-500">
SPARK
</h1>
</NuxtLink>
<div class="sm:hidden relative">
<span
class="pi pi-ellipsis-v text-surface-400 font-bold! text-xl! group-focus-within:opacity-0 group-focus-within:rotate-90 transition-all duration-300"
></span>
<span
class="absolute top-0 left-0 pi pi-times text-surface-400 font-bold! text-xl! opacity-0 -rotate-90 group-focus-within:opacity-100 group-focus-within:rotate-0 transition-all duration-300"
></span>
</div>
</div>
<div
class="flex grow pb-2.5 md:pt-2.5 items-end sm:items-center flex-row-reverse sm:flex-row w-full sm:w-auto justify-between md:justify-end opacity-0 group-focus-within:opacity-100 sm:opacity-100 origin-top scale-0 group-focus-within:scale-100 sm:scale-100 transition-transform duration-300"
>
<div
class="flex flex-col gap-1 mr-1.5 md:mr-1 lg:gap-2 lg:mr-2 sm:flex-row items-end sm:items-center"
>
<NuxtLink to="/" class="nav-link" active-class="active">
首页
</NuxtLink>
@@ -248,6 +284,7 @@ provide("latestRelease", latestRelease);
<a href="https://gxde.top/" class="nav-link" active-class="active">
GXDE OS
</a>
</div>
<Button
:icon="`pi ${
sDarkConfig === 'auto'
@@ -258,11 +295,12 @@ provide("latestRelease", latestRelease);
}`"
aria-label="Toggle Dark Mode"
size="small"
class="shrink-0"
class="shrink-0 m-1.5 sm:m-0"
rounded
severity="secondary"
@click="toggleDarkMode"
/>
</div>
</nav>
</header>
<div>
@@ -322,10 +360,11 @@ provide("latestRelease", latestRelease);
<style scoped lang="scss">
header {
transform: translateY(calc(var(--s-progress) * 12 * var(--spacing)));
transform: translateY();
transition: {
property: transform;
duration: 0.1s;
property: transform, overflow;
duration: 0.1s, 0s;
delay: 0s, 0.3s;
}
&::before {
@@ -334,21 +373,27 @@ header {
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) * 4 * var(--spacing));
height: 100%;
border-radius: calc(var(--s-progress) * var(--radius-2xl));
border-bottom-right-radius: calc(var(--s-progress) * var(--radius-2xl));
border-bottom-left-radius: calc(var(--s-progress) * var(--radius-2xl));
background-color: var(--p-surface-0);
backdrop-filter: blur(calc(4 * var(--spacing)));
z-index: -1;
transition: {
property: transform, width, border-radius;
duration: 0.1s;
property: transform, width, border-radius, background-color, height;
duration: 0.1s, 0.1s, 0.1s, 0.3s, 0.3s;
}
}
&:focus-within::before,
&:hover::before {
background-color: rgba(from var(--p-surface-0) r g b / 0.8);
border-bottom-right-radius: var(--radius-2xl);
border-bottom-left-radius: var(--radius-2xl);
}
h1 {
font-size: 1.75em;
color: var(--p-surface-500);
}
nav::before {
@@ -356,16 +401,15 @@ header {
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;
visibility: hidden;
}
.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;
@@ -379,8 +423,9 @@ header {
nav.mounted {
&::before {
visibility: visible;
transition: {
property: width, transform;
property: width, transform, opacity, scale, translate;
duration: 0.3s;
}
}

View File

@@ -1,6 +1,6 @@
@import "tailwindcss";
@import 'primeicons/primeicons.css';
@import '../fonts/KNYuanmo-Regular/result.css';
@import "primeicons/primeicons.css";
@import "../fonts/KNYuanmo-Regular/result.css";
@custom-variant dark (&:where(.s-dark, .s-dark *));
@@ -39,12 +39,13 @@
--color-surface-800: var(--p-surface-800);
--color-surface-900: var(--p-surface-900);
--color-surface-950: var(--p-surface-950);
--s-title-font: 'KN Yuanmo SC', sans-serif;
--s-title-font: "KN Yuanmo SC", sans-serif;
--s-background: var(--p-secondary-50);
}
:root {
font-family: 'BlinkMacSystemFont', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
font-family: "BlinkMacSystemFont", Roboto, Helvetica, Arial, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
background-color: var(--s-background) !important;
}
@@ -54,7 +55,6 @@
--p-highlight-focus-color: var(--p-primary-color) !important;
}
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
@@ -71,7 +71,6 @@
z-index: 9999;
}
@utility s-color-* {
--s-color: --value([color]);
--s-c1: --value([color]);
@@ -81,32 +80,36 @@
--s-c5: --value([color]);
--s-c6: --value([color]);
--s-c7: --value([color]);
--s-color: --value(--color-*);
--s-c1: --value(--color-*);
--s-c2: --value(--color-*);
--s-c3: --value(--color-*);
--s-c4: --value(--color-*);
--s-c5: --value(--color-*);
--s-c6: --value(--color-*);
--s-c7: --value(--color-*);
--s-color: --value(--color- *);
--s-c1: --value(--color- *);
--s-c2: --value(--color- *);
--s-c3: --value(--color- *);
--s-c4: --value(--color- *);
--s-c5: --value(--color- *);
--s-c6: --value(--color- *);
--s-c7: --value(--color- *);
}
@utility s-deco-* {
--s-deco: --value([color]);
--s-deco: --value(--color-*);
--s-deco: --value(--color- *);
}
@utility s-bg-* {
--s-bg: --value([color]);
--s-bg: --value(--color-*);
--s-bg: --value(--color- *);
}
@utility s-bg-2-* {
--s-bg-2: --value([color]);
--s-bg-2: --value(--color-*);
--s-bg-2: --value(--color- *);
}
@utility s-bg-3-* {
--s-bg-3: --value([color]);
--s-bg-3: --value(--color-*);
--s-bg-3: --value(--color- *);
}
@utility s-size-* {
--s-size: --value(number);
}