Merge branch 'develop' of repo.ravanertebat.com:TM/tm_panel into develop

This commit is contained in:
Karim Pirzargar
2026-04-27 12:29:33 +03:30
3 changed files with 73 additions and 12 deletions
@@ -19,6 +19,7 @@ export function ThemeToggleSwitch() {
const [mounted, setMounted] = useState(false);
const [isTransitioning, setIsTransitioning] = useState(false);
const isDarkTheme = theme === "dark";
const tripleTapMaxDelay = 500;
useEffect(() => {
setMounted(true);
@@ -34,6 +35,45 @@ export function ThemeToggleSwitch() {
return () => window.clearTimeout(transitionTimer);
}, [isTransitioning]);
useEffect(() => {
if (!mounted) return;
let tapCount = 0;
let lastTapAt = 0;
const isTypingInInput = (target: EventTarget | null) => {
if (!(target instanceof HTMLElement)) return false;
const tagName = target.tagName.toLowerCase();
if (tagName === "input" || tagName === "textarea" || tagName === "select") {
return true;
}
return target.isContentEditable;
};
const handleKeyDown = (event: KeyboardEvent) => {
if (event.repeat) return;
if (event.key.toLowerCase() !== "t") return;
if (event.ctrlKey || event.metaKey || event.altKey) return;
if (isTypingInInput(event.target)) return;
const now = Date.now();
tapCount = now - lastTapAt <= tripleTapMaxDelay ? tapCount + 1 : 1;
lastTapAt = now;
if (tapCount === 3) {
setIsTransitioning(true);
setTheme(theme === "dark" ? "light" : "dark");
tapCount = 0;
lastTapAt = 0;
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [mounted, setTheme, theme]);
if (!mounted) {
return null;
}
+9 -1
View File
@@ -29,12 +29,14 @@ export const NAV_DATA: NavData = [
url: "/",
icon: Icons.HomeIcon,
items: [],
visible: true,
},
{
title: "Admins",
url: "/admins",
icon: Icons.User,
items: [],
visible: true,
},
{
title: "Manage Companies",
@@ -46,12 +48,14 @@ export const NAV_DATA: NavData = [
url: "/companies",
title: "Companies",
items: [],
visible: true,
},
{
icon: Icons.Building,
url: "/company-categories",
title: "Company Categories",
items: [],
visible: true,
},
],
},
@@ -60,18 +64,21 @@ export const NAV_DATA: NavData = [
url: "/customers",
icon: Icons.User,
items: [],
visible: true,
},
{
title: "Tenders",
url: "/tenders",
icon: Icons.Table,
items: [],
visible: true,
},
{
title: "Notifications",
url: "/notification-history",
icon: Icons.NotificationIcon,
items: [],
visible: true,
},
{
title: "Contact Us",
@@ -85,13 +92,14 @@ export const NAV_DATA: NavData = [
url: "/marketing",
icon: GlobeSearch,
items: [],
visible:false
visible: true
},
{
title: "Inquiries",
url: "/inquiries",
icon: Icons.BriefcaseTimer,
items: [],
visible: true,
},
],
},
+24 -11
View File
@@ -15,6 +15,7 @@ export function Sidebar() {
const pathname = usePathname();
const { setIsOpen, isOpen, isMobile, toggleSidebar } = useSidebarContext();
const [expandedItems, setExpandedItems] = useState<string[]>([]);
const isVisible = (item: { visible?: boolean }) => item.visible !== false;
const toggleExpanded = (title: string) => {
setExpandedItems((prev) =>
@@ -26,9 +27,9 @@ export function Sidebar() {
const newExpandedItems: string[] = [];
NAV_DATA.forEach((section) => {
section.items.forEach((item) => {
section.items.filter(isVisible).forEach((item) => {
if (item.items.length > 0) {
const hasActiveSubItem = item.items.some(
const hasActiveSubItem = item.items.filter(isVisible).some(
(subItem: NavSubItem) =>
subItem.url === pathname ||
(pathname.startsWith(subItem.url) && subItem.url !== "/"),
@@ -115,7 +116,14 @@ export function Sidebar() {
isCollapsed ? "w-full px-1" : "pr-3",
)}
>
{NAV_DATA.map((section) => (
{NAV_DATA.map((section) => {
const visibleItems = section.items.filter(isVisible);
if (!visibleItems.length) {
return null;
}
return (
<div key={section.label} className="mb-6">
{!isCollapsed && (
<h2 className="mb-4 px-2 text-[11px] font-semibold uppercase tracking-[0.12em] text-dark-5 dark:text-dark-6">
@@ -125,18 +133,21 @@ export function Sidebar() {
<nav role="navigation" aria-label={section.label}>
<ul className={cn("space-y-2", isCollapsed && "space-y-1")}>
{section.items.map((item) => (
{visibleItems.map((item) => {
const visibleSubItems = item.items.filter(isVisible);
return (
<li key={item.title}>
{item.items.length ? (
{visibleSubItems.length ? (
<div>
<MenuItem
isActive={
item.items.some(
visibleSubItems.some(
({ url }: { url: string }) =>
url === pathname,
) ||
(item.items.length > 0 &&
item.items.some(
(visibleSubItems.length > 0 &&
visibleSubItems.some(
({ url }: { url: string }) =>
pathname.startsWith(url) && url !== "/",
))
@@ -178,7 +189,7 @@ export function Sidebar() {
className="ml-9 mr-0 space-y-1.5 pb-[15px] pr-0 pt-2"
role="menu"
>
{item.items.map((subItem: NavSubItem) => (
{visibleSubItems.map((subItem: NavSubItem) => (
<li key={subItem.title} role="none">
<MenuItem
as="link"
@@ -232,11 +243,13 @@ export function Sidebar() {
})()
)}
</li>
))}
);
})}
</ul>
</nav>
</div>
))}
);
})}
</div>
{/* Toggle button at bottom for collapsed state */}