104 lines
4.0 KiB
Vue
104 lines
4.0 KiB
Vue
<script setup>
|
|
import { computed } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { useAuthStore } from '../stores/auth'
|
|
|
|
const auth = useAuthStore()
|
|
const router = useRouter()
|
|
|
|
const navItems = [
|
|
{ to: '/dashboard', label: 'اليوم', icon: 'M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z' },
|
|
{ to: '/fleet', label: 'الأسطول', icon: 'M3 13l1.5-5A2 2 0 0 1 6.4 6.5h11.2A2 2 0 0 1 19.5 8L21 13v6a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1v-1H6v1a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1z' },
|
|
{ to: '/routes', label: 'الخطوط', icon: 'M9 20l-5-2V5l5 2m0 13l6-2m-6 2V7m6 11l5 2V6l-5-2m0 15V5m0 2L9 5' },
|
|
{ to: '/students', label: 'الطلاب', icon: 'M12 3l9 4.5-9 4.5-9-4.5L12 3zM3 12l9 4.5 9-4.5M3 16.5l9 4.5 9-4.5' },
|
|
{ to: '/broadcasts', label: 'الإعلانات', icon: 'M11 5L6 9H2v6h4l5 4V5zM19 8a5 5 0 0 1 0 8' },
|
|
]
|
|
|
|
const contractLabel = computed(() => ({
|
|
trial: 'تجريبي', active: 'نشط', suspended: 'معلَّق', terminated: 'منتهٍ',
|
|
}[auth.org?.contract_status] || auth.org?.contract_status))
|
|
|
|
const contractClass = computed(() => ({
|
|
trial: 'pill-info', active: 'pill-good', suspended: 'pill-warn', terminated: 'pill-bad',
|
|
}[auth.org?.contract_status] || 'pill-neutral'))
|
|
|
|
async function doLogout() {
|
|
await auth.logout()
|
|
router.replace('/login')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="shell">
|
|
<aside class="sidebar">
|
|
<div class="brand">
|
|
<span class="brand-dot"></span>
|
|
<span>مواصلاتي</span>
|
|
</div>
|
|
<nav class="nav">
|
|
<router-link v-for="item in navItems" :key="item.to" :to="item.to" class="nav-item" active-class="active">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
|
<path :d="item.icon" />
|
|
</svg>
|
|
<span>{{ item.label }}</span>
|
|
</router-link>
|
|
</nav>
|
|
</aside>
|
|
|
|
<div class="main">
|
|
<header class="topbar">
|
|
<div class="org-info">
|
|
<strong>{{ auth.org?.name_ar }}</strong>
|
|
<span class="pill" :class="contractClass">{{ contractLabel }}</span>
|
|
</div>
|
|
<div class="account">
|
|
<span class="admin-name">{{ auth.admin?.name }}</span>
|
|
<button class="btn btn-ghost btn-sm" @click="doLogout">خروج</button>
|
|
</div>
|
|
</header>
|
|
<main class="content">
|
|
<router-view />
|
|
</main>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.shell { display: flex; min-height: 100vh; }
|
|
|
|
.sidebar {
|
|
width: 232px; flex-shrink: 0; background: var(--surface); border-inline-start: 1px solid var(--line);
|
|
display: flex; flex-direction: column; padding: 20px 14px;
|
|
}
|
|
.brand {
|
|
display: flex; align-items: center; gap: 9px; font-weight: 800; font-size: 15.5px;
|
|
color: var(--brand-deep); padding: 8px 10px 24px;
|
|
}
|
|
.brand-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--brand); }
|
|
.nav { display: flex; flex-direction: column; gap: 3px; }
|
|
.nav-item {
|
|
display: flex; align-items: center; gap: 12px; padding: 11px 12px; border-radius: var(--r-sm);
|
|
color: var(--ink-soft); text-decoration: none; font-size: 14.5px; font-weight: 600;
|
|
transition: background .15s ease, color .15s ease;
|
|
}
|
|
.nav-item svg { width: 19px; height: 19px; flex-shrink: 0; }
|
|
.nav-item:hover { background: var(--surface-2); color: var(--ink); }
|
|
.nav-item.active { background: var(--brand-soft); color: var(--brand-deep); }
|
|
|
|
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
|
.topbar {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 16px 28px; border-bottom: 1px solid var(--line); background: var(--surface);
|
|
}
|
|
.org-info { display: flex; align-items: center; gap: 12px; font-size: 15px; }
|
|
.account { display: flex; align-items: center; gap: 14px; }
|
|
.admin-name { color: var(--ink-soft); font-size: 13.5px; }
|
|
|
|
.content { flex: 1; padding: 28px; max-width: 1180px; width: 100%; margin: 0 auto; }
|
|
|
|
@media (max-width: 860px) {
|
|
.sidebar { position: fixed; inset-inline-start: 0; top: 0; bottom: 0; z-index: 20; transform: translateX(100%); }
|
|
.content { padding: 18px; }
|
|
}
|
|
</style>
|