1
1
import React , { Suspense , useState } from "react" ;
2
- import { useAtom , useAtomValue } from "jotai" ;
2
+ import { useAtom , useAtomValue , useSetAtom } from "jotai" ;
3
3
import { Button } from "@/shadcn/ui/button" ;
4
4
import { Dialog , DialogContent } from "@/shadcn/ui/dialog" ;
5
5
import {
@@ -29,6 +29,8 @@ import { userAtom } from "@/store/auth";
29
29
import { Link } from "react-router-dom" ;
30
30
import { LazyNewPlaylistDialog } from "../video/LazyNewPlaylistDialog" ;
31
31
import { useToast } from "@/shadcn/ui/use-toast" ;
32
+ import { queueAtom } from "@/store/queue" ;
33
+
32
34
const SelectedVideosModal = ( {
33
35
isSmall,
34
36
open,
@@ -38,7 +40,7 @@ const SelectedVideosModal = ({
38
40
open : boolean ;
39
41
onOpenChange : ( open : boolean ) => void ;
40
42
} ) => {
41
- const { selectedVideos } = useVideoSelection ( ) ;
43
+ const { selectedVideos, setSelectedVideos } = useVideoSelection ( ) ;
42
44
43
45
const getThumbnailSrc = ( video : PlaceholderVideo ) => {
44
46
const size = isSmall ? "sm" : "md" ;
@@ -47,16 +49,40 @@ const SelectedVideosModal = ({
47
49
48
50
return (
49
51
< Dialog open = { open } onOpenChange = { onOpenChange } >
50
- < DialogContent >
51
- { selectedVideos . map ( ( video ) => (
52
- < div key = { video . id } className = "flex items-center space-x-4 p-2" >
53
- < VideoThumbnail
54
- src = { getThumbnailSrc ( video ) }
55
- alt = { video . title }
56
- className = "h-auto w-24 rounded"
57
- />
58
- < div >
59
- < h3 className = "font-semibold" > { video . title } </ h3 >
52
+ < DialogContent className = "flex max-h-[50vh] min-w-min max-w-[min(500px,calc(100vw-40px))] flex-col gap-0 overflow-y-auto overflow-x-hidden px-0 py-6" >
53
+ { selectedVideos . map ( ( video , idx ) => (
54
+ < div
55
+ key = { video . id }
56
+ className = {
57
+ "flex items-center space-x-2 px-2 py-1 " +
58
+ ( idx % 2 === 0 ? "bg-base-3" : "" )
59
+ }
60
+ >
61
+ < Button
62
+ variant = "ghost"
63
+ size = "icon-lg"
64
+ className = "size-10 shrink-0"
65
+ onClick = { ( ) =>
66
+ setSelectedVideos ( ( prev ) =>
67
+ prev . filter ( ( v ) => v . id !== video . id ) ,
68
+ )
69
+ }
70
+ >
71
+ < div className = "i-heroicons:x-mark" />
72
+ < span className = "sr-only" > Remove</ span >
73
+ </ Button >
74
+ < Link
75
+ to = { `/watch/${ video . id } ` }
76
+ className = "block w-24 shrink-0 overflow-hidden rounded"
77
+ >
78
+ < VideoThumbnail
79
+ src = { getThumbnailSrc ( video ) }
80
+ alt = { video . title }
81
+ className = ""
82
+ />
83
+ </ Link >
84
+ < div className = "min-w-80" >
85
+ < h3 className = "line-clamp-2 font-semibold" > { video . title } </ h3 >
60
86
< p className = "text-sm text-gray-500" > { } </ p >
61
87
{ /* what was i doing here again why is this block empty ^ */ }
62
88
</ div >
@@ -141,37 +167,7 @@ const SelectionFooter = () => {
141
167
Open in Multiview
142
168
</ Button >
143
169
144
- < DropdownMenu >
145
- < DropdownMenuTrigger asChild >
146
- < Button
147
- variant = "base-outline"
148
- size = "sm"
149
- disabled = { ! selectedVideos . length }
150
- className = "flex items-center"
151
- >
152
- < span className = "i-heroicons:folder-open mr-2" />
153
- { t ( "component.mainNav.playlist" ) }
154
- < div className = "i-lucide:chevron-up ml-2 size-4" > </ div >
155
- </ Button >
156
- </ DropdownMenuTrigger >
157
- < DropdownMenuContent >
158
- < DropdownMenuItem onClick = { ( ) => setPage ( 1 ) } >
159
- < div className = "i-heroicons:queue-list" />
160
- Add to Queue
161
- </ DropdownMenuItem >
162
- < DropdownMenuGroup >
163
- < DropdownMenuSub >
164
- < DropdownMenuSubTrigger className = "bg-base-1" >
165
- < div className = "i-solar:playlist-broken" />
166
- Add to Playlist
167
- </ DropdownMenuSubTrigger >
168
- < DropdownMenuPortal >
169
- < PlaylistMenuItems />
170
- </ DropdownMenuPortal >
171
- </ DropdownMenuSub >
172
- </ DropdownMenuGroup >
173
- </ DropdownMenuContent >
174
- </ DropdownMenu >
170
+ < SelectionModifyPlaylistMenu disabled = { ! selectedVideos . length } />
175
171
176
172
< DropdownMenu >
177
173
< DropdownMenuTrigger asChild >
@@ -263,14 +259,77 @@ const SelectionFooter = () => {
263
259
) ;
264
260
} ;
265
261
266
- function PlaylistMenuItems ( ) {
262
+ function SelectionModifyPlaylistMenu ( { disabled } : { disabled : boolean } ) {
263
+ const { t } = useTranslation ( ) ;
264
+ const { selectedVideos } = useVideoSelection ( ) ;
265
+
266
+ const setQueue = useSetAtom ( queueAtom ) ;
267
+ const { toast } = useToast ( ) ;
268
+
269
+ return (
270
+ < DropdownMenu >
271
+ < DropdownMenuTrigger asChild >
272
+ < Button
273
+ variant = "base-outline"
274
+ size = "sm"
275
+ disabled = { disabled }
276
+ className = "flex items-center"
277
+ >
278
+ < span className = "i-heroicons:folder-open mr-2" />
279
+ { t ( "component.mainNav.playlist" ) }
280
+ < div className = "i-lucide:chevron-up ml-2 size-4" > </ div >
281
+ </ Button >
282
+ </ DropdownMenuTrigger >
283
+ < DropdownMenuContent >
284
+ < DropdownMenuItem
285
+ onClick = { ( ) => {
286
+ setQueue ( ( prev ) => {
287
+ return [
288
+ ...selectedVideos . filter (
289
+ ( v ) => v . type === "stream" || v . type === "clip" ,
290
+ ) ,
291
+ ...prev . filter (
292
+ ( v ) => ! selectedVideos . find ( ( { id } ) => id === v . id ) ,
293
+ ) ,
294
+ ] ;
295
+ } ) ;
296
+
297
+ toast ( {
298
+ variant : "primary" ,
299
+ title : "Added to queue" ,
300
+ duration : 2000 ,
301
+ } ) ;
302
+ } }
303
+ >
304
+ < div className = "i-heroicons:queue-list" />
305
+ Add to Queue
306
+ </ DropdownMenuItem >
307
+ < DropdownMenuGroup >
308
+ < DropdownMenuSub >
309
+ < DropdownMenuSubTrigger className = "bg-base-1" >
310
+ < div className = "i-solar:playlist-broken" />
311
+ Add to Playlist
312
+ </ DropdownMenuSubTrigger >
313
+ < DropdownMenuPortal >
314
+ < SelectionModifyPlaylistSubmenu />
315
+ </ DropdownMenuPortal >
316
+ </ DropdownMenuSub >
317
+ </ DropdownMenuGroup >
318
+ </ DropdownMenuContent >
319
+ </ DropdownMenu >
320
+ ) ;
321
+ }
322
+
323
+ function SelectionModifyPlaylistSubmenu ( ) {
267
324
const { t } = useTranslation ( ) ;
268
325
const { toast } = useToast ( ) ;
269
326
270
327
const { mutate } = usePlaylistVideoMassAddMutation ( {
271
328
onSuccess : ( ) => {
272
329
toast ( {
273
330
title : "Added to playlist" ,
331
+ duration : 2000 ,
332
+ variant : "primary" ,
274
333
} ) ;
275
334
} ,
276
335
} ) ;
0 commit comments