import { useEffect, useRef, useState } from 'react'; import { Button } from '@/components/ui/button'; import { DESIGN_RESIZE, HISTORY_UNDO, HISTORY_REDO, dispatcher, useEditorState, } from '@designcombo/core'; import logoDark from '@/assets/logo-dark.png'; import { Icons } from '../shared/icons'; import { Popover, PopoverContent, PopoverTrigger, } from '@/components/ui/popover'; import { ChevronDown, Download } from 'lucide-react'; import { Label } from '../ui/label'; import { Progress } from '../ui/progress'; import { download } from '@/utils/download'; const baseUrl = 'https://renderer.designcombo.dev'; // https://renderer.designcombo.dev/status/{id} export default function Navbar() { const handleUndo = () => { dispatcher.dispatch(HISTORY_UNDO); }; const handleRedo = () => { dispatcher.dispatch(HISTORY_REDO); }; const openLink = (url: string) => { window.open(url, '_blank'); // '_blank' will open the link in a new tab }; return (
logo
Untitled video
); } interface IDownloadState { renderId: string; progress: number; isDownloading: boolean; } const DownloadPopover = () => { const [open, setOpen] = useState(false); const popoverRef = useRef(null); const [downloadState, setDownloadState] = useState({ progress: 0, isDownloading: false, renderId: '', }); const { trackItemIds, trackItemsMap, transitionIds, transitionsMap, tracks, duration, size, } = useEditorState(); const handleExport = () => { const payload = { trackItemIds, trackItemsMap, transitionIds, transitionsMap, tracks, size: size, duration: duration - 750, fps: 30, projectId: 'main', }; setDownloadState({ ...downloadState, isDownloading: true, }); fetch(`${baseUrl}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload), }) .then((res) => res.json()) .then(({ render }) => { setDownloadState({ ...downloadState, renderId: render.id, isDownloading: true, }); }); }; useEffect(() => { console.log('renderId', downloadState.renderId); let interval: NodeJS.Timeout; if (downloadState.renderId) { interval = setInterval(() => { fetch(`${baseUrl}/status/${downloadState.renderId}`) .then((res) => res.json()) .then(({ render: { progress, output } }) => { if (progress === 100) { clearInterval(interval); setDownloadState({ ...downloadState, renderId: '', progress: 0, isDownloading: false, }); download(output, `${downloadState.renderId}`); setOpen(false); } else { setDownloadState({ ...downloadState, progress, isDownloading: true, }); } }); }, 1000); } return () => { if (interval) clearInterval(interval); }; }, [downloadState.renderId]); return ( {downloadState.isDownloading ? ( <>
{parseInt(downloadState.progress.toString())}%
) : ( <>
)}
); }; interface ResizeOptionProps { label: string; icon: string; value: ResizeValue; } interface ResizeValue { width: number; height: number; name: string; } const RESIZE_OPTIONS: ResizeOptionProps[] = [ { label: '16:9', icon: 'landscape', value: { width: 1920, height: 1080, name: '16:9', }, }, { label: '9:16', icon: 'portrait', value: { width: 1080, height: 1920, name: '9:16', }, }, { label: '1:1', icon: 'square', value: { width: 1080, height: 1080, name: '1:1', }, }, ]; const ResizeVideo = () => { const handleResize = (payload: ResizeValue) => { dispatcher.dispatch(DESIGN_RESIZE, { payload, }); }; return (
{RESIZE_OPTIONS.map((option, index) => ( ))}
); }; const ResizeOption = ({ label, icon, value, handleResize, }: ResizeOptionProps & { handleResize: (payload: ResizeValue) => void }) => { const Icon = Icons[icon]; return (
handleResize(value)} className="flex items-center gap-4 hover:bg-zinc-50/10 cursor-pointer" >
{label}
Tiktok, Instagram
); };