71 lines
2.1 KiB
Vue
71 lines
2.1 KiB
Vue
|
|
<template>
|
||
|
|
<aside class="rail" aria-label="主导航">
|
||
|
|
<div class="mark">RO</div>
|
||
|
|
<nav class="rail-nav">
|
||
|
|
<button
|
||
|
|
v-for="item in navItems"
|
||
|
|
:key="item.id"
|
||
|
|
class="nav-btn"
|
||
|
|
:class="{ active: activeView === item.id }"
|
||
|
|
type="button"
|
||
|
|
:aria-label="item.label"
|
||
|
|
:title="item.label"
|
||
|
|
@click="emit('navigate', item.id)"
|
||
|
|
>
|
||
|
|
<span v-html="item.icon"></span>
|
||
|
|
</button>
|
||
|
|
</nav>
|
||
|
|
<button class="nav-btn muted" type="button" aria-label="打开合规对话" title="打开合规对话" @click="emit('openChat')">
|
||
|
|
<span v-html="messageIcon"></span>
|
||
|
|
</button>
|
||
|
|
</aside>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup>
|
||
|
|
import { icons } from '../../data/icons.js'
|
||
|
|
|
||
|
|
defineProps({
|
||
|
|
navItems: { type: Array, required: true },
|
||
|
|
activeView: { type: String, required: true }
|
||
|
|
})
|
||
|
|
|
||
|
|
const emit = defineEmits(['navigate', 'openChat'])
|
||
|
|
|
||
|
|
const messageIcon = icons.message
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
.rail {
|
||
|
|
position: sticky;
|
||
|
|
top: 0;
|
||
|
|
height: 100dvh;
|
||
|
|
display: grid;
|
||
|
|
grid-template-rows: auto 1fr auto;
|
||
|
|
gap: 18px;
|
||
|
|
padding: 18px 12px;
|
||
|
|
background: var(--nav);
|
||
|
|
color: #fff;
|
||
|
|
z-index: 20;
|
||
|
|
}
|
||
|
|
.mark { width: 48px; height: 48px; display: grid; place-items: center; border-radius: 14px; background: linear-gradient(135deg,#fff,#9db2ff); color: #10215c; font-weight: 850; }
|
||
|
|
.rail-nav { display: grid; gap: 10px; align-content: start; }
|
||
|
|
.nav-btn {
|
||
|
|
width: 48px;
|
||
|
|
min-height: 48px;
|
||
|
|
display: grid;
|
||
|
|
place-items: center;
|
||
|
|
border: 0;
|
||
|
|
border-radius: 14px;
|
||
|
|
background: transparent;
|
||
|
|
color: var(--nav-muted);
|
||
|
|
transition: background 160ms var(--ease), color 160ms var(--ease), transform 160ms var(--ease);
|
||
|
|
}
|
||
|
|
.nav-btn:hover, .nav-btn.active { background: rgba(255,255,255,.1); color: #fff; transform: translateY(-1px); }
|
||
|
|
.nav-btn svg { width: 18px; height: 18px; stroke: currentColor; stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; }
|
||
|
|
|
||
|
|
@media (max-width: 760px) {
|
||
|
|
.rail { position: sticky; height: auto; grid-template-columns: auto 1fr auto; grid-template-rows: none; padding: 10px 12px; }
|
||
|
|
.rail-nav { display: flex; overflow-x: auto; }
|
||
|
|
}
|
||
|
|
</style>
|