From da6c494fcb757be1dc6d06351b297b397e173b31 Mon Sep 17 00:00:00 2001 From: Mahdi Date: Tue, 1 Sep 2026 15:39:18 +0330 Subject: [PATCH] Match dashboard header and shell layout to the Mento mockup. Co-authored-by: Cursor --- apps/web/src/components/UiIcon.vue | 133 ++++++ apps/web/src/layouts/AppLayout.vue | 550 +++++++++++++------------ apps/web/src/lib/jalali.ts | 6 + apps/web/src/views/HomeView.vue | 630 +++++++++++++++++++---------- 4 files changed, 867 insertions(+), 452 deletions(-) create mode 100644 apps/web/src/components/UiIcon.vue diff --git a/apps/web/src/components/UiIcon.vue b/apps/web/src/components/UiIcon.vue new file mode 100644 index 0000000..71d29c5 --- /dev/null +++ b/apps/web/src/components/UiIcon.vue @@ -0,0 +1,133 @@ + + + + + diff --git a/apps/web/src/layouts/AppLayout.vue b/apps/web/src/layouts/AppLayout.vue index abbeb81..a57a400 100644 --- a/apps/web/src/layouts/AppLayout.vue +++ b/apps/web/src/layouts/AppLayout.vue @@ -3,7 +3,8 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue'; import { RouterLink, RouterView, useRoute, useRouter } from 'vue-router'; import { useAuthStore } from '@/stores/auth'; import { api } from '@/lib/api'; -import { formatJalaliLong } from '@/lib/jalali'; +import { formatJalaliShort, toFaDigits } from '@/lib/jalali'; +import UiIcon from '@/components/UiIcon.vue'; import type { ActivitySummaryDto, NotificationDto, @@ -30,7 +31,7 @@ const userInitials = computed(() => { .map((p) => p[0]) .join(''); }); -const todayLabel = computed(() => formatJalaliLong(new Date())); +const todayLabel = computed(() => formatJalaliShort(new Date())); const salesOpen = ref(false); const moreOpen = ref(false); @@ -38,7 +39,7 @@ const settingsOpen = ref(false); const globalSearch = ref(''); const activityBadge = ref(0); -const salesPaths = ['/quotes', '/invoices', '/sales/forecast', '/reports']; +const salesPaths = ['/quotes', '/invoices', '/sales/forecast', '/reports', '/notes', '/tickets']; const morePaths = ['/activities/calendar', '/projects', '/project-cards', '/loyalty']; const settingsPaths = [ '/settings/team', @@ -59,6 +60,7 @@ function pathIn(prefixes: string[]) { const salesActive = computed(() => pathIn(salesPaths)); const moreActive = computed(() => pathIn(morePaths)); const settingsActive = computed(() => pathIn(settingsPaths)); +const productsActive = computed(() => route.path.startsWith('/settings/products')); watch( () => route.path, @@ -135,9 +137,7 @@ async function markRead(item: NotificationDto) { } closeNotif(); closeMenu(); - if (item.link) { - await router.push(item.link); - } + if (item.link) await router.push(item.link); } async function markAll() { @@ -180,11 +180,9 @@ function submitSearch() { watch(menuOpen, (open) => { document.body.style.overflow = open || notifOpen.value ? 'hidden' : ''; }); - watch(notifOpen, (open) => { document.body.style.overflow = open || menuOpen.value ? 'hidden' : ''; }); - watch( () => route.fullPath, () => { @@ -196,9 +194,7 @@ watch( onMounted(() => { void refreshNotifs(); void loadActivityBadge(); - pollTimer = setInterval(() => { - void refreshNotifs(); - }, 45000); + pollTimer = setInterval(() => void refreshNotifs(), 45000); }); onUnmounted(() => { @@ -209,33 +205,23 @@ onUnmounted(() => {