| import { getAllLayouts } from '../../data/layouts'; | |
| import { LayoutType } from '../../types/canvas.types'; | |
| import { useState } from 'react'; | |
| interface LayoutSelectorProps { | |
| onSelectLayout: (layoutId: LayoutType) => void; | |
| } | |
| export default function LayoutSelector({ onSelectLayout }: LayoutSelectorProps) { | |
| const layouts = getAllLayouts(); | |
| const [loadingImages, setLoadingImages] = useState<Set<string>>(new Set(layouts.map(l => l.id))); | |
| const handleImageLoad = (layoutId: string) => { | |
| setLoadingImages(prev => { | |
| const newSet = new Set(prev); | |
| newSet.delete(layoutId); | |
| return newSet; | |
| }); | |
| }; | |
| return ( | |
| <div | |
| className="layout-selector absolute left-[calc(100%+4px)] top-[5px] bg-[#f8f9fa] border border-[#3faee6] rounded-[10px] p-[5px] shadow-lg inline-block" | |
| onDragStart={(e) => { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| }} | |
| onDrag={(e) => { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| }} | |
| onDragOver={(e) => { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| }} | |
| > | |
| {/* 2x3 Grid - 2 layouts per row, 3 rows total */} | |
| <div className="flex flex-col gap-0"> | |
| {/* First Row - 2 layouts */} | |
| <div className="flex gap-0"> | |
| {layouts.slice(0, 2).map((layout) => ( | |
| <button | |
| key={layout.id} | |
| onClick={() => onSelectLayout(layout.id)} | |
| onDragStart={(e) => e.preventDefault()} | |
| className="flex flex-col items-center gap-[5px] p-[10px] rounded-[5px] hover:bg-[#e9ecef] transition-colors flex-1" | |
| > | |
| <div className="w-[96.5px] h-[47.291px] rounded-[5px] flex items-center justify-center overflow-hidden relative" onDragStart={(e) => e.preventDefault()}> | |
| {loadingImages.has(layout.id) && ( | |
| <div className="absolute inset-0 skeleton-shimmer"></div> | |
| )} | |
| <img | |
| src={layout.thumbnail} | |
| alt={layout.name} | |
| className={`w-full h-full object-cover transition-opacity duration-200 ${loadingImages.has(layout.id) ? 'opacity-0' : 'opacity-100'}`} | |
| onLoad={() => handleImageLoad(layout.id)} | |
| draggable={false} | |
| /> | |
| </div> | |
| <p className="text-[14px] font-normal text-[#545865] text-center"> | |
| {layout.name} | |
| </p> | |
| </button> | |
| ))} | |
| </div> | |
| {/* Second Row - 2 layouts */} | |
| <div className="flex gap-0"> | |
| {layouts.slice(2, 4).map((layout) => ( | |
| <button | |
| key={layout.id} | |
| onClick={() => onSelectLayout(layout.id)} | |
| onDragStart={(e) => e.preventDefault()} | |
| className="flex flex-col items-center gap-[5px] p-[10px] rounded-[5px] hover:bg-[#e9ecef] transition-colors flex-1" | |
| > | |
| <div className="w-[96.5px] h-[47.291px] rounded-[5px] flex items-center justify-center overflow-hidden relative" onDragStart={(e) => e.preventDefault()}> | |
| {loadingImages.has(layout.id) && ( | |
| <div className="absolute inset-0 skeleton-shimmer"></div> | |
| )} | |
| <img | |
| src={layout.thumbnail} | |
| alt={layout.name} | |
| className={`w-full h-full object-cover transition-opacity duration-200 ${loadingImages.has(layout.id) ? 'opacity-0' : 'opacity-100'}`} | |
| onLoad={() => handleImageLoad(layout.id)} | |
| draggable={false} | |
| /> | |
| </div> | |
| <p className="text-[14px] font-normal text-[#545865] text-center"> | |
| {layout.name} | |
| </p> | |
| </button> | |
| ))} | |
| </div> | |
| {/* Third Row - 1 layout (Academia Hub) */} | |
| <div className="flex gap-0"> | |
| {layouts.slice(4, 6).map((layout) => ( | |
| <button | |
| key={layout.id} | |
| onClick={() => onSelectLayout(layout.id)} | |
| onDragStart={(e) => e.preventDefault()} | |
| className="flex flex-col items-center gap-[5px] p-[10px] rounded-[5px] hover:bg-[#e9ecef] transition-colors flex-1" | |
| > | |
| <div className="w-[96.5px] h-[47.291px] rounded-[5px] flex items-center justify-center overflow-hidden relative" onDragStart={(e) => e.preventDefault()}> | |
| {loadingImages.has(layout.id) && ( | |
| <div className="absolute inset-0 skeleton-shimmer"></div> | |
| )} | |
| <img | |
| src={layout.thumbnail} | |
| alt={layout.name} | |
| className={`w-full h-full object-cover transition-opacity duration-200 ${loadingImages.has(layout.id) ? 'opacity-0' : 'opacity-100'}`} | |
| onLoad={() => handleImageLoad(layout.id)} | |
| draggable={false} | |
| /> | |
| </div> | |
| <p className="text-[14px] font-normal text-[#545865] text-center"> | |
| {layout.name} | |
| </p> | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |