/** * LivePreview Component * * A reusable live preview container for displaying real-time previews of settings. * Used across features like Cookie Consent, GDPR Notice, Email templates, etc. * * This component provides a consistent sticky preview panel with a standardized * header, optional backdrop/overlay, and flexible content area for custom previews. * * @example * ```tsx * *
Your preview content here
*
* ``` * * @component LivePreview * @package Swift Commerce */ import * as React from "react" import { Eye, LucideIcon } from "lucide-react" import { cn } from "@/lib/utils" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" export interface LivePreviewProps { /** Title for the preview card (default: "Live Preview") */ title?: string /** Description text below the title */ description?: string /** Custom icon component (default: Eye) */ icon?: LucideIcon /** Distance from top when sticky (default: 100px) */ stickyTop?: number /** Whether the preview container should be sticky (default: true) */ sticky?: boolean /** Minimum height of the preview area (default: 400px) */ minHeight?: number /** Whether to show a dark overlay backdrop */ showOverlay?: boolean /** Overlay opacity (0-1, default: 0.3) */ overlayOpacity?: number /** Background color of the preview area */ backgroundColor?: string /** Whether to show the background pattern (dots/grid) */ showPattern?: boolean /** Pattern type */ pattern?: "dots" | "grid" | "none" /** Additional className for the outer container */ className?: string /** Additional className for the preview area */ previewClassName?: string /** Header actions (buttons, etc.) */ headerActions?: React.ReactNode /** Children to render inside the preview area */ children: React.ReactNode } /** * Background patterns for the preview area */ const patterns = { dots: `radial-gradient(circle, rgba(0,0,0,0.05) 1px, transparent 1px)`, grid: `linear-gradient(rgba(0,0,0,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(0,0,0,0.03) 1px, transparent 1px)`, none: undefined, } const patternSizes = { dots: "16px 16px", grid: "20px 20px", none: undefined, } export function LivePreview({ title = "Live Preview", description = "See how your changes will look", icon: Icon = Eye, stickyTop = 220, sticky = true, minHeight = 400, showOverlay = false, overlayOpacity = 0.3, backgroundColor, showPattern = true, pattern = "dots", className, previewClassName, headerActions, children, }: LivePreviewProps) { const patternStyle = showPattern && pattern !== "none" ? { backgroundImage: patterns[pattern], backgroundSize: patternSizes[pattern], } : {} return (
{title} {description && ( {description} )}
{headerActions && (
{headerActions}
)}
{children}
) } /** * LivePreviewContent - A helper component for positioning content within LivePreview * * Provides preset positioning options commonly used in preview panels. */ export interface LivePreviewContentProps { /** Position of the content within the preview */ position?: | "center" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "full" /** Additional className */ className?: string /** Children to render */ children: React.ReactNode } const positionStyles = { center: "top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2", top: "top-0 left-0 right-0", bottom: "bottom-0 left-0 right-0", "top-left": "top-4 left-4", "top-right": "top-4 right-4", "bottom-left": "bottom-4 left-4", "bottom-right": "bottom-4 right-4", full: "inset-0", } export function LivePreviewContent({ position = "center", className, children, }: LivePreviewContentProps) { return (
{children}
) } /** * LivePreviewFloatingButton - A helper for rendering floating action buttons in preview */ export interface LivePreviewFloatingButtonProps { /** Position of the button */ position?: "bottom-left" | "bottom-right" | "top-left" | "top-right" /** Background color */ color?: string /** Size of the button (default: 32px) */ size?: number /** Additional className */ className?: string /** Children (usually an icon) */ children: React.ReactNode } export function LivePreviewFloatingButton({ position = "bottom-right", color = "#7c3aed", size = 32, className, children, }: LivePreviewFloatingButtonProps) { const positionClasses = { "bottom-left": "bottom-4 left-4", "bottom-right": "bottom-4 right-4", "top-left": "top-4 left-4", "top-right": "top-4 right-4", } return (
{children}
) } export default LivePreview