feat: add music examples

This commit is contained in:
zernonia 2023-09-05 16:56:31 +08:00
parent a8ebf5ea73
commit 6b747b14a4
10 changed files with 853 additions and 34 deletions

View File

@ -38,7 +38,7 @@
"postcss": "^8.4.24", "postcss": "^8.4.24",
"radix-vue": "^0.1.30", "radix-vue": "^0.1.30",
"tailwind-merge": "^1.14.0", "tailwind-merge": "^1.14.0",
"tailwindcss": "^3.3.2", "tailwindcss": "^3.3.3",
"typescript": "^5.0.2", "typescript": "^5.0.2",
"unplugin-icons": "^0.16.6", "unplugin-icons": "^0.16.6",
"vite": "^4.3.9", "vite": "^4.3.9",

View File

@ -0,0 +1,5 @@
<script setup>
import MusicExample from "@/examples/music/Example.vue"
</script>
<MusicExample />

View File

@ -0,0 +1,147 @@
<script setup lang="ts">
import AlbumArtwork from './components/AlbumArtwork.vue'
import Menu from './components/Menu.vue'
import PodcastEmptyPlaceholder from './components/PodcastEmptyPlaceholder.vue'
import Sidebar from './components/Sidebar.vue'
import { listenNowAlbums, madeForYouAlbums } from './data/albums'
import { playlists } from './data/playlists'
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from '@/lib/registry/default/ui/tabs'
import { Separator } from '@/lib/registry/default/ui/separator'
import { Button } from '@/lib/registry/default/ui/button'
import { ScrollArea, ScrollBar } from '@/lib/registry/default/ui/scroll-area'
import PlusCircledIcon from '~icons/radix-icons/plus-circled'
</script>
<template>
<!-- <div class="md:hidden">
<Image
src="/examples/music-light.png"
width={1280}
height={1114}
alt="Music"
class="block dark:hidden"
/>
<Image
src="/examples/music-dark.png"
width={1280}
height={1114}
alt="Music"
class="hidden dark:block"
/>
</div> -->
<div class="hidden md:block">
<Menu />
<div class="border-t">
<div class="bg-background">
<div class="grid lg:grid-cols-5">
<Sidebar :playlists="playlists" class="hidden lg:block" />
<div class="col-span-3 lg:col-span-4 lg:border-l">
<div class="h-full px-4 py-6 lg:px-8">
<Tabs default-value="music" class="h-full space-y-6">
<div class="space-between flex items-center">
<TabsList>
<TabsTrigger value="music" class="relative">
Music
</TabsTrigger>
<TabsTrigger value="podcasts">
Podcasts
</TabsTrigger>
<TabsTrigger value="live" disabled>
Live
</TabsTrigger>
</TabsList>
<div class="ml-auto mr-4">
<Button>
<PlusCircledIcon class="mr-2 h-4 w-4" />
Add music
</Button>
</div>
</div>
<TabsContent
value="music"
class="border-none p-0 outline-none"
>
<div class="flex items-center justify-between">
<div class="space-y-1">
<h2 class="text-2xl font-semibold tracking-tight">
Listen Now
</h2>
<p class="text-sm text-muted-foreground">
Top picks for you. Updated daily.
</p>
</div>
</div>
<Separator class="my-4" />
<div class="relative">
<ScrollArea>
<div class="flex space-x-4 pb-4">
<AlbumArtwork
v-for="album in listenNowAlbums"
:key="album.name"
:album="album"
class="w-[250px]"
aspect-ratio="portrait"
:width="250"
:height="330"
/>
</div>
<ScrollBar orientation="horizontal" />
</ScrollArea>
</div>
<div class="mt-6 space-y-1">
<h2 class="text-2xl font-semibold tracking-tight">
Made for You
</h2>
<p class="text-sm text-muted-foreground">
Your personal playlists. Updated daily.
</p>
</div>
<Separator class="my-4" />
<div class="relative">
<ScrollArea>
<div class="flex space-x-4 pb-4">
<AlbumArtwork
v-for="album in madeForYouAlbums"
:key="album.name"
:album="album"
class="w-[150px]"
aspect-ratio="square"
:width="150"
:height="150"
/>
</div>
<ScrollBar orientation="horizontal" />
</ScrollArea>
</div>
</TabsContent>
<TabsContent
value="podcasts"
class="h-full flex-col border-none p-0 data-[state=active]:flex"
>
<div class="flex items-center justify-between">
<div class="space-y-1">
<h2 class="text-2xl font-semibold tracking-tight">
New Episodes
</h2>
<p class="text-sm text-muted-foreground">
Your favorite podcasts. Updated daily.
</p>
</div>
</div>
<Separator class="my-4" />
<PodcastEmptyPlaceholder />
</TabsContent>
</Tabs>
</div>
</div>
</div>
</div>
</div>
</div>
</template>

