"use client"; import { memo, useCallback, useEffect, useMemo, useRef } from "react"; import { Section, SectionContent, SectionHeader, SectionTitle, } from "@/components/section"; import { ColorPickerContent } from "@/components/ui/color-picker"; import { Popover, PopoverTrigger } from "@/components/ui/popover"; import { BACKGROUND_BLUR_INTENSITY_PRESETS, DEFAULT_BACKGROUND_BLUR_INTENSITY, } from "@/background/blur"; import { DEFAULT_BACKGROUND_COLOR } from "@/background/color"; import { patternCraftGradients } from "@/data/colors/pattern-craft"; import { colors } from "@/data/colors/solid"; import { syntaxUIGradients } from "@/data/colors/syntax-ui"; import { useEditor } from "@/editor/use-editor"; import { effectPreviewService } from "@/services/renderer/effect-preview"; import { cn } from "@/utils/ui"; const BLUR_PREVIEW_UNIFORM_DIMENSIONS = { width: 1920, height: 1080, } as const; const CUSTOM_COLOR_SWATCH_BACKGROUND = "conic-gradient(from 180deg at 50% 50%, #ff5e5e 0deg, #ffb35e 55deg, #fff26b 110deg, #6bff8f 165deg, #5ee7ff 220deg, #6f7cff 275deg, #d76bff 330deg, #ff5e9b 360deg)"; const BlurPreview = memo( ({ blur, isSelected, onSelect, }: { blur: { label: string; value: number }; isSelected: boolean; onSelect: () => void; }) => { const canvasRef = useRef(null); useEffect(() => { const renderPreview = () => { if (!canvasRef.current) return; effectPreviewService.renderPreview({ effectType: "blur", params: { intensity: blur.value }, targetCanvas: canvasRef.current, uniformDimensions: BLUR_PREVIEW_UNIFORM_DIMENSIONS, }); }; renderPreview(); return effectPreviewService.onPreviewImageReady({ callback: renderPreview, }); }, [blur.value]); return ( ); }, ); BlurPreview.displayName = "BlurPreview"; const BackgroundPreviews = memo( ({ backgrounds, currentBackgroundColor, isColorBackground, onSelect, useBackgroundColor = false, }: { backgrounds: readonly string[]; currentBackgroundColor: string; isColorBackground: boolean; onSelect: (bg: string) => void; useBackgroundColor?: boolean; }) => { return useMemo( () => backgrounds.map((bg) => ( onPreview(`#${color}`)} onChangeEnd={(color) => onCommit(`#${color}`)} /> ); } const COLOR_SECTIONS = [ { id: "colors", title: "Colors", backgrounds: colors, useBackgroundColor: true, showCustomPicker: true }, { id: "pattern-craft", title: "Pattern craft", backgrounds: patternCraftGradients, showCustomPicker: false }, { id: "syntax-ui", title: "Syntax UI", backgrounds: syntaxUIGradients, showCustomPicker: false }, ] as const; export function BackgroundContent() { const editor = useEditor(); const activeProject = useEditor((e) => e.project.getActive()); const handleBlurSelect = useCallback( async (blurIntensity: number) => { await editor.project.updateSettings({ settings: { background: { type: "blur", blurIntensity } }, }); }, [editor.project], ); const previewBackgroundColor = useCallback( async (color: string) => { await editor.project.updateSettings({ settings: { background: { type: "color", color } }, pushHistory: false, }); }, [editor.project], ); const commitBackgroundColor = useCallback( async (color: string) => { await editor.project.updateSettings({ settings: { background: { type: "color", color } }, pushHistory: true, }); }, [editor.project], ); const isBlurBackground = activeProject.settings.background.type === "blur"; const isColorBackground = activeProject.settings.background.type === "color"; const currentBlurIntensity = isBlurBackground ? (activeProject.settings.background as { blurIntensity: number }) .blurIntensity : DEFAULT_BACKGROUND_BLUR_INTENSITY; const currentBackgroundColor = isColorBackground ? (activeProject.settings.background as { color: string }).color : DEFAULT_BACKGROUND_COLOR; const hasPresetColorMatch = colors.some( (color) => color.toLowerCase() === currentBackgroundColor.toLowerCase(), ); const handlePresetColorSelect = useCallback( (color: string) => { void commitBackgroundColor(color); }, [commitBackgroundColor], ); const blurPreviews = useMemo( () => BACKGROUND_BLUR_INTENSITY_PRESETS.map((blur) => ( handleBlurSelect(blur.value)} /> )), [isBlurBackground, currentBlurIntensity, handleBlurSelect], ); return (
Blur
{blurPreviews}
{COLOR_SECTIONS.map((section) => (
{section.title}
{section.showCustomPicker ? ( ) : null}
))}
); }