diff options
Diffstat (limited to 'apps/web/src/components')
| -rw-r--r-- | apps/web/src/components/editor/media-panel.tsx | 86 | ||||
| -rw-r--r-- | apps/web/src/components/editor/timeline.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/components/header.tsx | 18 | ||||
| -rw-r--r-- | apps/web/src/components/icons.tsx | 17 | ||||
| -rw-r--r-- | apps/web/src/components/landing/hero.tsx | 4 |
5 files changed, 92 insertions, 35 deletions
diff --git a/apps/web/src/components/editor/media-panel.tsx b/apps/web/src/components/editor/media-panel.tsx index 0d6a1f1c..95cfa0a8 100644 --- a/apps/web/src/components/editor/media-panel.tsx +++ b/apps/web/src/components/editor/media-panel.tsx @@ -7,7 +7,7 @@ import { useMediaStore } from "@/stores/media-store"; import { processMediaFiles } from "@/lib/media-processing"; import { Plus, Image, Video, Music, Trash2, Upload } from "lucide-react"; import { useDragDrop } from "@/hooks/use-drag-drop"; -import { useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { toast } from "sonner"; // MediaPanel lets users add, view, and drag media (images, videos, audio) into the project. @@ -17,6 +17,8 @@ export function MediaPanel() { const { mediaItems, addMediaItem, removeMediaItem } = useMediaStore(); const fileInputRef = useRef<HTMLInputElement>(null); const [isProcessing, setIsProcessing] = useState(false); + const [searchQuery, setSearchQuery] = useState(""); + const [mediaFilter, setMediaFilter] = useState("all"); const processFiles = async (files: FileList | File[]) => { // If no files, do nothing @@ -78,6 +80,24 @@ export function MediaPanel() { e.dataTransfer.effectAllowed = "copy"; }; + const [filteredMediaItems, setFilteredMediaItems] = useState(mediaItems); + + useEffect(() => { + const filtered = mediaItems.filter((item) => { + if (mediaFilter && mediaFilter !== 'all' && item.type !== mediaFilter) { + return false; + } + + if (searchQuery && !item.name.toLowerCase().includes(searchQuery.toLowerCase())) { + return false; + } + + return true; + }); + + setFilteredMediaItems(filtered); + }, [mediaItems, mediaFilter, searchQuery]); + const renderPreview = (item: any) => { // Render a preview for each media type (image, video, audio, unknown) // Each preview is draggable to the timeline @@ -187,30 +207,52 @@ export function MediaPanel() { <div className="p-2 border-b"> {/* Button to add/upload media */} - <Button - variant="outline" - size="sm" - className="w-full" - onClick={handleFileSelect} - disabled={isProcessing} - > - {isProcessing ? ( - <> - <Upload className="h-4 w-4 mr-2 animate-spin" /> - Processing... - </> - ) : ( - <> - <Plus className="h-4 w-4 mr-2" /> - Add Media - </> - )} - </Button> + <div className="flex gap-2"> + {/* Search and filter controls */} + <select + value={mediaFilter} + onChange={(e) => setMediaFilter(e.target.value)} + className="px-2 py-1 text-xs border rounded bg-background" + > + <option value="all">All</option> + <option value="video">Video</option> + <option value="audio">Audio</option> + <option value="image">Image</option> + </select> + <input + type="text" + placeholder="Search media..." + className="min-w-[60px] flex-1 px-2 py-1 text-xs border rounded bg-background" + value={searchQuery} + onChange={(e) => setSearchQuery(e.target.value)} + /> + + {/* Add media button */} + <Button + variant="outline" + size="sm" + onClick={handleFileSelect} + disabled={isProcessing} + className="flex-none min-w-[80px] whitespace-nowrap" + > + {isProcessing ? ( + <> + <Upload className="h-4 w-4 mr-2 animate-spin" /> + Processing... + </> + ) : ( + <> + <Plus className="h-4 w-4" /> + Add + </> + )} + </Button> + </div> </div> <div className="flex-1 overflow-y-auto p-2"> {/* Show message if no media, otherwise show media grid */} - {mediaItems.length === 0 ? ( + {filteredMediaItems.length === 0 ? ( <div className="flex flex-col items-center justify-center py-8 text-center h-full"> <div className="w-16 h-16 rounded-full bg-muted/30 flex items-center justify-center mb-4"> <Image className="h-8 w-8 text-muted-foreground" /> @@ -225,7 +267,7 @@ export function MediaPanel() { ) : ( <div className="grid grid-cols-2 gap-2"> {/* Render each media item as a draggable button */} - {mediaItems.map((item) => ( + {filteredMediaItems.map((item) => ( <div key={item.id} className="relative group"> <Button variant="outline" diff --git a/apps/web/src/components/editor/timeline.tsx b/apps/web/src/components/editor/timeline.tsx index c397dd1a..0d021604 100644 --- a/apps/web/src/components/editor/timeline.tsx +++ b/apps/web/src/components/editor/timeline.tsx @@ -1711,7 +1711,7 @@ function TimelineTrackContent({ return (
<div
key={clip.id}
- className={`timeline-clip absolute h-full rounded-sm border transition-all duration-200 ${getTrackColor(track.type)} flex items-center py-3 min-w-[80px] overflow-hidden group hover:shadow-lg ${isSelected ? "ring-2 ring-blue-500 z-10" : ""}`}
+ className={`timeline-clip absolute h-full border transition-all duration-200 ${getTrackColor(track.type)} flex items-center py-3 min-w-[80px] overflow-hidden group hover:shadow-lg ${isSelected ? "ring-2 ring-blue-500 z-10" : ""}`}
style={{ width: `${clipWidth}px`, left: `${clipLeft}px` }}
onClick={(e) => {
e.stopPropagation();
diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx index 8c3ce610..812b0afc 100644 --- a/apps/web/src/components/header.tsx +++ b/apps/web/src/components/header.tsx @@ -36,19 +36,17 @@ export function Header() { const rightContent = (
<nav className="flex items-center">
+ <Link href="/contributors">
+ <Button variant="text" className="text-sm">
+ Contributors
+ </Button>
+ </Link>
<Link href="https://github.com/OpenCut-app/OpenCut" target="_blank">
- <Button
- variant="text"
- className="flex items-center text-sm text-muted-foreground hover:text-foreground"
- >
- <span className="hidden sm:inline">GitHub</span>
- <span className="text-foreground flex items-center">
- {star}+
- <Star className="w-4 h-4 ml-1" />
- </span>
+ <Button variant="text" className="text-sm">
+ GitHub
</Button>
</Link>
- <Link href={session ? "/editor" : "/login"}>
+ <Link href={session ? "/editor" : "/auth/login"}>
<Button size="sm" className="text-sm ml-4">
Start editing
<ArrowRight className="h-4 w-4" />
diff --git a/apps/web/src/components/icons.tsx b/apps/web/src/components/icons.tsx index 5cc24157..e63b6c79 100644 --- a/apps/web/src/components/icons.tsx +++ b/apps/web/src/components/icons.tsx @@ -20,3 +20,20 @@ export function GoogleIcon({ className }: { className?: string }) { </svg> ); } + +export function GithubIcon({ className }: { className?: string }) { + return ( + <svg + xmlns="http://www.w3.org/2000/svg" + className={className} + viewBox="0 -3.5 256 256" + preserveAspectRatio="xMinYMin meet" + > + <g fill="#161614"> + <path d="M127.505 0C57.095 0 0 57.085 0 127.505c0 56.336 36.534 104.13 87.196 120.99 6.372 1.18 8.712-2.766 8.712-6.134 0-3.04-.119-13.085-.173-23.739-35.473 7.713-42.958-15.044-42.958-15.044-5.8-14.738-14.157-18.656-14.157-18.656-11.568-7.914.872-7.752.872-7.752 12.804.9 19.546 13.14 19.546 13.14 11.372 19.493 29.828 13.857 37.104 10.6 1.144-8.242 4.449-13.866 8.095-17.05-28.32-3.225-58.092-14.158-58.092-63.014 0-13.92 4.981-25.295 13.138-34.224-1.324-3.212-5.688-16.18 1.235-33.743 0 0 10.707-3.427 35.073 13.07 10.17-2.826 21.078-4.242 31.914-4.29 10.836.048 21.752 1.464 31.942 4.29 24.337-16.497 35.029-13.07 35.029-13.07 6.94 17.563 2.574 30.531 1.25 33.743 8.175 8.929 13.122 20.303 13.122 34.224 0 48.972-29.828 59.756-58.22 62.912 4.573 3.957 8.648 11.717 8.648 23.612 0 17.06-.148 30.791-.148 34.991 0 3.393 2.295 7.369 8.759 6.117 50.634-16.879 87.122-64.656 87.122-120.973C255.009 57.085 197.922 0 127.505 0" /> + + <path d="M47.755 181.634c-.28.633-1.278.823-2.185.389-.925-.416-1.445-1.28-1.145-1.916.275-.652 1.273-.834 2.196-.396.927.415 1.455 1.287 1.134 1.923M54.027 187.23c-.608.564-1.797.302-2.604-.589-.834-.889-.99-2.077-.373-2.65.627-.563 1.78-.3 2.616.59.834.899.996 2.08.36 2.65M58.33 194.39c-.782.543-2.06.034-2.849-1.1-.781-1.133-.781-2.493.017-3.038.792-.545 2.05-.055 2.85 1.07.78 1.153.78 2.513-.019 3.069M65.606 202.683c-.699.77-2.187.564-3.277-.488-1.114-1.028-1.425-2.487-.724-3.258.707-.772 2.204-.555 3.302.488 1.107 1.026 1.445 2.496.7 3.258M75.01 205.483c-.307.998-1.741 1.452-3.185 1.028-1.442-.437-2.386-1.607-2.095-2.616.3-1.005 1.74-1.478 3.195-1.024 1.44.435 2.386 1.596 2.086 2.612M85.714 206.67c.036 1.052-1.189 1.924-2.705 1.943-1.525.033-2.758-.818-2.774-1.852 0-1.062 1.197-1.926 2.721-1.951 1.516-.03 2.758.815 2.758 1.86M96.228 206.267c.182 1.026-.872 2.08-2.377 2.36-1.48.27-2.85-.363-3.039-1.38-.184-1.052.89-2.105 2.367-2.378 1.508-.262 2.857.355 3.049 1.398" /> + </g> + </svg> + ); +} diff --git a/apps/web/src/components/landing/hero.tsx b/apps/web/src/components/landing/hero.tsx index 7b2586c3..2830097d 100644 --- a/apps/web/src/components/landing/hero.tsx +++ b/apps/web/src/components/landing/hero.tsx @@ -109,8 +109,8 @@ export function Hero({ signupCount }: HeroProps) { animate={{ opacity: 1 }}
transition={{ delay: 0.4, duration: 0.8 }}
>
- A simple but powerful video editor that gets the job done. In your
- browser.
+ A simple but powerful video editor that gets the job done. Works on
+ any platform.
</motion.p>
<motion.div
|
