fix layout issues and export on windows
This commit is contained in:
@@ -31,12 +31,12 @@ export default function PlaybackControls({
|
||||
const progress = duration > 0 ? (currentTime / duration) * 100 : 0;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-4 px-6 py-3 rounded-full bg-black/60 backdrop-blur-md border border-white/10 shadow-xl transition-all duration-300 hover:bg-black/70 hover:border-white/20">
|
||||
<div className="flex items-center gap-3 px-4 py-2 rounded-full bg-black/60 backdrop-blur-md border border-white/10 shadow-xl transition-all duration-300 hover:bg-black/70 hover:border-white/20">
|
||||
<Button
|
||||
onClick={onTogglePlayPause}
|
||||
size="icon"
|
||||
className={cn(
|
||||
"w-10 h-10 rounded-full transition-all duration-200 border border-white/10",
|
||||
"w-8 h-8 rounded-full transition-all duration-200 border border-white/10",
|
||||
isPlaying
|
||||
? "bg-white/10 text-white hover:bg-white/20"
|
||||
: "bg-white text-black hover:bg-white/90 hover:scale-105 shadow-[0_0_15px_rgba(255,255,255,0.3)]"
|
||||
@@ -44,19 +44,19 @@ export default function PlaybackControls({
|
||||
aria-label={isPlaying ? 'Pause' : 'Play'}
|
||||
>
|
||||
{isPlaying ? (
|
||||
<Pause className="w-4 h-4 fill-current" />
|
||||
<Pause className="w-3.5 h-3.5 fill-current" />
|
||||
) : (
|
||||
<Play className="w-4 h-4 fill-current ml-0.5" />
|
||||
<Play className="w-3.5 h-3.5 fill-current ml-0.5" />
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<span className="text-xs font-medium text-slate-300 tabular-nums w-[40px] text-right">
|
||||
<span className="text-[10px] font-medium text-slate-300 tabular-nums w-[35px] text-right">
|
||||
{formatTime(currentTime)}
|
||||
</span>
|
||||
|
||||
<div className="flex-1 relative h-8 flex items-center group">
|
||||
<div className="flex-1 relative h-6 flex items-center group">
|
||||
{/* Custom Track Background */}
|
||||
<div className="absolute left-0 right-0 h-1 bg-white/10 rounded-full overflow-hidden">
|
||||
<div className="absolute left-0 right-0 h-0.5 bg-white/10 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full bg-[#34B27B] rounded-full"
|
||||
style={{ width: `${progress}%` }}
|
||||
@@ -76,7 +76,7 @@ export default function PlaybackControls({
|
||||
|
||||
{/* Custom Thumb (visual only, follows progress) */}
|
||||
<div
|
||||
className="absolute w-3 h-3 bg-white rounded-full shadow-lg pointer-events-none group-hover:scale-125 transition-transform duration-100"
|
||||
className="absolute w-2.5 h-2.5 bg-white rounded-full shadow-lg pointer-events-none group-hover:scale-125 transition-transform duration-100"
|
||||
style={{
|
||||
left: `${progress}%`,
|
||||
transform: 'translateX(-50%)'
|
||||
@@ -84,7 +84,7 @@ export default function PlaybackControls({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<span className="text-xs font-medium text-slate-500 tabular-nums w-[40px]">
|
||||
<span className="text-[10px] font-medium text-slate-500 tabular-nums w-[35px]">
|
||||
{formatTime(duration)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -280,47 +280,50 @@ export default function VideoEditor() {
|
||||
|
||||
<div className="flex-1 p-4 gap-4 flex min-h-0 relative">
|
||||
{/* Left Column - Video & Timeline */}
|
||||
<div className="flex-[7] flex flex-col gap-4 min-w-0 h-full">
|
||||
<div className="flex-[7] flex flex-col gap-3 min-w-0 h-full">
|
||||
{/* Video Preview Area */}
|
||||
<div className="flex-1 min-h-0 bg-black/40 rounded-2xl border border-white/5 shadow-2xl overflow-hidden relative group">
|
||||
<div className="absolute inset-0 flex flex-col">
|
||||
<div className="flex-1 relative min-h-0 flex items-center justify-center">
|
||||
<VideoPlayback
|
||||
ref={videoPlaybackRef}
|
||||
videoPath={videoPath || ''}
|
||||
onDurationChange={setDuration}
|
||||
onTimeUpdate={setCurrentTime}
|
||||
onPlayStateChange={setIsPlaying}
|
||||
onError={setError}
|
||||
wallpaper={wallpaper}
|
||||
zoomRegions={zoomRegions}
|
||||
selectedZoomId={selectedZoomId}
|
||||
onSelectZoom={handleSelectZoom}
|
||||
onZoomFocusChange={handleZoomFocusChange}
|
||||
isPlaying={isPlaying}
|
||||
showShadow={showShadow}
|
||||
showBlur={showBlur}
|
||||
cropRegion={cropRegion}
|
||||
/>
|
||||
<div className="flex-shrink-0 bg-black/40 rounded-2xl border border-white/5 shadow-2xl overflow-hidden">
|
||||
<div className="flex flex-col">
|
||||
{/* Video Container - Fixed aspect ratio */}
|
||||
<div className="relative w-full" style={{ paddingBottom: '56.25%' }}> {/* 16:9 aspect ratio */}
|
||||
<div className="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div className="relative w-full h-full max-w-full max-h-full">
|
||||
<VideoPlayback
|
||||
ref={videoPlaybackRef}
|
||||
videoPath={videoPath || ''}
|
||||
onDurationChange={setDuration}
|
||||
onTimeUpdate={setCurrentTime}
|
||||
onPlayStateChange={setIsPlaying}
|
||||
onError={setError}
|
||||
wallpaper={wallpaper}
|
||||
zoomRegions={zoomRegions}
|
||||
selectedZoomId={selectedZoomId}
|
||||
onSelectZoom={handleSelectZoom}
|
||||
onZoomFocusChange={handleZoomFocusChange}
|
||||
isPlaying={isPlaying}
|
||||
showShadow={showShadow}
|
||||
showBlur={showBlur}
|
||||
cropRegion={cropRegion}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Floating Playback Controls */}
|
||||
<div className="px-6 pb-6 pt-2 pointer-events-none">
|
||||
<div className="pointer-events-auto">
|
||||
<PlaybackControls
|
||||
isPlaying={isPlaying}
|
||||
currentTime={currentTime}
|
||||
duration={duration}
|
||||
onTogglePlayPause={togglePlayPause}
|
||||
onSeek={handleSeek}
|
||||
/>
|
||||
</div>
|
||||
{/* Playback Controls - Below video */}
|
||||
<div className="px-4 pb-3 pt-2">
|
||||
<PlaybackControls
|
||||
isPlaying={isPlaying}
|
||||
currentTime={currentTime}
|
||||
duration={duration}
|
||||
onTogglePlayPause={togglePlayPause}
|
||||
onSeek={handleSeek}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Timeline Area */}
|
||||
<div className="h-[220px] flex-shrink-0 bg-[#09090b] rounded-2xl border border-white/5 shadow-lg overflow-hidden flex flex-col">
|
||||
<div className="flex-1 min-h-[180px] bg-[#09090b] rounded-2xl border border-white/5 shadow-lg overflow-hidden flex flex-col">
|
||||
<TimelineEditor
|
||||
videoDuration={duration}
|
||||
currentTime={currentTime}
|
||||
|
||||
@@ -57,9 +57,16 @@ export class FrameRenderer {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = this.config.width;
|
||||
canvas.height = this.config.height;
|
||||
if ('colorSpace' in canvas) {
|
||||
// @ts-ignore
|
||||
canvas.colorSpace = 'srgb';
|
||||
|
||||
// Try to set colorSpace if supported (may not be available on all platforms)
|
||||
try {
|
||||
if (canvas && 'colorSpace' in canvas) {
|
||||
// @ts-ignore
|
||||
canvas.colorSpace = 'srgb';
|
||||
}
|
||||
} catch (error) {
|
||||
// Silently ignore colorSpace errors on platforms that don't support it
|
||||
console.warn('[FrameRenderer] colorSpace not supported on this platform:', error);
|
||||
}
|
||||
|
||||
// Initialize PixiJS app with transparent background (background rendered separately)
|
||||
@@ -95,6 +102,10 @@ export class FrameRenderer {
|
||||
this.compositeCanvas.width = this.config.width;
|
||||
this.compositeCanvas.height = this.config.height;
|
||||
this.compositeCtx = this.compositeCanvas.getContext('2d', { willReadFrequently: false });
|
||||
|
||||
if (!this.compositeCtx) {
|
||||
throw new Error('Failed to get 2D context for composite canvas');
|
||||
}
|
||||
|
||||
// Setup shadow canvas if needed
|
||||
if (this.config.showShadow) {
|
||||
@@ -102,6 +113,10 @@ export class FrameRenderer {
|
||||
this.shadowCanvas.width = this.config.width;
|
||||
this.shadowCanvas.height = this.config.height;
|
||||
this.shadowCtx = this.shadowCanvas.getContext('2d', { willReadFrequently: false });
|
||||
|
||||
if (!this.shadowCtx) {
|
||||
throw new Error('Failed to get 2D context for shadow canvas');
|
||||
}
|
||||
}
|
||||
|
||||
// Setup mask
|
||||
|
||||
Reference in New Issue
Block a user