mirror of
https://github.com/fawney19/Aether.git
synced 2026-01-04 08:42:27 +08:00
Initial commit
This commit is contained in:
88
frontend/src/components/layout/SidebarNav.vue
Normal file
88
frontend/src/components/layout/SidebarNav.vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<nav class="sidebar-nav w-full px-3">
|
||||
<div v-for="(group, index) in items" :key="index" class="space-y-1 mb-5">
|
||||
|
||||
<!-- Section Header -->
|
||||
<div v-if="group.title" class="px-2.5 pb-1 flex items-center gap-2" :class="index > 0 ? 'pt-1' : ''">
|
||||
<span class="text-[10px] font-medium text-muted-foreground/50 font-mono tabular-nums">{{ String(index + 1).padStart(2, '0') }}</span>
|
||||
<span class="text-[10px] font-semibold text-muted-foreground/70 uppercase tracking-[0.1em]">{{ group.title }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Links -->
|
||||
<div class="space-y-0.5">
|
||||
<template v-for="item in group.items" :key="item.href">
|
||||
<RouterLink
|
||||
:to="item.href"
|
||||
class="group relative flex items-center justify-between px-2.5 py-2 rounded-lg transition-all duration-200"
|
||||
:class="[
|
||||
isItemActive(item.href)
|
||||
? 'bg-primary/10 text-primary font-medium'
|
||||
: 'text-muted-foreground hover:text-foreground hover:bg-muted/50'
|
||||
]"
|
||||
@click="handleNavigate(item.href)"
|
||||
>
|
||||
<div class="flex items-center gap-2.5">
|
||||
<component
|
||||
:is="item.icon"
|
||||
class="h-4 w-4 transition-colors duration-200"
|
||||
:class="isItemActive(item.href) ? 'text-primary' : 'text-muted-foreground/70 group-hover:text-foreground'"
|
||||
:stroke-width="isItemActive(item.href) ? 2 : 1.75"
|
||||
/>
|
||||
<span class="text-[13px] tracking-tight">{{ item.name }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Active Indicator -->
|
||||
<div
|
||||
v-if="isItemActive(item.href)"
|
||||
class="w-1 h-1 rounded-full bg-primary"
|
||||
></div>
|
||||
</RouterLink>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Component } from 'vue'
|
||||
|
||||
export interface NavigationItem {
|
||||
name: string
|
||||
href: string
|
||||
icon: Component
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface NavigationGroup {
|
||||
title?: string
|
||||
items: NavigationItem[]
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
items: NavigationGroup[]
|
||||
activePath?: string
|
||||
isActive?: (href: string) => boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'navigate', href: string): void
|
||||
}>()
|
||||
|
||||
function isItemActive(href: string) {
|
||||
if (props.isActive) {
|
||||
return props.isActive(href)
|
||||
}
|
||||
if (props.activePath) {
|
||||
return props.activePath === href || props.activePath.startsWith(`${href}/`)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function handleNavigate(href: string) {
|
||||
emit('navigate', href)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Navigation styles handled by Tailwind */
|
||||
</style>
|
||||
Reference in New Issue
Block a user