ultisuite-client/components/drive/richtext/docs-graphic-layout-previews.tsx
R3D347HR4Y 303b2b1074
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
wow
2026-06-11 01:22:40 +02:00

184 lines
5.2 KiB
TypeScript

"use client"
import type { DocsGraphicPositionMode, DocsGraphicWrap } from "@/lib/drive/docs-graphic-types"
import { cn } from "@/lib/utils"
function PreviewFrame({ children, className }: { children: React.ReactNode; className?: string }) {
return (
<div
className={cn(
"docs-graphic-layout-preview relative overflow-hidden rounded border border-muted-foreground/25 bg-background",
className
)}
aria-hidden
>
{children}
</div>
)
}
function TextLines({
count = 3,
className,
inset,
}: {
count?: number
className?: string
inset?: string
}) {
return (
<div className={cn("flex flex-col gap-[3px]", inset, className)}>
{Array.from({ length: count }).map((_, i) => (
<span
key={i}
className="block h-[3px] rounded-full bg-muted-foreground/35"
style={{ width: i === count - 1 ? "72%" : "100%" }}
/>
))}
</div>
)
}
function ImageBlock({ className }: { className?: string }) {
return (
<span
className={cn(
"block shrink-0 rounded-[2px] border border-primary/50 bg-primary/25",
className
)}
/>
)
}
export function DocsGraphicWrapPreview({ wrap }: { wrap: DocsGraphicWrap }) {
switch (wrap) {
case "inline":
return (
<PreviewFrame className="flex h-11 items-center gap-1 px-1.5">
<TextLines count={1} className="w-[22%]" />
<ImageBlock className="size-4" />
<TextLines count={1} className="flex-1" />
</PreviewFrame>
)
case "square":
return (
<PreviewFrame className="flex h-11 gap-1.5 p-1.5">
<ImageBlock className="h-full w-[34%]" />
<TextLines count={3} className="flex-1 pt-0.5" />
</PreviewFrame>
)
case "tight":
return (
<PreviewFrame className="flex h-11 gap-0.5 p-1">
<ImageBlock className="h-full w-[30%]" />
<TextLines count={4} className="flex-1 gap-[2px] pt-0" />
</PreviewFrame>
)
case "through":
return (
<PreviewFrame className="h-11 p-1.5">
<ImageBlock className="absolute inset-1.5 opacity-45" />
<TextLines count={3} className="relative z-10 h-full justify-center" />
</PreviewFrame>
)
case "top-bottom":
return (
<PreviewFrame className="flex h-11 flex-col gap-1 p-1.5">
<ImageBlock className="h-[42%] w-full" />
<TextLines count={2} className="flex-1" />
</PreviewFrame>
)
case "behind":
return (
<PreviewFrame className="h-11 p-1.5">
<ImageBlock className="absolute inset-1.5 opacity-35" />
<TextLines count={3} className="relative z-10 h-full justify-center" />
</PreviewFrame>
)
case "in-front":
return (
<PreviewFrame className="h-11 p-1.5">
<TextLines count={3} className="absolute inset-x-1.5 top-2" />
<ImageBlock className="absolute bottom-1.5 left-1/2 z-10 h-[52%] w-[46%] -translate-x-1/2 opacity-90" />
</PreviewFrame>
)
default:
return <PreviewFrame className="h-11" />
}
}
export function DocsGraphicPositionModePreview({
mode,
}: {
mode: DocsGraphicPositionMode
}) {
if (mode === "move-with-text") {
return (
<PreviewFrame className="flex h-11 flex-col justify-center gap-1 p-1.5">
<div className="flex items-center gap-1">
<TextLines count={1} className="w-[28%]" />
<ImageBlock className="size-4" />
<TextLines count={1} className="flex-1" />
</div>
<TextLines count={1} className="w-full" />
<TextLines count={1} className="w-[80%]" />
</PreviewFrame>
)
}
return (
<PreviewFrame className="h-11 p-1">
<span className="absolute inset-1 rounded border border-dashed border-muted-foreground/30" />
<ImageBlock className="absolute right-2 top-2 h-[38%] w-[32%]" />
<TextLines count={2} className="absolute bottom-2 left-2 right-2" />
</PreviewFrame>
)
}
export function DocsGraphicMarginPreview({ mm }: { mm: number }) {
const gap = mm === 0 ? 1 : mm <= 3 ? 3 : mm <= 6 ? 5 : 8
return (
<PreviewFrame className="flex h-11 items-start gap-0 p-1.5">
<div className="flex h-full items-start" style={{ gap: `${gap}px` }}>
<ImageBlock className="h-[70%] w-[38%]" />
<TextLines count={3} className="w-[52%] pt-0.5" />
</div>
</PreviewFrame>
)
}
export function DocsGraphicPageAnchorPreview({
h,
v,
active,
}: {
h: 0 | 0.5 | 1
v: 0 | 0.5 | 1
active?: boolean
}) {
return (
<span
className={cn(
"flex size-9 rounded-md border p-1",
active
? "border-primary bg-primary/5"
: "border-border bg-background hover:border-muted-foreground/50"
)}
>
<span
className={cn(
"relative flex size-full rounded-[2px] border border-muted-foreground/30",
h === 0 && "justify-start",
h === 0.5 && "justify-center",
h === 1 && "justify-end",
v === 0 && "items-start",
v === 0.5 && "items-center",
v === 1 && "items-end"
)}
>
<span className="size-2 rounded-[1px] bg-primary/70" />
</span>
</span>
)
}