diff --git a/apps/web/src/components/nav/NavHubPanel.vue b/apps/web/src/components/nav/NavHubPanel.vue new file mode 100644 index 0000000..926f393 --- /dev/null +++ b/apps/web/src/components/nav/NavHubPanel.vue @@ -0,0 +1,280 @@ + + + + + + + {{ hub.title }} + {{ hub.desc }} + + + + + + + + + + + {{ card.title }} + + + + + + + {{ card.desc }} + + + + + دسترسی سریع + + + + {{ item.title }} + + + + + + + diff --git a/apps/web/src/layouts/AppLayout.vue b/apps/web/src/layouts/AppLayout.vue index f34333c..f2635d5 100644 --- a/apps/web/src/layouts/AppLayout.vue +++ b/apps/web/src/layouts/AppLayout.vue @@ -8,6 +8,8 @@ import UiIcon from '@/components/UiIcon.vue'; import MentoLogo from '@/components/brand/MentoLogo.vue'; import QuickCreate from '@/components/QuickCreate.vue'; import BrandName from '@/components/brand/BrandName.vue'; +import NavHubPanel from '@/components/nav/NavHubPanel.vue'; +import { NAV_HUBS, type NavHubDef, type NavHubKey } from '@/lib/nav-hubs'; import type { ActivitySummaryDto, NotificationDto, @@ -29,17 +31,10 @@ const todayLabel = computed(() => formatJalaliShort(new Date())); const SIDEBAR_KEY = 'mento_sidebar_collapsed'; const collapsed = ref(false); -const customersOpen = ref(false); -const salesOpen = ref(false); -const activitiesOpen = ref(false); -const supportOpen = ref(false); -const toolsOpen = ref(false); -const settingsOpen = ref(false); +const openHubKey = ref(null); const globalSearch = ref(''); const activityBadge = ref(0); -type FoldKey = 'customers' | 'sales' | 'activities' | 'support' | 'tools' | 'settings'; - function pathIn(prefixes: string[]) { return prefixes.some( (p) => route.path === p || route.path.startsWith(`${p}/`), @@ -66,18 +61,16 @@ const settingsActive = computed(() => '/settings/faq', ]), ); -const peopleContactsActive = computed( - () => customersActive.value && route.query.tab !== 'companies', -); -const companyContactsActive = computed( - () => customersActive.value && route.query.tab === 'companies', -); -const myActivitiesActive = computed( - () => - route.path === '/activities' || - route.path.startsWith('/activities/new') || - (route.path.startsWith('/activities/') && !route.path.startsWith('/activities/calendar')), -); +const openHub = computed(() => { + if (!openHubKey.value) return null; + const hub = NAV_HUBS.find((item) => item.key === openHubKey.value); + if (!hub) return null; + return { + ...hub, + cards: hub.cards.filter((card) => !card.admin || canSettings.value), + shortcuts: hub.shortcuts.filter((item) => !item.admin || canSettings.value), + }; +}); function givenName(fullName: string): string { const parts = fullName.trim().split(/\s+/).filter(Boolean); @@ -115,37 +108,19 @@ watch([profileFullName, collapsed], () => { void fitProfileName(); }); -watch( - () => route.path, - () => { - if (customersActive.value) customersOpen.value = true; - if (salesActive.value) salesOpen.value = true; - if (activitiesActive.value) activitiesOpen.value = true; - if (supportActive.value) supportOpen.value = true; - if (toolsActive.value) toolsOpen.value = true; - if (settingsActive.value) settingsOpen.value = true; - }, - { immediate: true }, -); - -function toggleFold(key: FoldKey) { - if (key === 'customers') customersOpen.value = !customersOpen.value; - if (key === 'sales') salesOpen.value = !salesOpen.value; - if (key === 'activities') activitiesOpen.value = !activitiesOpen.value; - if (key === 'support') supportOpen.value = !supportOpen.value; - if (key === 'tools') toolsOpen.value = !toolsOpen.value; - if (key === 'settings') settingsOpen.value = !settingsOpen.value; +function closeHub() { + openHubKey.value = null; } -function onFoldClick(key: FoldKey, fallback: string, event: Event) { - event.preventDefault(); - event.stopPropagation(); - if (collapsed.value) { - void router.push(fallback); - closeMenu(); - return; - } - toggleFold(key); +function onHubClick(key: NavHubKey) { + openHubKey.value = openHubKey.value === key ? null : key; + closeMenu(); +} + +function goHub(to: string) { + closeHub(); + closeMenu(); + void router.push(to); } const menuOpen = ref(false); @@ -175,6 +150,7 @@ function closeNotif() { } function onLogout() { + closeHub(); closeMenu(); closeNotif(); auth.logout(); @@ -254,17 +230,19 @@ function submitSearch() { void router.push({ name: 'contacts', query: { q } }); } -watch(menuOpen, (open) => { - document.body.style.overflow = open || notifOpen.value ? 'hidden' : ''; -}); -watch(notifOpen, (open) => { - document.body.style.overflow = open || menuOpen.value ? 'hidden' : ''; -}); +function syncBodyLock() { + document.body.style.overflow = + menuOpen.value || notifOpen.value || Boolean(openHubKey.value) ? 'hidden' : ''; +} +watch(menuOpen, syncBodyLock); +watch(notifOpen, syncBodyLock); +watch(openHubKey, syncBodyLock); watch( () => route.fullPath, () => { closeMenu(); closeNotif(); + closeHub(); }, ); @@ -295,7 +273,7 @@ onUnmounted(() => { - +
{{ hub.desc }}