mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 21:54:56 +00:00
Refactor navigation menu layout
This commit is contained in:
@@ -8,6 +8,7 @@ import { NavigationItem, NavigationGroupHeader } from '@/components/molecules'
|
||||
import { navigationGroups, NavigationItemData } from '@/lib/navigation-config'
|
||||
import { FeatureToggles } from '@/types/project'
|
||||
import { useRoutePreload } from '@/hooks/use-route-preload'
|
||||
import navigationMenuCopy from '@/data/navigation-menu.json'
|
||||
|
||||
interface NavigationMenuProps {
|
||||
activeTab: string
|
||||
@@ -16,6 +17,140 @@ interface NavigationMenuProps {
|
||||
errorCount?: number
|
||||
}
|
||||
|
||||
interface NavigationMenuControlsProps {
|
||||
onExpandAll: () => void
|
||||
onCollapseAll: () => void
|
||||
}
|
||||
|
||||
interface NavigationMenuGroupListProps {
|
||||
activeTab: string
|
||||
expandedGroups: Set<string>
|
||||
featureToggles: FeatureToggles
|
||||
errorCount: number
|
||||
onToggleGroup: (groupId: string) => void
|
||||
onItemClick: (value: string) => void
|
||||
onItemHover: (value: string) => void
|
||||
onItemLeave: (value: string) => void
|
||||
}
|
||||
|
||||
function NavigationMenuControls({
|
||||
onExpandAll,
|
||||
onCollapseAll,
|
||||
}: NavigationMenuControlsProps) {
|
||||
return (
|
||||
<div className="flex gap-2 mt-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={onExpandAll}
|
||||
className="flex-1"
|
||||
>
|
||||
<CaretDoubleDown size={16} className="mr-2" />
|
||||
{navigationMenuCopy.labels.expandAll}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={onCollapseAll}
|
||||
className="flex-1"
|
||||
>
|
||||
<CaretDoubleUp size={16} className="mr-2" />
|
||||
{navigationMenuCopy.labels.collapseAll}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function NavigationMenuHeader({
|
||||
onExpandAll,
|
||||
onCollapseAll,
|
||||
}: NavigationMenuControlsProps) {
|
||||
return (
|
||||
<SidebarHeader className="px-4 py-4 border-b">
|
||||
<h2 className="text-lg font-semibold">{navigationMenuCopy.labels.title}</h2>
|
||||
<NavigationMenuControls
|
||||
onExpandAll={onExpandAll}
|
||||
onCollapseAll={onCollapseAll}
|
||||
/>
|
||||
</SidebarHeader>
|
||||
)
|
||||
}
|
||||
|
||||
function NavigationMenuGroupList({
|
||||
activeTab,
|
||||
expandedGroups,
|
||||
featureToggles,
|
||||
errorCount,
|
||||
onToggleGroup,
|
||||
onItemClick,
|
||||
onItemHover,
|
||||
onItemLeave,
|
||||
}: NavigationMenuGroupListProps) {
|
||||
const isItemVisible = (item: NavigationItemData) => {
|
||||
if (!item.featureKey) return true
|
||||
return featureToggles[item.featureKey]
|
||||
}
|
||||
|
||||
const getVisibleItemsCount = (groupId: string) => {
|
||||
const group = navigationGroups.find((g) => g.id === groupId)
|
||||
if (!group) return 0
|
||||
return group.items.filter(isItemVisible).length
|
||||
}
|
||||
|
||||
const getItemBadge = (item: NavigationItemData) => {
|
||||
if (item.id === 'errors') return errorCount
|
||||
return item.badge
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-2 py-4">
|
||||
{navigationGroups.map((group) => {
|
||||
const visibleItemsCount = getVisibleItemsCount(group.id)
|
||||
if (visibleItemsCount === 0) return null
|
||||
|
||||
const isExpanded = expandedGroups.has(group.id)
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
key={group.id}
|
||||
open={isExpanded}
|
||||
onOpenChange={() => onToggleGroup(group.id)}
|
||||
>
|
||||
<NavigationGroupHeader
|
||||
label={group.label}
|
||||
count={visibleItemsCount}
|
||||
isExpanded={isExpanded}
|
||||
/>
|
||||
<CollapsibleContent className="mt-1">
|
||||
<div className="space-y-1 pl-2">
|
||||
{group.items.map((item) => {
|
||||
if (!isItemVisible(item)) return null
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
onMouseEnter={() => onItemHover(item.value)}
|
||||
onMouseLeave={() => onItemLeave(item.value)}
|
||||
>
|
||||
<NavigationItem
|
||||
icon={item.icon}
|
||||
label={item.label}
|
||||
isActive={activeTab === item.value}
|
||||
badge={getItemBadge(item)}
|
||||
onClick={() => onItemClick(item.value)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function NavigationMenu({
|
||||
activeTab,
|
||||
onTabChange,
|
||||
@@ -54,20 +189,14 @@ export function NavigationMenu({
|
||||
})
|
||||
}
|
||||
|
||||
const isItemVisible = (item: NavigationItemData) => {
|
||||
if (!item.featureKey) return true
|
||||
return featureToggles[item.featureKey]
|
||||
}
|
||||
|
||||
const getVisibleItemsCount = (groupId: string) => {
|
||||
const group = navigationGroups.find((g) => g.id === groupId)
|
||||
if (!group) return 0
|
||||
return group.items.filter(isItemVisible).length
|
||||
}
|
||||
|
||||
const handleExpandAll = () => {
|
||||
const allGroupIds = navigationGroups
|
||||
.filter((group) => getVisibleItemsCount(group.id) > 0)
|
||||
.filter((group) =>
|
||||
group.items.some((item) => {
|
||||
if (!item.featureKey) return true
|
||||
return featureToggles[item.featureKey]
|
||||
})
|
||||
)
|
||||
.map((group) => group.id)
|
||||
setExpandedGroups(new Set(allGroupIds))
|
||||
}
|
||||
@@ -76,83 +205,24 @@ export function NavigationMenu({
|
||||
setExpandedGroups(new Set())
|
||||
}
|
||||
|
||||
const getItemBadge = (item: NavigationItemData) => {
|
||||
if (item.id === 'errors') return errorCount
|
||||
return item.badge
|
||||
}
|
||||
|
||||
return (
|
||||
<Sidebar side="left" collapsible="offcanvas">
|
||||
<SidebarHeader className="px-4 py-4 border-b">
|
||||
<h2 className="text-lg font-semibold">Navigation</h2>
|
||||
<div className="flex gap-2 mt-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleExpandAll}
|
||||
className="flex-1"
|
||||
>
|
||||
<CaretDoubleDown size={16} className="mr-2" />
|
||||
Expand All
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleCollapseAll}
|
||||
className="flex-1"
|
||||
>
|
||||
<CaretDoubleUp size={16} className="mr-2" />
|
||||
Collapse All
|
||||
</Button>
|
||||
</div>
|
||||
</SidebarHeader>
|
||||
<NavigationMenuHeader
|
||||
onExpandAll={handleExpandAll}
|
||||
onCollapseAll={handleCollapseAll}
|
||||
/>
|
||||
<SidebarContent>
|
||||
<ScrollArea className="h-full px-4">
|
||||
<div className="space-y-2 py-4">
|
||||
{navigationGroups.map((group) => {
|
||||
const visibleItemsCount = getVisibleItemsCount(group.id)
|
||||
if (visibleItemsCount === 0) return null
|
||||
|
||||
const isExpanded = expandedGroups.has(group.id)
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
key={group.id}
|
||||
open={isExpanded}
|
||||
onOpenChange={() => toggleGroup(group.id)}
|
||||
>
|
||||
<NavigationGroupHeader
|
||||
label={group.label}
|
||||
count={visibleItemsCount}
|
||||
isExpanded={isExpanded}
|
||||
/>
|
||||
<CollapsibleContent className="mt-1">
|
||||
<div className="space-y-1 pl-2">
|
||||
{group.items.map((item) => {
|
||||
if (!isItemVisible(item)) return null
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
onMouseEnter={() => handleItemHover(item.value)}
|
||||
onMouseLeave={() => handleItemLeave(item.value)}
|
||||
>
|
||||
<NavigationItem
|
||||
icon={item.icon}
|
||||
label={item.label}
|
||||
isActive={activeTab === item.value}
|
||||
badge={getItemBadge(item)}
|
||||
onClick={() => handleItemClick(item.value)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<NavigationMenuGroupList
|
||||
activeTab={activeTab}
|
||||
expandedGroups={expandedGroups}
|
||||
featureToggles={featureToggles}
|
||||
errorCount={errorCount}
|
||||
onToggleGroup={toggleGroup}
|
||||
onItemClick={handleItemClick}
|
||||
onItemHover={handleItemHover}
|
||||
onItemLeave={handleItemLeave}
|
||||
/>
|
||||
</ScrollArea>
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
|
||||
7
src/data/navigation-menu.json
Normal file
7
src/data/navigation-menu.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"labels": {
|
||||
"title": "Navigation",
|
||||
"expandAll": "Expand All",
|
||||
"collapseAll": "Collapse All"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user