fix sidebar
This commit is contained in:
parent
70d99473e1
commit
9bd798188d
@ -839,3 +839,9 @@ function UsersTable({ data, columns }) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
`Sidebar.Exit` از `logoutKeycloak` داخلی UI Kit استفاده میکند و callback خروج از سامانه مقصد نیاز ندارد.
|
`Sidebar.Exit` از `logoutKeycloak` داخلی UI Kit استفاده میکند و callback خروج از سامانه مقصد نیاز ندارد.
|
||||||
|
|
||||||
|
### Sidebar active route notes
|
||||||
|
|
||||||
|
`Sidebar` compares `currentPath` with each item's `path` and `aliases`, ignoring query strings, hashes, and trailing slashes. Use the actual application route as `path`; use `aliases` only for alternate routes that should keep the same item active.
|
||||||
|
|
||||||
|
Active sidebar items are rendered as non-links to avoid redundant same-route navigations. This is especially useful on pages that synchronize URL query params.
|
||||||
|
|||||||
358
dist/layout.js
vendored
358
dist/layout.js
vendored
File diff suppressed because one or more lines are too long
@ -25,9 +25,19 @@ import { IoExit } from "react-icons/io5/index.js";
|
|||||||
import { logoutKeycloak } from "../core/keycloak.jsx";
|
import { logoutKeycloak } from "../core/keycloak.jsx";
|
||||||
import { usePermission } from "../core/permission.jsx";
|
import { usePermission } from "../core/permission.jsx";
|
||||||
|
|
||||||
|
const normalizeSidebarPath = (value = "") => {
|
||||||
|
const path = String(value).split(/[?#]/)[0] || "";
|
||||||
|
|
||||||
|
if (!path || path === "/") return path || "/";
|
||||||
|
|
||||||
|
return path.replace(/\/+$/, "");
|
||||||
|
};
|
||||||
|
|
||||||
export const isSidebarPathActive = (currentPath, item) => {
|
export const isSidebarPathActive = (currentPath, item) => {
|
||||||
const normalizedPath = currentPath?.split("?")[0] || "";
|
const normalizedPath = normalizeSidebarPath(currentPath);
|
||||||
const candidatePaths = [item?.path, ...(item?.aliases || [])].filter(Boolean);
|
const candidatePaths = [item?.path, ...(item?.aliases || [])]
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(normalizeSidebarPath);
|
||||||
|
|
||||||
return candidatePaths.some(
|
return candidatePaths.some(
|
||||||
(path) => normalizedPath === path || normalizedPath.startsWith(`${path}/`),
|
(path) => normalizedPath === path || normalizedPath.startsWith(`${path}/`),
|
||||||
@ -58,19 +68,39 @@ const DesktopNavItem = ({
|
|||||||
linkComponent,
|
linkComponent,
|
||||||
onNavigate,
|
onNavigate,
|
||||||
}) => {
|
}) => {
|
||||||
const content = (
|
const commonProps = {
|
||||||
<IconButton
|
variant: isActive ? "solid" : "ghost",
|
||||||
variant="ghost"
|
colorScheme: isActive ? "blue" : undefined,
|
||||||
icon={<Icon as={item.icon} />}
|
icon: <Icon as={item.icon} />,
|
||||||
fontSize="xl"
|
fontSize: "xl",
|
||||||
size={{ base: "sm", lg: "lg" }}
|
size: { base: "sm", lg: "lg" },
|
||||||
isDisabled={isDisabled}
|
"aria-label": item.title,
|
||||||
isActive={isActive}
|
"aria-current": isActive ? "page" : undefined,
|
||||||
aria-label={item.title}
|
};
|
||||||
aria-current={isActive ? "page" : undefined}
|
|
||||||
onClick={isDisabled ? undefined : onNavigate}
|
let content;
|
||||||
/>
|
|
||||||
);
|
if (isDisabled || isActive) {
|
||||||
|
content = (
|
||||||
|
<IconButton
|
||||||
|
{...commonProps}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
cursor={isActive && !isDisabled ? "default" : undefined}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const linkProps = linkComponent
|
||||||
|
? { as: linkComponent, href: item.path }
|
||||||
|
: { as: "a", href: item.path };
|
||||||
|
|
||||||
|
content = (
|
||||||
|
<IconButton
|
||||||
|
{...commonProps}
|
||||||
|
{...linkProps}
|
||||||
|
onClick={onNavigate}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@ -83,17 +113,7 @@ const DesktopNavItem = ({
|
|||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
closeDelay={150}
|
closeDelay={150}
|
||||||
>
|
>
|
||||||
{isDisabled ? (
|
<Box as="span">{content}</Box>
|
||||||
<Box as="span">{content}</Box>
|
|
||||||
) : (
|
|
||||||
<SidebarLink
|
|
||||||
linkComponent={linkComponent}
|
|
||||||
href={item.path}
|
|
||||||
_hover={{ textDecoration: "none" }}
|
|
||||||
>
|
|
||||||
{content}
|
|
||||||
</SidebarLink>
|
|
||||||
)}
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -134,14 +154,15 @@ const MobileNavigationButton = ({
|
|||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isDisabled) {
|
if (isDisabled || isActive) {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
flex="1"
|
flex="1"
|
||||||
minW={0}
|
minW={0}
|
||||||
display="flex"
|
display="flex"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
aria-disabled="true"
|
aria-disabled={isDisabled ? "true" : undefined}
|
||||||
|
aria-current={isActive ? "page" : undefined}
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
</Box>
|
</Box>
|
||||||
@ -398,8 +419,16 @@ const SidebarRoot = ({
|
|||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isDisabled) {
|
if (isDisabled || isActive) {
|
||||||
return <Box key={item.path}>{content}</Box>;
|
return (
|
||||||
|
<Box
|
||||||
|
key={item.path}
|
||||||
|
aria-disabled={isDisabled ? "true" : undefined}
|
||||||
|
aria-current={isActive ? "page" : undefined}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user