conflict-nuxt-4/app/components/auto-import/Header.vue
2026-02-14 13:06:29 +03:30

249 lines
7.6 KiB
Vue
Executable File

<template>
<header
class="bg-gray-100 h-16 dark:bg-dark-primary border-gray-200 dark:border-dark-primary-800 px-6 grid grid-cols-12 items-center sticky top-0 z-40 gap-4"
>
<!-- سمت چپ هدر -->
<div class="col-span-3 lg:col-span-2 xl:col-span-3 hidden lg:block">
<template v-if="headerSchema.breadcrumb">
<Breadcrumb
:breadcrumbData="defaultSidebar.topMenu"
:tabs="tabs"
:activeTabId="activeTabModel"
/>
</template>
<template v-if="headerSchema.logo">
<nuxt-link :to="{ name: 'DashboardBasePage' }">
<div class="flex items-center gap-3">
<img :src="logoSrc" alt="" class="h-9 w-9" />
<div v-if="useSystemTheme.currentTheme.value" class="flex flex-col">
<span class="font-bold text-gray-900 dark:text-light-primary">
{{ useSystemTheme.currentTheme.value.title || "" }}
</span>
<span class="text-xs text-gray-500 dark:text-gray-400">
{{ useSystemTheme.currentTheme.value.subTitle || "" }}
</span>
</div>
</div>
</nuxt-link>
</template>
</div>
<div class="col-span-3 lg:col-span-2 xl:col-span-3 lg:hidden">
<button
@click="commonStore.toggleSidebar"
class="flex cursor-pointer items-center justify-center w-8 h-8 rounded-md text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-dark-primary-800 transition-colors duration-200"
aria-label="باز کردن منو"
>
<UIcon name="i-heroicons-bars-3" class="w-5 h-5" />
</button>
</div>
<!-- وسط هدر -->
<div
class="col-span-6 lg:col-span-8 xl:col-span-6 flex justify-center pt-4"
>
<TabBar
:tabs="tabs"
v-model:active-tab="activeTabModel"
mode="soft"
:width="tabBarWidth"
@tab-change="emit('tab-change', $event)"
/>
</div>
<!-- راست هدر -->
<div
class="col-span-3 lg:col-span-2 xl:col-span-3 flex items-center justify-end gap-3"
>
<!-- Dark mode -->
<UButton
variant="ghost"
size="sm"
color="gray"
:icon="
useSystemTheme.isDark.value ? 'i-heroicons-sun' : 'i-heroicons-moon'
"
@click="useSystemTheme.toggleDarkMode"
/>
<!-- Language -->
<UDropdownMenu :items="headerItems.languages" dir="rtl">
<UButton
variant="ghost"
size="sm"
icon="i-heroicons-language"
label="فارسی"
/>
</UDropdownMenu>
<!-- Notifications -->
<UButton
variant="ghost"
size="sm"
icon="i-heroicons-bell"
:badge="unreadNotifications"
/>
<!-- User menu -->
<UDropdownMenu
v-if="isClient && userAvatar"
:items="userMenuItems"
dir="rtl"
>
<!-- <UAvatar
v-if="userInitial"
:label="userInitial"
size="sm"
class="cursor-pointer"
/> -->
<!-- <span v-if="userInitial" class="text-white text-lg font-bold">{{
userInitial
}}</span>
<UAvatar v-else :src="userAvatar" size="sm" class="cursor-pointer" /> -->
<!-- اگر avatar داشت -->
<UAvatar :src="userAvatar" size="sm" class="cursor-pointer" />
<!-- اگر avatar نداشت -->
<!-- <UAvatar
v-else
:label="userInitial"
size="sm"
class="cursor-pointer bg-primary text-white font-bold"
/> -->
</UDropdownMenu>
<UDropdownMenu v-else-if="isClient" :items="userMenuItems" dir="rtl">
<span class="text-white text-lg font-bold">{{ userInitial }}</span>
</UDropdownMenu>
</div>
</header>
</template>
<script setup>
import { ref, computed, onMounted } from "vue";
import headerItems from "@/json/header/header.json";
import { composSystemTheme } from "@/composables/composSystemTheme";
import defaultSidebar from "@/json/sidebar/dashboard.json";
import { useCommonStore } from "@/stores/commonStore";
import { useAuthStore } from "@/stores/authStore";
import { useRouter } from "vue-router";
const commonStore = useCommonStore();
const authStore = useAuthStore();
const router = useRouter();
/* ---------------- PROPS ---------------- */
const props = defineProps({
tabs: { type: Array, required: true, default: [] },
activeTab: { type: String, default: "" },
unreadNotifications: { type: Number, default: 0 },
tabBarWidth: { type: String, default: "40em" },
headerSchema: { type: Object, default: {} },
});
const emit = defineEmits([
"update:activeTab",
"tab-change",
"user-menu-select",
]);
const logoSrc = ref("");
/* ---------------- ACTIVE TAB ---------------- */
const activeTabModel = computed({
get: () => props.activeTab,
set: (val) => emit("update:activeTab", val),
});
/* ---------------- THEME ---------------- */
const useSystemTheme = composSystemTheme();
/* ---------------- USER MENU HANDLER ---------------- */
const handleUserMenu = async (action) => {
if (action.key === "logout") {
localStorage.clear();
sessionStorage.clear();
const cookies = document.cookie.split(";");
for (let cookie of cookies) {
const eqPos = cookie.indexOf("=");
const name = eqPos > -1 ? cookie.substr(0, eqPos).trim() : cookie.trim();
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/";
}
authStore.userReset();
navigateTo("/login");
await router.push("/login");
} else if (action.key === "profile") {
await router.push("/profile");
} else if (action.key === "settings") {
await router.push("/settings");
} else if (action.key === "developer") {
await router.push("/developer");
} else if (action.key === "admin") {
await router.push("/admin");
} else {
emit("user-menu-select", action);
}
};
/* ---------------- USER MENU ITEMS ---------------- */
const userMenuItems = computed(() =>
headerItems.userMenu.map((group) =>
group.map((item) => ({
...item,
onSelect: () => handleUserMenu(item),
})),
),
);
/* ---------------- AVATAR ---------------- */
// const userAvatar = "https://api.dicebear.com/7.x/avataaars/svg?seed=admin";
const isClient = ref(false);
const userAvatar = computed(() => {
if (!process.client) return null;
try {
const user = JSON.parse(localStorage.getItem("user") || "{}");
const avatar = user?.user_data?.avatar;
if (!avatar) return null;
const BASE_URL = "https://hamfahmi.ir/";
const url = BASE_URL + `api/media${avatar}`;
// console.log("avatar ==> ", url);
return url;
} catch (e) {
console.error(e);
return null;
}
});
const userInitial = computed(() => {
if (!process.client) return "؟";
try {
const user = JSON.parse(localStorage.getItem("user") || {});
const firstName = user?.user_data?.first_name?.trim() || "";
const lastName = user?.user_data?.last_name?.trim() || "";
const first = firstName[0] || "";
const second = lastName[0] || firstName[1] || "";
return first + second || "؟";
} catch (e) {
return "؟";
}
});
// function toggleSidebarMenu() {
// commonStore.isSidebarOpen();
// }
onMounted(() => {
isClient.value = true;
useSystemTheme.applyTheme();
setTimeout(() => {
logoSrc.value = useSystemTheme.logo.value;
}, 300);
});
</script>