1
0
mirror of https://github.com/sendevia/website.git synced 2026-03-06 07:40:50 +08:00

引入侧边导航栏

This commit is contained in:
2025-09-20 22:11:04 +08:00
parent eee52386fa
commit 4438f2a2dd
2 changed files with 278 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
<template>
<nav id="navigation" spec="rail">
<ul id="navigation-destinations">
<li v-for="item in navItems" :key="item.link" :class="isActive(item.link) ? 'navigation-segment-active' : 'navigation-segment-inactive'">
<a :href="item.link">
<div class="navigation-destination-accent">
<div class="navigation-segment-icon">
<span>
{{ item.icon }}
</span>
</div>
</div>
<div class="navigation-destination-label">
{{ item.text }}
</div>
</a>
</li>
</ul>
</nav>
</template>
<script setup lang="ts">
import { computed } from "vue";
import { useData } from "vitepress";
const { theme, page } = useData();
const navItems = computed(() => [
{ text: "首页", icon: "home", link: "/" },
{ text: "Markdown 示例", icon: "counter_1", link: "/posts/markdown-examples" },
{ text: "API 示例", icon: "counter_2", link: "/posts/api-examples" },
]);
function isActive(link: string) {
const current = page.value.relativePath.replace(/(\/index)?\.md$/, "");
const target = link.replace(/\/$/, "").replace(/\.html$/, "");
return current === target.replace(/^\//, "") || (target === "" && current === "index");
}
</script>

View File

@@ -0,0 +1,239 @@
@use "sass:meta";
@use "../mixin";
// https://m3.material.io/components/navigation-bar/
// 页面导航
#navigation {
display: flex;
align-items: center;
justify-content: space-between;
background-color: var(--md-sys-color-surface-container-low);
transition: filter var(--md-sys-motion-duration-extra-long1) var(--md-sys-motion-easing-standard);
a {
display: flex;
align-items: center;
align-self: stretch;
flex-direction: column;
gap: 8px;
width: 100%;
cursor: pointer;
text-decoration: none;
}
#navigation-fab {
margin: 12px;
transition: var(--md-sys-motion-duration-medium4) var(--md-sys-motion-easing-standard);
button {
box-shadow: none;
}
}
#navigation-destinations {
display: flex;
flex-grow: 1;
padding: 0px;
transition: var(--md-sys-motion-duration-medium4) var(--md-sys-motion-easing-standard) var(--md-sys-motion-duration-short4);
.navigation-segment-active {
.navigation-destination-accent {
display: flex;
align-items: center;
flex: none;
justify-content: center;
margin-top: 4px;
position: relative;
width: 56px;
height: 32px;
border-radius: var(--md-sys-shape-corner-extra-large);
background-color: var(--md-sys-color-secondary-container);
overflow: hidden;
.navigation-segment-icon {
height: 24px;
width: 24px;
position: absolute;
color: var(--md-sys-color-on-secondary-container);
pointer-events: none;
transition: var(--md-sys-motion-duration-medium2) var(--md-sys-motion-easing-standard);
span {
@include mixin.material-symbols();
font-variation-settings: "FILL" 1, "wght" 300, "GRAD" 0, "opsz" 24;
transition: var(--md-sys-motion-duration-medium2) var(--md-sys-motion-easing-standard);
&:hover {
transition: var(--md-sys-motion-duration-long2) var(--md-sys-motion-easing-standard);
}
}
}
}
.navigation-destination-label {
@include mixin.typescale-style("label-small", $font-variation-settings: "wght" 600);
margin-bottom: 6px;
color: var(--md-sys-color-on-surface);
text-decoration: none;
text-align: center;
}
&:hover {
.navigation-destination-accent {
.navigation-segment-icon span {
font-variation-settings: "FILL" 1, "wght" 600, "GRAD" 0, "opsz" 24;
}
}
}
}
.navigation-segment-inactive {
@extend .navigation-segment-active;
.navigation-destination-accent {
height: 32px;
width: 32px;
background: none;
transition: var(--md-sys-motion-duration-medium2) var(--md-sys-motion-easing-standard);
.navigation-segment-icon span {
font-variation-settings: "FILL" 0, "wght" 300, "GRAD" 0, "opsz" 24;
}
}
.navigation-destination-label {
font-variation-settings: "wght" 400;
}
&:hover {
.navigation-destination-accent {
height: 32px;
background-color: var(--md-sys-color-surface-variant);
.navigation-segment-icon span {
font-variation-settings: "FILL" 0, "wght" 600, "GRAD" 0, "opsz" 24;
}
}
.navigation-destination-label {
font-variation-settings: "wght" 600;
}
}
&:active {
.navigation-destination-accent {
.navigation-segment-icon span {
font-variation-settings: "FILL" 0, "wght" 200, "GRAD" 0, "opsz" 24;
}
}
.navigation-destination-label {
font-variation-settings: "wght" 600;
}
}
}
}
&[spec="bar"] {
flex-direction: row;
bottom: 0px;
height: 80px;
width: 100%;
overflow-y: hidden;
z-index: 5;
#navigation-Hero,
#navigation-fab {
display: none;
}
#navigation-destinations {
align-items: center;
flex-direction: row;
justify-content: space-around;
div[spec="menu"] {
display: none !important;
}
.navigation-segment-active {
margin: 0px 4px 0px 4px;
.navigation-destination-accent {
height: 32px;
width: 64px;
margin: 0px 0px 4px 0px;
}
.navigation-destination-label {
margin: 0px;
}
}
.navigation-segment-inactive:hover {
.navigation-destination-accent {
width: 64px;
}
}
}
}
&[spec="rail"] {
flex-direction: column;
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
z-index: 3;
#navigation-fab {
display: flex;
align-items: center;
justify-content: center;
}
#navigation-destinations {
flex-direction: column;
justify-content: center;
width: 100%;
.navigation-segment-inactive:hover {
.navigation-destination-accent {
width: 56px;
}
}
}
}
}