fix sidebar
All checks were successful
Build and Deploy Next.js + Nginx Docker Image / build-and-deploy (push) Successful in 49s
Build and Deploy Next.js + Nginx Docker Image / deploy (push) Successful in 7s

This commit is contained in:
Mohamadzadeh 2026-08-19 19:00:54 +03:30
parent 70d99473e1
commit 9bd798188d
3 changed files with 254 additions and 199 deletions

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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 (