mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
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:
@@ -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 >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user