feat: enhance responsive layout of video page by adjusting visibility of the sidebar, video title, and new version button on various screen sizes.

This commit is contained in:
Yusuf İpek
2026-02-21 19:29:43 +03:00
parent e32196c430
commit 4cb4089caa
+130 -80
View File
@@ -1879,7 +1879,7 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
<Skeleton className="h-8 w-full rounded" /> <Skeleton className="h-8 w-full rounded" />
</div> </div>
</div> </div>
<div className={cn("w-80 shrink-0 border-l bg-card flex flex-col overflow-hidden", isFullscreenMode && !showComments && "hidden")}> <div className={cn("hidden lg:flex w-80 shrink-0 border-l bg-card flex-col overflow-hidden", isFullscreenMode && !showComments && "hidden")}>
<div className="shrink-0 flex items-center justify-between p-4 border-b"> <div className="shrink-0 flex items-center justify-between p-4 border-b">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Skeleton className="h-5 w-5" /> <Skeleton className="h-5 w-5" />
@@ -1987,7 +1987,7 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
onMouseLeave={() => isDragging && handleTimelineMouseUp()} onMouseLeave={() => isDragging && handleTimelineMouseUp()}
> >
<div className="flex-1 flex flex-col lg:flex-row overflow-y-auto lg:overflow-hidden min-h-0"> <div className="flex-1 flex flex-col lg:flex-row overflow-y-auto lg:overflow-hidden min-h-0">
<div className={cn("flex-none lg:flex-1 w-full aspect-video lg:aspect-auto flex flex-col min-h-0", isFullscreenMode && "relative")}> <div className={cn("flex-1 w-full flex flex-col min-h-0", isFullscreenMode && "relative")}>
<div className={cn( <div className={cn(
"shrink-0 flex items-center justify-between h-12 px-4 border-b bg-background/50", "shrink-0 flex items-center justify-between h-12 px-4 border-b bg-background/50",
isFullscreenMode ? "absolute top-0 left-0 right-0 z-50 transition-opacity duration-300" : "", isFullscreenMode ? "absolute top-0 left-0 right-0 z-50 transition-opacity duration-300" : "",
@@ -2002,7 +2002,7 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
Back Back
</Link> </Link>
<Separator orientation="vertical" className="h-5" /> <Separator orientation="vertical" className="h-5" />
<div className="min-w-0"> <div className="hidden sm:block min-w-0">
<span className="text-sm font-medium">{video.title}</span> <span className="text-sm font-medium">{video.title}</span>
<span className="text-xs text-muted-foreground ml-2"> {video.project.name}</span> <span className="text-xs text-muted-foreground ml-2"> {video.project.name}</span>
</div> </div>
@@ -2080,77 +2080,104 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
{mode === 'dashboard' && ( {mode === 'dashboard' && (
<> <>
<Dialog open={showVersionDialog} onOpenChange={setShowVersionDialog}> <div className="hidden sm:flex items-center gap-2">
<DialogTrigger asChild> <Dialog open={showVersionDialog} onOpenChange={setShowVersionDialog}>
<Button variant="outline" size="sm"> <DialogTrigger asChild>
<Plus className="h-4 w-4 mr-1" /> <Button variant="outline" size="sm">
New Version <Plus className="h-4 w-4 mr-1" />
</Button> New Version
</DialogTrigger> </Button>
<DialogContent> </DialogTrigger>
<DialogHeader> <DialogContent>
<DialogTitle>Add New Version</DialogTitle> <DialogHeader>
<DialogDescription> <DialogTitle>Add New Version</DialogTitle>
Upload a new version of this video. The new version will become active. <DialogDescription>
</DialogDescription> Upload a new version of this video. The new version will become active.
</DialogHeader> </DialogDescription>
<div className="space-y-4 mt-2"> </DialogHeader>
<div className="space-y-2"> <div className="space-y-4 mt-2">
<Label>Video URL</Label> <div className="space-y-2">
<div className="relative"> <Label>Video URL</Label>
<LinkIcon className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <div className="relative">
<LinkIcon className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
placeholder="https://youtube.com/watch?v=..."
value={newVersionUrl}
onChange={(e) => handleNewVersionUrlChange(e.target.value)}
className="pl-10"
disabled={isCreatingVersion}
/>
</div>
{newVersionUrlError && (
<p className="text-sm text-destructive flex items-center gap-1">
<AlertCircle className="h-4 w-4" />
{newVersionUrlError}
</p>
)}
{newVersionSource && (
<p className="text-sm text-green-600 flex items-center gap-1">
<CheckCircle2 className="h-4 w-4" />
{newVersionSource.providerId.charAt(0).toUpperCase() +
newVersionSource.providerId.slice(1)}{' '}
video detected
</p>
)}
</div>
<div className="space-y-2">
<Label>Version Label (optional)</Label>
<Input <Input
placeholder="https://youtube.com/watch?v=..." placeholder="e.g. Final Cut, Review Round 2"
value={newVersionUrl} value={newVersionLabel}
onChange={(e) => handleNewVersionUrlChange(e.target.value)} onChange={(e) => setNewVersionLabel(e.target.value)}
className="pl-10"
disabled={isCreatingVersion} disabled={isCreatingVersion}
/> />
</div> </div>
{newVersionUrlError && ( <Button
<p className="text-sm text-destructive flex items-center gap-1"> onClick={handleCreateVersion}
<AlertCircle className="h-4 w-4" /> disabled={!newVersionSource || isCreatingVersion}
{newVersionUrlError} className="w-full"
</p> >
)} {isCreatingVersion && <Loader2 className="h-4 w-4 mr-2 animate-spin" />}
{newVersionSource && ( Add Version {video.versions.length + 1}
<p className="text-sm text-green-600 flex items-center gap-1"> </Button>
<CheckCircle2 className="h-4 w-4" />
{newVersionSource.providerId.charAt(0).toUpperCase() +
newVersionSource.providerId.slice(1)}{' '}
video detected
</p>
)}
</div> </div>
<div className="space-y-2"> </DialogContent>
<Label>Version Label (optional)</Label> </Dialog>
<Input
placeholder="e.g. Final Cut, Review Round 2"
value={newVersionLabel}
onChange={(e) => setNewVersionLabel(e.target.value)}
disabled={isCreatingVersion}
/>
</div>
<Button
onClick={handleCreateVersion}
disabled={!newVersionSource || isCreatingVersion}
className="w-full"
>
{isCreatingVersion && <Loader2 className="h-4 w-4 mr-2 animate-spin" />}
Add Version {video.versions.length + 1}
</Button>
</div>
</DialogContent>
</Dialog>
{video.versions.length >= 2 && ( {video.versions.length >= 2 && (
<Button variant="outline" size="sm" asChild> <Button variant="outline" size="sm" asChild>
<Link href={`/projects/${propProjectId}/videos/${videoId}/compare`}> <Link href={`/projects/${propProjectId}/videos/${videoId}/compare`}>
<GitCompareArrows className="h-4 w-4 mr-1" /> <GitCompareArrows className="h-4 w-4 mr-1" />
Compare Compare
</Link> </Link>
</Button> </Button>
)} )}
</div>
{/* Mobile Actions Dropdown */}
<div className="sm:hidden">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon" className="h-8 w-8">
<MoreVertical className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onSelect={() => setShowVersionDialog(true)}>
<Plus className="h-4 w-4 mr-2" />
New Version
</DropdownMenuItem>
{video.versions.length >= 2 && (
<DropdownMenuItem asChild>
<Link href={`/projects/${propProjectId}/videos/${videoId}/compare`}>
<GitCompareArrows className="h-4 w-4 mr-2" />
Compare
</Link>
</DropdownMenuItem>
)}
</DropdownMenuContent>
</DropdownMenu>
</div>
</> </>
)} )}
</div> </div>
@@ -2277,7 +2304,7 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
{formatTime(currentTime)} / {formatTime(duration)} {formatTime(currentTime)} / {formatTime(duration)}
</span> </span>
<div className="ml-auto"> <div className="ml-auto flex items-center">
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm" className="h-8 gap-1 text-xs"> <Button variant="ghost" size="sm" className="h-8 gap-1 text-xs">
@@ -2308,7 +2335,7 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
{isFullscreenMode ? <Minimize className="h-4 w-4" /> : <Maximize className="h-4 w-4" />} {isFullscreenMode ? <Minimize className="h-4 w-4" /> : <Maximize className="h-4 w-4" />}
</Button> </Button>
{isFullscreenMode && ( {isFullscreenMode ? (
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
@@ -2318,6 +2345,16 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
> >
{showComments ? <MessageSquareOff className="h-4 w-4" /> : <MessageSquare className="h-4 w-4" />} {showComments ? <MessageSquareOff className="h-4 w-4" /> : <MessageSquare className="h-4 w-4" />}
</Button> </Button>
) : (
<Button
variant="ghost"
size="icon"
className="h-8 w-8 lg:hidden"
onClick={() => setIsMobileCommentsOpen(true)}
title="Show comments"
>
<MessageSquare className="h-4 w-4" />
</Button>
)} )}
</div> </div>
</div> </div>
@@ -2360,13 +2397,24 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
</div> </div>
</div> </div>
<div className={cn("w-full lg:w-80 shrink-0 border-t lg:border-t-0 lg:border-l bg-card flex flex-col overflow-hidden transition-[height] duration-300", {/* Mobile Backdrop */}
isFullscreenMode && !showComments ? "hidden" : "", <div
isMobileCommentsOpen ? "h-[500px] lg:h-auto" : "h-[60px] lg:h-auto" className={cn(
"fixed inset-0 z-40 bg-black/50 backdrop-blur-sm lg:hidden transition-opacity duration-300",
isMobileCommentsOpen ? "opacity-100" : "opacity-0 pointer-events-none"
)}
onClick={() => setIsMobileCommentsOpen(false)}
/>
<div className={cn(
"bg-card flex flex-col overflow-hidden z-50",
"fixed inset-y-0 right-0 w-[85%] sm:w-[400px] shadow-2xl transition-transform duration-300 transform",
isMobileCommentsOpen ? "translate-x-0" : "translate-x-full",
"lg:static lg:w-80 lg:shrink-0 lg:border-l lg:transition-none lg:translate-x-0 lg:shadow-none lg:z-auto",
isFullscreenMode && !showComments ? "hidden" : ""
)}> )}>
<div <div
className="shrink-0 flex items-center justify-between p-4 border-b cursor-pointer lg:cursor-default" className="shrink-0 flex items-center justify-between p-4 border-b lg:cursor-default"
onClick={() => setIsMobileCommentsOpen(!isMobileCommentsOpen)}
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<MessageSquare className="h-5 w-5" /> <MessageSquare className="h-5 w-5" />
@@ -2377,7 +2425,9 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
<Button variant="ghost" size="sm" onClick={(e) => { e.stopPropagation(); handleToggleShowResolved(); }}> <Button variant="ghost" size="sm" onClick={(e) => { e.stopPropagation(); handleToggleShowResolved(); }}>
{showResolved ? 'Hide' : 'Show'} Resolved {showResolved ? 'Hide' : 'Show'} Resolved
</Button> </Button>
<ChevronUp className={cn("h-4 w-4 transition-transform lg:hidden", isMobileCommentsOpen && "rotate-180")} /> <Button variant="ghost" size="icon" className="h-8 w-8 lg:hidden" onClick={() => setIsMobileCommentsOpen(false)}>
<X className="h-4 w-4" />
</Button>
</div> </div>
</div> </div>
@@ -2443,7 +2493,7 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="h-6 w-6 opacity-0 group-hover:opacity-100" className="h-6 w-6"
> >
<MoreVertical className="h-4 w-4" /> <MoreVertical className="h-4 w-4" />
</Button> </Button>
@@ -2647,7 +2697,7 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="h-5 w-5 opacity-0 group-hover/reply:opacity-100 shrink-0" className="h-5 w-5 shrink-0"
> >
<MoreVertical className="h-3 w-3" /> <MoreVertical className="h-3 w-3" />
</Button> </Button>
@@ -3187,7 +3237,7 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
)} )}
</div> </div>
</div> </div>
</div> </div >
<Dialog open={!!previewImage} onOpenChange={(open) => !open && setPreviewImage(null)}> <Dialog open={!!previewImage} onOpenChange={(open) => !open && setPreviewImage(null)}>
<DialogContent <DialogContent
@@ -3248,6 +3298,6 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
</div> </div>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</div> </div >
); );
} }