Introduce a footer-triggered Version History drawer with categorized release notes, hardcoded release data, and semver tracking at v0.3.0. Also ships blog blockquote/table styling, site-wide typography, home page image updates, header refinements, and related bug fixes. Co-authored-by: Cursor <cursoragent@cursor.com>
63 lines
2.1 KiB
TypeScript
63 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
Accordion,
|
|
AccordionContent,
|
|
AccordionItem,
|
|
AccordionTrigger,
|
|
} from "@/components/ui/accordion";
|
|
import type { CollapseBlockPayload } from "@/lib/blog-blocks";
|
|
import { type } from "@/lib/typography";
|
|
import { cn } from "@/lib/utils";
|
|
import { Icon } from "@iconify/react";
|
|
|
|
interface BlogCollapseSectionProps {
|
|
section: CollapseBlockPayload;
|
|
/** Optional prefix for accordion item ids (e.g. for multiple sections on one page). */
|
|
idPrefix?: string;
|
|
}
|
|
|
|
|
|
export function BlogCollapseSection({
|
|
section,
|
|
idPrefix = "collapse",
|
|
}: BlogCollapseSectionProps) {
|
|
if (!section.items.length) return null;
|
|
|
|
return (
|
|
<div className="my-8 space-y-4 border rounded-blog p-6">
|
|
{section.title ? (
|
|
<h2 className={cn(type.h2, "!mt-0 mb-4 scroll-mt-24")}>
|
|
{section.title}
|
|
</h2>
|
|
) : null}
|
|
<Accordion type="single" collapsible className="w-full gap-1">
|
|
{section.items.map((item, i) => (
|
|
<AccordionItem
|
|
key={i}
|
|
value={`${idPrefix}-${i}`}
|
|
className="border-none !m-0 hover:bg-muted has-[[data-state=open]]:bg-muted px-4 rounded-md"
|
|
>
|
|
<AccordionTrigger className={cn(type["list-title"], "group/trigger cursor-pointer py-4 text-right hover:no-underline [&>svg]:shrink-0")}>
|
|
<span className="flex gap-1 items-center">
|
|
<Icon
|
|
icon="lucide:circle-small"
|
|
className="size-5 group-data-[state=open]/trigger:hidden"
|
|
/>
|
|
<Icon
|
|
icon="lucide:dot"
|
|
className="size-5 hidden group-data-[state=open]/trigger:inline-block"
|
|
/>
|
|
{item.question}
|
|
</span>
|
|
</AccordionTrigger>
|
|
<AccordionContent className={cn(type.body, "text-justify text-muted-foreground [&_a]:text-accent [&_a]:underline hover:[&_a]:no-underline")}>
|
|
<div dangerouslySetInnerHTML={{ __html: item.answer }} />
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
))}
|
|
</Accordion>
|
|
</div>
|
|
);
|
|
}
|