# 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`
Props & Usage **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 ``` **Dependencies**: PlayerControls, WaveformDisplay **Related**: PlayerControls, WaveformDisplay
--- ### PlayerControls **Purpose**: Reusable audio player control buttons for play/pause, skip, shuffle, and repeat **Location**: `components/PlayerControls.tsx`
Props & Usage **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 ``` **Dependencies**: None (presentational component) **Related**: AudioPlayer
--- ### WaveformDisplay **Purpose**: Canvas-based audio waveform visualization with progress tracking and interactive seeking **Location**: `components/WaveformDisplay.tsx`
Props & Usage **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 ``` **Dependencies**: Canvas API, Web Audio API **Related**: AudioPlayer
--- ## Content Cards ### SongCard **Purpose**: Displays song information with cover image, title, artist, and playback stats **Location**: `components/SongCard.tsx`
Props & Usage **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 router.push(`/songs/${song.id}`)} onPlay={playSong} showArtist={true} showPlayCount={true} variant="default" /> ``` **Dependencies**: Next.js Image, Link **Related**: TrackList, AudioPlayer
--- ### AlbumCard **Purpose**: Displays album information with cover art, title, artist, release year, and track count **Location**: `components/AlbumCard.tsx`
Props & Usage **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 router.push(`/album/${album.id}`)} showArtist={true} showTrackCount={true} /> ``` **Dependencies**: Next.js Image, Link **Related**: ArtistCard
--- ### ArtistCard **Purpose**: Displays artist profile with circular avatar, name, and verification badge **Location**: `components/ArtistCard.tsx`
Props & Usage **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 router.push(`/artist/${artist.id}`)} showVerified={true} size="md" /> ``` **Dependencies**: Next.js Image, Link **Related**: AlbumCard, LabelCard
--- ### PlaylistCard **Purpose**: Displays playlist with cover image, title, song count, and privacy indicator **Location**: `components/PlaylistCard.tsx`
Props & Usage **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 router.push(`/playlist/${playlist.id}`)} showSongCount={true} showPrivacy={true} editable={isOwner} /> ``` **Dependencies**: Next.js Image, Link **Related**: TrackList
--- ### LabelCard **Purpose**: Displays record label information with logo, name, and artist roster count **Location**: `components/LabelCard.tsx`
Props & Usage **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 router.push(`/label/${label.id}`)} showArtistCount={true} /> ``` **Dependencies**: Next.js Image, Link **Related**: ArtistCard
--- ### GenreBadge **Purpose**: Small clickable badge displaying music genre with color-coded styling **Location**: `components/GenreBadge.tsx`
Props & Usage **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 filterByGenre(genre.slug)} size="sm" /> ``` **Dependencies**: None (presentational component) **Related**: UploadForm
--- ## Forms ### AuthForm **Purpose**: Multi-mode authentication form for login, registration, and password reset flows **Location**: `components/AuthForm.tsx`
Props & Usage **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 // Register mode // Password reset mode ``` **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
--- ### UploadForm **Purpose**: Multi-field form for uploading songs with audio file, metadata, and genre tagging **Location**: `components/UploadForm.tsx`
Props & Usage **Props**: | Prop | Type | Description | |------|------|-------------| | onSuccess? | (songId: string) => void | Success callback with created song ID | | onCancel? | () => void | Cancel button handler | | initialData? | Partial | Pre-fill form data (for editing) | **Usage Example**: ```tsx 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
--- ### ProfileForm **Purpose**: User profile editing form with username, display name, bio, and website fields **Location**: `components/ProfileForm.tsx`
Props & Usage **Props**: | Prop | Type | Description | |------|------|-------------| | user | User | Current user object | | onSuccess? | () => void | Success callback | | onCancel? | () => void | Cancel button handler | **Usage Example**: ```tsx 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
--- ### CreatePlaylistModal **Purpose**: Modal dialog for creating new playlists with title, description, and privacy settings **Location**: `components/CreatePlaylistModal.tsx`
Props & Usage **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 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
--- ## Navigation ### Header **Purpose**: Fixed top navigation header with logo, navigation links, search, and user menu **Location**: `components/Header.tsx`
Props & Usage **Props**: | Prop | Type | Description | |------|------|-------------| | transparent? | boolean | Transparent background (default: false) | **Usage Example**: ```tsx
``` **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
--- ### NavLink **Purpose**: Navigation link component with automatic active state highlighting **Location**: `components/NavLink.tsx`
Props & Usage **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 Discover Artists ``` **Dependencies**: Next.js usePathname, Link **Related**: Header
--- ### UserMenu **Purpose**: Dropdown menu showing authentication state with profile, upload, playlists, and logout actions **Location**: `components/UserMenu.tsx`
Props & Usage **Props**: | Prop | Type | Description | |------|------|-------------| | user | User \| null | Current authenticated user | **Usage Example**: ```tsx ``` **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
--- ### SearchBar **Purpose**: Search input with real-time suggestions dropdown, debouncing, and loading indicator **Location**: `components/SearchBar.tsx`
Props & Usage **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 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
--- ## Sharing ### ShareButton **Purpose**: Button that generates shareable links and opens the share modal **Location**: `components/ShareButton.tsx`
Props & Usage **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 ``` **API Calls**: - Generate link: `POST /api/share/{type}/{id}` **Dependencies**: ShareModal **Related**: ShareModal
--- ### ShareModal **Purpose**: Modal displaying shareable link with copy-to-clipboard and social media share buttons **Location**: `components/ShareModal.tsx`
Props & Usage **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 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
--- ## Display ### TrackList **Purpose**: Scrollable list of tracks with position numbers, song information, artist details, and duration **Location**: `components/TrackList.tsx`
Props & Usage **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 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
--- ## 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