diff --git a/resources/js/components/app-sidebar.tsx b/resources/js/components/app-sidebar.tsx index f6b1e31..d1c7874 100644 --- a/resources/js/components/app-sidebar.tsx +++ b/resources/js/components/app-sidebar.tsx @@ -19,7 +19,7 @@ import product from '@/routes/product'; const mainNavItems: NavItem[] = [ { title: 'Dashboard', - href: dashboard(), + href: dashboard().url, icon: LayoutGrid, }, ]; @@ -44,7 +44,7 @@ export function AppSidebar() { - + diff --git a/resources/js/components/nav-main.tsx b/resources/js/components/nav-main.tsx index b100b0e..3ee9699 100644 --- a/resources/js/components/nav-main.tsx +++ b/resources/js/components/nav-main.tsx @@ -16,7 +16,7 @@ export function NavMain({ items: NavItem[]; label?: string; }) { - const { isCurrentUrl } = useCurrentUrl(); + const { isCurrentOrParentUrl } = useCurrentUrl(); return ( @@ -26,7 +26,7 @@ export function NavMain({ diff --git a/resources/js/components/ui/sidebar.tsx b/resources/js/components/ui/sidebar.tsx index fa86e48..2e31489 100644 --- a/resources/js/components/ui/sidebar.tsx +++ b/resources/js/components/ui/sidebar.tsx @@ -506,7 +506,7 @@ function SidebarMenuButton({ data-slot="sidebar-menu-button" data-sidebar="menu-button" data-size={size} - data-active={isActive} + data-active={isActive || undefined} className={cn(sidebarMenuButtonVariants({ variant, size }), className)} {...props} /> @@ -662,7 +662,7 @@ function SidebarMenuSubButton({ data-slot="sidebar-menu-sub-button" data-sidebar="menu-sub-button" data-size={size} - data-active={isActive} + data-active={isActive || undefined} className={cn( "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground ring-sidebar-ring outline-hidden group-data-[collapsible=icon]:hidden hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[size=md]:text-sm data-[size=sm]:text-xs data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground", className diff --git a/resources/js/hooks/use-current-url.ts b/resources/js/hooks/use-current-url.ts index ee8cd2b..c67d3cc 100644 --- a/resources/js/hooks/use-current-url.ts +++ b/resources/js/hooks/use-current-url.ts @@ -40,23 +40,34 @@ export function useCurrentUrl(): UseCurrentUrlReturn { currentUrl?: string, startsWith: boolean = false, ) => { - const urlToCompare = currentUrl ?? currentUrlPath; const urlString = toUrl(urlToCheck); + const currentPath = currentUrl ?? currentUrlPath; - const comparePath = (path: string): boolean => - startsWith ? urlToCompare.startsWith(path) : path === urlToCompare; + const clean = (p: string) => { + if (!p) return '/'; + // Remove query and hash, then trailing slash + let path = p.split('?')[0].split('#')[0]; + if (path.startsWith('http')) { + try { + path = new URL(path).pathname; + } catch { + // Ignore + } + } + return path.replace(/\/+$/, '') || '/'; + }; - if (!urlString.startsWith('http')) { - return comparePath(urlString); + const normCurrent = clean(currentPath); + const normCheck = clean(urlString); + + if (startsWith) { + if (normCheck === '/') { + return normCurrent === '/'; + } + return normCurrent.startsWith(normCheck); } - try { - const absoluteUrl = new URL(urlString); - - return comparePath(absoluteUrl.pathname); - } catch { - return false; - } + return normCurrent === normCheck; }; const isCurrentOrParentUrl: IsCurrentOrParentUrlFn = ( diff --git a/resources/js/lib/utils.ts b/resources/js/lib/utils.ts index 3ead67f..db028d6 100644 --- a/resources/js/lib/utils.ts +++ b/resources/js/lib/utils.ts @@ -7,6 +7,9 @@ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } -export function toUrl(url: NonNullable): string { - return typeof url === 'string' ? url : url.url; +export function toUrl(url: InertiaLinkProps['href']): string { + if (!url) return ''; + if (typeof url === 'string') return url; + if (typeof url === 'object' && url !== null && 'url' in url) return url.url as string; + return String(url); }