Initial commit

This commit is contained in:
Rami Bitar
2026-06-03 13:58:11 -04:00
commit 47b773444e
125 changed files with 16971 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
import { ComponentConfig } from "@reacteditor/core";
import { HelpCircle } from "lucide-react";
import { FAQ, type FAQProps } from "@/components/faq/faq";
export const faqEditor: ComponentConfig<FAQProps> = {
label: "FAQ",
icon: <HelpCircle size={16} />,
category: "content",
defaultProps: {
tagline: "Help",
heading: "Common questions",
subheading: "",
items: [
{
question: "What's your return policy?",
answer:
"Free returns within 30 days of delivery. Items should be unworn with original tags attached.",
},
{
question: "Where do you ship?",
answer:
"We ship worldwide. Free standard shipping on orders over $150 in the US, $250 international.",
},
{
question: "How are your products made?",
answer:
"In small batches at family-run mills in Portugal, Italy, and Japan. Every piece is sampled and approved by our team.",
},
{
question: "How do I care for my pieces?",
answer:
"Cold wash, lay flat to dry, iron when damp. Care details are on every product page and on the inner label.",
},
],
},
fields: {
tagline: { label: "Tagline", type: "text", contentEditable: true },
heading: { label: "Heading", type: "text", contentEditable: true },
subheading: { label: "Subheading", type: "textarea", contentEditable: true },
items: {
label: "Items",
type: "array",
defaultItemProps: { question: "", answer: "" },
getItemSummary: (it) => it?.question || "Question",
arrayFields: {
question: { label: "Question", type: "text", contentEditable: true },
answer: { label: "Answer", type: "textarea", contentEditable: true },
},
},
},
render: (props) => <FAQ {...props} />,
};

56
components/faq/faq.tsx Normal file
View File

@@ -0,0 +1,56 @@
import { useState } from "react";
import { Plus, Minus } from "lucide-react";
import { Heading } from "@/components/Heading";
export type FAQProps = {
tagline: string;
heading: string;
subheading: string;
items: Array<{ question: string; answer: string }>;
};
export function FAQ({ tagline, heading, subheading, items }: FAQProps) {
const [open, setOpen] = useState<number | null>(0);
return (
<section className="bg-background py-20 md:py-28">
<div className="container mx-auto max-w-3xl px-6">
<Heading
tagline={tagline}
title={heading}
subtitle={subheading}
align="center"
size="lg"
className="mb-12"
/>
<div className="divide-y divide-border border-y border-border">
{items.map((item, i) => {
const isOpen = open === i;
return (
<div key={i}>
<button
onClick={() => setOpen(isOpen ? null : i)}
className="flex w-full items-center justify-between py-6 text-left"
>
<span className="text-base font-medium tracking-tight md:text-lg">
{item.question}
</span>
{isOpen ? (
<Minus size={18} strokeWidth={1.5} className="flex-shrink-0" />
) : (
<Plus size={18} strokeWidth={1.5} className="flex-shrink-0" />
)}
</button>
{isOpen ? (
<p className="pb-6 pr-8 text-sm leading-relaxed text-muted-foreground md:text-base">
{item.answer}
</p>
) : null}
</div>
);
})}
</div>
</div>
</section>
);
}