Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions apps/web/src/components/faq/FaqSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,26 @@ export function FaqSection() {
className="w-[30px] lg:w-[50px] absolute right-0 top-0"
/>


<div className="max-w-4xl mx-auto">
<Accordion type="single" collapsible className="w-full space-y-4">
{faqs.map((faq, index) => (
<AccordionItem
value={`item-${index}`}
key={index}
className="border border-[#252525] rounded-lg bg-[#151515]/20 backdrop-blur-xl overflow-hidden"
>
<AccordionTrigger className="px-6 py-4 text-left text-base lg:text-lg font-medium hover:bg-[#252525]/30 transition-colors [&[data-state=open]]:bg-[#252525]/50">
{faq.question}
</AccordionTrigger>
<AccordionContent className="px-6 pb-4 text-[#d1d1d1] text-sm lg:text-base leading-relaxed">
{faq.answer}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
<Accordion type="single" collapsible className="w-full space-y-4">
{faqs.map((faq, index) => (
<AccordionItem
value={`item-${index}`}
key={index}
className="border border-border rounded-lg bg-background/20 backdrop-blur-xl overflow-hidden"
>
<AccordionTrigger className="px-6 py-4 text-left text-base lg:text-lg font-medium hover:bg-background.hover transition-colors [&[data-state=open]]:bg-background.hover/50">
{faq.question}
</AccordionTrigger>

<AccordionContent className="p-3 sm:p-4 lg:p-6 text-text.tertiary text-sm lg:text-base leading-relaxed">
{faq.answer}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
</div>
</div>
);
Expand Down
82 changes: 73 additions & 9 deletions apps/web/src/components/landing-sections/navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client";
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import PrimaryButton from "../ui/custom-button";
import { motion, useScroll, useMotionValueEvent } from "framer-motion";
import Image from "next/image";
Expand All @@ -15,6 +15,7 @@ const Navbar = () => {
const isPricingPage = pathname === "/pricing";
const [showNavbar, setShowNavbar] = useState(isPricingPage ? true : false);
const [isOpen, setIsOpen] = useState(false);
const [activeSection, setActiveSection] = useState("");
const { trackButtonClick, trackLinkClick } = useAnalytics();

const handleGetStartedClick = (location: "navbar" | "mobile_menu") => {
Expand All @@ -30,18 +31,19 @@ const Navbar = () => {
);
};

React.useEffect(() => {
// Close mobile menu on Escape
useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === "Escape" && isOpen) {
setIsOpen(false);
(document.activeElement as HTMLElement)?.blur();
}
};

document.addEventListener("keydown", handleEscape);
return () => document.removeEventListener("keydown", handleEscape);
}, [isOpen]);

// Show navbar when scrolling down (except on Pricing page)
useMotionValueEvent(scrollYProgress, "change", (latest) => {
if (!isPricingPage) {
setShowNavbar(latest > 0);
Expand All @@ -53,23 +55,67 @@ const Navbar = () => {
{ name: "Features", href: "/#features" },
{ name: "Demo", href: "/#demo" },
{ name: "How it works", href: "/#HIW" },
{ name: "FAQ", href: "/#faq" },
{ name: "Stats", href: "/#Stats" },
{ name: "Contact", href: "/#Contact" },
{ name: "FAQ", href: "/#faq" },

];


// scroll spy to highlight active section
useEffect(() => {
const sectionIds = links
.filter((link) => link.href.startsWith("/#"))
.map((link) => link.href.replace("/#", ""));

const handleIntersect = (entries: IntersectionObserverEntry[]) => {
// Filter for intersecting sections
const visibleEntries = entries.filter(entry => entry.isIntersecting);

if (visibleEntries.length > 0) {
// Find the section with highest visibility
let mostVisibleEntry = visibleEntries[0];

for (const entry of visibleEntries) {
if (entry.intersectionRatio > mostVisibleEntry.intersectionRatio) {
mostVisibleEntry = entry;
}
}

// Update active section if target has an id
if (mostVisibleEntry.target.id) {
setActiveSection(mostVisibleEntry.target.id);
}
}
};

const observer = new IntersectionObserver(handleIntersect, {
root: null,
rootMargin: "0px",
threshold: 0.5,
});

sectionIds.forEach((id) => {
const el = document.getElementById(id);
if (el) observer.observe(el);
});

return () => observer.disconnect();
}, [links]);

return (
<motion.nav
initial={{ opacity: 0 }}
animate={showNavbar ? { opacity: 1 } : { opacity: 0, display: "none" }}
transition={{ duration: 0.3 }}
className={cn(
" z-40 flex items-center justify-between px-4 py-3 bg-neutral-900/5 backdrop-blur-xl border-white/10",
"z-40 flex items-center justify-between px-4 py-3 bg-neutral-900/5 backdrop-blur-xl border-white/10",
isPricingPage
? "relative h-max md:w-full top-0 border-b"
: "fixed rounded-3xl top-4 border w-[94%] md:w-[80%] mx-auto left-1/2 -translate-x-1/2"
)}
>
{/* Left: Logo + Menu */}
<div className="flex items-center gap-3">
<button
className="min-[1115px]:hidden text-white"
Expand All @@ -91,23 +137,39 @@ const Navbar = () => {
<span>Opensox AI</span>
</div>
</div>

{/* Center: Desktop Links */}
<div className="hidden min-[1115px]:flex items-center gap-5 max-[1270px]:gap-4 max-[1173px]:gap-3 tracking-tight text-lg max-[1270px]:text-base max-[1173px]:text-sm font-light max-[1173px]:font-normal text-[#d1d1d1]">
{links.map((link, index) => {
const isActive = pathname === link.href;
const isActive =
pathname === link.href ||
(link.href.startsWith("/#") &&
activeSection === link.href.replace("/#", ""));

return (
<Link
key={index}
href={link.href}
className={cn(
"cursor-pointer hover:text-white",
isActive && "text-white"
"relative cursor-pointer hover:text-white transition-colors duration-300",
isActive && "text-white font-medium"
)}
>
{link.name}

{isActive && (
<motion.span
layoutId="underline"
className="absolute left-0 right-0 bottom-0 mx-auto w-[55%] h-[2px] bg-brand-purple rounded-full"
transition={{ type: "spring", stiffness: 300, damping: 25 }}
/>
)}
</Link>
);
})}
</div>

{/* Right: Buttons */}
<div className="flex items-center gap-3">
<Link
href="https://github.com/apsinghdev/opensox"
Expand All @@ -130,6 +192,8 @@ const Navbar = () => {
</PrimaryButton>
</Link>
</div>

{/* Mobile Menu */}
{isOpen && (
<motion.div
initial={{ opacity: 0, y: -10 }}
Expand Down Expand Up @@ -166,4 +230,4 @@ const Navbar = () => {
);
};

export default Navbar;
export default Navbar;