background selection
|
After Width: | Height: | Size: 11 MiB |
|
After Width: | Height: | Size: 20 MiB |
|
After Width: | Height: | Size: 4.2 MiB |
|
After Width: | Height: | Size: 521 KiB |
|
After Width: | Height: | Size: 560 KiB |
|
After Width: | Height: | Size: 525 KiB |
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 12 MiB |
|
After Width: | Height: | Size: 15 MiB |
|
After Width: | Height: | Size: 18 MiB |
|
After Width: | Height: | Size: 20 MiB |
|
After Width: | Height: | Size: 8.5 MiB |
|
After Width: | Height: | Size: 2.1 MiB |
@@ -1,6 +1,33 @@
|
||||
export default function SettingsPanel() {
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const WALLPAPER_COUNT = 12;
|
||||
const WALLPAPER_PATHS = Array.from({ length: WALLPAPER_COUNT }, (_, i) => `/wallpapers/wallpaper${i + 1}.jpg`);
|
||||
|
||||
export default function SettingsPanel({ selected, onWallpaperChange }: { selected: string, onWallpaperChange: (path: string) => void }) {
|
||||
return (
|
||||
<div className="flex-[3] min-w-0 bg-card border border-border rounded-xl p-8 flex flex-col shadow-sm">
|
||||
<div className="mb-6">
|
||||
<div className="text-lg font-semibold mb-2">Choose Background</div>
|
||||
<div className="grid grid-cols-6 gap-3">
|
||||
{WALLPAPER_PATHS.map((path, idx) => (
|
||||
<div
|
||||
key={path}
|
||||
className={cn(
|
||||
"aspect-square rounded-lg border-2 overflow-hidden cursor-pointer transition-all w-16 h-16",
|
||||
selected === path
|
||||
? "border-primary/40 ring-1 ring-primary/40 scale-105"
|
||||
: "border-border hover:border-primary/60 hover:scale-105"
|
||||
)}
|
||||
style={{ backgroundImage: `url(${path})`, backgroundSize: "cover", backgroundPosition: "center" }}
|
||||
aria-label={`Wallpaper ${idx + 1}`}
|
||||
tabIndex={0}
|
||||
onClick={() => onWallpaperChange(path)}
|
||||
onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') onWallpaperChange(path); }}
|
||||
role="button"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 w-full flex items-center justify-center text-muted-foreground text-base">
|
||||
Settings
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import VideoPlayback, { VideoPlaybackRef } from "./VideoPlayback";
|
||||
import PlaybackControls from "./PlaybackControls";
|
||||
import TimelineEditor from "./TimelineEditor";
|
||||
import SettingsPanel from "./SettingsPanel";
|
||||
|
||||
const WALLPAPER_COUNT = 12;
|
||||
const WALLPAPER_PATHS = Array.from({ length: WALLPAPER_COUNT }, (_, i) => `/wallpapers/wallpaper${i + 1}.jpg`);
|
||||
|
||||
export default function VideoEditor() {
|
||||
const [videoPath, setVideoPath] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -13,6 +17,7 @@ export default function VideoEditor() {
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [currentTime, setCurrentTime] = useState(0);
|
||||
const [duration, setDuration] = useState(0);
|
||||
const [wallpaper, setWallpaper] = useState<string>(WALLPAPER_PATHS[0]);
|
||||
|
||||
const videoPlaybackRef = useRef<VideoPlaybackRef>(null);
|
||||
const isSeeking = useRef(false);
|
||||
@@ -85,6 +90,7 @@ export default function VideoEditor() {
|
||||
onTimeUpdate={setCurrentTime}
|
||||
onPlayStateChange={setIsPlaying}
|
||||
onError={setError}
|
||||
wallpaper={wallpaper}
|
||||
/>
|
||||
<PlaybackControls
|
||||
isPlaying={isPlaying}
|
||||
@@ -100,7 +106,7 @@ export default function VideoEditor() {
|
||||
</div>
|
||||
<TimelineEditor />
|
||||
</div>
|
||||
<SettingsPanel />
|
||||
<SettingsPanel selected={wallpaper} onWallpaperChange={setWallpaper} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ interface VideoPlaybackProps {
|
||||
onTimeUpdate: (time: number) => void;
|
||||
onPlayStateChange: (playing: boolean) => void;
|
||||
onError: (error: string) => void;
|
||||
wallpaper?: string;
|
||||
}
|
||||
|
||||
export interface VideoPlaybackRef {
|
||||
@@ -20,6 +21,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
|
||||
onTimeUpdate,
|
||||
onPlayStateChange,
|
||||
onError,
|
||||
wallpaper,
|
||||
}, ref) => {
|
||||
const videoRef = useRef<HTMLVideoElement | null>(null);
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
@@ -70,9 +72,9 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
|
||||
}, [videoPath]);
|
||||
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
className="w-full aspect-video rounded-xl p-8 flex items-center justify-center overflow-hidden bg-cover bg-center"
|
||||
style={{ backgroundImage: 'url(/wallpaper.png)' }}
|
||||
style={{ backgroundImage: `url(${wallpaper || '/wallpapers/wallpaper1.jpg'})` }}
|
||||
>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
|
||||