Skip to content

Commit b76f205

Browse files
committed
feat: Introduce a responsive dialog/drawer component and refactor post management to use React Query.
1 parent a9121c1 commit b76f205

17 files changed

Lines changed: 820 additions & 329 deletions

client/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"@simplewebauthn/browser": "^11.0.0",
3737
"@tanstack/react-query": "^5.90.18",
3838
"axios": "^1.7.7",
39-
"class-variance-authority": "^0.7.0",
39+
"class-variance-authority": "^0.7.1",
4040
"clsx": "^2.1.1",
4141
"cmdk": "1.1.1",
4242
"framer-motion": "^12.23.26",
@@ -60,7 +60,7 @@
6060
"sweetalert2": "^11.14.4",
6161
"tailwind-merge": "^2.5.4",
6262
"tailwindcss-animate": "^1.0.7",
63-
"vaul": "^1.1.1",
63+
"vaul": "^1.1.2",
6464
"yup": "^1.4.0",
6565
"zustand": "^5.0.3"
6666
},

client/src/Pages/Music/AddToPlaylist.jsx

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
22
import { Button } from "@/components/ui/button"
3-
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from "@/components/ui/drawer"
3+
import {
4+
ResponsiveDialog,
5+
ResponsiveDialogContent,
6+
ResponsiveDialogHeader,
7+
ResponsiveDialogTitle,
8+
} from "@/components/ui/revola"
49
import { Input } from "@/components/ui/input"
510
import { Label } from "@/components/ui/label"
611
import { ScrollArea } from "@/components/ui/scroll-area"
@@ -73,13 +78,13 @@ const AddToPlaylist = ({ dialogOpen, setDialogOpen, song }) => {
7378

7479
return (
7580
<>
76-
<Drawer open={dialogOpen} onOpenChange={setDialogOpen}>
77-
<DrawerContent className="max-h-[90vh]">
78-
<DrawerHeader className="space-y-4">
79-
<DrawerTitle className="flex items-center gap-2 text-xl">
81+
<ResponsiveDialog open={dialogOpen} onOpenChange={setDialogOpen}>
82+
<ResponsiveDialogContent className="sm:max-w-md p-0">
83+
<ResponsiveDialogHeader className="space-y-4 px-4 pt-4 sm:px-6 sm:pt-6">
84+
<ResponsiveDialogTitle className="flex items-center gap-2 text-xl">
8085
<ListMusic className="w-5 h-5" />
8186
Add to Playlist
82-
</DrawerTitle>
87+
</ResponsiveDialogTitle>
8388

8489
<div className="relative">
8590
<Search className="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" />
@@ -100,9 +105,9 @@ const AddToPlaylist = ({ dialogOpen, setDialogOpen, song }) => {
100105
</Button>
101106
)}
102107
</div>
103-
</DrawerHeader>
108+
</ResponsiveDialogHeader>
104109

105-
<div className="space-y-4 py-2 px-4 pb-6">
110+
<div className="space-y-4 py-2 px-4 pb-6 sm:px-6">
106111
<Button
107112
variant="outline"
108113
className="w-full flex items-center gap-2 h-10 text-base hover:bg-primary hover:text-primary-foreground transition-all duration-200"
@@ -177,15 +182,15 @@ const AddToPlaylist = ({ dialogOpen, setDialogOpen, song }) => {
177182
)}
178183
</ScrollArea>
179184
</div>
180-
</DrawerContent>
181-
</Drawer>
185+
</ResponsiveDialogContent>
186+
</ResponsiveDialog>
182187

183-
<Drawer open={newPlaylistDialog} onOpenChange={setNewPlaylistDialog}>
184-
<DrawerContent className="max-h-[60vh]">
185-
<DrawerHeader>
186-
<DrawerTitle className="text-xl">Create New Playlist</DrawerTitle>
187-
</DrawerHeader>
188-
<form onSubmit={handleCreatePlaylist} className="space-y-4 px-4 pb-6">
188+
<ResponsiveDialog open={newPlaylistDialog} onOpenChange={setNewPlaylistDialog}>
189+
<ResponsiveDialogContent className="sm:max-w-md p-0">
190+
<ResponsiveDialogHeader className="px-4 pt-4 sm:px-6 sm:pt-6">
191+
<ResponsiveDialogTitle className="text-xl">Create New Playlist</ResponsiveDialogTitle>
192+
</ResponsiveDialogHeader>
193+
<form onSubmit={handleCreatePlaylist} className="space-y-4 px-4 pb-6 sm:px-6">
189194
<div className="space-y-2">
190195
<Label htmlFor="playlistName">Playlist Name</Label>
191196
<Input
@@ -224,8 +229,8 @@ const AddToPlaylist = ({ dialogOpen, setDialogOpen, song }) => {
224229
</Button>
225230
</div>
226231
</form>
227-
</DrawerContent>
228-
</Drawer>
232+
</ResponsiveDialogContent>
233+
</ResponsiveDialog>
229234
</>
230235
)
231236
}

