Skip to content
Merged
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
21 changes: 21 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));

@theme {
--color-background: hsl(var(--background));
--color-foreground: hsl(var(--foreground));
--color-card: hsl(var(--card));
--color-card-foreground: hsl(var(--card-foreground));
--color-popover: hsl(var(--popover));
--color-popover-foreground: hsl(var(--popover-foreground));
--color-primary: hsl(var(--primary));
--color-primary-foreground: hsl(var(--primary-foreground));
--color-secondary: hsl(var(--secondary));
--color-secondary-foreground: hsl(var(--secondary-foreground));
--color-muted: hsl(var(--muted));
--color-muted-foreground: hsl(var(--muted-foreground));
--color-accent: hsl(var(--accent));
--color-accent-foreground: hsl(var(--accent-foreground));
--color-destructive: hsl(var(--destructive));
--color-destructive-foreground: hsl(var(--destructive-foreground));
--color-border: hsl(var(--border));
--color-input: hsl(var(--input));
--color-ring: hsl(var(--ring));
}
@layer base {
:root {
--background: 0 0% 100%;
Expand Down
2 changes: 1 addition & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<html lang="en" className="dark" suppressHydrationWarning>
<html lang="en" className="dark overflow-y-scroll" suppressHydrationWarning>
<body
className="flex min-h-[100dvh] flex-col overflow-x-hidden"
suppressHydrationWarning
Expand Down
322 changes: 246 additions & 76 deletions components/ai/chat-mockup.tsx

Large diffs are not rendered by default.

322 changes: 218 additions & 104 deletions features/landing/ai-demo.tsx

Large diffs are not rendered by default.

316 changes: 170 additions & 146 deletions features/landing/faq.tsx
Original file line number Diff line number Diff line change
@@ -1,167 +1,191 @@
"use client";

import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { ChevronDown } from "lucide-react";

import { landingFaqs } from "@/lib/data/landing";

function FAQItem({
question,
answer,
isOpen,
onClick,
}: {
question: string;
answer: string;
isOpen: boolean;
onClick: () => void;
}) {
return (
<div className="overflow-hidden rounded-2xl border border-border bg-background shadow-sm">
<button
onClick={onClick}
aria-expanded={isOpen}
aria-controls={`faq-answer-${question.replace(/\s+/g, "-")}`}
id={`faq-button-${question.replace(/\s+/g, "-")}`}
className="flex w-full items-center justify-between px-6 py-5 text-left transition-colors hover:bg-muted/30"
>
<span className="pr-6 text-base font-semibold text-foreground md:text-lg">
{question}
</span>

<ChevronDown
className={`h-5 w-5 flex-shrink-0 text-muted-foreground transition-transform duration-300 ${
isOpen ? "rotate-180" : ""
}`}
/>
</button>

<AnimatePresence initial={false}>
{isOpen && (
<motion.div
id={`faq-answer-${question.replace(/\s+/g, "-")}`}
role="region"
aria-labelledby={`faq-button-${question.replace(/\s+/g, "-")}`}
initial={{ height: 0, opacity: 0 }}
animate={{
height: "auto",
opacity: 1,
}}
exit={{
height: 0,
opacity: 0,
}}
transition={{
duration: 0.25,
}}
>
<div className="border-t border-border px-6 py-5">
<p className="leading-8 text-muted-foreground">{answer}</p>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}
import { motion, Variants, AnimatePresence } from "framer-motion";
import {
ChevronDown,
Sparkles,
ArrowRight,
MessageCircleQuestion,
} from "lucide-react";
import { landingFaqs as faqs } from "@/lib/data/landing";
import Link from "next/link";

export default function FAQ() {
const [openIndex, setOpenIndex] = useState<number | null>(0);

const containerVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1,
delayChildren: 0.1,
},
},
};

const itemVariants: Variants = {
hidden: { opacity: 0, y: 30 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.8,
ease: [0.22, 1, 0.36, 1],
},
},
};

return (
<section className="relative overflow-hidden border-b border-border bg-background py-24">
{/* Background Glows - No grid pattern */}
<div className="absolute inset-0 -z-10">
<div className="absolute left-0 top-20 h-[500px] w-[500px] rounded-full bg-blue-500/5 blur-[120px]" />
<div className="absolute right-0 bottom-20 h-[500px] w-[500px] rounded-full bg-indigo-500/5 blur-[120px]" />
<section className="relative flex min-h-[100dvh] flex-col items-center pt-20 pb-16 lg:pt-28 lg:pb-24 overflow-hidden bg-slate-50 dark:bg-[#090e17]">
{/* Premium High-Contrast Background Elements */}
<div className="absolute inset-0 z-0 overflow-hidden pointer-events-none">
{/* Light Mode Blobs - Premium prominent pastel mesh */}
<div className="absolute -left-[10%] top-[20%] h-[600px] w-[600px] rounded-full bg-gradient-to-tr from-cyan-400/15 via-blue-500/10 to-transparent blur-[120px] dark:hidden pointer-events-none" />
<div className="absolute -right-[10%] top-[-10%] h-[600px] w-[600px] rounded-full bg-gradient-to-bl from-fuchsia-400/15 via-purple-500/10 to-transparent blur-[120px] dark:hidden pointer-events-none" />

{/* Dark Mode Blobs */}
<div className="hidden dark:block absolute left-[20%] top-[-10%] h-[500px] w-[500px] rounded-full bg-blue-600/10 blur-[120px]" />
</div>

<div className="mx-auto max-w-5xl px-6 lg:px-8">
{/* Header */}
<div className="relative z-10 w-full mx-auto max-w-[800px] px-6 lg:px-8">
<motion.div
initial={{ opacity: 0, y: 24 }}
whileInView={{
opacity: 1,
y: 0,
}}
transition={{ duration: 0.5 }}
viewport={{ once: true }}
className="mx-auto mb-16 text-center"
variants={containerVariants}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-50px" }}
className="flex flex-col items-center"
>
<span className="inline-flex rounded-full border border-blue-200/60 bg-blue-50/80 px-4 py-2 text-sm font-semibold text-[#1D4ED8] shadow-sm backdrop-blur-md dark:border-blue-500/20 dark:bg-blue-500/10 dark:text-blue-400">
Frequently Asked Questions
</span>

<h2 className="mt-6 text-4xl font-extrabold tracking-tight text-foreground md:text-5xl">
Got Questions?
</h2>
{/* Header */}
<div className="mx-auto mb-10 lg:mb-14 text-center font-sans">
<motion.div variants={itemVariants}>
<div className="mb-5 inline-flex items-center rounded-full border border-indigo-100 bg-indigo-50 py-[6px] pl-[12px] pr-[16px] shadow-sm dark:bg-[rgba(99,102,241,0.05)] dark:border-indigo-400/20 dark:backdrop-blur-md">
<Sparkles className="mr-2 h-4 w-4 text-indigo-600 dark:text-indigo-400" />
<span className="text-[12px] font-[700] tracking-[0.06em] uppercase text-indigo-700 dark:text-indigo-300">
Common Questions
</span>
</div>
</motion.div>

<p className="mt-6 text-lg leading-relaxed text-muted-foreground">
Everything you need to know about Hyper Learning, AI-powered
learning, syllabus mapping, and exam preparation.
</p>
</motion.div>
<motion.h2
variants={itemVariants}
className="text-[36px] md:text-[48px] lg:text-[56px] font-[900] leading-[1.05] tracking-[-0.03em] text-slate-900 dark:text-white drop-shadow-sm dark:drop-shadow-none"
>
Everything You Need
<br />
<span className="text-blue-600 dark:bg-gradient-to-r dark:from-blue-400 dark:via-indigo-400 dark:to-purple-400 dark:bg-clip-text dark:text-transparent">
To Know
</span>
</motion.h2>

{/* FAQ List */}
<div className="space-y-4">
{landingFaqs.map((faq, index) => (
<motion.div
key={faq.question}
initial={{
opacity: 0,
y: 20,
}}
whileInView={{
opacity: 1,
y: 0,
}}
transition={{
duration: 0.4,
delay: index * 0.05,
}}
viewport={{ once: true }}
<motion.p
variants={itemVariants}
className="mt-5 max-w-[540px] mx-auto text-[15px] md:text-[16px] leading-[1.7] font-[500] text-slate-600 dark:text-slate-300"
>
<FAQItem
question={faq.question}
answer={faq.answer}
isOpen={openIndex === index}
onClick={() => setOpenIndex(openIndex === index ? null : index)}
/>
</motion.div>
))}
</div>
Have questions about how Hyper Learning works? Check out our most
frequently asked questions below.
</motion.p>
</div>

{/* Bottom CTA */}
<motion.div
initial={{
opacity: 0,
y: 24,
}}
whileInView={{
opacity: 1,
y: 0,
}}
transition={{
duration: 0.5,
delay: 0.1,
}}
viewport={{ once: true }}
className="mt-16 rounded-3xl border border-border bg-background/80 p-8 text-center shadow-lg backdrop-blur-sm"
>
<h3 className="text-2xl font-bold text-foreground">
Still Have Questions?
</h3>
{/* FAQ Accordions - Ultra Premium Unified Card */}
<motion.div
variants={itemVariants}
className="w-full relative group/card"
>
{/* Soft backdrop glow */}
<div className="absolute -inset-1 rounded-[28px] bg-gradient-to-b from-slate-200/50 to-slate-100/10 opacity-50 blur-xl transition duration-500 group-hover/card:opacity-100 dark:from-white/10 dark:to-transparent" />

<p className="mt-4 text-muted-foreground">
Reach out through our contact page or use the AI assistant to get
help with your learning journey.
</p>
<div className="relative w-full overflow-hidden rounded-[24px] border border-transparent bg-white shadow-[0_8px_30px_rgb(0,0,0,0.12)] dark:border-white/[0.08] dark:bg-[#0f172a]/60 dark:shadow-[inset_0_1px_1px_rgba(255,255,255,0.05)] dark:backdrop-blur-2xl">
<div className="divide-y divide-slate-100 dark:divide-white/10">
{faqs.map((faq, index) => {
const isOpen = openIndex === index;
return (
<div
key={index}
className={`transition-colors duration-500 ease-out ${isOpen ? "bg-slate-50/50 dark:bg-white/[0.03]" : "hover:bg-slate-50/50 dark:hover:bg-white/[0.02]"}`}
>
<button
onClick={() => setOpenIndex(isOpen ? null : index)}
className="flex w-full items-center justify-between px-5 py-4 md:px-8 md:py-7 text-left outline-none group"
>
<span
className={`text-[15px] md:text-[17px] font-[600] tracking-tight transition-colors duration-300 ${
isOpen
? "text-[#3B82F6] dark:text-blue-400"
: "text-slate-900 group-hover:text-blue-600 dark:text-white dark:group-hover:text-blue-400"
}`}
>
{faq.question}
</span>
<div
className={`ml-4 md:ml-6 flex h-8 w-8 md:h-9 md:w-9 shrink-0 items-center justify-center rounded-full transition-all duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] ${
isOpen
? "bg-blue-100 text-[#3B82F6] shadow-sm dark:bg-blue-500/20 dark:text-blue-400"
: "bg-slate-100 text-slate-400 group-hover:bg-blue-50 group-hover:text-blue-500 group-hover:scale-110 dark:bg-white/5 dark:text-slate-500 dark:group-hover:bg-white/10"
}`}
>
<ChevronDown
className={`h-4 w-4 transition-transform duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] ${
isOpen ? "rotate-180" : ""
}`}
/>
</div>
</button>

<div className="mt-6 inline-flex rounded-xl border border-blue-200/60 bg-blue-50/80 px-5 py-3 text-sm font-semibold text-[#1D4ED8] shadow-sm backdrop-blur-md dark:border-blue-500/20 dark:bg-blue-500/10 dark:text-blue-400">
We&apos;re continuously improving Hyper Learning based on student
feedback.
</div>
<AnimatePresence initial={false}>
{isOpen && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: "auto", opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{
duration: 0.4,
ease: [0.22, 1, 0.36, 1],
}}
>
<div className="px-5 pb-5 pt-0 md:px-8 md:pb-8 text-[14px] md:text-[15px] leading-[1.6] md:leading-[1.75] font-[500] text-slate-600 dark:text-slate-400">
{faq.answer}
</div>
</motion.div>
)}
</AnimatePresence>
</div>
);
})}
</div>
</div>
</motion.div>

{/* Still Have Questions CTA */}
<motion.div
variants={itemVariants}
className="mt-12 w-full max-w-[800px] overflow-hidden rounded-[24px] border border-transparent bg-white p-8 text-center shadow-[0_8px_30px_rgb(0,0,0,0.12)] transition-all duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)] hover:scale-[1.02] hover:-translate-y-2 hover:border-indigo-400/50 hover:bg-white hover:shadow-[0_30px_60px_-12px_rgba(99,102,241,0.25)] dark:border-white/[0.08] dark:bg-[#0f172a]/60 dark:hover:border-indigo-500/[0.5] dark:hover:bg-[#1e293b]/80 md:p-10"
>
<div className="mx-auto mb-5 inline-flex h-14 w-14 items-center justify-center rounded-[16px] bg-[#3B82F6] text-white shadow-lg shadow-blue-500/25 dark:bg-gradient-to-br dark:from-white/10 dark:to-white/5 dark:shadow-[inset_0_1px_1px_rgba(255,255,255,0.1)] dark:border dark:border-white/10">
<MessageCircleQuestion className="h-6 w-6" />
</div>
<h3 className="text-[20px] font-[800] tracking-tight text-slate-900 dark:text-white">
Still have questions?
</h3>
<p className="mt-2 text-[15px] font-[500] text-slate-600 dark:text-slate-400">
Can&apos;t find the answer you&apos;re looking for? Please chat to
our friendly team.
</p>
<div className="mt-8 flex flex-col items-center justify-center gap-4 sm:flex-row">
<Link href="/contact">
<button className="inline-flex h-12 w-full sm:w-auto items-center justify-center rounded-full bg-[#3B82F6] px-8 text-[14px] font-[700] text-white shadow-md shadow-blue-500/20 transition-all hover:scale-105 hover:bg-blue-600 hover:shadow-lg hover:shadow-blue-500/30 dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100">
Contact Support
</button>
</Link>
<Link href="/auth/signup">
<button className="group inline-flex h-12 w-full sm:w-auto items-center justify-center rounded-full border border-slate-200 bg-white px-8 text-[14px] font-[700] text-slate-900 shadow-sm transition-all hover:bg-slate-50 hover:border-slate-300 dark:border-white/[0.15] dark:bg-transparent dark:text-white dark:hover:bg-white/5">
Get Started Free
<ArrowRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
</button>
</Link>
</div>
</motion.div>
</motion.div>
</div>
</section>
Expand Down
Loading
Loading