update: dashboard now calculate domains
This commit is contained in:
@@ -118,6 +118,41 @@ export default function Dashboard() {
|
|||||||
}))
|
}))
|
||||||
.filter((item) => item.subItems.length > 0);
|
.filter((item) => item.subItems.length > 0);
|
||||||
|
|
||||||
|
const adminFilteredItems = filteredMenuItems.filter(
|
||||||
|
(item) => item.en === "admin",
|
||||||
|
);
|
||||||
|
const nonAdminFilteredItems = filteredMenuItems.filter(
|
||||||
|
(item) => item.en !== "admin",
|
||||||
|
);
|
||||||
|
|
||||||
|
const permissionDomainMap = new Map<string, string>();
|
||||||
|
(profile?.permissions || []).forEach((permission: any) => {
|
||||||
|
if (permission?.page_name) {
|
||||||
|
permissionDomainMap.set(
|
||||||
|
permission.page_name,
|
||||||
|
permission?.domain_fa_name || "سایر حوزه ها",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupedFilteredItems = nonAdminFilteredItems.reduce(
|
||||||
|
(acc, item) => {
|
||||||
|
const firstSubItem = item.subItems?.find((sub) =>
|
||||||
|
permissionDomainMap.has(sub.name),
|
||||||
|
);
|
||||||
|
const domainTitle = firstSubItem
|
||||||
|
? permissionDomainMap.get(firstSubItem.name) || "سایر حوزه ها"
|
||||||
|
: "سایر حوزه ها";
|
||||||
|
if (!acc[domainTitle]) {
|
||||||
|
acc[domainTitle] = [];
|
||||||
|
}
|
||||||
|
acc[domainTitle].push(item);
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Record<string, ItemWithSubItems[]>,
|
||||||
|
);
|
||||||
|
const showDomainGrouping = Object.keys(groupedFilteredItems).length > 1;
|
||||||
|
|
||||||
function findSubItemByPath(
|
function findSubItemByPath(
|
||||||
items: ItemWithSubItems[],
|
items: ItemWithSubItems[],
|
||||||
path: string,
|
path: string,
|
||||||
@@ -243,110 +278,322 @@ export default function Dashboard() {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{checkIsMobile()
|
{checkIsMobile()
|
||||||
? filteredMenuItems.map(({ fa, icon: Icon, subItems }, index) => {
|
? (
|
||||||
const filteredSubItems = subItems.filter(
|
<>
|
||||||
(item) =>
|
{adminFilteredItems.map(({ fa, icon: Icon, subItems }, index) => (
|
||||||
!item.path.includes("$") &&
|
<section
|
||||||
getFaPermissions(item.name).includes(search.trim()),
|
key={`admin-mobile-${index}`}
|
||||||
);
|
className="w-full space-y-5 border border-gray-200 dark:border-dark-600 bg-white dark:bg-dark-800 rounded-2xl p-6 shadow-sm"
|
||||||
|
>
|
||||||
if (filteredSubItems.length === 0) return null;
|
<div className="flex items-center gap-3">
|
||||||
|
<Icon className="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
||||||
return (
|
<h2 className="text-xl font-bold text-dark-900 dark:text-white">
|
||||||
<section
|
{fa}
|
||||||
key={index}
|
</h2>
|
||||||
className="w-full space-y-5 border border-gray-200 dark:border-dark-600 bg-white dark:bg-dark-800 rounded-2xl p-6 shadow-sm"
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<Icon className="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
|
||||||
<h2 className="text-xl font-bold text-dark-900 dark:text-white">
|
|
||||||
{fa}
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 gap-4">
|
|
||||||
{filteredSubItems.map((sub, subIndex) => (
|
|
||||||
<motion.button
|
|
||||||
key={subIndex}
|
|
||||||
onClick={() => navigate({ to: sub.path })}
|
|
||||||
whileHover={{ scale: 1.03 }}
|
|
||||||
whileTap={{ scale: 0.97 }}
|
|
||||||
className="flex items-center gap-2 cursor-pointer bg-gray-50 dark:bg-dark-700 text-right border border-gray-200 dark:border-dark-600 hover:border-primary-500 dark:hover:border-primary-400 shadow-sm rounded-xl p-3 transition-all duration-200"
|
|
||||||
>
|
|
||||||
<ArrowRightCircleIcon className="w-5 h-5 text-primary-500 dark:text-primary-400" />
|
|
||||||
<span className="text-sm font-medium text-dark-800 dark:text-white">
|
|
||||||
{getFaPermissions(sub.name)}
|
|
||||||
</span>
|
|
||||||
</motion.button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: filteredMenuItems.map(({ fa, icon: Icon, subItems }, index) => (
|
|
||||||
<motion.div
|
|
||||||
key={index}
|
|
||||||
initial={{ opacity: 0, x: -10 }}
|
|
||||||
animate={{ opacity: 1, x: 0 }}
|
|
||||||
transition={{ delay: index * 0.05 }}
|
|
||||||
className="flex-none w-48 backdrop-blur-xl bg-white/20 dark:bg-dark-800/80 rounded-xl shadow-lg border border-white/30 dark:border-dark-700/30 overflow-hidden"
|
|
||||||
>
|
|
||||||
<div className="backdrop-blur-sm bg-white/30 dark:bg-dark-700/30 px-3 py-2 border-b border-white/20 dark:border-dark-600/20">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<div className="p-1.5 rounded-md backdrop-blur-sm bg-primary-500/20 dark:bg-primary-400/20">
|
|
||||||
<Icon className="w-3.5 h-3.5 text-primary-600 dark:text-primary-400" />
|
|
||||||
</div>
|
</div>
|
||||||
<span className="text-xs font-semibold text-dark-800 dark:text-dark-100 truncate">
|
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 gap-4">
|
||||||
{fa}
|
{subItems.map((sub, subIndex) => (
|
||||||
</span>
|
<motion.button
|
||||||
</div>
|
key={subIndex}
|
||||||
</div>
|
onClick={() => navigate({ to: sub.path })}
|
||||||
|
whileHover={{ scale: 1.03 }}
|
||||||
<div className="p-1.5 space-y-0.5">
|
whileTap={{ scale: 0.97 }}
|
||||||
{subItems.map((sub, subIndex) => {
|
className="flex items-center gap-2 cursor-pointer bg-gray-50 dark:bg-dark-700 text-right border border-gray-200 dark:border-dark-600 hover:border-primary-500 dark:hover:border-primary-400 shadow-sm rounded-xl p-3 transition-all duration-200"
|
||||||
const isActive = tabs.some(
|
|
||||||
(tab) =>
|
|
||||||
tab.path === sub.path && activeTabId === tab.id,
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<motion.div
|
|
||||||
key={subIndex}
|
|
||||||
initial={{ opacity: 0, x: -5 }}
|
|
||||||
animate={{ opacity: 1, x: 0 }}
|
|
||||||
transition={{
|
|
||||||
delay: index * 0.05 + subIndex * 0.02,
|
|
||||||
}}
|
|
||||||
whileHover={{ x: 1 }}
|
|
||||||
whileTap={{ scale: 0.98 }}
|
|
||||||
onClick={() => openTab(sub)}
|
|
||||||
className={`flex items-center gap-1.5 px-2 py-1.5 text-xs rounded-md cursor-pointer transition-all duration-200 focus:outline-none ${
|
|
||||||
isActive
|
|
||||||
? "backdrop-blur-sm bg-primary-500/20 dark:bg-primary-400/20 text-primary-700 dark:text-primary-300 "
|
|
||||||
: "hover:backdrop-blur-sm hover:bg-white/30 dark:hover:bg-dark-600/30 border-none"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`w-1.5 h-1.5 rounded-full ${
|
|
||||||
isActive
|
|
||||||
? "bg-primary-600 dark:bg-primary-400"
|
|
||||||
: "bg-dark-400 dark:bg-dark-500"
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
className={`truncate ${
|
|
||||||
isActive
|
|
||||||
? "text-primary-700 dark:text-white font-medium"
|
|
||||||
: "text-dark-600 dark:text-dark-200/80"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{getFaPermissions(sub.name)}
|
<ArrowRightCircleIcon className="w-5 h-5 text-primary-500 dark:text-primary-400" />
|
||||||
|
<span className="text-sm font-medium text-dark-800 dark:text-white">
|
||||||
|
{getFaPermissions(sub.name)}
|
||||||
|
</span>
|
||||||
|
</motion.button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
{showDomainGrouping
|
||||||
|
? Object.entries(groupedFilteredItems).map(
|
||||||
|
([domainTitle, domainItems], domainIndex) => (
|
||||||
|
<section
|
||||||
|
key={`domain-mobile-${domainTitle}-${domainIndex}`}
|
||||||
|
className="w-full space-y-3 border border-gray-200 dark:border-dark-600 bg-white dark:bg-dark-800 rounded-2xl p-4 shadow-sm"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2 pb-2 border-b border-gray-200 dark:border-dark-600">
|
||||||
|
<Squares2X2Icon className="w-4 h-4 text-primary-500" />
|
||||||
|
<h2 className="text-sm font-bold text-primary-700 dark:text-primary-300">
|
||||||
|
{domainTitle}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
{domainItems.map(({ fa, icon: Icon, subItems }, index) => (
|
||||||
|
<section
|
||||||
|
key={`domain-item-mobile-${domainTitle}-${index}`}
|
||||||
|
className="w-full space-y-3 border border-gray-200 dark:border-dark-600 bg-gray-50 dark:bg-dark-700 rounded-xl p-4"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Icon className="w-5 h-5 text-primary-600 dark:text-primary-400" />
|
||||||
|
<h3 className="text-base font-bold text-dark-900 dark:text-white">
|
||||||
|
{fa}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
||||||
|
{subItems.map((sub, subIndex) => (
|
||||||
|
<motion.button
|
||||||
|
key={subIndex}
|
||||||
|
onClick={() => navigate({ to: sub.path })}
|
||||||
|
whileHover={{ scale: 1.03 }}
|
||||||
|
whileTap={{ scale: 0.97 }}
|
||||||
|
className="flex items-center gap-2 cursor-pointer bg-white dark:bg-dark-800 text-right border border-gray-200 dark:border-dark-600 hover:border-primary-500 dark:hover:border-primary-400 shadow-sm rounded-xl p-3 transition-all duration-200"
|
||||||
|
>
|
||||||
|
<ArrowRightCircleIcon className="w-5 h-5 text-primary-500 dark:text-primary-400" />
|
||||||
|
<span className="text-sm font-medium text-dark-800 dark:text-white">
|
||||||
|
{getFaPermissions(sub.name)}
|
||||||
|
</span>
|
||||||
|
</motion.button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
</section>
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: nonAdminFilteredItems.map(({ fa, icon: Icon, subItems }, index) => (
|
||||||
|
<section
|
||||||
|
key={`plain-mobile-${index}`}
|
||||||
|
className="w-full space-y-5 border border-gray-200 dark:border-dark-600 bg-white dark:bg-dark-800 rounded-2xl p-6 shadow-sm"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<Icon className="w-6 h-6 text-primary-600 dark:text-primary-400" />
|
||||||
|
<h2 className="text-xl font-bold text-dark-900 dark:text-white">
|
||||||
|
{fa}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 gap-4">
|
||||||
|
{subItems.map((sub, subIndex) => (
|
||||||
|
<motion.button
|
||||||
|
key={subIndex}
|
||||||
|
onClick={() => navigate({ to: sub.path })}
|
||||||
|
whileHover={{ scale: 1.03 }}
|
||||||
|
whileTap={{ scale: 0.97 }}
|
||||||
|
className="flex items-center gap-2 cursor-pointer bg-gray-50 dark:bg-dark-700 text-right border border-gray-200 dark:border-dark-600 hover:border-primary-500 dark:hover:border-primary-400 shadow-sm rounded-xl p-3 transition-all duration-200"
|
||||||
|
>
|
||||||
|
<ArrowRightCircleIcon className="w-5 h-5 text-primary-500 dark:text-primary-400" />
|
||||||
|
<span className="text-sm font-medium text-dark-800 dark:text-white">
|
||||||
|
{getFaPermissions(sub.name)}
|
||||||
|
</span>
|
||||||
|
</motion.button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<>
|
||||||
|
{adminFilteredItems.map(({ fa, icon: Icon, subItems }, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={`admin-desktop-${index}`}
|
||||||
|
initial={{ opacity: 0, x: -10 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ delay: index * 0.05 }}
|
||||||
|
className="flex-none w-48 backdrop-blur-xl bg-white/20 dark:bg-dark-800/80 rounded-xl shadow-lg border border-white/30 dark:border-dark-700/30 overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="backdrop-blur-sm bg-white/30 dark:bg-dark-700/30 px-3 py-2 border-b border-white/20 dark:border-dark-600/20">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="p-1.5 rounded-md backdrop-blur-sm bg-primary-500/20 dark:bg-primary-400/20">
|
||||||
|
<Icon className="w-3.5 h-3.5 text-primary-600 dark:text-primary-400" />
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-semibold text-dark-800 dark:text-dark-100 truncate">
|
||||||
|
{fa}
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-1.5 space-y-0.5">
|
||||||
|
{subItems.map((sub, subIndex) => {
|
||||||
|
const isActive = tabs.some(
|
||||||
|
(tab) => tab.path === sub.path && activeTabId === tab.id,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
key={subIndex}
|
||||||
|
initial={{ opacity: 0, x: -5 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ delay: index * 0.05 + subIndex * 0.02 }}
|
||||||
|
whileHover={{ x: 1 }}
|
||||||
|
whileTap={{ scale: 0.98 }}
|
||||||
|
onClick={() => openTab(sub)}
|
||||||
|
className={`flex items-center gap-1.5 px-2 py-1.5 text-xs rounded-md cursor-pointer transition-all duration-200 focus:outline-none ${
|
||||||
|
isActive
|
||||||
|
? "backdrop-blur-sm bg-primary-500/20 dark:bg-primary-400/20 text-primary-700 dark:text-primary-300 "
|
||||||
|
: "hover:backdrop-blur-sm hover:bg-white/30 dark:hover:bg-dark-600/30 border-none"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`w-1.5 h-1.5 rounded-full ${
|
||||||
|
isActive
|
||||||
|
? "bg-primary-600 dark:bg-primary-400"
|
||||||
|
: "bg-dark-400 dark:bg-dark-500"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={`truncate ${
|
||||||
|
isActive
|
||||||
|
? "text-primary-700 dark:text-white font-medium"
|
||||||
|
: "text-dark-600 dark:text-dark-200/80"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{getFaPermissions(sub.name)}
|
||||||
|
</span>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
{showDomainGrouping
|
||||||
|
? Object.entries(groupedFilteredItems).map(
|
||||||
|
([domainTitle, domainItems], domainIndex) => (
|
||||||
|
<div
|
||||||
|
key={`domain-desktop-${domainTitle}-${domainIndex}`}
|
||||||
|
className="flex-none w-56 space-y-2"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2 px-1">
|
||||||
|
<Squares2X2Icon className="w-4 h-4 text-primary-500" />
|
||||||
|
<span className="text-xs font-bold text-primary-700 dark:text-primary-300">
|
||||||
|
{domainTitle}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{domainItems.map(({ fa, icon: Icon, subItems }, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={`domain-item-desktop-${domainTitle}-${index}`}
|
||||||
|
initial={{ opacity: 0, x: -10 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ delay: index * 0.05 }}
|
||||||
|
className="w-full backdrop-blur-xl bg-white/20 dark:bg-dark-800/80 rounded-xl shadow-lg border border-white/30 dark:border-dark-700/30 overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="backdrop-blur-sm bg-white/30 dark:bg-dark-700/30 px-3 py-2 border-b border-white/20 dark:border-dark-600/20">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="p-1.5 rounded-md backdrop-blur-sm bg-primary-500/20 dark:bg-primary-400/20">
|
||||||
|
<Icon className="w-3.5 h-3.5 text-primary-600 dark:text-primary-400" />
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-semibold text-dark-800 dark:text-dark-100 truncate">
|
||||||
|
{fa}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-1.5 space-y-0.5">
|
||||||
|
{subItems.map((sub, subIndex) => {
|
||||||
|
const isActive = tabs.some(
|
||||||
|
(tab) =>
|
||||||
|
tab.path === sub.path &&
|
||||||
|
activeTabId === tab.id,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
key={subIndex}
|
||||||
|
initial={{ opacity: 0, x: -5 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{
|
||||||
|
delay: index * 0.05 + subIndex * 0.02,
|
||||||
|
}}
|
||||||
|
whileHover={{ x: 1 }}
|
||||||
|
whileTap={{ scale: 0.98 }}
|
||||||
|
onClick={() => openTab(sub)}
|
||||||
|
className={`flex items-center gap-1.5 px-2 py-1.5 text-xs rounded-md cursor-pointer transition-all duration-200 focus:outline-none ${
|
||||||
|
isActive
|
||||||
|
? "backdrop-blur-sm bg-primary-500/20 dark:bg-primary-400/20 text-primary-700 dark:text-primary-300 "
|
||||||
|
: "hover:backdrop-blur-sm hover:bg-white/30 dark:hover:bg-dark-600/30 border-none"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`w-1.5 h-1.5 rounded-full ${
|
||||||
|
isActive
|
||||||
|
? "bg-primary-600 dark:bg-primary-400"
|
||||||
|
: "bg-dark-400 dark:bg-dark-500"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={`truncate ${
|
||||||
|
isActive
|
||||||
|
? "text-primary-700 dark:text-white font-medium"
|
||||||
|
: "text-dark-600 dark:text-dark-200/80"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{getFaPermissions(sub.name)}
|
||||||
|
</span>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: nonAdminFilteredItems.map(({ fa, icon: Icon, subItems }, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={`plain-desktop-${index}`}
|
||||||
|
initial={{ opacity: 0, x: -10 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ delay: index * 0.05 }}
|
||||||
|
className="flex-none w-48 backdrop-blur-xl bg-white/20 dark:bg-dark-800/80 rounded-xl shadow-lg border border-white/30 dark:border-dark-700/30 overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="backdrop-blur-sm bg-white/30 dark:bg-dark-700/30 px-3 py-2 border-b border-white/20 dark:border-dark-600/20">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="p-1.5 rounded-md backdrop-blur-sm bg-primary-500/20 dark:bg-primary-400/20">
|
||||||
|
<Icon className="w-3.5 h-3.5 text-primary-600 dark:text-primary-400" />
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-semibold text-dark-800 dark:text-dark-100 truncate">
|
||||||
|
{fa}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-1.5 space-y-0.5">
|
||||||
|
{subItems.map((sub, subIndex) => {
|
||||||
|
const isActive = tabs.some(
|
||||||
|
(tab) =>
|
||||||
|
tab.path === sub.path && activeTabId === tab.id,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
key={subIndex}
|
||||||
|
initial={{ opacity: 0, x: -5 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{
|
||||||
|
delay: index * 0.05 + subIndex * 0.02,
|
||||||
|
}}
|
||||||
|
whileHover={{ x: 1 }}
|
||||||
|
whileTap={{ scale: 0.98 }}
|
||||||
|
onClick={() => openTab(sub)}
|
||||||
|
className={`flex items-center gap-1.5 px-2 py-1.5 text-xs rounded-md cursor-pointer transition-all duration-200 focus:outline-none ${
|
||||||
|
isActive
|
||||||
|
? "backdrop-blur-sm bg-primary-500/20 dark:bg-primary-400/20 text-primary-700 dark:text-primary-300 "
|
||||||
|
: "hover:backdrop-blur-sm hover:bg-white/30 dark:hover:bg-dark-600/30 border-none"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`w-1.5 h-1.5 rounded-full ${
|
||||||
|
isActive
|
||||||
|
? "bg-primary-600 dark:bg-primary-400"
|
||||||
|
: "bg-dark-400 dark:bg-dark-500"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={`truncate ${
|
||||||
|
isActive
|
||||||
|
? "text-primary-700 dark:text-white font-medium"
|
||||||
|
: "text-dark-600 dark:text-dark-200/80"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{getFaPermissions(sub.name)}
|
||||||
|
</span>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
))}
|
||||||
})}
|
</>
|
||||||
</div>
|
)}
|
||||||
</motion.div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user