800 lines
18 KiB
Markdown
800 lines
18 KiB
Markdown
# Component Catalog
|
|
|
|
A comprehensive guide to all reusable React components in the Sonic Cloud platform.
|
|
|
|
---
|
|
|
|
## Audio & Playback
|
|
|
|
### AudioPlayer
|
|
**Purpose**: Fixed bottom audio player that displays the currently playing song with full playback controls
|
|
**Location**: `components/AudioPlayer.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| currentSong | Song | Currently playing song object |
|
|
| isPlaying | boolean | Playback state flag |
|
|
| onPlayPause | () => void | Toggle play/pause handler |
|
|
| onNext | () => void | Skip to next track handler |
|
|
| onPrevious | () => void | Go to previous track handler |
|
|
| progress | number | Playback progress (0-100) |
|
|
| volume | number | Volume level (0-100) |
|
|
| onSeek | (time: number) => void | Seek to specific time handler |
|
|
| onVolumeChange | (level: number) => void | Volume adjustment handler |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<AudioPlayer
|
|
currentSong={currentSong}
|
|
isPlaying={isPlaying}
|
|
onPlayPause={handlePlayPause}
|
|
onNext={handleNext}
|
|
onPrevious={handlePrevious}
|
|
progress={progress}
|
|
volume={volume}
|
|
onSeek={handleSeek}
|
|
onVolumeChange={setVolume}
|
|
/>
|
|
```
|
|
|
|
**Dependencies**: PlayerControls, WaveformDisplay
|
|
**Related**: PlayerControls, WaveformDisplay
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### PlayerControls
|
|
**Purpose**: Reusable audio player control buttons for play/pause, skip, shuffle, and repeat
|
|
**Location**: `components/PlayerControls.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| isPlaying | boolean | Current playback state |
|
|
| onPlayPause | () => void | Toggle play/pause |
|
|
| onNext | () => void | Skip to next track |
|
|
| onPrevious | () => void | Go to previous track |
|
|
| shuffle | boolean | Shuffle mode enabled |
|
|
| repeat | 'none' \| 'all' \| 'one' | Repeat mode |
|
|
| onShuffleToggle | () => void | Toggle shuffle |
|
|
| onRepeatToggle | () => void | Cycle repeat modes |
|
|
| size? | 'sm' \| 'md' \| 'lg' | Button size variant |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<PlayerControls
|
|
isPlaying={isPlaying}
|
|
onPlayPause={togglePlayback}
|
|
onNext={skipNext}
|
|
onPrevious={skipPrevious}
|
|
shuffle={shuffleEnabled}
|
|
repeat={repeatMode}
|
|
onShuffleToggle={toggleShuffle}
|
|
onRepeatToggle={cycleRepeat}
|
|
size="md"
|
|
/>
|
|
```
|
|
|
|
**Dependencies**: None (presentational component)
|
|
**Related**: AudioPlayer
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### WaveformDisplay
|
|
**Purpose**: Canvas-based audio waveform visualization with progress tracking and interactive seeking
|
|
**Location**: `components/WaveformDisplay.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| audioUrl | string | URL of audio file to visualize |
|
|
| progress | number | Current playback progress (0-100) |
|
|
| onSeek | (time: number) => void | Callback when user seeks |
|
|
| height? | number | Canvas height in pixels (default: 80) |
|
|
| barWidth? | number | Waveform bar width (default: 2) |
|
|
| barGap? | number | Space between bars (default: 1) |
|
|
| primaryColor? | string | Waveform color (default: theme primary) |
|
|
| progressColor? | string | Played portion color (default: accent) |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<WaveformDisplay
|
|
audioUrl={song.audioUrl}
|
|
progress={currentProgress}
|
|
onSeek={handleSeek}
|
|
height={100}
|
|
primaryColor="#3b82f6"
|
|
progressColor="#10b981"
|
|
/>
|
|
```
|
|
|
|
**Dependencies**: Canvas API, Web Audio API
|
|
**Related**: AudioPlayer
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Content Cards
|
|
|
|
### SongCard
|
|
**Purpose**: Displays song information with cover image, title, artist, and playback stats
|
|
**Location**: `components/SongCard.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| song | Song | Song object with metadata |
|
|
| onClick? | () => void | Click handler for card |
|
|
| onPlay? | () => void | Play button handler |
|
|
| showArtist? | boolean | Display artist name (default: true) |
|
|
| showPlayCount? | boolean | Display play count (default: true) |
|
|
| variant? | 'default' \| 'compact' | Card layout style |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<SongCard
|
|
song={song}
|
|
onClick={() => router.push(`/songs/${song.id}`)}
|
|
onPlay={playSong}
|
|
showArtist={true}
|
|
showPlayCount={true}
|
|
variant="default"
|
|
/>
|
|
```
|
|
|
|
**Dependencies**: Next.js Image, Link
|
|
**Related**: TrackList, AudioPlayer
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### AlbumCard
|
|
**Purpose**: Displays album information with cover art, title, artist, release year, and track count
|
|
**Location**: `components/AlbumCard.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| album | Album | Album object with metadata |
|
|
| onClick? | () => void | Click handler for card |
|
|
| showArtist? | boolean | Display artist name (default: true) |
|
|
| showTrackCount? | boolean | Display track count (default: true) |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<AlbumCard
|
|
album={album}
|
|
onClick={() => router.push(`/album/${album.id}`)}
|
|
showArtist={true}
|
|
showTrackCount={true}
|
|
/>
|
|
```
|
|
|
|
**Dependencies**: Next.js Image, Link
|
|
**Related**: ArtistCard
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### ArtistCard
|
|
**Purpose**: Displays artist profile with circular avatar, name, and verification badge
|
|
**Location**: `components/ArtistCard.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| artist | Artist | Artist profile object |
|
|
| onClick? | () => void | Click handler for card |
|
|
| showVerified? | boolean | Display verified badge (default: true) |
|
|
| showFollowers? | boolean | Display follower count (default: false) |
|
|
| size? | 'sm' \| 'md' \| 'lg' | Avatar size variant |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<ArtistCard
|
|
artist={artist}
|
|
onClick={() => router.push(`/artist/${artist.id}`)}
|
|
showVerified={true}
|
|
size="md"
|
|
/>
|
|
```
|
|
|
|
**Dependencies**: Next.js Image, Link
|
|
**Related**: AlbumCard, LabelCard
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### PlaylistCard
|
|
**Purpose**: Displays playlist with cover image, title, song count, and privacy indicator
|
|
**Location**: `components/PlaylistCard.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| playlist | Playlist | Playlist object with metadata |
|
|
| onClick? | () => void | Click handler for card |
|
|
| showSongCount? | boolean | Display song count (default: true) |
|
|
| showPrivacy? | boolean | Display privacy badge (default: true) |
|
|
| editable? | boolean | Show edit actions (default: false) |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<PlaylistCard
|
|
playlist={playlist}
|
|
onClick={() => router.push(`/playlist/${playlist.id}`)}
|
|
showSongCount={true}
|
|
showPrivacy={true}
|
|
editable={isOwner}
|
|
/>
|
|
```
|
|
|
|
**Dependencies**: Next.js Image, Link
|
|
**Related**: TrackList
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### LabelCard
|
|
**Purpose**: Displays record label information with logo, name, and artist roster count
|
|
**Location**: `components/LabelCard.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| label | Label | Label profile object |
|
|
| onClick? | () => void | Click handler for card |
|
|
| showArtistCount? | boolean | Display artist count (default: true) |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<LabelCard
|
|
label={label}
|
|
onClick={() => router.push(`/label/${label.id}`)}
|
|
showArtistCount={true}
|
|
/>
|
|
```
|
|
|
|
**Dependencies**: Next.js Image, Link
|
|
**Related**: ArtistCard
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### GenreBadge
|
|
**Purpose**: Small clickable badge displaying music genre with color-coded styling
|
|
**Location**: `components/GenreBadge.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| genre | Genre | Genre object with name and color |
|
|
| onClick? | () => void | Click handler for badge |
|
|
| size? | 'xs' \| 'sm' \| 'md' | Badge size variant |
|
|
| removable? | boolean | Show remove button (default: false) |
|
|
| onRemove? | () => void | Remove button handler |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<GenreBadge
|
|
genre={genre}
|
|
onClick={() => filterByGenre(genre.slug)}
|
|
size="sm"
|
|
/>
|
|
```
|
|
|
|
**Dependencies**: None (presentational component)
|
|
**Related**: UploadForm
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Forms
|
|
|
|
### AuthForm
|
|
**Purpose**: Multi-mode authentication form for login, registration, and password reset flows
|
|
**Location**: `components/AuthForm.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| mode | 'login' \| 'register' \| 'forgot' \| 'reset' | Form mode |
|
|
| onSuccess? | () => void | Success callback |
|
|
| resetToken? | string | Password reset token (for reset mode) |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
// Login mode
|
|
<AuthForm mode="login" onSuccess={handleLoginSuccess} />
|
|
|
|
// Register mode
|
|
<AuthForm mode="register" onSuccess={handleRegisterSuccess} />
|
|
|
|
// Password reset mode
|
|
<AuthForm mode="reset" resetToken={token} onSuccess={handleResetSuccess} />
|
|
```
|
|
|
|
**API Calls**:
|
|
- Login: `POST /api/auth/login`
|
|
- Register: `POST /api/auth/register`
|
|
- Forgot: `POST /api/auth/forgot-password`
|
|
- Reset: `POST /api/auth/reset-password`
|
|
|
|
**Dependencies**: React Hook Form, JWT storage
|
|
**Related**: UserMenu, Header
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### UploadForm
|
|
**Purpose**: Multi-field form for uploading songs with audio file, metadata, and genre tagging
|
|
**Location**: `components/UploadForm.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| onSuccess? | (songId: string) => void | Success callback with created song ID |
|
|
| onCancel? | () => void | Cancel button handler |
|
|
| initialData? | Partial<Song> | Pre-fill form data (for editing) |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<UploadForm
|
|
onSuccess={(songId) => router.push(`/songs/${songId}`)}
|
|
onCancel={() => router.back()}
|
|
/>
|
|
```
|
|
|
|
**Form Fields**:
|
|
- Audio file upload (required)
|
|
- Title (required)
|
|
- Album selection (optional)
|
|
- Genre tags (multi-select)
|
|
- Cover image URL (optional)
|
|
- Lyrics (optional)
|
|
- Privacy toggle (public/private)
|
|
|
|
**API Calls**:
|
|
- Upload: `POST /api/songs/upload`
|
|
|
|
**Dependencies**: File upload handling, GenreBadge
|
|
**Related**: GenreBadge
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### ProfileForm
|
|
**Purpose**: User profile editing form with username, display name, bio, and website fields
|
|
**Location**: `components/ProfileForm.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| user | User | Current user object |
|
|
| onSuccess? | () => void | Success callback |
|
|
| onCancel? | () => void | Cancel button handler |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<ProfileForm
|
|
user={currentUser}
|
|
onSuccess={() => toast.success('Profile updated')}
|
|
onCancel={() => router.back()}
|
|
/>
|
|
```
|
|
|
|
**Form Fields**:
|
|
- Username (unique, alphanumeric + underscore)
|
|
- Display name (optional)
|
|
- Bio (optional, max 500 chars)
|
|
- Website URL (optional, validated)
|
|
- Avatar URL (optional)
|
|
|
|
**API Calls**:
|
|
- Update: `PUT /api/users/me`
|
|
|
|
**Dependencies**: React Hook Form, URL validation
|
|
**Related**: UserMenu
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### CreatePlaylistModal
|
|
**Purpose**: Modal dialog for creating new playlists with title, description, and privacy settings
|
|
**Location**: `components/CreatePlaylistModal.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| isOpen | boolean | Modal open state |
|
|
| onClose | () => void | Close modal handler |
|
|
| onSuccess? | (playlistId: string) => void | Success callback with playlist ID |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<CreatePlaylistModal
|
|
isOpen={isModalOpen}
|
|
onClose={() => setIsModalOpen(false)}
|
|
onSuccess={(id) => router.push(`/playlist/${id}`)}
|
|
/>
|
|
```
|
|
|
|
**Form Fields**:
|
|
- Playlist title (required)
|
|
- Description (optional)
|
|
- Privacy toggle (public/private)
|
|
|
|
**API Calls**:
|
|
- Create: `POST /api/playlists`
|
|
|
|
**Dependencies**: Modal backdrop, React Hook Form
|
|
**Related**: PlaylistCard
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Navigation
|
|
|
|
### Header
|
|
**Purpose**: Fixed top navigation header with logo, navigation links, search, and user menu
|
|
**Location**: `components/Header.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| transparent? | boolean | Transparent background (default: false) |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<Header transparent={false} />
|
|
```
|
|
|
|
**Features**:
|
|
- Logo with home link
|
|
- Primary navigation links (Discover, Artists, Genres, Labels)
|
|
- Search bar integration
|
|
- User menu with auth state
|
|
- Mobile hamburger menu
|
|
- Responsive breakpoints
|
|
|
|
**Dependencies**: NavLink, UserMenu, SearchBar
|
|
**Related**: NavLink, UserMenu, SearchBar
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### NavLink
|
|
**Purpose**: Navigation link component with automatic active state highlighting
|
|
**Location**: `components/NavLink.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| href | string | Link destination path |
|
|
| children | ReactNode | Link text/content |
|
|
| exact? | boolean | Exact path match (default: false) |
|
|
| activeClassName? | string | Custom active state class |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<NavLink href="/discover" exact>
|
|
Discover
|
|
</NavLink>
|
|
|
|
<NavLink href="/artist" activeClassName="text-blue-500">
|
|
Artists
|
|
</NavLink>
|
|
```
|
|
|
|
**Dependencies**: Next.js usePathname, Link
|
|
**Related**: Header
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### UserMenu
|
|
**Purpose**: Dropdown menu showing authentication state with profile, upload, playlists, and logout actions
|
|
**Location**: `components/UserMenu.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| user | User \| null | Current authenticated user |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<UserMenu user={currentUser} />
|
|
```
|
|
|
|
**Menu Items (Authenticated)**:
|
|
- Profile link
|
|
- Upload song link
|
|
- My playlists link
|
|
- Settings link (if applicable)
|
|
- Logout button
|
|
|
|
**Menu Items (Unauthenticated)**:
|
|
- Login link
|
|
- Register link
|
|
|
|
**Dependencies**: JWT auth context, Next.js Link
|
|
**Related**: Header, AuthForm
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### SearchBar
|
|
**Purpose**: Search input with real-time suggestions dropdown, debouncing, and loading indicator
|
|
**Location**: `components/SearchBar.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| placeholder? | string | Input placeholder text |
|
|
| onSearch? | (query: string) => void | Search submit handler |
|
|
| debounceMs? | number | Debounce delay (default: 300ms) |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<SearchBar
|
|
placeholder="Search songs, artists, albums..."
|
|
onSearch={(query) => router.push(`/search?q=${query}`)}
|
|
debounceMs={300}
|
|
/>
|
|
```
|
|
|
|
**Features**:
|
|
- Real-time search as you type
|
|
- Suggestion dropdown with categorized results (Songs, Artists, Albums)
|
|
- Loading spinner during API calls
|
|
- Keyboard navigation (arrow keys, enter, escape)
|
|
- Click outside to close
|
|
|
|
**API Calls**:
|
|
- Search: `GET /api/search?q={query}`
|
|
|
|
**Dependencies**: Debounce hook, fetch API
|
|
**Related**: Header
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Sharing
|
|
|
|
### ShareButton
|
|
**Purpose**: Button that generates shareable links and opens the share modal
|
|
**Location**: `components/ShareButton.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| type | 'song' \| 'playlist' \| 'album' | Content type to share |
|
|
| id | string | Content ID |
|
|
| variant? | 'icon' \| 'button' | Display style (default: 'button') |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<ShareButton type="song" id={song.id} variant="button" />
|
|
<ShareButton type="playlist" id={playlist.id} variant="icon" />
|
|
```
|
|
|
|
**API Calls**:
|
|
- Generate link: `POST /api/share/{type}/{id}`
|
|
|
|
**Dependencies**: ShareModal
|
|
**Related**: ShareModal
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
### ShareModal
|
|
**Purpose**: Modal displaying shareable link with copy-to-clipboard and social media share buttons
|
|
**Location**: `components/ShareModal.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| isOpen | boolean | Modal open state |
|
|
| onClose | () => void | Close modal handler |
|
|
| shareUrl | string | Full shareable URL |
|
|
| title | string | Content title for social sharing |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<ShareModal
|
|
isOpen={isShareModalOpen}
|
|
onClose={() => setIsShareModalOpen(false)}
|
|
shareUrl={shareUrl}
|
|
title={song.title}
|
|
/>
|
|
```
|
|
|
|
**Features**:
|
|
- Copy link to clipboard button
|
|
- Social share buttons (Twitter, Facebook, WhatsApp)
|
|
- QR code generation (optional)
|
|
- Share analytics tracking
|
|
|
|
**Dependencies**: Clipboard API, social share URLs
|
|
**Related**: ShareButton
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Display
|
|
|
|
### TrackList
|
|
**Purpose**: Scrollable list of tracks with position numbers, song information, artist details, and duration
|
|
**Location**: `components/TrackList.tsx`
|
|
|
|
<details>
|
|
<summary>Props & Usage</summary>
|
|
|
|
**Props**:
|
|
| Prop | Type | Description |
|
|
|------|------|-------------|
|
|
| tracks | Song[] | Array of song objects |
|
|
| onTrackClick? | (song: Song, index: number) => void | Track selection handler |
|
|
| showArtist? | boolean | Display artist name (default: true) |
|
|
| showAlbum? | boolean | Display album name (default: false) |
|
|
| showDuration? | boolean | Display duration (default: true) |
|
|
| numbered? | boolean | Show track numbers (default: true) |
|
|
| currentTrackId? | string | ID of currently playing track |
|
|
|
|
**Usage Example**:
|
|
```tsx
|
|
<TrackList
|
|
tracks={albumTracks}
|
|
onTrackClick={(song, index) => playTrack(song, index)}
|
|
showArtist={true}
|
|
showAlbum={false}
|
|
numbered={true}
|
|
currentTrackId={currentSong?.id}
|
|
/>
|
|
```
|
|
|
|
**Features**:
|
|
- Hover states for interactivity
|
|
- Currently playing track highlight
|
|
- Click to play functionality
|
|
- Responsive column layout
|
|
|
|
**Dependencies**: SongCard (data structure)
|
|
**Related**: AudioPlayer, AlbumCard, PlaylistCard
|
|
|
|
</details>
|
|
|
|
---
|
|
|
|
## Component Dependencies Tree
|
|
|
|
```
|
|
AudioPlayer
|
|
├── PlayerControls
|
|
└── WaveformDisplay
|
|
|
|
Header
|
|
├── NavLink
|
|
├── UserMenu
|
|
│ └── AuthForm
|
|
└── SearchBar
|
|
|
|
ShareButton
|
|
└── ShareModal
|
|
|
|
UploadForm
|
|
└── GenreBadge
|
|
|
|
TrackList
|
|
└── (uses Song type)
|
|
|
|
Standalone Components:
|
|
- SongCard
|
|
- AlbumCard
|
|
- ArtistCard
|
|
- PlaylistCard
|
|
- LabelCard
|
|
- ProfileForm
|
|
- CreatePlaylistModal
|
|
```
|
|
|
|
---
|
|
|
|
## Styling Conventions
|
|
|
|
All components use **Tailwind CSS** for styling with the following patterns:
|
|
|
|
- **Color Palette**: Primary (blue), Accent (green), Neutral (gray)
|
|
- **Spacing**: Consistent use of `p-4`, `m-2`, `gap-4` units
|
|
- **Typography**: `text-sm`, `text-base`, `text-lg`, `font-semibold`
|
|
- **Responsive**: Mobile-first with `sm:`, `md:`, `lg:` breakpoints
|
|
- **Dark Mode**: Not currently implemented (future consideration)
|
|
|
|
---
|
|
|
|
## Type Definitions
|
|
|
|
All components use types defined in `/types`:
|
|
- `types/song.ts` - Song, Album, Artist entities
|
|
- `types/user.ts` - User, AuthState
|
|
- `types/playlist.ts` - Playlist, PlaylistSong
|
|
- `types/api.ts` - API request/response types
|