Prefer specific active navigation links
This commit is contained in:
@ -19,15 +19,19 @@ function matchesPath(currentPath: string, href: string) {
|
|||||||
return currentPath === href || currentPath.startsWith(`${href}/`);
|
return currentPath === href || currentPath.startsWith(`${href}/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findActiveHref(currentPath: string, items: Array<{ href: string }>) {
|
||||||
|
return items
|
||||||
|
.filter((item) => matchesPath(currentPath, item.href))
|
||||||
|
.sort((a, b) => b.href.length - a.href.length)[0]?.href;
|
||||||
|
}
|
||||||
|
|
||||||
export function MobileNav({ pathname, userRole }: MobileNavProps) {
|
export function MobileNav({ pathname, userRole }: MobileNavProps) {
|
||||||
const { dict } = useLocale();
|
const { dict } = useLocale();
|
||||||
const navigation = useMemo(() => getNavigationForRole(userRole as AppRole), [userRole]);
|
const navigation = useMemo(() => getNavigationForRole(userRole as AppRole), [userRole]);
|
||||||
const buildOpenGroups = () => {
|
const buildOpenGroups = () => {
|
||||||
const grouped = navigation.filter(isNavGroup);
|
const grouped = navigation.filter(isNavGroup);
|
||||||
return grouped.reduce<Record<string, boolean>>((acc, item) => {
|
return grouped.reduce<Record<string, boolean>>((acc, item) => {
|
||||||
const isGroupActive = item.children.some(
|
const isGroupActive = Boolean(findActiveHref(pathname, item.children));
|
||||||
(child) => matchesPath(pathname, child.href)
|
|
||||||
);
|
|
||||||
acc[item.key] = isGroupActive;
|
acc[item.key] = isGroupActive;
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
@ -39,9 +43,7 @@ export function MobileNav({ pathname, userRole }: MobileNavProps) {
|
|||||||
setOpenGroups((current) => {
|
setOpenGroups((current) => {
|
||||||
const next = { ...current };
|
const next = { ...current };
|
||||||
navigation.filter(isNavGroup).forEach((item) => {
|
navigation.filter(isNavGroup).forEach((item) => {
|
||||||
const isGroupActive = item.children.some(
|
const isGroupActive = Boolean(findActiveHref(pathname, item.children));
|
||||||
(child) => matchesPath(pathname, child.href)
|
|
||||||
);
|
|
||||||
if (isGroupActive) {
|
if (isGroupActive) {
|
||||||
next[item.key] = true;
|
next[item.key] = true;
|
||||||
}
|
}
|
||||||
@ -55,9 +57,8 @@ export function MobileNav({ pathname, userRole }: MobileNavProps) {
|
|||||||
<div className="space-y-2 pb-1">
|
<div className="space-y-2 pb-1">
|
||||||
{navigation.map((item) => {
|
{navigation.map((item) => {
|
||||||
if (isNavGroup(item)) {
|
if (isNavGroup(item)) {
|
||||||
const isGroupActive = item.children.some(
|
const activeChildHref = findActiveHref(pathname, item.children);
|
||||||
(child) => matchesPath(pathname, child.href)
|
const isGroupActive = Boolean(activeChildHref);
|
||||||
);
|
|
||||||
const isOpen = openGroups[item.key] ?? isGroupActive;
|
const isOpen = openGroups[item.key] ?? isGroupActive;
|
||||||
return (
|
return (
|
||||||
<div key={item.key} className="rounded border border-line/70 bg-slate-50">
|
<div key={item.key} className="rounded border border-line/70 bg-slate-50">
|
||||||
@ -83,8 +84,7 @@ export function MobileNav({ pathname, userRole }: MobileNavProps) {
|
|||||||
{isOpen ? (
|
{isOpen ? (
|
||||||
<div className="grid gap-2 border-t border-line/70 bg-white p-2">
|
<div className="grid gap-2 border-t border-line/70 bg-white p-2">
|
||||||
{item.children.map((child) => {
|
{item.children.map((child) => {
|
||||||
const isActive =
|
const isActive = activeChildHref === child.href;
|
||||||
matchesPath(pathname, child.href);
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={child.href}
|
key={child.href}
|
||||||
|
|||||||
@ -20,15 +20,19 @@ function matchesPath(currentPath: string, href: string) {
|
|||||||
return currentPath === href || currentPath.startsWith(`${href}/`);
|
return currentPath === href || currentPath.startsWith(`${href}/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findActiveHref(currentPath: string, items: Array<{ href: string }>) {
|
||||||
|
return items
|
||||||
|
.filter((item) => matchesPath(currentPath, item.href))
|
||||||
|
.sort((a, b) => b.href.length - a.href.length)[0]?.href;
|
||||||
|
}
|
||||||
|
|
||||||
export function Sidebar({ pathname, user }: SidebarProps) {
|
export function Sidebar({ pathname, user }: SidebarProps) {
|
||||||
const { dict } = useLocale();
|
const { dict } = useLocale();
|
||||||
const navigation = useMemo(() => getNavigationForRole(user.role as never), [user.role]);
|
const navigation = useMemo(() => getNavigationForRole(user.role as never), [user.role]);
|
||||||
const buildOpenGroups = () => {
|
const buildOpenGroups = () => {
|
||||||
const grouped = navigation.filter(isNavGroup);
|
const grouped = navigation.filter(isNavGroup);
|
||||||
return grouped.reduce<Record<string, boolean>>((acc, item) => {
|
return grouped.reduce<Record<string, boolean>>((acc, item) => {
|
||||||
const isGroupActive = item.children.some(
|
const isGroupActive = Boolean(findActiveHref(pathname, item.children));
|
||||||
(child) => matchesPath(pathname, child.href)
|
|
||||||
);
|
|
||||||
acc[item.key] = isGroupActive;
|
acc[item.key] = isGroupActive;
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
@ -40,9 +44,7 @@ export function Sidebar({ pathname, user }: SidebarProps) {
|
|||||||
setOpenGroups((current) => {
|
setOpenGroups((current) => {
|
||||||
const next = { ...current };
|
const next = { ...current };
|
||||||
navigation.filter(isNavGroup).forEach((item) => {
|
navigation.filter(isNavGroup).forEach((item) => {
|
||||||
const isGroupActive = item.children.some(
|
const isGroupActive = Boolean(findActiveHref(pathname, item.children));
|
||||||
(child) => matchesPath(pathname, child.href)
|
|
||||||
);
|
|
||||||
if (isGroupActive) {
|
if (isGroupActive) {
|
||||||
next[item.key] = true;
|
next[item.key] = true;
|
||||||
}
|
}
|
||||||
@ -70,9 +72,8 @@ export function Sidebar({ pathname, user }: SidebarProps) {
|
|||||||
<nav className="space-y-1 pr-1">
|
<nav className="space-y-1 pr-1">
|
||||||
{navigation.map((item) => {
|
{navigation.map((item) => {
|
||||||
if (isNavGroup(item)) {
|
if (isNavGroup(item)) {
|
||||||
const isGroupActive = item.children.some(
|
const activeChildHref = findActiveHref(pathname, item.children);
|
||||||
(child) => matchesPath(pathname, child.href)
|
const isGroupActive = Boolean(activeChildHref);
|
||||||
);
|
|
||||||
const isOpen = openGroups[item.key] ?? isGroupActive;
|
const isOpen = openGroups[item.key] ?? isGroupActive;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -108,8 +109,7 @@ export function Sidebar({ pathname, user }: SidebarProps) {
|
|||||||
{isOpen ? (
|
{isOpen ? (
|
||||||
<div className="mt-1 space-y-1 pl-3">
|
<div className="mt-1 space-y-1 pl-3">
|
||||||
{item.children.map((child) => {
|
{item.children.map((child) => {
|
||||||
const isActive =
|
const isActive = activeChildHref === child.href;
|
||||||
matchesPath(pathname, child.href);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
Reference in New Issue
Block a user