View File

@ -0,0 +1,91 @@
<script setup lang="ts">
import type { Album } from '../data/albums'
import { playlists } from '../data/playlists'
import PlusCircledIcon from '~icons/radix-icons/plus-circled'
import { cn } from '@/lib/utils'
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuTrigger,
} from '@/lib/registry/default/ui/context-menu'
interface AlbumArtworkProps {
album: Album
aspectRatio?: 'portrait' | 'square'
width?: number
height?: number
}
withDefaults(defineProps<AlbumArtworkProps>(), {
aspectRatio: 'portrait',
})
</script>
<template>
<div :class="cn('space-y-3', $attrs.class ?? '')">
<ContextMenu>
<ContextMenuTrigger>
<div class="overflow-hidden rounded-md">
<img
:src="album.cover"
:alt="album.name"
:width="width"
:height="height"
:class="cn(
'h-auto w-auto object-cover transition-all hover:scale-105',
aspectRatio === 'portrait' ? 'aspect-[3/4]' : 'aspect-square',
)"
>
</div>
</ContextMenuTrigger>
<ContextMenuContent class="w-40">
<ContextMenuItem>Add to Library</ContextMenuItem>
<ContextMenuSub>
<ContextMenuSubTrigger>Add to Playlist</ContextMenuSubTrigger>
<ContextMenuSubContent class="w-48">
<ContextMenuItem>
<PlusCircledIcon class="mr-2 h-4 w-4" />
New Playlist
</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem v-for="playlist in playlists" :key="playlist">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
class="mr-2 h-4 w-4"
viewBox="0 0 24 24"
>
<path d="M21 15V6M18.5 18a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5ZM12 12H3M16 6H3M12 18H3" />
</svg>
{{ playlist }}
</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuSeparator />
<ContextMenuItem>Play Next</ContextMenuItem>
<ContextMenuItem>Play Later</ContextMenuItem>
<ContextMenuItem>Create Station</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem>Like</ContextMenuItem>
<ContextMenuItem>Share</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
<div class="space-y-1 text-sm">
<h3 class="font-medium leading-none">
{{ album.name }}
</h3>
<p class="text-xs text-muted-foreground">
{{ album.artist }}
</p>
</div>
</div>
</template>

View File