client/src/Pages/Music/BottomPlayer/PlayerControls.jsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,14 @@ const PlayerControls = memo(({ onMinimize, onOpenModal }) => {
4848
e.stopPropagation()
4949
onOpenModal()
5050
}}
51-
className="hidden sm:flex h-9 w-9 hover:bg-white/10 text-white/70 hover:text-white"
51+
className="hidden sm:flex h-9 w-9"
5252
>
5353
<ListMusic size={18} />
5454
</Button>
5555
</motion.div>
5656

5757
<motion.div whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
58-
<Button
59-
variant="ghost"
60-
size="icon"
61-
className={cn("h-9 w-9 hover:bg-white/10 text-white/70 hover:text-white")}
62-
onClick={onMinimize}
63-
>
58+
<Button variant="ghost" size="icon" className={cn("h-9 w-9 ")} onClick={onMinimize}>
6459
<ChevronDown size={18} />
6560
</Button>
6661
</motion.div>

client/src/Pages/Music/BottomPlayer/SongInfo.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ const SongInfo = memo(({ currentSong, onOpenSheet }) => {
4343

4444
<div className="flex flex-col min-w-0 flex-1 max-w-[140px] sm:max-w-[200px]">
4545
<div className="overflow-hidden">
46-
<p className="text-sm font-semibold text-white truncate">{decodedName}</p>
46+
<p className="text-sm font-semibold truncate">{decodedName}</p>
4747
</div>
48-
<p className="text-xs text-white/50 truncate">{decodedArtist}</p>
48+
<p className="text-xs truncate text-muted-foreground">{decodedArtist}</p>
4949
</div>
5050
</button>
5151
)

client/src/Pages/Music/Common.jsx

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,7 @@ export const MusicControls = memo(({ size = "default" }) => {
8686
variant="ghost"
8787
size="icon"
8888
onClick={handlePrevSong}
89-
className={cn(
90-
"text-white/70 hover:text-white hover:bg-white/10",
91-
isLarge ? "h-12 w-12" : "h-9 w-9",
92-
)}
89+
className={cn("", isLarge ? "h-12 w-12" : "h-9 w-9")}
9390
>
9491
<SkipBack className={isLarge ? "h-5 w-5" : "h-4 w-4"} fill="currentColor" />
9592
</Button>
@@ -117,10 +114,7 @@ export const MusicControls = memo(({ size = "default" }) => {
117114
variant="ghost"
118115
size="icon"
119116
onClick={handleNextSong}
120-
className={cn(
121-
"text-white/70 hover:text-white hover:bg-white/10",
122-
isLarge ? "h-12 w-12" : "h-9 w-9",
123-
)}
117+
className={cn("", isLarge ? "h-12 w-12" : "h-9 w-9")}
124118
>
125119
<SkipForward className={isLarge ? "h-5 w-5" : "h-4 w-4"} fill="currentColor" />
126120
</Button>
@@ -151,12 +145,7 @@ export const VolumeControl = memo(({ showVolume = false }) => {
151145
return (
152146
<div className="flex items-center gap-2 group">
153147
<motion.div whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }}>
154-
<Button
155-
variant="ghost"
156-
size="icon"
157-
className="h-9 w-9 text-white/70 hover:text-white hover:bg-white/10"
158-
onClick={toggleMute}
159-
>
148+
<Button variant="ghost" size="icon" className="h-9 w-9" onClick={toggleMute}>
160149
{isMuted || volume === 0 ? <VolumeX size={18} /> : <Volume2 size={18} />}
161150
</Button>
162151
</motion.div>

client/src/Pages/Music/SearchDialog.jsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Loader2, Search, X, XCircle } from "lucide-react"
22
import { useCallback, useEffect, useState } from "react"
33
import { Button } from "@/components/ui/button"
4-
import { Dialog, DialogContent } from "@/components/ui/dialog"
4+
import { ResponsiveDialog, ResponsiveDialogContent } from "@/components/ui/revola"
55
import { Input } from "@/components/ui/input"
66
import { ScrollArea } from "@/components/ui/scroll-area"
77
import { useBackendSearchQuery } from "@/hooks/queries/useSongQueries"
@@ -28,12 +28,12 @@ const SearchDialog = ({ open, setOpen }) => {
2828
}, [setOpen])
2929

3030
return (
31-
<Dialog open={open} onOpenChange={handleClose}>
32-
<DialogContent
33-
closeButton={false}
34-
className="sm:max-w-6xl p-0 overflow-hidden max-sm:h-screen max-sm:w-full"
31+
<ResponsiveDialog open={open} onOpenChange={handleClose}>
32+
<ResponsiveDialogContent
33+
showCloseButton={false}
34+
className="sm:max-w-6xl p-0 overflow-hidden max-sm:max-h-[95%]"
3535
>
36-
<div className="sticky max-sm:top-5 z-10 bg-background px-4 py-3 border-b flex justify-between h-20">
36+
<div className="sticky max-sm:top-0 z-10 bg-background px-4 py-3 border-b flex justify-between h-20">
3737
<div className="relative flex items-center sm:w-[95%]">
3838
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
3939
<Input
@@ -63,7 +63,7 @@ const SearchDialog = ({ open, setOpen }) => {
6363
</Button>
6464
</div>
6565

66-
<ScrollArea className="sm:h-[70vh]">
66+
<ScrollArea className="h-[60vh] sm:h-[70vh]">
6767
<div className="p-4">
6868
{isLoading ? (
6969
<div className="flex items-center justify-center h-40">
@@ -102,8 +102,8 @@ const SearchDialog = ({ open, setOpen }) => {
102102
)}
103103
</div>
104104
</ScrollArea>
105-
</DialogContent>
106-
</Dialog>
105+
</ResponsiveDialogContent>
106+
</ResponsiveDialog>
107107
)
108108
}
109109

client/src/Pages/Music/SleepTimer.jsx

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,18 @@ import { Badge } from "@/components/ui/badge"
44
import { Button } from "@/components/ui/button"
55
import { Card, CardContent } from "@/components/ui/card"
66
import {
7-
Dialog,
8-
DialogContent,
9-
DialogHeader,
10-
DialogTitle,
11-
DialogTrigger,
12-
} from "@/components/ui/dialog"
7+
ResponsiveDialog,
8+
ResponsiveDialogContent,
9+
ResponsiveDialogHeader,
10+
ResponsiveDialogTitle,
11+
ResponsiveDialogTrigger,
12+
} from "@/components/ui/revola"
1313
import { Label } from "@/components/ui/label"
1414
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
1515
import { Slider } from "@/components/ui/slider"
1616
import { usePlayerStore } from "@/stores/playerStore"
1717

1818
const SleepTimerModal = () => {
19-
// Individual selectors for sleep timer state
2019
const sleepTimer = usePlayerStore((s) => s.sleepTimer)
2120
const setSleepTimer = usePlayerStore((s) => s.setSleepTimer)
2221
const clearSleepTimer = usePlayerStore((s) => s.clearSleepTimer)
@@ -41,8 +40,8 @@ const SleepTimerModal = () => {
4140
}
4241

4342
return (
44-
<Dialog>
45-
<DialogTrigger asChild>
43+
<ResponsiveDialog>
44+
<ResponsiveDialogTrigger asChild>
4645
<Button
4746
variant="ghost"
4847
size="icon"
@@ -55,17 +54,17 @@ const SleepTimerModal = () => {
5554
<span className="absolute -top-1 -right-1 h-2 w-2 bg-destructive rounded-full animate-pulse" />
5655
)}
5756
</Button>
58-
</DialogTrigger>
59-
<DialogContent className="sm:max-w-[500px]">
60-
<DialogHeader>
61-
<DialogTitle className="flex items-center gap-2">
57+
</ResponsiveDialogTrigger>
58+
<ResponsiveDialogContent className="sm:max-w-[500px] p-0">
59+
<ResponsiveDialogHeader className="px-4 pt-4 sm:px-6 sm:pt-6">
60+
<ResponsiveDialogTitle className="flex items-center gap-2">
6261
<Clock size={24} />
6362
Sleep Timer
64-
</DialogTitle>
65-
</DialogHeader>
63+
</ResponsiveDialogTitle>
64+
</ResponsiveDialogHeader>
6665

67-
<Card className="w-full">
68-
<CardContent className="p-6 space-y-4">
66+
<Card className="w-full border-0 shadow-none">
67+
<CardContent className="p-4 sm:p-6 space-y-4">
6968
<RadioGroup
7069
defaultValue={timerType}
7170
onValueChange={setTimerType}
@@ -143,7 +142,8 @@ const SleepTimerModal = () => {
143142
</Badge>
144143
</div>
145144
<Button variant="destructive" size="sm" onClick={clearSleepTimer} className="gap-2">
146-
<X size={16} /> Cancel
145+
<X size={16} />
146+
Cancel
147147
</Button>
148148
</div>
149149
)}
@@ -158,8 +158,8 @@ const SleepTimerModal = () => {
158158
</Button>
159159
</CardContent>
160160
</Card>
161-
</DialogContent>
162-
</Dialog>
161+
</ResponsiveDialogContent>
162+
</ResponsiveDialog>
163163
)
164164
}
165165

0 commit comments

Comments
 (0)