mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
stuff
This commit is contained in:
@@ -3,7 +3,7 @@ import { toast } from 'sonner'
|
||||
|
||||
import AppDialogs from '@/components/app/AppDialogs'
|
||||
import AppMainPanel from '@/components/app/AppMainPanel'
|
||||
import { NavigationMenu } from '@/components/organisms/NavigationMenu'
|
||||
import { NavigationMenu } from '@/lib/json-ui/json-components'
|
||||
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar'
|
||||
import appStrings from '@/data/app-shortcuts.json'
|
||||
import useAppNavigation from '@/hooks/use-app-navigation'
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
import { useState } from 'react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Sidebar, SidebarContent, SidebarHeader } from '@/components/ui/sidebar'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { Collapsible, CollapsibleContent } from '@/components/ui/collapsible'
|
||||
import { CaretDoubleDown, CaretDoubleUp, CaretDown } from '@phosphor-icons/react'
|
||||
import { CollapsibleTrigger } from '@/components/ui/collapsible'
|
||||
import { Badge, Flex, Text, IconWrapper } from '@/components/atoms'
|
||||
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
|
||||
onTabChange: (tab: string) => void
|
||||
featureToggles: FeatureToggles
|
||||
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 - inlined */}
|
||||
<CollapsibleTrigger className="w-full flex items-center gap-2 px-2 py-2 rounded-lg hover:bg-muted transition-colors group">
|
||||
<CaretDown
|
||||
size={16}
|
||||
weight="bold"
|
||||
className={`text-muted-foreground transition-transform ${
|
||||
isExpanded ? 'rotate-0' : '-rotate-90'
|
||||
}`}
|
||||
/>
|
||||
<h3 className="flex-1 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider">
|
||||
{group.label}
|
||||
</h3>
|
||||
<span className="text-xs text-muted-foreground">{visibleItemsCount}</span>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="mt-1">
|
||||
<div className="space-y-1 pl-2">
|
||||
{group.items.map((item) => {
|
||||
if (!isItemVisible(item)) return null
|
||||
|
||||
const isActive = activeTab === item.value
|
||||
const badge = getItemBadge(item)
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
onMouseEnter={() => onItemHover(item.value)}
|
||||
onMouseLeave={() => onItemLeave(item.value)}
|
||||
>
|
||||
{/* NavigationItem - inlined */}
|
||||
<button
|
||||
onClick={() => onItemClick(item.value)}
|
||||
className={`w-full flex items-center gap-3 px-3 py-2 rounded-lg transition-colors ${
|
||||
isActive
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'hover:bg-muted text-foreground'
|
||||
}`}
|
||||
>
|
||||
<IconWrapper
|
||||
icon={item.icon}
|
||||
size="md"
|
||||
variant={isActive ? 'default' : 'muted'}
|
||||
/>
|
||||
<Text className="flex-1 text-left font-medium" variant="small">
|
||||
{item.label}
|
||||
</Text>
|
||||
{badge !== undefined && badge > 0 && (
|
||||
<Badge
|
||||
variant={isActive ? 'secondary' : 'destructive'}
|
||||
className="ml-auto"
|
||||
>
|
||||
{badge}
|
||||
</Badge>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function NavigationMenu({
|
||||
activeTab,
|
||||
onTabChange,
|
||||
featureToggles,
|
||||
errorCount = 0,
|
||||
}: NavigationMenuProps) {
|
||||
const [expandedGroups, setExpandedGroups] = useState<Set<string>>(
|
||||
new Set(['overview', 'development', 'automation', 'design', 'backend', 'testing', 'tools'])
|
||||
)
|
||||
|
||||
const { preloadRoute, cancelPreload } = useRoutePreload({ delay: 100 })
|
||||
|
||||
const handleItemClick = (value: string) => {
|
||||
onTabChange(value)
|
||||
}
|
||||
|
||||
const handleItemHover = (value: string) => {
|
||||
console.log(`[NAV] 🖱️ Hover detected on: ${value}`)
|
||||
preloadRoute(value)
|
||||
}
|
||||
|
||||
const handleItemLeave = (value: string) => {
|
||||
console.log(`[NAV] 👋 Hover left: ${value}`)
|
||||
cancelPreload(value)
|
||||
}
|
||||
|
||||
const toggleGroup = (groupId: string) => {
|
||||
setExpandedGroups((prev) => {
|
||||
const newSet = new Set(prev)
|
||||
if (newSet.has(groupId)) {
|
||||
newSet.delete(groupId)
|
||||
} else {
|
||||
newSet.add(groupId)
|
||||
}
|
||||
return newSet
|
||||
})
|
||||
}
|
||||
|
||||
const handleExpandAll = () => {
|
||||
const allGroupIds = navigationGroups
|
||||
.filter((group) =>
|
||||
group.items.some((item) => {
|
||||
if (!item.featureKey) return true
|
||||
return featureToggles[item.featureKey]
|
||||
})
|
||||
)
|
||||
.map((group) => group.id)
|
||||
setExpandedGroups(new Set(allGroupIds))
|
||||
}
|
||||
|
||||
const handleCollapseAll = () => {
|
||||
setExpandedGroups(new Set())
|
||||
}
|
||||
|
||||
return (
|
||||
<Sidebar side="left" collapsible="offcanvas">
|
||||
<NavigationMenuHeader
|
||||
onExpandAll={handleExpandAll}
|
||||
onCollapseAll={handleCollapseAll}
|
||||
/>
|
||||
<SidebarContent>
|
||||
<ScrollArea className="h-full px-4">
|
||||
<NavigationMenuGroupList
|
||||
activeTab={activeTab}
|
||||
expandedGroups={expandedGroups}
|
||||
featureToggles={featureToggles}
|
||||
errorCount={errorCount}
|
||||
onToggleGroup={toggleGroup}
|
||||
onItemClick={handleItemClick}
|
||||
onItemHover={handleItemHover}
|
||||
onItemLeave={handleItemLeave}
|
||||
/>
|
||||
</ScrollArea>
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user