@ -0,0 +1,230 @@
<script setup lang="ts">
import {
Menubar,
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarLabel,
MenubarMenu,
MenubarRadioGroup,
MenubarRadioItem,
MenubarSeparator,
MenubarShortcut,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from '@/lib/registry/default/ui/menubar'
</script>
<template>
<Menubar class="rounded-none border-b border-none px-2 lg:px-4">
<MenubarMenu>
<MenubarTrigger class="font-bold">
Music
</MenubarTrigger>
<MenubarContent>
<MenubarItem>About Music</MenubarItem>
<MenubarSeparator />
<MenubarItem>
Preferences... <MenubarShortcut>,</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem>
Hide Music... <MenubarShortcut>H</MenubarShortcut>
</MenubarItem>
<MenubarItem>
Hide Others... <MenubarShortcut>H</MenubarShortcut>
</MenubarItem>
<MenubarShortcut />
<MenubarItem>
Quit Music <MenubarShortcut>Q</MenubarShortcut>
</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger class="relative">
File
</MenubarTrigger>
<MenubarContent>
<MenubarSub>
<MenubarSubTrigger>New</MenubarSubTrigger>
<MenubarSubContent class="w-[230px]">
<MenubarItem>
Playlist <MenubarShortcut>N</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled>
Playlist from Selection <MenubarShortcut>N</MenubarShortcut>
</MenubarItem>
<MenubarItem>
Smart Playlist... <MenubarShortcut>N</MenubarShortcut>
</MenubarItem>
<MenubarItem>Playlist Folder</MenubarItem>
<MenubarItem disabled>
Genius Playlist
</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarItem>
Open Stream URL... <MenubarShortcut>U</MenubarShortcut>
</MenubarItem>
<MenubarItem>
Close Window <MenubarShortcut>W</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>Library</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem>Update Cloud Library</MenubarItem>
<MenubarItem>Update Genius</MenubarItem>
<MenubarSeparator />
<MenubarItem>Organize Library...</MenubarItem>
<MenubarItem>Export Library...</MenubarItem>
<MenubarSeparator />
<MenubarItem>Import Playlist...</MenubarItem>
<MenubarItem disabled>
Export Playlist...
</MenubarItem>
<MenubarItem>Show Duplicate Items</MenubarItem>
<MenubarSeparator />
<MenubarItem>Get Album Artwork</MenubarItem>
<MenubarItem disabled>
Get Track Names
</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarItem>
Import... <MenubarShortcut>O</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled>
Burn Playlist to Disc...
</MenubarItem>
<MenubarSeparator />
<MenubarItem>
Show in Finder <MenubarShortcut>R</MenubarShortcut>
</MenubarItem>
<MenubarItem>Convert</MenubarItem>
<MenubarSeparator />
<MenubarItem>Page Setup...</MenubarItem>
<MenubarItem disabled>
Print... <MenubarShortcut>P</MenubarShortcut>
</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Edit</MenubarTrigger>
<MenubarContent>
<MenubarItem disabled>
Undo <MenubarShortcut>Z</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled>
Redo <MenubarShortcut>Z</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem disabled>
Cut <MenubarShortcut>X</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled>
Copy <MenubarShortcut>C</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled>
Paste <MenubarShortcut>V</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem>
Select All <MenubarShortcut>A</MenubarShortcut>
</MenubarItem>
<MenubarItem disabled>
Deselect All <MenubarShortcut>A</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem>
Smart Dictation...
<MenubarShortcut>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
class="h-4 w-4"
viewBox="0 0 24 24"
>
<path d="m12 8-9.04 9.06a2.82 2.82 0 1 0 3.98 3.98L16 12" />
<circle cx="17" cy="7" r="5" />
</svg>
</MenubarShortcut>
</MenubarItem>
<MenubarItem>
Emoji & Symbols
<MenubarShortcut>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
class="h-4 w-4"
viewBox="0 0 24 24"
>
<circle cx="12" cy="12" r="10" />
<path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
</svg>
</MenubarShortcut>
</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>View</MenubarTrigger>
<MenubarContent>
<MenubarCheckboxItem>Show Playing Next</MenubarCheckboxItem>
<MenubarCheckboxItem checked>
Show Lyrics
</MenubarCheckboxItem>
<MenubarSeparator />
<MenubarItem inset disabled>
Show Status Bar
</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>
Hide Sidebar
</MenubarItem>
<MenubarItem disabled inset>
Enter Full Screen
</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger class="hidden md:block">
Account
</MenubarTrigger>
<MenubarContent force-mount>
<MenubarLabel inset>
Switch Account
</MenubarLabel>
<MenubarSeparator />
<MenubarRadioGroup value="benoit">
<MenubarRadioItem value="andy">
Andy
</MenubarRadioItem>
<MenubarRadioItem value="benoit">
Benoit
</MenubarRadioItem>
<MenubarRadioItem value="Luis">
Luis
</MenubarRadioItem>
</MenubarRadioGroup>
<MenubarSeparator />
<MenubarItem inset>
Manage Famliy...
</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>
Add Account...
</MenubarItem>
</MenubarContent>
</MenubarMenu>
</Menubar>
</template>

View File

@ -0,0 +1,66 @@
<script setup lang="ts">
import { Button } from '@/lib/registry/default/ui/button'
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/lib/registry/default/ui/dialog'
import { Input } from '@/lib/registry/default/ui/input'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<div class="flex h-[450px] shrink-0 items-center justify-center rounded-md border border-dashed">
<div class="mx-auto flex max-w-[420px] flex-col items-center justify-center text-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
class="h-10 w-10 text-muted-foreground"
viewBox="0 0 24 24"
>
<circle cx="12" cy="11" r="1" />
<path d="M11 17a1 1 0 0 1 2 0c0 .5-.34 3-.5 4.5a.5.5 0 0 1-1 0c-.16-1.5-.5-4-.5-4.5ZM8 14a5 5 0 1 1 8 0" />
<path d="M17 18.5a9 9 0 1 0-10 0" />
</svg>
<h3 class="mt-4 text-lg font-semibold">
No episodes added
</h3>
<p class="mb-4 mt-2 text-sm text-muted-foreground">
You have not added any podcasts. Add one below.
</p>
<Dialog>
<DialogTrigger>
<Button size="sm" class="relative">
Add Podcast
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Add Podcast</DialogTitle>
<DialogDescription>
Copy and paste the podcast feed URL to import.
</DialogDescription>
</DialogHeader>
<div class="grid gap-4 py-4">
<div class="grid gap-2">
<Label for="url">Podcast URL</Label>
<Input id="url" placeholder="https://example.com/feed.xml" />
</div>
</div>
<DialogFooter>
<Button>Import Podcast</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
</div>
</template>

View File

@ -0,0 +1,204 @@
<script setup lang="ts">
import type { Playlist } from '../data/playlists'
import { cn } from '@/lib/utils'
import { Button } from '@/lib/registry/default/ui/button'
import { ScrollArea } from '@/lib/registry/default/ui/scroll-area'
interface SidebarProps {
playlists: Playlist[]
}
defineProps<SidebarProps>()
</script>
<template>
<div :class="cn('pb-12', $attrs.class ?? '')">
<div class="space-y-4 py-4">
<div class="px-3 py-2">
<h2 class="mb-2 px-4 text-lg font-semibold tracking-tight">
Discover
</h2>
<div class="space-y-1">
<Button variant="secondary" class="w-full justify-start">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
class="mr-2 h-4 w-4"
>
<circle cx="12" cy="12" r="10" />
<polygon points="10 8 16 12 10 16 10 8" />
</svg>
Listen Now
</Button>
<Button variant="ghost" class="w-full justify-start">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
class="mr-2 h-4 w-4"
>
<rect width="7" height="7" x="3" y="3" rx="1" />
<rect width="7" height="7" x="14" y="3" rx="1" />
<rect width="7" height="7" x="14" y="14" rx="1" />
<rect width="7" height="7" x="3" y="14" rx="1" />
</svg>
Browse
</Button>
<Button variant="ghost" class="w-full justify-start">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
class="mr-2 h-4 w-4"
>
<path d="M4.9 19.1C1 15.2 1 8.8 4.9 4.9" />
<path d="M7.8 16.2c-2.3-2.3-2.3-6.1 0-8.5" />
<circle cx="12" cy="12" r="2" />
<path d="M16.2 7.8c2.3 2.3 2.3 6.1 0 8.5" />
<path d="M19.1 4.9C23 8.8 23 15.1 19.1 19" />
</svg>
Radio
</Button>
</div>
</div>
<div class="px-3 py-2">
<h2 class="mb-2 px-4 text-lg font-semibold tracking-tight">
Library
</h2>
<div class="space-y-1">
<Button variant="ghost" class="w-full justify-start">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
class="mr-2 h-4 w-4"
>
<path d="M21 15V6" />
<path d="M18.5 18a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5Z" />
<path d="M12 12H3" />
<path d="M16 6H3" />
<path d="M12 18H3" />
</svg>
Playlists
</Button>
<Button variant="ghost" class="w-full justify-start">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
class="mr-2 h-4 w-4"
>
<circle cx="8" cy="18" r="4" />
<path d="M12 18V2l7 4" />
</svg>
Songs
</Button>
<Button variant="ghost" class="w-full justify-start">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
class="mr-2 h-4 w-4"
>
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</svg>
Made for You
</Button>
<Button variant="ghost" class="w-full justify-start">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
class="mr-2 h-4 w-4"
>
<path d="m12 8-9.04 9.06a2.82 2.82 0 1 0 3.98 3.98L16 12" />
<circle cx="17" cy="7" r="5" />
</svg>
Artists
</Button>
<Button variant="ghost" class="w-full justify-start">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
class="mr-2 h-4 w-4"
>
<path d="m16 6 4 14" />
<path d="M12 6v14" />
<path d="M8 8v12" />
<path d="M4 4v16" />
</svg>
Albums
</Button>
</div>
</div>
<div class="py-2">
<h2 class="relative px-7 text-lg font-semibold tracking-tight">
Playlists
</h2>
<ScrollArea class="h-[300px] px-1">
<div class="space-y-1 p-2">
<Button
v-for="(playlist, i) in playlists"
:key="`${playlist}-${i}`"
variant="ghost"
class="w-full justify-start font-normal"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
class="mr-2 h-4 w-4"
>
<path d="M21 15V6" />
<path d="M18.5 18a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5Z" />
<path d="M12 12H3" />
<path d="M16 6H3" />
<path d="M12 18H3" />
</svg>
{{ playlist }}
</Button>
</div>
</ScrollArea>
</div>
</div>
</div>
</template>

View File

@ -0,0 +1,71 @@
export interface Album {
name: string
artist: string
cover: string
}
export const listenNowAlbums: Album[] = [
{
name: 'React Rendezvous',
artist: 'Ethan Byte',
cover:
'https://images.unsplash.com/photo-1611348586804-61bf6c080437?w=300&dpr=2&q=80',
},
{
name: 'Async Awakenings',
artist: 'Nina Netcode',
cover:
'https://images.unsplash.com/photo-1468817814611-b7edf94b5d60?w=300&dpr=2&q=80',
},
{
name: 'The Art of Reusability',
artist: 'Lena Logic',
cover:
'https://images.unsplash.com/photo-1528143358888-6d3c7f67bd5d?w=300&dpr=2&q=80',
},
{
name: 'Stateful Symphony',
artist: 'Beth Binary',
cover:
'https://images.unsplash.com/photo-1490300472339-79e4adc6be4a?w=300&dpr=2&q=80',
},
]
export const madeForYouAlbums: Album[] = [
{
name: 'Thinking Components',
artist: 'Lena Logic',
cover:
'https://images.unsplash.com/photo-1615247001958-f4bc92fa6a4a?w=300&dpr=2&q=80',
},
{
name: 'Functional Fury',
artist: 'Beth Binary',
cover:
'https://images.unsplash.com/photo-1513745405825-efaf9a49315f?w=300&dpr=2&q=80',
},
{
name: 'React Rendezvous',
artist: 'Ethan Byte',
cover:
'https://images.unsplash.com/photo-1614113489855-66422ad300a4?w=300&dpr=2&q=80',
},
{
name: 'Stateful Symphony',
artist: 'Beth Binary',
cover:
'https://images.unsplash.com/photo-1446185250204-f94591f7d702?w=300&dpr=2&q=80',
},
{
name: 'Async Awakenings',
artist: 'Nina Netcode',
cover:
'https://images.unsplash.com/photo-1468817814611-b7edf94b5d60?w=300&dpr=2&q=80',
},
{
name: 'The Art of Reusability',
artist: 'Lena Logic',
cover:
'https://images.unsplash.com/photo-1490300472339-79e4adc6be4a?w=300&dpr=2&q=80',
},
]

View File

@ -0,0 +1,16 @@
export type Playlist = (typeof playlists)[number]
export const playlists = [
'Recently Added',
'Recently Played',
'Top Songs',
'Top Albums',
'Top Artists',
'Logic Discography',
'Bedtime Beats',
'Feeling Happy',
'I miss Y2K Pop',
'Runtober',
'Mellow Days',
'Eminem Essentials',
]

View File

@ -70,7 +70,7 @@ importers:
version: 0.268.0(vue@3.3.4) version: 0.268.0(vue@3.3.4)
tailwindcss-animate: tailwindcss-animate:
specifier: ^1.0.6 specifier: ^1.0.6
version: 1.0.6(tailwindcss@3.3.2) version: 1.0.6(tailwindcss@3.3.3)
v-calendar: v-calendar:
specifier: ^3.0.3 specifier: ^3.0.3
version: 3.0.3(@popperjs/core@2.11.8)(vue@3.3.4) version: 3.0.3(@popperjs/core@2.11.8)(vue@3.3.4)
@ -118,8 +118,8 @@ importers:
specifier: ^1.14.0 specifier: ^1.14.0
version: 1.14.0 version: 1.14.0
tailwindcss: tailwindcss:
specifier: ^3.3.2 specifier: ^3.3.3
version: 3.3.2(ts-node@10.9.1) version: 3.3.3(ts-node@10.9.1)
typescript: typescript:
specifier: ^5.0.2 specifier: ^5.0.2
version: 5.0.2 version: 5.0.2
@ -4598,16 +4598,6 @@ packages:
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
dev: false dev: false
/fast-glob@3.3.0:
resolution: {integrity: sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==}
engines: {node: '>=8.6.0'}
dependencies:
'@nodelib/fs.stat': 2.0.5
'@nodelib/fs.walk': 1.2.8
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.5
/fast-glob@3.3.1: /fast-glob@3.3.1:
resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
engines: {node: '>=8.6.0'} engines: {node: '>=8.6.0'}
@ -6261,27 +6251,27 @@ packages:
enhanced-resolve: 4.5.0 enhanced-resolve: 4.5.0
dev: false dev: false
/postcss-import@15.1.0(postcss@8.4.24): /postcss-import@15.1.0(postcss@8.4.28):
resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
peerDependencies: peerDependencies:
postcss: ^8.0.0 postcss: ^8.0.0
dependencies: dependencies:
postcss: 8.4.24 postcss: 8.4.28
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
read-cache: 1.0.0 read-cache: 1.0.0
resolve: 1.22.4 resolve: 1.22.4
/postcss-js@4.0.1(postcss@8.4.24): /postcss-js@4.0.1(postcss@8.4.28):
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
engines: {node: ^12 || ^14 || >= 16} engines: {node: ^12 || ^14 || >= 16}
peerDependencies: peerDependencies:
postcss: ^8.4.21 postcss: ^8.4.21
dependencies: dependencies:
camelcase-css: 2.0.1 camelcase-css: 2.0.1
postcss: 8.4.24 postcss: 8.4.28
/postcss-load-config@4.0.1(postcss@8.4.24)(ts-node@10.9.1): /postcss-load-config@4.0.1(postcss@8.4.28)(ts-node@10.9.1):
resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==}
engines: {node: '>= 14'} engines: {node: '>= 14'}
peerDependencies: peerDependencies:
@ -6294,17 +6284,17 @@ packages:
optional: true optional: true
dependencies: dependencies:
lilconfig: 2.1.0 lilconfig: 2.1.0
postcss: 8.4.24 postcss: 8.4.28
ts-node: 10.9.1(@types/node@20.4.7)(typescript@5.2.2) ts-node: 10.9.1(@types/node@20.4.7)(typescript@5.2.2)
yaml: 2.3.1 yaml: 2.3.1
/postcss-nested@6.0.1(postcss@8.4.24): /postcss-nested@6.0.1(postcss@8.4.28):
resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
engines: {node: '>=12.0'} engines: {node: '>=12.0'}
peerDependencies: peerDependencies:
postcss: ^8.2.14 postcss: ^8.2.14
dependencies: dependencies:
postcss: 8.4.24 postcss: 8.4.28
postcss-selector-parser: 6.0.13 postcss-selector-parser: 6.0.13
/postcss-selector-parser@6.0.13: /postcss-selector-parser@6.0.13:
@ -6967,16 +6957,16 @@ packages:
resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==} resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==}
dev: true dev: true
/tailwindcss-animate@1.0.6(tailwindcss@3.3.2): /tailwindcss-animate@1.0.6(tailwindcss@3.3.3):
resolution: {integrity: sha512-4WigSGMvbl3gCCact62ZvOngA+PRqhAn7si3TQ3/ZuPuQZcIEtVap+ENSXbzWhpojKB8CpvnIsrwBu8/RnHtuw==} resolution: {integrity: sha512-4WigSGMvbl3gCCact62ZvOngA+PRqhAn7si3TQ3/ZuPuQZcIEtVap+ENSXbzWhpojKB8CpvnIsrwBu8/RnHtuw==}
peerDependencies: peerDependencies:
tailwindcss: '>=3.0.0 || insiders' tailwindcss: '>=3.0.0 || insiders'
dependencies: dependencies:
tailwindcss: 3.3.2(ts-node@10.9.1) tailwindcss: 3.3.3(ts-node@10.9.1)
dev: false dev: false
/tailwindcss@3.3.2(ts-node@10.9.1): /tailwindcss@3.3.3(ts-node@10.9.1):
resolution: {integrity: sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==} resolution: {integrity: sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
hasBin: true hasBin: true
dependencies: dependencies:
@ -6985,7 +6975,7 @@ packages:
chokidar: 3.5.3 chokidar: 3.5.3
didyoumean: 1.2.2 didyoumean: 1.2.2
dlv: 1.1.3 dlv: 1.1.3
fast-glob: 3.3.0 fast-glob: 3.3.1
glob-parent: 6.0.2 glob-parent: 6.0.2
is-glob: 4.0.3 is-glob: 4.0.3
jiti: 1.19.3 jiti: 1.19.3
@ -6994,13 +6984,12 @@ packages:
normalize-path: 3.0.0 normalize-path: 3.0.0
object-hash: 3.0.0 object-hash: 3.0.0
picocolors: 1.0.0 picocolors: 1.0.0
postcss: 8.4.24 postcss: 8.4.28
postcss-import: 15.1.0(postcss@8.4.24) postcss-import: 15.1.0(postcss@8.4.28)
postcss-js: 4.0.1(postcss@8.4.24) postcss-js: 4.0.1(postcss@8.4.28)
postcss-load-config: 4.0.1(postcss@8.4.24)(ts-node@10.9.1) postcss-load-config: 4.0.1(postcss@8.4.28)(ts-node@10.9.1)
postcss-nested: 6.0.1(postcss@8.4.24) postcss-nested: 6.0.1(postcss@8.4.28)
postcss-selector-parser: 6.0.13 postcss-selector-parser: 6.0.13
postcss-value-parser: 4.2.0
resolve: 1.22.4 resolve: 1.22.4
sucrase: 3.34.0 sucrase: 3.34.0
transitivePeerDependencies: transitivePeerDependencies:
@ -7205,7 +7194,7 @@ packages:
execa: 5.1.1 execa: 5.1.1
globby: 11.1.0 globby: 11.1.0
joycon: 3.1.1 joycon: 3.1.1
postcss-load-config: 4.0.1(postcss@8.4.24)(ts-node@10.9.1) postcss-load-config: 4.0.1(postcss@8.4.28)(ts-node@10.9.1)
resolve-from: 5.0.0 resolve-from: 5.0.0
rollup: 3.28.1 rollup: 3.28.1
source-map: 0.8.0-beta.0 source-map: 0.8.0-beta.0