Files
buzz-sheet/lib/image-export/templates/primitives.tsx
T

162 lines
3.9 KiB
TypeScript

/* eslint-disable @next/next/no-img-element -- Pure image-renderer templates never mount in the webpage. */
import type { ComponentProps, CSSProperties, ReactNode } from "react";
import { cn } from "@/lib/utils";
type ImageProps = Omit<ComponentProps<"img">, "width" | "height"> & {
width?: number;
height?: number;
fill?: boolean;
sizes?: string;
unoptimized?: boolean;
priority?: boolean;
quality?: number;
};
// The renderer receives original image sources, not Next.js optimized image URLs.
export function Image({
src,
alt = "",
width,
height,
fill,
className,
style,
}: ImageProps) {
return (
<img
src={src}
alt={alt}
width={width}
height={height}
className={className}
style={{
...(fill
? ({
position: "absolute",
inset: 0,
width: "100%",
height: "100%",
} as CSSProperties)
: {}),
...style,
}}
/>
);
}
export function getImageProps({ src }: ImageProps) {
return { props: { src } };
}
export function Link({
children,
className,
}: {
children: ReactNode;
className?: string;
[key: string]: unknown;
}) {
return <div className={className}>{children}</div>;
}
export function Kbd({
children,
className,
}: {
children: ReactNode;
className?: string;
}) {
return <span className={className}>{children}</span>;
}
export function ArrowUpRightIcon() {
return <span>↗</span>;
}
export function ImageIcon({
className,
}: {
className?: string;
[key: string]: unknown;
}) {
return <span className={className}>◇</span>;
}
export function ConditionSwitcher({
children,
}: {
children: ReactNode;
label: string;
labels: string[];
}) {
return <>{children}</>;
}
export function Separator() {
return <div className="h-px w-full bg-border" />;
}
export function Badge({ children }: { children: ReactNode; variant?: string }) {
return (
<span className="inline-flex h-5 items-center justify-center rounded-full bg-secondary px-2 py-0.5 text-xs font-medium text-secondary-foreground">
{children}
</span>
);
}
type BoxProps = ComponentProps<"div">;
export function Card({ className, children, ...props }: BoxProps) {
return (
<div
{...props}
className={cn(
"flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10",
className,
)}
>
{children}
</div>
);
}
export function CardHeader({ className, ...props }: BoxProps) {
return (
<div
{...props}
className={cn(
"grid auto-rows-min items-start gap-1 rounded-t-xl px-4",
className,
)}
/>
);
}
export function CardTitle({ className, ...props }: BoxProps) {
return (
<div
{...props}
className={cn(
"font-heading text-base leading-snug font-medium",
className,
)}
/>
);
}
export function CardContent({ className, ...props }: BoxProps) {
return <div {...props} className={cn("px-4", className)} />;
}
export function GuideExportBranding({
backgroundUrl,
variant = "standard",
}: {
backgroundUrl: string;
variant?: "standard" | "constellation";
}) {
const constellation = variant === "constellation";
return (
<>
<Image alt="" src={backgroundUrl} fill className="object-cover" />
<div className="absolute inset-0 bg-[#050817]/65" />
<Image
alt=""
src="/icon/Watermark.png"
width={constellation ? 280 : 180}
height={constellation ? 158 : 101}
className={
constellation
? "guide-export-watermark absolute right-4 bottom-0 z-30 h-auto w-[280px] object-contain drop-shadow-[0_4px_3px_rgba(0,0,0,0.8)]"
: "guide-export-watermark absolute top-4 right-4 z-30 h-auto w-[180px] object-contain drop-shadow-[0_4px_3px_rgba(0,0,0,0.8)]"
}
/>
</>
);
}