diff --git a/package-lock.json b/package-lock.json index 42104690..d08f70fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,9 @@ "version": "0.1.0", "hasInstallScript": true, "dependencies": { + "@atlaskit/pragmatic-drag-and-drop": "^1.1.3", + "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3", + "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^1.1.0", "@axa-fr/react-oidc": "^7.21.0", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", @@ -74,6 +77,76 @@ "node": ">=6.0.0" } }, + "node_modules/@atlaskit/platform-feature-flags": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@atlaskit/platform-feature-flags/-/platform-feature-flags-0.2.5.tgz", + "integrity": "sha512-0fD2aDxn2mE59D4acUhVib+YF2HDYuuPH50aYwpQdcV/CsVkAaJsMKy8WhWSulcRFeMYp72kfIfdy0qGdRB7Uw==", + "dependencies": { + "@babel/runtime": "^7.0.0" + } + }, + "node_modules/@atlaskit/pragmatic-drag-and-drop": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@atlaskit/pragmatic-drag-and-drop/-/pragmatic-drag-and-drop-1.1.3.tgz", + "integrity": "sha512-lx6ZMPSU8zPhUfAkdKajNAFWDDIqdtM8eQzCsqCRalXWumpclcvqeN8VCLkmclcQDEUhV8c2utKbcuhm7hvRIw==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "bind-event-listener": "^2.1.1", + "raf-schd": "^4.0.3" + } + }, + "node_modules/@atlaskit/pragmatic-drag-and-drop-hitbox": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@atlaskit/pragmatic-drag-and-drop-hitbox/-/pragmatic-drag-and-drop-hitbox-1.0.3.tgz", + "integrity": "sha512-/Sbu/HqN2VGLYBhnsG7SbRNg98XKkbF6L7XDdBi+izRybfaK1FeMfodPpm/xnBHPJzwYMdkE0qtLyv6afhgMUA==", + "dependencies": { + "@atlaskit/pragmatic-drag-and-drop": "^1.1.0", + "@babel/runtime": "^7.0.0" + } + }, + "node_modules/@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/-/pragmatic-drag-and-drop-react-drop-indicator-1.1.0.tgz", + "integrity": "sha512-h6TClbK1axZflyQL17mDZO44psPyk3i7P7xn/lSzPfMEXdUuGHPsGBr5jH0QyxJ+flHA9GlfNDqggJK3L/HkFg==", + "dependencies": { + "@atlaskit/pragmatic-drag-and-drop": "^1.1.0", + "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.0", + "@atlaskit/tokens": "^1.43.0", + "@babel/runtime": "^7.0.0", + "@emotion/react": "^11.7.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/node_modules/@atlaskit/tokens": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/@atlaskit/tokens/-/tokens-1.43.0.tgz", + "integrity": "sha512-3rRxGRnJGQBVKGqNqy+Zuad3xuDZ7uD+aFGRcU2OpLuIpiFLX95agDZ9w0HGzNiDw9eWi2f1j8Uzq06AyaRqTw==", + "dependencies": { + "@atlaskit/ds-lib": "^2.2.0", + "@atlaskit/platform-feature-flags": "^0.2.0", + "@babel/runtime": "^7.0.0", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.20.0", + "bind-event-listener": "^2.1.1" + }, + "peerDependencies": { + "react": "^16.8.0" + } + }, + "node_modules/@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/node_modules/@atlaskit/tokens/node_modules/@atlaskit/ds-lib": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@atlaskit/ds-lib/-/ds-lib-2.2.5.tgz", + "integrity": "sha512-fE7uEuB4uAJvNGncY5k+ofUYmJmVcS43MDChvhz1qG2dweYx4hktFVOowiDjt7+RtLQOXuvs7WTn3wIy25er3w==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "bind-event-listener": "^2.1.1" + }, + "peerDependencies": { + "react": "^16.8.0" + } + }, "node_modules/@axa-fr/oidc-client": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/@axa-fr/oidc-client/-/oidc-client-7.21.0.tgz", @@ -235,7 +308,6 @@ "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz", "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==", - "dev": true, "dependencies": { "@babel/types": "^7.23.4", "@jridgewell/gen-mapping": "^0.3.2", @@ -275,7 +347,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -284,7 +355,6 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -297,7 +367,6 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -360,7 +429,6 @@ "version": "7.22.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -488,7 +556,6 @@ "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz", "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==", - "dev": true, "bin": { "parser": "bin/babel-parser.js" }, @@ -688,7 +755,6 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.22.13", "@babel/parser": "^7.22.15", @@ -702,7 +768,6 @@ "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz", "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.23.4", "@babel/generator": "^7.23.4", @@ -723,7 +788,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -2107,7 +2171,6 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2121,7 +2184,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2130,7 +2192,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2138,14 +2199,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -3797,6 +3856,11 @@ "tweetnacl": "^0.14.3" } }, + "node_modules/bind-event-listener": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bind-event-listener/-/bind-event-listener-2.1.1.tgz", + "integrity": "sha512-O+a5c0D2se/u2VlBJmPRn45IB6R4mYMh1ok3dWxrIZ2pmLqzggBhb875mbq73508ylzofc0+hT9W41x4Y2s8lg==" + }, "node_modules/blob-util": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", @@ -4788,7 +4852,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -8372,7 +8435,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -9101,8 +9163,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { "version": "3.3.7", diff --git a/package.json b/package.json index 0c69c21e..5392d6d9 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,9 @@ "prepare": "husky" }, "dependencies": { + "@atlaskit/pragmatic-drag-and-drop": "^1.1.3", + "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3", + "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^1.1.0", "@axa-fr/react-oidc": "^7.21.0", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", diff --git a/src/app/error.tsx b/src/app/(dashboard)/error.tsx similarity index 100% rename from src/app/error.tsx rename to src/app/(dashboard)/error.tsx diff --git a/src/components/ui/DashboardDrawer.tsx b/src/components/ui/DashboardDrawer.tsx index f7b59967..3910b9c1 100644 --- a/src/components/ui/DashboardDrawer.tsx +++ b/src/components/ui/DashboardDrawer.tsx @@ -12,7 +12,18 @@ import { import { Dashboard, FolderCopy } from "@mui/icons-material"; import MonitorIcon from "@mui/icons-material/Monitor"; import MenuBookIcon from "@mui/icons-material/MenuBook"; -import React, { ComponentType, ReactEventHandler, useState } from "react"; +import React, { + ComponentType, + ReactEventHandler, + useEffect, + useState, +} from "react"; +import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; +import { + Edge, + extractClosestEdge, +} from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge"; +import { getReorderDestinationIndex } from "@atlaskit/pragmatic-drag-and-drop-hitbox/util/get-reorder-destination-index"; import DrawerItemGroup from "./DrawerItemGroup"; import { DiracLogo } from "./DiracLogo"; @@ -66,42 +77,113 @@ export default function DashboardDrawer(props: DashboardDrawerProps) { items: { title: string; id: number; icon: ComponentType; path: string }[]; }[]); - /** - * Handles the drag end event for reordering items in the group. - * - * @param result - The result object containing information about the drag event. - */ - function onDragEnd(result: any) { - // Reorder the list of items in the group. - if (!result.destination) { - return; - } - const source = result.source; - const destination = result.destination; + useEffect(() => { + return monitorForElements({ + onDrop({ source, location }) { + const target = location.current.dropTargets[0]; + if (!target) { + return; + } + const sourceData = source.data; + const targetData = target.data; + + if (location.current.dropTargets.length == 2) { + const groupTitle = targetData.title; + const closestEdgeOfTarget = extractClosestEdge(targetData); + const targetIndex = targetData.index as number; + const sourceGroup = userSections.find( + (group) => group.title == sourceData.title, + ); + const targetGroup = userSections.find( + (group) => group.title == groupTitle, + ); + const sourceIndex = sourceData.index as number; + const destinationIndex = ( + closestEdgeOfTarget === "top" ? targetIndex : targetIndex + 1 + ) as number; - const sourceGroup = userSections.find( - (group) => group.title == source.droppableId, - ); - const destinationGroup = userSections.find( - (group) => group.title == destination.droppableId, - ); + reorderSections( + sourceGroup, + targetGroup, + sourceIndex, + destinationIndex, + ); + } else { + const groupTitle = targetData.title; + const sourceGroup = userSections.find( + (group) => group.title == sourceData.title, + ); + const targetGroup = userSections.find( + (group) => group.title == groupTitle, + ); + const sourceIndex = sourceData.index as number; + reorderSections(sourceGroup, targetGroup, sourceIndex); + } + }, + }); + }, [userSections]); + + function reorderSections( + sourceGroup: any, + destinationGroup: any, + sourceIndex: number, + destinationIndex: number | null = null, + ) { if (sourceGroup && destinationGroup) { - const sourceItems = [...sourceGroup.items]; - const destinationItems = [...destinationGroup.items]; - - const [removed] = sourceItems.splice(source.index, 1); - destinationItems.splice(destination.index, 0, removed); - - setSections((sections) => - sections.map((section) => - section.title === sourceGroup.title - ? { ...section, items: sourceItems } - : section.title === destinationGroup.title - ? { ...section, items: destinationItems } + if ( + sourceGroup.title === destinationGroup.title && + destinationIndex && + sourceIndex < destinationIndex + ) { + destinationIndex -= 1; + } + if ( + sourceGroup.title === destinationGroup.title && + (destinationIndex == null || sourceIndex === destinationIndex) + ) { + return; + } + + if (sourceGroup.title === destinationGroup.title) { + const sourceItems = [...sourceGroup.items]; + + const [removed] = sourceItems.splice(sourceIndex, 1); + + if (destinationIndex === null) { + destinationIndex = sourceItems.length; + } + sourceItems.splice(destinationIndex, 0, removed); + + setSections((sections) => + sections.map((section) => + section.title === sourceGroup.title + ? { ...section, items: sourceItems } : section, - ), - ); + ), + ); + } else { + const sourceItems = [...sourceGroup.items]; + + const [removed] = sourceItems.splice(sourceIndex, 1); + + const destinationItems = [...destinationGroup.items]; + + if (destinationIndex === null) { + destinationIndex = destinationItems.length; + } + destinationItems.splice(destinationIndex, 0, removed); + + setSections((sections) => + sections.map((section) => + section.title === sourceGroup.title + ? { ...section, items: sourceItems } + : section.title === destinationGroup.title + ? { ...section, items: destinationItems } + : section, + ), + ); + } } } diff --git a/src/components/ui/DrawerItem.tsx b/src/components/ui/DrawerItem.tsx new file mode 100644 index 00000000..34513168 --- /dev/null +++ b/src/components/ui/DrawerItem.tsx @@ -0,0 +1,117 @@ +import React, { useEffect, useState } from "react"; +import Link from "next/link"; +import { + ListItemButton, + ListItemIcon, + Icon, + ListItemText, +} from "@mui/material"; +import DragIndicatorIcon from "@mui/icons-material/DragIndicator"; +import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; +import { + draggable, + dropTargetForElements, +} from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; +import { DropIndicator } from "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box"; +import { + Edge, + attachClosestEdge, + extractClosestEdge, +} from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge"; + +export default function DrawerItem({ + item: { title, icon, path }, + index, + groupTitle, +}: { + item: { title: string; icon: React.ComponentType; path: string }; + index: number; + groupTitle: string; +}) { + const dragRef = React.useRef(null); + const handleRef = React.useRef(null); + + const [closestEdge, setClosestEdge]: any = useState(null); + + useEffect(() => { + if (!dragRef.current || !handleRef.current) return; + const element = dragRef.current; + const handleItem = handleRef.current; + const title = groupTitle; + + return combine( + draggable({ + element: element, + dragHandle: handleItem, + getInitialData: () => ({ index, title }), + }), + dropTargetForElements({ + element: element, + getData: ({ input, element }) => { + return attachClosestEdge( + { index, title }, + { input, element, allowedEdges: ["top", "bottom"] }, + ); + }, + onDrag({ self, source }) { + const isSource = source.element === element; + if (isSource) { + setClosestEdge(null); + return; + } + const closestEdge = extractClosestEdge(self.data); + + const sourceIndex = source.data.index; + if (typeof sourceIndex === "number") { + const isItemBeforeSource = + index === sourceIndex - 1 && source.data.title === title; + const isItemAfterSource = + index === sourceIndex + 1 && source.data.title === title; + + const isDropIndicatorHidden = + (isItemBeforeSource && closestEdge === "bottom") || + (isItemAfterSource && closestEdge === "top"); + + if (isDropIndicatorHidden) { + setClosestEdge(null); + return; + } + } + setClosestEdge(closestEdge); + }, + onDragLeave() { + setClosestEdge(null); + }, + onDrop: () => { + setClosestEdge(null); + }, + }), + ); + }, [index, groupTitle]); + + return ( + <> + + + + + +
+ +
+ {closestEdge && } +
+ + ); +} diff --git a/src/components/ui/DrawerItemGroup.tsx b/src/components/ui/DrawerItemGroup.tsx index 83c0bfad..e3c45144 100644 --- a/src/components/ui/DrawerItemGroup.tsx +++ b/src/components/ui/DrawerItemGroup.tsx @@ -1,16 +1,8 @@ -import { - Accordion, - AccordionDetails, - AccordionSummary, - Icon, - ListItemButton, - ListItemIcon, - ListItemText, -} from "@mui/material"; +import { Accordion, AccordionDetails, AccordionSummary } from "@mui/material"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; -import React from "react"; -import Link from "next/link"; -import DragIndicatorIcon from "@mui/icons-material/DragIndicator"; +import React, { useEffect } from "react"; +import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; +import DrawerItem from "./DrawerItem"; export default function DrawerItemGroup({ group: { title, extended: expanded, items }, @@ -41,6 +33,23 @@ export default function DrawerItemGroup({ > >; }) { + const dropRef = React.useRef(null); + const [hovered, setHovered] = React.useState(false); + + useEffect(() => { + if (!dropRef.current) return; + const dropItem = dropRef.current; + + return dropTargetForElements({ + element: dropItem, + getData: () => ({ title }), + onDragStart: () => setHovered(true), + onDrop: () => setHovered(false), + onDragEnter: () => setHovered(true), + onDragLeave: () => setHovered(false), + }); + }); + const handleChange = (title: string) => (event: any, isExpanded: any) => { // Set the extended state of the accordion group. setSections((sections) => @@ -51,17 +60,19 @@ export default function DrawerItemGroup({ ), ); }; - + const groupTitle = title; return ( {/* Accordion summary */} }> @@ -70,21 +81,12 @@ export default function DrawerItemGroup({ {/* Accordion details */} {items.map(({ title, id, icon, path }, index) => ( - - - - - -
- -
-
+ ))}