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>
58 lines
1.5 KiB
TypeScript
58 lines
1.5 KiB
TypeScript
"use client";
|
|
|
|
import type { TipBlockPayload } from "@/lib/blog-blocks";
|
|
import { Info, AlertTriangle, AlertCircle } from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface BlogTipProps {
|
|
payload: TipBlockPayload;
|
|
}
|
|
|
|
const variantConfig = {
|
|
info: {
|
|
icon: Info,
|
|
className:
|
|
"border-primary/40 bg-primary/5 text-foreground [&_strong]:text-primary",
|
|
iconClassName: "text-primary",
|
|
},
|
|
warn: {
|
|
icon: AlertTriangle,
|
|
className:
|
|
"border-amber-500/50 bg-amber-500/10 text-foreground [&_strong]:text-amber-600 dark:[&_strong]:text-amber-400",
|
|
iconClassName: "text-amber-500",
|
|
},
|
|
danger: {
|
|
icon: AlertCircle,
|
|
className:
|
|
"border-destructive/50 bg-destructive/10 text-foreground [&_strong]:text-destructive",
|
|
iconClassName: "text-destructive",
|
|
},
|
|
} as const;
|
|
|
|
export function BlogTip({ payload }: BlogTipProps) {
|
|
const { variant, content } = payload;
|
|
if (!content.trim()) return null;
|
|
|
|
const config = variantConfig[variant ?? 'info'];
|
|
const Icon = config.icon;
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"my-6 flex gap-3 rounded-blog border p-4 pr-4 shadow-sm",
|
|
config.className
|
|
)}
|
|
role="note"
|
|
>
|
|
<Icon
|
|
className={cn("mt-0.5 size-8 shrink-0", config.iconClassName)}
|
|
aria-hidden
|
|
/>
|
|
<div
|
|
className="blog-tip-content min-w-0 text-sm leading-relaxed [&_p]:my-2 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0 [&_a]:text-accent [&_a]:underline hover:[&_a]:no-underline"
|
|
dangerouslySetInnerHTML={{ __html: content }}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|