feat(v2): NexusLayout, Sidebar, NavGroup, NavItem, Topbar, FlowBoard placeholder
CI - Build & Test / Backend (.NET) (push) Failing after 22s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 14s
CI - Build & Test / Security Check (push) Successful in 2s

This commit is contained in:
2026-06-12 00:20:27 +02:00
parent f378d7aed4
commit 3672e56994
9 changed files with 725 additions and 1 deletions
+126
View File
@@ -0,0 +1,126 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { icons } from '../../composables/icons'
const props = defineProps<{
icon: string
label: string
route?: string
count?: string
active?: boolean
}>()
const router = useRouter()
const route = useRoute()
const isActive = computed(() => {
if (props.active) return true
if (props.route && route.path === props.route) return true
return false
})
function navigate() {
if (props.route) {
router.push(props.route)
}
}
</script>
<template>
<button
:class="['nav-item', { active: isActive }]"
@click="navigate"
>
<!-- Icon -->
<span class="nav-icon" v-html="icons[icon] || ''"></span>
<!-- Label -->
<span class="nav-label">{{ label }}</span>
<!-- Count badge -->
<span v-if="count !== undefined" class="count">{{ count }}</span>
</button>
</template>
<style scoped>
.nav-item {
display: flex;
align-items: center;
gap: 11px;
padding: 9px 11px;
border-radius: 10px;
border: none;
background: transparent;
color: var(--tx-2);
font-family: 'Manrope', sans-serif;
font-size: 13.5px;
font-weight: 500;
cursor: pointer;
position: relative;
transition: background .16s, color .16s;
text-decoration: none;
width: 100%;
text-align: left;
}
.nav-item:hover {
background: rgba(124,108,255,.08);
color: var(--tx);
}
.nav-item.active {
color: #fff;
background: linear-gradient(90deg, rgba(124,108,255,.22), rgba(124,108,255,.04));
box-shadow: inset 0 0 0 1px rgba(124,108,255,.25);
}
.nav-item.active::before {
content: '';
position: absolute;
left: -12px;
top: 50%;
transform: translateY(-50%);
width: 3px;
height: 20px;
border-radius: 3px;
background: var(--grad);
box-shadow: var(--glow-purple);
}
.nav-icon {
display: flex;
align-items: center;
justify-content: center;
width: 17px;
height: 17px;
flex: 0 0 auto;
opacity: .85;
}
.nav-icon :deep(svg) {
width: 17px;
height: 17px;
}
.nav-label {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.count {
margin-left: auto;
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
font-weight: 600;
padding: 1px 8px;
border-radius: 20px;
background: rgba(124,108,255,.16);
color: var(--tx);
line-height: 1.4;
flex-shrink: 0;
}
</style>