Skip to content

Commit 38d8a4a

Browse files
catomeanclaude
andcommitted
refactor: improve navigation architecture and add knowledge center
- Create useScrollNavigation hook for shared scroll logic (DRY) - Add centralized navigation color config (SSOT) - Convert components to named exports (Header, Footer, Navigation, MegaMenu) - Fix dropdown overlay positioning with Portal pattern - Add consulting section to homepage - Create Knowledge Center page with guides and FAQ - Add Knowledge menu item to navigation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 1f558d2 commit 38d8a4a

15 files changed

Lines changed: 764 additions & 183 deletions

File tree

app/bots/BotNavigation.tsx

Lines changed: 26 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,30 @@
11
'use client';
22

3-
import React, { useState, useEffect, Fragment } from 'react';
3+
import React, { useState, Fragment } from 'react';
44
import Link from 'next/link';
55
import type { Route } from 'next';
6-
import { usePathname } from 'next/navigation';
76
import { Dialog, Transition } from '@headlessui/react';
87
import { BotSwitcher, SiteMenuDropdown } from '@/components/navigation';
98
import { menuItems } from '@/data/menuItems';
10-
11-
interface MenuItem {
12-
id: string;
13-
label: string;
14-
icon?: string;
15-
section?: string;
16-
}
9+
import { useScrollNavigation, getNavColors } from '@/lib/hooks';
10+
import type { BotMenuItem } from '@/types/bot';
1711

1812
interface BotNavigationProps {
1913
botSlug: string;
2014
botTitle: string;
2115
botEmoji: string;
2216
botDescription?: string;
2317
accentColor?: string;
24-
menuItems: MenuItem[];
18+
menuItems: BotMenuItem[];
2519
chatLink?: string;
2620
sections?: boolean;
2721
}
2822

