@@ -6,14 +6,14 @@ import VideoPlayer from '@/components/VideoPlayer'
66import CommentSection from '@/components/CommentSection'
77import ThumbnailGrid from '@/components/ThumbnailGrid'
88import ThumbnailReel from '@/components/ThumbnailReel'
9- import ProjectInfo from '@/components/ProjectInfo'
109import { OTPInput } from '@/components/OTPInput'
1110import { Card , CardContent , CardHeader , CardTitle } from '@/components/ui/card'
1211import { Input } from '@/components/ui/input'
1312import { PasswordInput } from '@/components/ui/password-input'
1413import { Button } from '@/components/ui/button'
15- import { Lock , Check , Mail , KeyRound , MessageSquare } from 'lucide-react'
14+ import { Lock , Check , Mail , KeyRound } from 'lucide-react'
1615import { loadShareToken , saveShareToken } from '@/lib/share-token-store'
16+ import ThemeToggle from '@/components/ThemeToggle'
1717
1818interface SharePageClientProps {
1919 token : string
@@ -57,12 +57,6 @@ export default function SharePageClient({ token }: SharePageClientProps) {
5757 const [ initialVideoIndex , setInitialVideoIndex ] = useState < number > ( 0 )
5858 const [ shareToken , setShareToken ] = useState < string | null > ( null )
5959 const [ hideComments , setHideComments ] = useState ( false )
60- const [ videoState , setVideoState ] = useState < {
61- selectedVideo : any
62- isVideoApproved : boolean
63- displayVideos : any [ ]
64- displayLabel : string
65- } | null > ( null )
6660 const [ viewState , setViewState ] = useState < 'grid' | 'player' > ( 'grid' )
6761 const [ thumbnailsByName , setThumbnailsByName ] = useState < Map < string , string > > ( new Map ( ) )
6862 const [ thumbnailsLoading , setThumbnailsLoading ] = useState ( true )
@@ -849,12 +843,16 @@ export default function SharePageClient({ token }: SharePageClientProps) {
849843 return ! comment . videoId || activeVideoIds . has ( comment . videoId )
850844 } )
851845
852- // Show thumbnail grid for multi-video projects when in grid view
846+ // Show thumbnail grid for multi-video projects when in grid view (scrollable)
853847 if ( viewState === 'grid' && hasMultipleVideos ) {
854848 return (
855- < div className = "flex-1 min-h-0 bg-background flex flex-col overflow-hidden" >
849+ < div className = "fixed inset-0 bg-background flex flex-col overflow-hidden" >
850+ { /* Theme toggle for grid view */ }
851+ < div className = "absolute top-3 right-3 z-20" >
852+ < ThemeToggle />
853+ </ div >
856854 < div className = "flex-1 overflow-y-auto" >
857- < div className = "w-full px-4 sm:px-6 lg:px-8 py-6 sm:py-8" >
855+ < div className = "w-full px-3 sm:px-6 lg:px-8 py-4 sm:py-6 lg :py-8" >
858856 < ThumbnailGrid
859857 videosByName = { project . videosByName }
860858 thumbnailsByName = { thumbnailsByName }
@@ -870,9 +868,12 @@ export default function SharePageClient({ token }: SharePageClientProps) {
870868 )
871869 }
872870
871+ // Whether to show comment panel (not hidden by project settings, user toggle, or guest status)
872+ const showCommentPanel = ! project . hideFeedback && ! isGuest && ! hideComments
873+
873874 return (
874- < div className = "flex-1 min-h -0 bg-background flex flex-col overflow-hidden" >
875- { /* Thumbnail Reel for multi-video projects */ }
875+ < div className = "fixed inset -0 bg-background flex flex-col overflow-hidden" >
876+ { /* Thumbnail Reel for multi-video projects - always visible, collapsible */ }
876877 { hasMultipleVideos && (
877878 < ThumbnailReel
878879 videosByName = { project . videosByName }
@@ -881,123 +882,91 @@ export default function SharePageClient({ token }: SharePageClientProps) {
881882 onVideoSelect = { handleVideoSelect }
882883 onBackToGrid = { handleBackToGrid }
883884 showBackButton = { true }
885+ showCommentToggle = { ! project . hideFeedback && ! isGuest }
886+ isCommentPanelVisible = { ! hideComments }
887+ onToggleCommentPanel = { ( ) => setHideComments ( ! hideComments ) }
884888 />
885889 ) }
886890
887- { /* Main Content Area */ }
888- < div className = "flex-1 flex flex-col min-w-0 overflow-y-auto" >
889- { /* Content Area */ }
890- < div className = "w-full px-4 sm:px-6 lg:px-8 py-4 sm:py-8 flex-1 min-h-0 flex flex-col" >
891- { /* Content Area */ }
892- { readyVideos . length === 0 ? (
891+ { /* Theme toggle for single-video projects (floating in top-right) */ }
892+ { ! hasMultipleVideos && (
893+ < div className = "absolute top-3 right-3 z-20" >
894+ < ThemeToggle />
895+ </ div >
896+ ) }
897+
898+ { /* Main Content Area - fills remaining height */ }
899+ < div className = "flex-1 min-h-0 flex flex-col lg:flex-row p-2 sm:p-3 gap-2 sm:gap-3" >
900+ { readyVideos . length === 0 ? (
901+ < div className = "flex-1 flex items-center justify-center p-4" >
893902 < Card className = "bg-card border-border" >
894903 < CardContent className = "py-12 text-center" >
895904 < p className = "text-muted-foreground" >
896905 { tokensLoading ? 'Loading video...' : 'No videos are ready for review yet. Please check back later.' }
897906 </ p >
898907 </ CardContent >
899908 </ Card >
900- ) : (
901- < div className = { `flex-1 min-h-0 ${ ( project . hideFeedback || isGuest || hideComments ) ? 'flex flex-col max-w-7xl mx-auto w-full' : 'flex flex-col lg:grid gap-4 sm:gap-6 lg:grid-cols-3' } ` } >
902- { /* Video Player - order-1 on both mobile and desktop */ }
903- < div className = { `${ ( project . hideFeedback || isGuest || hideComments ) ? 'flex-1 min-h-0 flex flex-col relative' : 'order-1 lg:col-span-2' } ` } >
904- { /* Show Comments Toggle Button - visible when comments are hidden */ }
905- { ! project . hideFeedback && ! isGuest && hideComments && (
906- < Button
907- onClick = { ( ) => setHideComments ( false ) }
908- variant = "outline"
909- size = "sm"
910- className = "absolute top-4 right-4 z-10 hidden lg:flex items-center gap-2 bg-background/95 backdrop-blur-sm shadow-lg hover:bg-background"
911- title = "Show feedback & discussion"
912- >
913- < MessageSquare className = "w-4 h-4" />
914- Show Feedback
915- </ Button >
916- ) }
917- < VideoPlayer
918- videos = { readyVideos }
909+ </ div >
910+ ) : (
911+ < >
912+ { /* Video Player - fills available space */ }
913+ < div className = { `flex-1 min-h-0 min-w-0 flex flex-col rounded-xl overflow-hidden ${ showCommentPanel ? 'lg:flex-[2] xl:flex-[2.5]' : '' } ` } >
914+ < VideoPlayer
915+ videos = { readyVideos }
916+ projectId = { project . id }
917+ projectStatus = { project . status }
918+ defaultQuality = { defaultQuality }
919+ projectTitle = { project . title }
920+ projectDescription = { isGuest ? null : project . description }
921+ clientName = { isGuest ? null : project . clientName }
922+ isPasswordProtected = { isPasswordProtected || false }
923+ watermarkEnabled = { project . watermarkEnabled }
924+ activeVideoName = { activeVideoName }
925+ onApprove = { isGuest ? undefined : fetchProjectData }
926+ initialSeekTime = { initialSeekTime }
927+ initialVideoIndex = { initialVideoIndex }
928+ isAdmin = { false }
929+ isGuest = { isGuest }
930+ allowAssetDownload = { project . allowAssetDownload }
931+ clientCanApprove = { project . clientCanApprove }
932+ shareToken = { shareToken }
933+ comments = { ! project . hideFeedback && ! isGuest ? filteredComments : [ ] }
934+ timestampDisplayMode = { project . timestampDisplay || 'TIMECODE' }
935+ onCommentFocus = { ( commentId ) => setFocusCommentId ( commentId ) }
936+ usePreviewForApprovedPlayback = { project . usePreviewForApprovedPlayback }
937+ fillContainer = { true }
938+ />
939+ </ div >
940+
941+ { /* Comments Section - proportional side panel on desktop, collapsible on mobile */ }
942+ { showCommentPanel && (
943+ < div className = "shrink-0 lg:shrink lg:flex-1 lg:max-w-[30%] xl:max-w-[25%] lg:min-w-[280px] flex flex-col max-h-[35vh] lg:max-h-full lg:h-full overflow-hidden rounded-xl bg-card" >
944+ < CommentSection
919945 projectId = { project . id }
920- projectStatus = { project . status }
921- defaultQuality = { defaultQuality }
922- projectTitle = { project . title }
923- projectDescription = { isGuest ? null : project . description }
924- clientName = { isGuest ? null : project . clientName }
946+ comments = { filteredComments }
947+ focusCommentId = { focusCommentId }
948+ clientName = { project . clientName }
949+ clientEmail = { project . clientEmail }
950+ isApproved = { project . status === 'APPROVED' || project . status === 'SHARE_ONLY' }
951+ restrictToLatestVersion = { project . restrictCommentsToLatestVersion }
952+ videos = { readyVideos }
953+ isAdminView = { false }
954+ smtpConfigured = { project . smtpConfigured }
925955 isPasswordProtected = { isPasswordProtected || false }
926- watermarkEnabled = { project . watermarkEnabled }
927- activeVideoName = { activeVideoName }
928- onApprove = { isGuest ? undefined : fetchProjectData }
929- initialSeekTime = { initialSeekTime }
930- initialVideoIndex = { initialVideoIndex }
931- isAdmin = { false }
932- isGuest = { isGuest }
933- allowAssetDownload = { project . allowAssetDownload }
934- clientCanApprove = { project . clientCanApprove }
956+ recipients = { project . recipients || [ ] }
935957 shareToken = { shareToken }
936- comments = { ! project . hideFeedback && ! isGuest ? filteredComments : [ ] }
958+ showShortcutsButton = { true }
937959 timestampDisplayMode = { project . timestampDisplay || 'TIMECODE' }
938- onCommentFocus = { ( commentId ) => setFocusCommentId ( commentId ) }
939- onVideoStateChange = { setVideoState }
940- usePreviewForApprovedPlayback = { project . usePreviewForApprovedPlayback }
960+ mobileCollapsible = { true }
961+ initialMobileCollapsed = { true }
962+ authenticatedEmail = { authenticatedEmail }
963+ onToggleVisibility = { ( ) => setHideComments ( ! hideComments ) }
964+ showToggleButton = { false }
941965 />
942966 </ div >
943-
944- { /* Comments Section (input + collapsible messages) - order-2 */ }
945- { ! project . hideFeedback && ! isGuest && ! hideComments && (
946- < div className = "order-2 lg:sticky lg:top-6 lg:self-start" >
947- < CommentSection
948- projectId = { project . id }
949- comments = { filteredComments }
950- focusCommentId = { focusCommentId }
951- clientName = { project . clientName }
952- clientEmail = { project . clientEmail }
953- isApproved = { project . status === 'APPROVED' || project . status === 'SHARE_ONLY' }
954- restrictToLatestVersion = { project . restrictCommentsToLatestVersion }
955- videos = { readyVideos }
956- isAdminView = { false }
957- smtpConfigured = { project . smtpConfigured }
958- isPasswordProtected = { isPasswordProtected || false }
959- recipients = { project . recipients || [ ] }
960- shareToken = { shareToken }
961- showShortcutsButton = { true }
962- timestampDisplayMode = { project . timestampDisplay || 'TIMECODE' }
963- mobileCollapsible = { true }
964- initialMobileCollapsed = { true }
965- authenticatedEmail = { authenticatedEmail }
966- onToggleVisibility = { ( ) => setHideComments ( ! hideComments ) }
967- showToggleButton = { true }
968- />
969- </ div >
970- ) }
971-
972- { /* Project Info - order-3 on mobile only, hidden on desktop */ }
973- { videoState && ! isGuest && (
974- < div className = "order-3 lg:hidden" >
975- < ProjectInfo
976- selectedVideo = { videoState . selectedVideo }
977- displayLabel = { videoState . displayLabel }
978- isVideoApproved = { videoState . isVideoApproved }
979- projectId = { project . id }
980- projectTitle = { project . title }
981- projectDescription = { project . description }
982- clientName = { project . clientName }
983- isPasswordProtected = { isPasswordProtected || false }
984- watermarkEnabled = { project . watermarkEnabled }
985- defaultQuality = { defaultQuality }
986- onApprove = { fetchProjectData }
987- isAdmin = { false }
988- clientCanApprove = { project . clientCanApprove }
989- isGuest = { false }
990- hideDownloadButton = { false }
991- allowAssetDownload = { project . allowAssetDownload }
992- shareToken = { shareToken }
993- activeVideoName = { activeVideoName }
994- usePreviewForApprovedPlayback = { project . usePreviewForApprovedPlayback }
995- />
996- </ div >
997- ) }
998- </ div >
999- ) }
1000- </ div >
967+ ) }
968+ </ >
969+ ) }
1001970 </ div >
1002971 </ div >
1003972 )
0 commit comments