Bob AI: Replace the existing navigation bar with a new fixed, floati
This commit is contained in:
55
src/App.tsx
55
src/App.tsx
@@ -5,7 +5,7 @@ import FeaturesLabeledList from '@/components/sections/features/FeaturesLabeledL
|
||||
import FooterSimpleCard from '@/components/sections/footer/FooterSimpleCard';
|
||||
import HeroBrand from '@/components/sections/hero/HeroBrand';
|
||||
import MetricsMinimalCards from '@/components/sections/metrics/MetricsMinimalCards';
|
||||
import NavbarCentered from '@/components/ui/NavbarCentered';
|
||||
import FloatingNav from '@/components/ui/FloatingNav';
|
||||
import PricingLayeredCards from '@/components/sections/pricing/PricingLayeredCards';
|
||||
import SocialProofMarquee from '@/components/sections/social-proof/SocialProofMarquee';
|
||||
import TestimonialRatingCards from '@/components/sections/testimonial/TestimonialRatingCards';
|
||||
@@ -14,33 +14,32 @@ import HeroTrustedBy from '@/components/ui/HeroTrustedBy';
|
||||
export default function App() {
|
||||
return (
|
||||
<>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarCentered
|
||||
logo="TOKYO-MARKETING"
|
||||
navItems={[
|
||||
{
|
||||
name: "About",
|
||||
href: "#about",
|
||||
},
|
||||
{
|
||||
name: "Services",
|
||||
href: "#services",
|
||||
},
|
||||
{
|
||||
name: "Pricing",
|
||||
href: "#pricing",
|
||||
},
|
||||
{
|
||||
name: "Contact",
|
||||
href: "#contact",
|
||||
},
|
||||
]}
|
||||
ctaButton={{
|
||||
text: "Get Started",
|
||||
href: "#contact",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<FloatingNav
|
||||
logo="TOKYO-MARKETING"
|
||||
navItems={[
|
||||
{
|
||||
name: 'About',
|
||||
href: '#about',
|
||||
},
|
||||
{
|
||||
name: 'Services',
|
||||
href: '#services',
|
||||
},
|
||||
{
|
||||
name: 'Pricing',
|
||||
href: '#pricing',
|
||||
},
|
||||
{
|
||||
name: 'Contact',
|
||||
href: '#contact',
|
||||
},
|
||||
]}
|
||||
ctaButton={{
|
||||
text: 'Get Started',
|
||||
href: '#contact',
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
<div id="hero" data-section="hero">
|
||||
<HeroBrand
|
||||
|
||||
85
src/components/ui/FloatingNav.tsx
Normal file
85
src/components/ui/FloatingNav.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useButtonClick } from '@/hooks/useButtonClick';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
|
||||
type NavItem = {
|
||||
name: string;
|
||||
href: string;
|
||||
};
|
||||
|
||||
type CtaButton = {
|
||||
text: string;
|
||||
href: string;
|
||||
};
|
||||
|
||||
type FloatingNavProps = {
|
||||
logo: string;
|
||||
navItems: NavItem[];
|
||||
ctaButton: CtaButton;
|
||||
};
|
||||
|
||||
const NavLink = ({ name, href }: { name: string; href: string }) => {
|
||||
const handleClick = useButtonClick(href);
|
||||
return (
|
||||
<button
|
||||
onClick={handleClick}
|
||||
className="text-sm font-medium text-foreground/80 hover:text-foreground transition-colors"
|
||||
>
|
||||
{name}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default function FloatingNav({ logo, navItems, ctaButton }: FloatingNavProps) {
|
||||
const [visible, setVisible] = useState(true);
|
||||
const [lastScrollY, setLastScrollY] = useState(0);
|
||||
|
||||
const controlNavbar = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
if (window.scrollY > lastScrollY && window.scrollY > 100) {
|
||||
setVisible(false);
|
||||
} else {
|
||||
setVisible(true);
|
||||
}
|
||||
setLastScrollY(window.scrollY);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('scroll', controlNavbar);
|
||||
return () => {
|
||||
window.removeEventListener('scroll', controlNavbar);
|
||||
};
|
||||
}, [lastScrollY]);
|
||||
|
||||
const CtaButtonHandler = useButtonClick(ctaButton.href);
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{visible && (
|
||||
<motion.nav
|
||||
initial={{ y: -100, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
exit={{ y: -100, opacity: 0 }}
|
||||
transition={{ duration: 0.3, ease: 'easeInOut' }}
|
||||
className="fixed top-6 left-1/2 -translate-x-1/2 z-50"
|
||||
>
|
||||
<div className="flex items-center justify-between gap-8 px-4 py-2 border rounded-full border-accent bg-card/80 backdrop-blur-lg">
|
||||
<span className="text-lg font-bold text-foreground">{logo}</span>
|
||||
<div className="hidden md:flex items-center gap-6">
|
||||
{navItems.map((item) => (
|
||||
<NavLink key={item.name} name={item.name} href={item.href} />
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={CtaButtonHandler}
|
||||
className="primary-button px-4 py-2 text-sm font-medium rounded-full text-primary-cta-text"
|
||||
>
|
||||
{ctaButton.text}
|
||||
</button>
|
||||
</div>
|
||||
</motion.nav>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
@@ -141,15 +141,6 @@ body {
|
||||
min-height: 100vh;
|
||||
overscroll-behavior: none;
|
||||
overscroll-behavior-y: none;
|
||||
padding-top: 5rem;
|
||||
}
|
||||
|
||||
#nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
h1,
|
||||
|
||||
Reference in New Issue
Block a user