Let's create a React File Manager Chapter X: Active Sidebar Node
Hasan Zohdy
Posted on September 14, 2022
Now let's get the active node from the file manager and compare it to current node in SidebarNode
, it will be active if they are the same.
// SidebarNode.tsx
...
import useFileManager from "../../../hooks/useFileManager";
export default function SidebarNode({ icon, node }: SidebarNodeProps) {
const fileManager = useFileManager();
const [isActiveNode, setIsActiveNode] = useState(
node === fileManager.currentDirectoryNode,
);
useEffect(() => {
setIsActiveNode(node === fileManager.currentDirectoryNode);
}, [fileManager.currentDirectoryNode, node]);
...
}
So now we can now if the current node is the active node if it matches the current directory node in the file manager.
Now let's highlight the node if it is the same, NavLink
has active
prop so we can use it to highlight the node, but we need to move it first inside sidebar node.
// SidebarNode.tsx
import { NavLink } from "@mantine/core";
import { IconFolder } from "@tabler/icons";
import { useEffect, useState } from "react";
import useFileManager from "../../../hooks/useFileManager";
import { Node } from "../../../types/FileManager.types";
import { IconWrapper } from "./SidebarNode.styles";
export type SidebarNodeProps = {
node: Node;
icon?: React.ReactNode;
};
export default function SidebarNode({ icon, node }: SidebarNodeProps) {
const fileManager = useFileManager();
const [isActiveNode, setIsActiveNode] = useState(
node === fileManager.currentDirectoryNode,
);
useEffect(() => {
setIsActiveNode(node === fileManager.currentDirectoryNode);
}, [fileManager.currentDirectoryNode, node]);
return (
<>
<NavLink
label={
<>
<IconWrapper>{icon}</IconWrapper>
<span>{node.name}</span>
</>
}
/>
</>
);
}
SidebarNode.defaultProps = {
icon: <IconFolder fill="#31caf9" />,
};
Now let's update Sidebar
component and remove nav links from it.
// Sidebar.tsx
...
return (
<>
<Card shadow="sm">
<SidebarNode
node={rootDirectory}
icon={<IconHome2 size={16} color="#78a136" />}
/>
{rootChildren?.map(child => (
<SidebarNode
key={child.path}
icon={<IconFolder size={16} fill="#31caf9" />}
node={child}
/>
))}
</Card>
</>
);
But we need to make more customization to NavLink
for styling, so let's create navProps
prop so it accepts any NavLink
props.
// SidebarNode.tsx
import { NavLink, NavLinkProps } from "@mantine/core";
import { IconFolder } from "@tabler/icons";
import { useEffect, useState } from "react";
import useFileManager from "../../../hooks/useFileManager";
import { Node } from "../../../types/FileManager.types";
import { IconWrapper } from "./SidebarNode.styles";
export type SidebarNodeProps = {
node: Node;
icon?: React.ReactNode;
navProps?: Partial<NavLinkProps>;
};
export default function SidebarNode({
icon,
node,
navProps = {},
}: SidebarNodeProps) {
const fileManager = useFileManager();
const [isActiveNode, setIsActiveNode] = useState(
node === fileManager.currentDirectoryNode,
);
useEffect(() => {
setIsActiveNode(node === fileManager.currentDirectoryNode);
}, [fileManager.currentDirectoryNode, node]);
return (
<>
<NavLink
{...navProps}
label={
<>
<IconWrapper>{icon}</IconWrapper>
<span>{node.name}</span>
</>
}
/>
</>
);
}
SidebarNode.defaultProps = {
icon: <IconFolder fill="#31caf9" />,
};
Now we can set the same props for the root and the children for paddings.
// Sidebar.tsx
...
return (
<>
<Card shadow="sm">
<SidebarNode
node={rootDirectory}
navProps={{
p: 0,
}}
icon={<IconHome2 size={16} color="#78a136" />}
/>
{rootChildren?.map(child => (
<SidebarNode
navProps={{
p: 0,
pl: 10,
}}
key={child.path}
icon={<IconFolder size={16} fill="#31caf9" />}
node={child}
/>
))}
</Card>
</>
);
Now let's mark the nav link as active if it is the same node.
// SidebarNode.tsx
import { NavLink, NavLinkProps } from "@mantine/core";
import { IconFolder } from "@tabler/icons";
import { useEffect, useState } from "react";
import useFileManager from "../../../hooks/useFileManager";
import { Node } from "../../../types/FileManager.types";
import { IconWrapper } from "./SidebarNode.styles";
export type SidebarNodeProps = {
node: Node;
icon?: React.ReactNode;
navProps?: Partial<NavLinkProps>;
};
export default function SidebarNode({
icon,
node,
navProps = {},
}: SidebarNodeProps) {
const fileManager = useFileManager();
const [isActiveNode, setIsActiveNode] = useState(
node === fileManager.currentDirectoryNode,
);
useEffect(() => {
setIsActiveNode(node === fileManager.currentDirectoryNode);
}, [fileManager.currentDirectoryNode, node]);
return (
<>
<NavLink
{...navProps}
active={isActiveNode}
label={
<>
<IconWrapper>{icon}</IconWrapper>
<span>{node.name}</span>
</>
}
/>
</>
);
}
...
Now we can see something like this:
In the next part, we will add the ability to navigate between directories.
Article Repository
You can see chapter files in Github Repository
Don't forget the
main
branch has the latest updated code.
Tell me where you are now
If you're following up with me this series, tell me where are you now and what you're struggling with, i'll try to help you as much as i can.
Salam.
Posted on September 14, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.