Skip to content

Commit 705860d

Browse files
committed
fix: simplify Product submenu to single menu with indented sub-pages
- Create single submenu structure with all items visible at once - Main categories (Principles, Guidelines, Resources) are unindented - Sub-pages (UX Patterns, Visual Patterns, Workflow & Rituals) are indented under Guidelines - No additional user action required to access sub-pages - Visual hierarchy: - Main categories: text-foreground color, no indentation - Sub-pages: text-muted-foreground color, pl-8 indentation (desktop), ml-4 (mobile) - Clear visual distinction between main and sub items - Simplified navigation: - Single hover/click action opens entire submenu - All items accessible without nested interactions - Consistent behavior across desktop and mobile - Removed complex nested submenu logic - Clean code structure: - Removed unused isGuidelinesSubmenuOpen state - Simplified submenu rendering logic - Added isIndented flag for easy styling control - Maintained proper z-index layering (z-[60])
1 parent 205195b commit 705860d

File tree

1 file changed

+38
-140
lines changed

1 file changed

+38
-140
lines changed

src/components/layout/Header.tsx

Lines changed: 38 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import Logo from './Logo';
1111
const Header = () => {
1212
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
1313
const [isProductSubmenuOpen, setIsProductSubmenuOpen] = useState(false);
14-
const [isGuidelinesSubmenuOpen, setIsGuidelinesSubmenuOpen] = useState(false);
1514
const { t } = useLanguage();
1615
const router = useRouter();
1716

@@ -25,16 +24,10 @@ const Header = () => {
2524
hasSubmenu: true,
2625
submenuItems: [
2726
{ name: t('product.sections.principles'), href: '/product#principles' },
28-
{
29-
name: t('product.sections.guidelines'),
30-
href: '/product#guidelines',
31-
hasSubmenu: true,
32-
submenuItems: [
33-
{ name: 'UX Patterns', href: '/product/UX-patterns' },
34-
{ name: 'Visual Patterns', href: '/product/visual-patterns' },
35-
{ name: 'Workflow & Rituals', href: '/product/workflow-rituals' },
36-
]
37-
},
27+
{ name: t('product.sections.guidelines'), href: '/product#guidelines' },
28+
{ name: 'UX Patterns', href: '/product/UX-patterns', isIndented: true },
29+
{ name: 'Visual Patterns', href: '/product/visual-patterns', isIndented: true },
30+
{ name: 'Workflow & Rituals', href: '/product/workflow-rituals', isIndented: true },
3831
{ name: t('product.sections.resources'), href: '/product#resources' },
3932
]
4033
},
@@ -90,74 +83,23 @@ const Header = () => {
9083
>
9184
<div className="py-2">
9285
{item.submenuItems?.map((subItem, subIndex) => (
93-
<div key={subItem.name} className="relative">
94-
{subItem.hasSubmenu ? (
95-
<div
96-
onMouseEnter={() => setIsGuidelinesSubmenuOpen(true)}
97-
onMouseLeave={() => setIsGuidelinesSubmenuOpen(false)}
98-
className="relative"
99-
>
100-
<motion.button
101-
whileHover={{ x: 4 }}
102-
onClick={() => {
103-
router.push(subItem.href);
104-
setIsProductSubmenuOpen(false);
105-
}}
106-
className="w-full flex items-center justify-between px-4 py-3 text-left hover:bg-accent transition-colors"
107-
>
108-
<span className="font-medium text-foreground">
109-
{subItem.name}
110-
</span>
111-
<ChevronDown className={`w-4 h-4 transition-transform duration-200 ${isGuidelinesSubmenuOpen ? 'rotate-180' : ''}`} />
112-
</motion.button>
113-
114-
{/* Guidelines Submenu */}
115-
<AnimatePresence>
116-
{isGuidelinesSubmenuOpen && (
117-
<motion.div
118-
initial={{ opacity: 0, x: 10 }}
119-
animate={{ opacity: 1, x: 0 }}
120-
exit={{ opacity: 0, x: 10 }}
121-
transition={{ duration: 0.2 }}
122-
className="absolute top-0 left-full ml-2 w-56 bg-background/98 backdrop-blur-sm border border-border rounded-lg shadow-xl z-[70]"
123-
>
124-
<div className="py-2">
125-
{subItem.submenuItems?.map((guidelineItem, guidelineIndex) => (
126-
<motion.button
127-
key={guidelineItem.name}
128-
whileHover={{ x: 4 }}
129-
onClick={() => {
130-
router.push(guidelineItem.href);
131-
setIsProductSubmenuOpen(false);
132-
setIsGuidelinesSubmenuOpen(false);
133-
}}
134-
className="w-full flex items-center px-4 py-3 text-left hover:bg-accent transition-colors"
135-
>
136-
<span className="font-medium text-muted-foreground pl-4">
137-
{guidelineItem.name}
138-
</span>
139-
</motion.button>
140-
))}
141-
</div>
142-
</motion.div>
143-
)}
144-
</AnimatePresence>
145-
</div>
146-
) : (
147-
<motion.button
148-
whileHover={{ x: 4 }}
149-
onClick={() => {
150-
router.push(subItem.href);
151-
setIsProductSubmenuOpen(false);
152-
}}
153-
className="w-full flex items-center px-4 py-3 text-left hover:bg-accent transition-colors"
154-
>
155-
<span className="font-medium text-foreground">
156-
{subItem.name}
157-
</span>
158-
</motion.button>
159-
)}
160-
</div>
86+
<motion.button
87+
key={subItem.name}
88+
whileHover={{ x: 4 }}
89+
onClick={() => {
90+
router.push(subItem.href);
91+
setIsProductSubmenuOpen(false);
92+
}}
93+
className={`w-full flex items-center px-4 py-3 text-left hover:bg-accent transition-colors ${
94+
subItem.isIndented ? 'pl-8' : ''
95+
}`}
96+
>
97+
<span className={`font-medium ${
98+
subItem.isIndented ? 'text-muted-foreground' : 'text-foreground'
99+
}`}>
100+
{subItem.name}
101+
</span>
102+
</motion.button>
161103
))}
162104
</div>
163105
</motion.div>
@@ -235,67 +177,23 @@ const Header = () => {
235177
>
236178
<div className="ml-6 space-y-1">
237179
{item.submenuItems?.map((subItem, subIndex) => (
238-
<div key={subItem.name}>
239-
{subItem.hasSubmenu ? (
240-
<div>
241-
<motion.button
242-
onClick={() => {
243-
setIsGuidelinesSubmenuOpen(!isGuidelinesSubmenuOpen);
244-
}}
245-
className="flex items-center justify-between w-full px-4 py-2 rounded-lg hover:bg-accent transition-colors cursor-pointer text-left"
246-
>
247-
<span className="font-medium text-sm text-foreground">
248-
{subItem.name}
249-
</span>
250-
<ChevronDown className={`w-4 h-4 transition-transform duration-200 ${isGuidelinesSubmenuOpen ? 'rotate-180' : ''}`} />
251-
</motion.button>
252-
253-
<AnimatePresence>
254-
{isGuidelinesSubmenuOpen && (
255-
<motion.div
256-
initial={{ opacity: 0, height: 0 }}
257-
animate={{ opacity: 1, height: 'auto' }}
258-
exit={{ opacity: 0, height: 0 }}
259-
transition={{ duration: 0.2 }}
260-
className="overflow-hidden"
261-
>
262-
<div className="ml-6 space-y-1">
263-
{subItem.submenuItems?.map((guidelineItem, guidelineIndex) => (
264-
<motion.button
265-
key={guidelineItem.name}
266-
onClick={() => {
267-
setIsMobileMenuOpen(false);
268-
setIsProductSubmenuOpen(false);
269-
setIsGuidelinesSubmenuOpen(false);
270-
router.push(guidelineItem.href);
271-
}}
272-
className="flex items-center px-4 py-2 rounded-lg hover:bg-accent transition-colors cursor-pointer w-full text-left"
273-
>
274-
<span className="font-medium text-sm text-muted-foreground">
275-
{guidelineItem.name}
276-
</span>
277-
</motion.button>
278-
))}
279-
</div>
280-
</motion.div>
281-
)}
282-
</AnimatePresence>
283-
</div>
284-
) : (
285-
<motion.button
286-
onClick={() => {
287-
setIsMobileMenuOpen(false);
288-
setIsProductSubmenuOpen(false);
289-
router.push(subItem.href);
290-
}}
291-
className="flex items-center px-4 py-2 rounded-lg hover:bg-accent transition-colors cursor-pointer w-full text-left"
292-
>
293-
<span className="font-medium text-sm text-foreground">
294-
{subItem.name}
295-
</span>
296-
</motion.button>
297-
)}
298-
</div>
180+
<motion.button
181+
key={subItem.name}
182+
onClick={() => {
183+
setIsMobileMenuOpen(false);
184+
setIsProductSubmenuOpen(false);
185+
router.push(subItem.href);
186+
}}
187+
className={`flex items-center px-4 py-2 rounded-lg hover:bg-accent transition-colors cursor-pointer w-full text-left ${
188+
subItem.isIndented ? 'ml-4' : ''
189+
}`}
190+
>
191+
<span className={`font-medium text-sm ${
192+
subItem.isIndented ? 'text-muted-foreground' : 'text-foreground'
193+
}`}>
194+
{subItem.name}
195+
</span>
196+
</motion.button>
299197
))}
300198
</div>
301199
</motion.div>

0 commit comments

Comments
 (0)