SPB Git forge

spb/polyllm

Public
15commits 1branches 0releases
2.2 MBsize
maindefault branch
13 days agolast push
TypeScript 97.4% SQL 1% JavaScript 0.9% CSS 0.6%
2.8 KB · 66 lines tsx
Raw Blame History
1"use client";2import * as React from "react";3import { AnimatePresence, motion, useReducedMotion } from "motion/react";4import { Plus } from "lucide-react";5import { cn } from "@/lib/utils";6import { Section, SectionHeading } from "./section";7import { Reveal } from "./reveal";8import { FAQ_ITEMS } from "./mock-data";910export function Faq() {11  const [open, setOpen] = React.useState<number | null>(0);12  const reduce = useReducedMotion();13  return (14    <Section id="faq" tone="subtle">15      <div className="grid gap-10 lg:grid-cols-12">16        <div className="lg:col-span-4">17          <SectionHeading eyebrow="FAQ" title="Questions, answered plainly" description="If yours isn't here, the privacy policy and terms are short and written for humans." />18        </div>19        <Reveal delay={0.1} className="lg:col-span-8">20          <ul className="divide-y divide-border rounded-xl border border-border bg-bg-elevated">21            {FAQ_ITEMS.map((item, i) => {22              const isOpen = open === i;23              const panelId = `faq-panel-${i}`;24              const btnId = `faq-button-${i}`;25              return (26                <li key={item.q}>27                  <h3>28                    <button29                      id={btnId}30                      type="button"31                      aria-expanded={isOpen}32                      aria-controls={panelId}33                      onClick={() => setOpen(isOpen ? null : i)}34                      className="flex w-full items-center justify-between gap-4 px-4 py-4 text-left text-[15px] font-medium transition-colors hover:bg-bg-subtle/60 sm:px-5"35                    >36                      <span>{item.q}</span>37                      <Plus className={cn("size-4 shrink-0 text-fg-subtle transition-transform duration-200", isOpen && "rotate-45")} aria-hidden />38                    </button>39                  </h3>40                  <AnimatePresence initial={false}>41                    {isOpen ? (42                      <motion.div43                        id={panelId}44                        role="region"45                        aria-labelledby={btnId}46                        key="panel"47                        initial={reduce ? false : { height: 0, opacity: 0 }}48                        animate={{ height: "auto", opacity: 1 }}49                        exit={reduce ? undefined : { height: 0, opacity: 0 }}50                        transition={{ duration: 0.24, ease: [0.16, 1, 0.3, 1] }}51                        className="overflow-hidden"52                      >53                        <p className="px-4 pb-5 text-[14.5px] leading-7 text-fg-muted sm:px-5">{item.a}</p>54                      </motion.div>55                    ) : null}56                  </AnimatePresence>57                </li>58              );59            })}60          </ul>61        </Reveal>62      </div>63    </Section>64  );65}66