/** * Advanced Drag-and-Drop Components * Enhanced section reordering with visual feedback and smooth animations */ "use client"; import React, { useState, useCallback } from "react"; import { DragDropContext, Droppable, Draggable, DropResult, DragUpdate, } from "@hello-pangea/dnd"; import { useEditor } from "./context"; import { BaseSection } from "./types"; // Icon mapping for drag and drop UI const iconMap: Record = { drag: "โ‹ฎโ‹ฎ", delete: "๐Ÿ—‘๏ธ", copy: "๐Ÿ“‹", eye: "๐Ÿ‘๏ธ", eyeOff: "๐Ÿ™ˆ", settings: "โš™๏ธ", hero: "๐ŸŽฏ", features: "โญ", cta: "๐Ÿ””", pricing: "๐Ÿ’ฐ", testimonials: "๐Ÿ’ฌ", contact: "๐Ÿ“ž", gallery: "๐Ÿ–ผ๏ธ", text: "๐Ÿ“", custom: "๐Ÿ”ง", }; // Enhanced Section Item Component with Drag-and-Drop interface DraggableSectionItemProps { section: BaseSection; index: number; isSelected: boolean; isDragDisabled?: boolean; onSelect: (sectionId: string) => void; onDelete: (sectionId: string) => void; onDuplicate: (sectionId: string) => void; onToggleVisibility: (sectionId: string) => void; onSettings: (sectionId: string) => void; } export function DraggableSectionItem({ section, index, isSelected, isDragDisabled = false, onSelect, onDelete, onDuplicate, onToggleVisibility, onSettings, }: DraggableSectionItemProps) { const [isHovering, setIsHovering] = useState(false); const [showActions, setShowActions] = useState(false); const handleMouseEnter = useCallback(() => { setIsHovering(true); setShowActions(true); }, []); const handleMouseLeave = useCallback(() => { setIsHovering(false); setTimeout(() => setShowActions(false), 300); // Delay to allow clicking actions }, []); return ( {(provided, snapshot) => (
onSelect(section.id)} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} style={provided.draggableProps.style} > {/* Drag Handle */}
{iconMap.drag}
{/* Section Content */}
{iconMap[section.type] || iconMap.custom}

{section.name}

{section.type}

{/* Section Status Indicators */}
{section.isActive ? "ํ™œ์„ฑ" : "๋น„ํ™œ์„ฑ"} {section.settings.isLocked && ( ๐Ÿ”’ ์ž ๊น€ )} #{section.order + 1}
{/* Action Buttons */}
{/* Drag Overlay for Visual Feedback */} {snapshot.isDragging && (
์ด๋™ ์ค‘...
)}
)}
); } // Drop Zone Indicator Component interface DropZoneIndicatorProps { isOver: boolean; canDrop: boolean; } function DropZoneIndicator({ isOver, canDrop }: DropZoneIndicatorProps) { if (!canDrop) return null; return (
); } // Enhanced Droppable Section List interface DroppableSectionListProps { sections: BaseSection[]; selectedSection: string | null; onSectionSelect: (sectionId: string) => void; onSectionReorder: (startIndex: number, endIndex: number) => void; onSectionDelete: (sectionId: string) => void; onSectionDuplicate: (sectionId: string) => void; onSectionToggleVisibility: (sectionId: string) => void; onSectionSettings: (sectionId: string) => void; isDragDisabled?: boolean; className?: string; } export function DroppableSectionList({ sections, selectedSection, onSectionSelect, onSectionReorder, onSectionDelete, onSectionDuplicate, onSectionToggleVisibility, onSectionSettings, isDragDisabled = false, className = "", }: DroppableSectionListProps) { const [draggedOverIndex, setDraggedOverIndex] = useState(null); const handleDragEnd = useCallback( (result: DropResult) => { setDraggedOverIndex(null); if ( !result.destination || result.destination.index === result.source.index ) { return; } onSectionReorder(result.source.index, result.destination.index); }, [onSectionReorder] ); const handleDragUpdate = useCallback((update: DragUpdate) => { setDraggedOverIndex(update.destination?.index ?? null); }, []); // Sort sections by order const sortedSections = [...sections].sort((a, b) => a.order - b.order); return (
{(provided, snapshot) => (
{sortedSections.length === 0 ? (
๐Ÿ“„

์„น์…˜์ด ์—†์Šต๋‹ˆ๋‹ค

ํ…œํ”Œ๋ฆฟ์„ ์„ ํƒํ•˜์—ฌ ์ƒˆ ์„น์…˜์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”

) : ( <> {sortedSections.map((section, index) => ( {index === 0 && draggedOverIndex === 0 && ( )} {draggedOverIndex === index + 1 && ( )} ))} )} {provided.placeholder}
)}
); } // Section Bulk Actions Component interface SectionBulkActionsProps { selectedSections: string[]; onBulkDelete: (sectionIds: string[]) => void; onBulkToggleVisibility: (sectionIds: string[], visible: boolean) => void; onBulkDuplicate: (sectionIds: string[]) => void; onClearSelection: () => void; } export function SectionBulkActions({ selectedSections, onBulkDelete, onBulkToggleVisibility, onBulkDuplicate, onClearSelection, }: SectionBulkActionsProps) { if (selectedSections.length === 0) return null; return (
{selectedSections.length}๊ฐœ ์„น์…˜ ์„ ํƒ๋จ
); } // Enhanced Section List with All Features interface EnhancedSectionListProps { className?: string; } export function EnhancedSectionList({ className = "", }: EnhancedSectionListProps) { const { state, selectSection, deleteSection, duplicateSection, moveSection, updateSection, } = useEditor(); const [selectedSections, setSelectedSections] = useState([]); const [isDragDisabled, setIsDragDisabled] = useState(false); // Handle section reordering const handleSectionReorder = useCallback( (startIndex: number, endIndex: number) => { const sortedSections = [...state.sections].sort( (a, b) => a.order - b.order ); const sectionToMove = sortedSections[startIndex]; if (sectionToMove) { moveSection(sectionToMove.id, endIndex); } }, [state.sections, moveSection] ); // Handle section selection const handleSectionSelect = useCallback( (sectionId: string) => { selectSection(sectionId); // Handle multi-selection with Ctrl/Cmd key // This would need keyboard event handling in a real implementation setSelectedSections([sectionId]); }, [selectSection] ); // Handle visibility toggle const handleToggleVisibility = useCallback( (sectionId: string) => { const section = state.sections.find((s) => s.id === sectionId); if (section) { updateSection(sectionId, { isActive: !section.isActive }); } }, [state.sections, updateSection] ); // Handle section settings const handleSectionSettings = useCallback( (sectionId: string) => { selectSection(sectionId); // Additional settings logic would go here }, [selectSection] ); // Bulk operations const handleBulkDelete = useCallback( (sectionIds: string[]) => { if (confirm(`${sectionIds.length}๊ฐœ ์„น์…˜์„ ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?`)) { sectionIds.forEach((id) => deleteSection(id)); setSelectedSections([]); } }, [deleteSection] ); const handleBulkToggleVisibility = useCallback( (sectionIds: string[], visible: boolean) => { sectionIds.forEach((id) => { updateSection(id, { isActive: visible }); }); }, [updateSection] ); const handleBulkDuplicate = useCallback( (sectionIds: string[]) => { sectionIds.forEach((id) => duplicateSection(id)); setSelectedSections([]); }, [duplicateSection] ); return (

์„น์…˜ ๊ด€๋ฆฌ

{state.sections.length}๊ฐœ
setSelectedSections([])} />
); }