|
|
import { Download, Loader2 } from 'lucide-react'; |
|
|
import { useState, useRef, useEffect } from 'react'; |
|
|
import { LayoutType, CanvasSize } from '../../types/canvas.types'; |
|
|
|
|
|
interface ExportButtonProps { |
|
|
onExport: (filename: string) => void; |
|
|
isExporting?: boolean; |
|
|
currentLayout: LayoutType | null; |
|
|
canvasSize: CanvasSize; |
|
|
} |
|
|
|
|
|
export default function ExportButton({ onExport, isExporting = false, currentLayout, canvasSize }: ExportButtonProps) { |
|
|
|
|
|
const getCanvasSizeName = (size: CanvasSize): string => { |
|
|
switch (size) { |
|
|
case '1200x675': |
|
|
return 'Twitter'; |
|
|
case 'linkedin': |
|
|
return 'LinkedIn'; |
|
|
case 'hf': |
|
|
return 'HF'; |
|
|
default: |
|
|
return 'Twitter'; |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
const generateDefaultFilename = () => { |
|
|
const sizeName = getCanvasSizeName(canvasSize); |
|
|
if (currentLayout) { |
|
|
return `${currentLayout}_${sizeName}`; |
|
|
} |
|
|
return `thumbnail_${sizeName}`; |
|
|
}; |
|
|
|
|
|
const [filename, setFilename] = useState(generateDefaultFilename()); |
|
|
const [isFocused, setIsFocused] = useState(false); |
|
|
const [inputWidth, setInputWidth] = useState(0); |
|
|
const [isHoveringButton, setIsHoveringButton] = useState(false); |
|
|
const spanRef = useRef<HTMLSpanElement>(null); |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
setFilename(generateDefaultFilename()); |
|
|
}, [currentLayout, canvasSize]); |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
if (spanRef.current) { |
|
|
setInputWidth(spanRef.current.offsetWidth); |
|
|
} |
|
|
}, [filename]); |
|
|
|
|
|
const handleExport = () => { |
|
|
if (isExporting) return; |
|
|
onExport(filename); |
|
|
}; |
|
|
|
|
|
return ( |
|
|
<div |
|
|
className="fixed top-[7px] lg:top-[10px] right-[20px] lg:right-[22px] z-50 p-[4px] lg:p-[5px] inline-flex items-stretch gap-[4px] lg:gap-[5px]" |
|
|
style={{ |
|
|
backgroundColor: '#262933', |
|
|
borderRadius: '10px', |
|
|
boxShadow: '0px 0px 0px 0px rgba(0,0,0,0), 0px 0px 0px 0px rgba(0,0,0,0.03), 0px 0px 6.417px 0px rgba(0,0,0,0.09), 0px 0px 4.583px 0px rgba(0,0,0,0.15), 0px 0px 2.75px 0px rgba(0,0,0,0.17), 0px 16.847px 21.059px -4.212px rgba(14,13,13,0.1), 0px 8.423px 8.423px -4.212px rgba(0,0,0,0.04)', |
|
|
opacity: isExporting ? 0.5 : 1, |
|
|
transition: 'all 0.2s ease-in-out', |
|
|
width: 'fit-content' |
|
|
}} |
|
|
> |
|
|
{/* Download/Loading Icon with Blue Background - Clickable */} |
|
|
<button |
|
|
onClick={handleExport} |
|
|
disabled={isExporting} |
|
|
onMouseEnter={() => setIsHoveringButton(true)} |
|
|
onMouseLeave={() => setIsHoveringButton(false)} |
|
|
className="flex items-center justify-center rounded-[5px] w-[29px] lg:w-[32px] aspect-square flex-shrink-0 border-none p-0" |
|
|
style={{ |
|
|
backgroundColor: isHoveringButton ? '#0d6ecc' : '#1888ff', |
|
|
cursor: isExporting ? 'not-allowed' : 'pointer', |
|
|
transition: 'all 0.2s ease-in-out', |
|
|
transform: isHoveringButton && !isExporting ? 'scale(1.05)' : 'scale(1)' |
|
|
}} |
|
|
> |
|
|
{isExporting ? ( |
|
|
<Loader2 className="w-[14px] lg:w-4 h-[14px] lg:h-4" color="white" style={{ animation: 'spin 1s linear infinite' }} /> |
|
|
) : ( |
|
|
<Download className="w-[14px] lg:w-4 h-[14px] lg:h-4" color="white" /> |
|
|
)} |
|
|
</button> |
|
|
|
|
|
{/* Filename Container */} |
|
|
<div className="flex items-center gap-[2px] pr-[4px] lg:pr-[5px] min-h-[29px] lg:min-h-[32px]"> |
|
|
{/* Hidden span to measure text width */} |
|
|
<span |
|
|
ref={spanRef} |
|
|
className="absolute invisible whitespace-pre text-[14px] lg:text-[16px] font-normal p-[4px] lg:p-[5px]" |
|
|
style={{ |
|
|
fontFamily: 'Inter, sans-serif' |
|
|
}} |
|
|
> |
|
|
{filename || 'thumbnail_name'} |
|
|
</span> |
|
|
|
|
|
<input |
|
|
type="text" |
|
|
value={filename} |
|
|
onChange={(e) => setFilename(e.target.value)} |
|
|
onFocus={() => setIsFocused(true)} |
|
|
onBlur={() => setIsFocused(false)} |
|
|
disabled={isExporting} |
|
|
placeholder="thumbnail_name" |
|
|
className="bg-white/5 text-white text-[14px] lg:text-[16px] font-normal outline-none border-none p-[4px] lg:p-[5px] rounded" |
|
|
style={{ |
|
|
fontFamily: 'Inter, sans-serif', |
|
|
width: `${inputWidth}px`, |
|
|
cursor: isExporting ? 'not-allowed' : 'text', |
|
|
opacity: isFocused ? 1 : 0.5, |
|
|
transition: 'all 0.2s ease-in-out', |
|
|
backgroundColor: isFocused ? 'rgba(255, 255, 255, 0.1)' : 'rgba(255, 255, 255, 0.05)' |
|
|
}} |
|
|
onClick={(e) => e.stopPropagation()} |
|
|
/> |
|
|
<span |
|
|
className="text-white text-[14px] lg:text-[16px] font-normal" |
|
|
style={{ |
|
|
fontFamily: 'Inter, sans-serif', |
|
|
opacity: isFocused ? 1 : 0.5, |
|
|
transition: 'opacity 0.2s ease-in-out' |
|
|
}} |
|
|
> |
|
|
.png |
|
|
</span> |
|
|
</div> |
|
|
</div> |
|
|
); |
|
|
} |
|
|
|