shadimage

FAQ

src/components/thegridcn/faq.tsx

"use client";

import * as React from "react";
import { cn } from "@/lib/utils";

interface FAQItem {
  answer: string;
  question: string;
}

interface FAQProps extends React.HTMLAttributes<HTMLDivElement> {
  items: FAQItem[];
  label?: string;
  /** Allow multiple items open at once */
  multiple?: boolean;
}

export function FAQ({
  items,
  label,
  multiple = false,
  className,
  ...props
}: FAQProps) {
  const [openItems, setOpenItems] = React.useState<Set<number>>(new Set());

  function toggle(idx: number) {
    setOpenItems((prev) => {
      const next = new Set(multiple ? prev : []);
      if (prev.has(idx)) {
        next.delete(idx);
      } else {
        next.add(idx);
      }
      return next;
    });
  }

  return (
    <div
      data-slot="tron-faq"
      className={cn(
        "relative overflow-hidden rounded border border-primary/30 bg-card/80 backdrop-blur-sm",
        className
      )}
      {...props}
    >
      {/* Scanline overlay */}
      <div className="pointer-events-none absolute inset-0 bg-[repeating-linear-gradient(0deg,transparent,transparent_2px,rgba(0,0,0,0.03)_2px,rgba(0,0,0,0.03)_4px)]" />

      {label ? (
        <div className="border-primary/20 border-b px-5 py-3 text-[10px] text-foreground/50 uppercase tracking-widest">
          {label}
        </div>
      ) : null}

      <div className="relative divide-y divide-primary/10">
        {items.map((item, i) => {
          const isOpen = openItems.has(i);
          return (
            <div key={i}>
              <button
                type="button"
                onClick={() => toggle(i)}
                className="flex w-full items-center gap-3 px-5 py-4 text-left transition-colors hover:bg-primary/5"
              >
                {/* Animated plus/minus icon */}
                <span className="relative flex h-4 w-4 shrink-0 items-center justify-center">
                  <span className="absolute h-px w-3 bg-primary/60 transition-transform" />
                  <span
                    className={cn(
                      "absolute h-3 w-px bg-primary/60 transition-transform duration-200",
                      isOpen && "rotate-90 opacity-0"
                    )}
                  />
                </span>
                <span className="font-mono text-foreground/90 text-sm">
                  {item.question}
                </span>
              </button>

              {/* Answer with slide animation */}
              <div
                className={cn(
                  "grid transition-all duration-300 ease-in-out",
                  isOpen
                    ? "grid-rows-[1fr] opacity-100"
                    : "grid-rows-[0fr] opacity-0"
                )}
              >
                <div className="overflow-hidden">
                  <div className="px-5 pb-4 pl-12 text-foreground/50 text-xs leading-relaxed">
                    {item.answer}
                  </div>
                </div>
              </div>
            </div>
          );
        })}
      </div>

      {/* Corner decorations */}
      <div className="pointer-events-none absolute top-0 left-0 h-3 w-3 border-primary/50 border-t-2 border-l-2" />
      <div className="pointer-events-none absolute top-0 right-0 h-3 w-3 border-primary/50 border-t-2 border-r-2" />
      <div className="pointer-events-none absolute bottom-0 left-0 h-3 w-3 border-primary/50 border-b-2 border-l-2" />
      <div className="pointer-events-none absolute right-0 bottom-0 h-3 w-3 border-primary/50 border-r-2 border-b-2" />
    </div>
  );
}
Where it goes
faq