2923
/**
3024
* Reusable navigation component for bot detail pages
25+
* Uses shared scroll navigation hook and centralized color config
3126
*/
32-
const BotNavigation: React.FC<BotNavigationProps> = ({
27+
export const BotNavigation: React.FC<BotNavigationProps> = ({
3328
botSlug,
3429
botTitle,
3530
botEmoji,
@@ -39,111 +34,28 @@ const BotNavigation: React.FC<BotNavigationProps> = ({
3934
chatLink,
4035
sections = true,
4136
}) => {
42-
const _pathname = usePathname();
43-
const [activeSection, setActiveSection] = useState('');
44-
const [lastScrollY, setLastScrollY] = useState(0);
4537
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
4638

39+
// Use shared scroll navigation hook
40+
const { activeSection, isScrolled, scrollToSection } = useScrollNavigation({
41+
menuItems: sectionMenuItems,
42+
scrollOffset: 300,
43+
enabled: sections,
44+
});
45+
4746
// Filter site nav items (exclude button items like "Contact Us")
4847
const siteNavItems = menuItems.filter(item => !item.isButton);
4948

50-
// Handle scroll events to highlight active section
51-
useEffect(() => {
52-
const handleScroll = () => {
53-
const currentScrollY = window.scrollY;
54-
55-
// Determine active section when sections are enabled
56-
if (sections) {
57-
const sectionIds = sectionMenuItems
58-
.filter(item => item.section)
59-
.map(item => item.section as string);
60-
61-
// Find which section is currently in view
62-
const sectionElements = sectionIds
63-
.map(id => document.getElementById(id))
64-
.filter(Boolean);
65-
66-
for (let i = sectionElements.length - 1; i >= 0; i--) {
67-
const section = sectionElements[i];
68-
if (section && section.getBoundingClientRect().top <= 300) {
69-
setActiveSection(section.id);
70-
break;
71-
}
72-
}
73-
}
74-
75-
setLastScrollY(currentScrollY);
76-
};
77-
78-
window.addEventListener('scroll', handleScroll, { passive: true });
79-
handleScroll(); // Initial check
80-
81-
return () => window.removeEventListener('scroll', handleScroll);
82-
}, [lastScrollY, sectionMenuItems, sections]);
83-
84-
// Handle smooth scrolling when clicking a menu item
85-
const scrollToSection = (sectionId: string | undefined) => {
86-
if (!sectionId) return;
87-
88-
const element = document.getElementById(sectionId);
89-
if (element) {
90-
window.scrollTo({
91-
top: element.offsetTop - 100,
92-
behavior: 'smooth',
93-
});
94-
setActiveSection(sectionId);
95-
// Close mobile menu after clicking
96-
setIsMobileMenuOpen(false);
97-
}
98-
};
99-
100-
const colorClasses = {
101-
blue: {
102-
logo: 'bg-blue-100',
103-
title: 'text-blue-900',
104-
active: 'text-blue-700 bg-blue-50',
105-
hover: 'hover:text-blue-700 hover:bg-blue-50',
106-
accent: 'bg-blue-600 hover:bg-blue-700',
107-
border: 'border-blue-300',
108-
},
109-
green: {
110-
logo: 'bg-green-100',
111-
title: 'text-green-900',
112-
active: 'text-green-700 bg-green-50',
113-
hover: 'hover:text-green-700 hover:bg-green-50',
114-
accent: 'bg-green-600 hover:bg-green-700',
115-
border: 'border-green-300',
116-
},
117-
indigo: {
118-
logo: 'bg-indigo-100',
119-
title: 'text-indigo-900',
120-
active: 'text-indigo-700 bg-indigo-50',
121-
hover: 'hover:text-indigo-700 hover:bg-indigo-50',
122-
accent: 'bg-indigo-600 hover:bg-indigo-700',
123-
border: 'border-indigo-300',
124-
},
125-
red: {
126-
logo: 'bg-red-100',
127-
title: 'text-red-900',
128-
active: 'text-red-700 bg-red-50',
129-
hover: 'hover:text-red-700 hover:bg-red-50',
130-
accent: 'bg-red-600 hover:bg-red-700',
131-
border: 'border-red-300',
132-
},
133-
amber: {
134-
logo: 'bg-amber-100',
135-
title: 'text-amber-900',
136-
active: 'text-amber-700 bg-amber-50',
137-
hover: 'hover:text-amber-700 hover:bg-amber-50',
138-
accent: 'bg-amber-600 hover:bg-amber-700',
139-
border: 'border-amber-300',
140-
},
49+
// Handle scroll to section with mobile menu close
50+
const handleScrollToSection = (sectionId: string | undefined) => {
51+
scrollToSection(sectionId);
52+
setIsMobileMenuOpen(false);
14153
};
14254

143-
// Get the appropriate color classes or default to blue
144-
const colors = colorClasses[accentColor as keyof typeof colorClasses] || colorClasses.blue;
55+
// Get color classes from centralized config
56+
const colors = getNavColors(accentColor);
14557

146-
const navClasses = lastScrollY > 100
58+
const navClasses = isScrolled
14759
? 'bg-white shadow-md border-b border-gray-200'
14860
: 'bg-white border-b border-gray-200';
14961

@@ -152,9 +64,9 @@ const BotNavigation: React.FC<BotNavigationProps> = ({
15264
className={`transition-all duration-300 w-full py-3 fixed top-0 left-0 right-0 z-50 ${navClasses}`}
15365
>
15466
<div className="max-w-screen-xl mx-auto px-4 sm:px-6">
155-
<div className="flex justify-between items-center">
67+
<div className="flex justify-between items-center h-12">
15668
{/* Left side: Botsmann logo + divider + Bot Switcher */}
157-
<div className="flex items-center">
69+
<div className="flex items-center h-full">
15870
{/* Botsmann 'B' logo - links to home */}
15971
<Link
16072
href="/"
@@ -181,7 +93,7 @@ const BotNavigation: React.FC<BotNavigationProps> = ({
18193
{sectionMenuItems.map(item => (
18294
<button
18395
key={item.id}
184-
onClick={() => scrollToSection(item.section)}
96+
onClick={() => handleScrollToSection(item.section)}
18597
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap flex items-center ${
18698
activeSection === item.section
18799
? colors.active
@@ -333,7 +245,7 @@ const BotNavigation: React.FC<BotNavigationProps> = ({
333245
{sectionMenuItems.map(item => (
334246
<button
335247
key={item.id}
336-
onClick={() => scrollToSection(item.section)}
248+
onClick={() => handleScrollToSection(item.section)}
337249
className={`w-full text-left flex items-center px-3 py-2 rounded-md text-base font-medium transition-colors ${
338250
activeSection === item.section
339251
? colors.active
@@ -371,4 +283,6 @@ const BotNavigation: React.FC<BotNavigationProps> = ({
371283
);
372284
};
373285

286+
// Named export for consistency with best practices
287+
// Default export kept for backwards compatibility with existing imports
374288
export default BotNavigation;

app/bots/product-manager/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import Header from '@/components/Header';
2+
import { Header } from '@/components/Header';
33

44
/**
55
* Layout for the Product Manager Bot pages.

0 commit comments

Comments
 (0)