Skip to content

Commit

Permalink
update on Menu accordion UX/UI (#4774)
Browse files Browse the repository at this point in the history
- scroll vertical is a props on ScrollArea
MenuItem:
- Accordion are open by default
- Chevron is on the right
- CSS updates
  • Loading branch information
bilalabbad authored Oct 30, 2024
1 parent 9f7300a commit 0cd7597
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 32 deletions.
4 changes: 2 additions & 2 deletions frontend/app/src/components/search/search-anywhere.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ const SearchAnywhereTriggerButton = ({ className, ...props }: ButtonProps) => {
data-testid="search-anywhere-trigger"
{...props}
>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2 overflow-hidden">
<Icon icon="mdi:magnify" aria-hidden="true" className="text-xl" />
<span className="text-neutral-700 text-sm group-data-[collapsed=true]/sidebar:hidden transition-all">
<span className="text-neutral-700 text-sm group-data-[collapsed=true]/sidebar:hidden transition-all truncate">
Search
</span>
</div>
Expand Down
23 changes: 14 additions & 9 deletions frontend/app/src/components/ui/accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,40 @@ export const AccordionItem = AccordionPrimitive.Item;

export const AccordionTrigger = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> & { iconClassName?: string }
>(({ className, children, iconClassName, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={classNames(
"flex flex-1 items-center py-4 font-medium transition-all [&[data-state=open]>iconify-icon]:rotate-90",
"flex flex-1 items-center py-4 font-medium transition-all [&[data-state=open]>div>iconify-icon]:rotate-90",
className
)}
{...props}
>
<Icon
icon="mdi:chevron-right"
className="text-xl shrink-0 transition-transform duration-200"
/>
{children}

<div className={classNames("flex ml-auto rounded p-1", iconClassName)}>
<Icon
icon="mdi:chevron-right"
className="text-xl shrink-0 transition-transform duration-200"
/>
</div>
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));

export const AccordionContent = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
>(({ className, children, style, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
{...props}
>
<div className={classNames(className)}>{children}</div>
<div className={classNames(className)} style={style}>
{children}
</div>
</AccordionPrimitive.Content>
));
6 changes: 3 additions & 3 deletions frontend/app/src/components/ui/dropdown-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ export const DropdownMenuSubContent = forwardRef<

export const DropdownMenuAccordion = forwardRef<
ElementRef<typeof AccordionItem>,
ComponentPropsWithoutRef<typeof AccordionItem>
>((props, ref) => {
ComponentPropsWithoutRef<typeof AccordionItem> & { defaultOpen?: boolean }
>(({ defaultOpen, ...props }, ref) => {
return (
<Accordion type="single" collapsible>
<Accordion type="single" collapsible defaultValue={defaultOpen ? props.value : undefined}>
<AccordionItem {...props} ref={ref} />
</Accordion>
);
Expand Down
11 changes: 7 additions & 4 deletions frontend/app/src/components/ui/scroll-area.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import * as React from "react";

export const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> & {
scrollX?: boolean;
scrollY?: boolean;
}
>(({ className, children, scrollX = false, scrollY = true, ...props }, ref) => (
<ScrollAreaPrimitive.Root
ref={ref}
scrollHideDelay={0}
Expand All @@ -17,8 +20,8 @@ export const ScrollArea = React.forwardRef<
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar orientation="vertical" />
<ScrollBar orientation="horizontal" />
{scrollX && <ScrollBar orientation="horizontal" />}
{scrollY && <ScrollBar orientation="vertical" />}
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
));
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/pages/ipam/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function IpamLayout() {

<div className="flex-grow flex overflow-auto">
<div className="min-w-64 max-w-[400px] border-r flex">
<ScrollArea className="w-full p-2">
<ScrollArea scrollX className="w-full p-2">
<IpamTree className="w-full" />
</ScrollArea>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/pages/objects/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const ObjectPageLayout = () => {
{treeSchema && (
<>
<ResizablePanel defaultSize={20} minSize={10} maxSize={50}>
<ScrollArea className="h-full">
<ScrollArea scrollX className="h-full">
<HierarchicalTree
schema={treeSchema}
currentNodeId={objectid}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ const ExpandedMenuItemLink: React.FC<{ item: MenuItem }> = ({ item }) => (
<Link to={constructPath(item.path)} className={classNames(menuNavigationItemStyle, "h-10")}>
<Icon icon={item.icon} className="min-w-4" />
<span className="text-sm truncate">{item.label}</span>
<Icon
icon="mdi:arrow-top-right"
className="m-1 ml-auto text-sm opacity-0 group-hover:opacity-100 group-focus:opacity-100 group-data-[state=open]:opacity-100"
/>
</Link>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,9 @@ const RecursiveObjectMenuItem: React.FC<{
isCollapsed?: boolean;
level?: number;
}> = ({ item, isCollapsed, level = 0 }) => {
const commonStyleProps = {
className: menuNavigationItemStyle,
style: { marginLeft: level * 20 },
};

if (!item.children?.length) {
return (
<DropdownMenuItem {...commonStyleProps} asChild>
<DropdownMenuItem className={menuNavigationItemStyle} asChild>
<Link to={constructPath(item.path)}>
<Icon icon={item.icon} className="w-5 shrink-0 inline-flex justify-center items-center" />
{item.label}
Expand All @@ -51,17 +46,28 @@ const RecursiveObjectMenuItem: React.FC<{
}

return (
<DropdownMenuAccordion value={item.identifier}>
<DropdownMenuAccordionTrigger {...commonStyleProps}>
<DropdownMenuAccordion value={item.identifier} defaultOpen>
<DropdownMenuAccordionTrigger
className={classNames(
menuNavigationItemStyle,
"font-bold py-1 data-[state=open]:bg-transparent data-[state=open]:text-inherit data-[state=open]:data-[highlighted]:bg-neutral-100"
)}
iconClassName="hover:bg-neutral-200"
>
<Icon icon={item.icon} className="w-5 shrink-0 inline-flex justify-center items-center" />
{item.path ? (
<Link to={constructPath(item.path)} className="w-full text-left cursor-pointer">
<Link to={constructPath(item.path)} className="text-left cursor-pointer">
{item.label}
</Link>
) : (
item.label
)}
</DropdownMenuAccordionTrigger>
<DropdownMenuAccordionContent>

<DropdownMenuAccordionContent
style={{ marginLeft: (level + 1) * 18 }}
className="border-l border-neutral-200"
>
{item.children.map((child) => (
<RecursiveObjectMenuItem
key={child.identifier}
Expand Down Expand Up @@ -106,7 +112,7 @@ const TopLevelMenuItem: React.FC<{
side="left"
align="start"
sideOffset={isCollapsed ? 6 : 12}
className="h-[calc(100vh-57px)] mt-[57px] min-w-[224px] px-4 py-5 bg-white border rounded-r-lg rounded-l-none shadow-none relative -top-px overflow-auto data-[side=right]:slide-in-from-left-[100px]"
className="h-[calc(100vh-57px)] mt-[57px] min-w-[275px] px-4 py-5 bg-white border rounded-r-lg rounded-l-none shadow-none relative -top-px overflow-auto data-[side=right]:slide-in-from-left-[100px]"
>
<h3 className="text-xl font-medium text-neutral-800 mb-5">{item.label}</h3>
{item.children.map((child) => (
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/screens/layout/menu-navigation/styles.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export const menuNavigationItemStyle =
"flex items-center outline-none gap-2 px-3 py-2 rounded font-medium text-neutral-900 hover:bg-neutral-100 focus:bg-neutral-100 group data-[state=open]:bg-indigo-50 data-[state=open]:text-indigo-700";
"flex items-center outline-none gap-2 p-2 rounded font-medium text-neutral-900 hover:bg-neutral-100 focus:bg-neutral-100 group data-[state=open]:bg-indigo-50 data-[state=open]:text-indigo-700";

0 comments on commit 0cd7597

Please sign in to comment.