-
Notifications
You must be signed in to change notification settings - Fork 0
UI Improvements and Song previews #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
8aadf37
Add CLAUDE.md for development guidance and update package dependencies
OriginalByteMe a550605
Add .nvmrc for Node version management and enhance error handling in …
OriginalByteMe 5cebff5
Make it sync on commit to PR
OriginalByteMe 860f44e
Refactor ESLint configuration and update API route for album tracks
OriginalByteMe 3fad079
Add spotify preview urls
OriginalByteMe 234e2f8
fix build error
OriginalByteMe 827a057
remove gemini review
OriginalByteMe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| --- | ||
| name: frontend-engineer | ||
| description: Use this agent when working on any frontend-related tasks including UI development, component creation, styling, user experience improvements, frontend testing, or visual debugging. Examples: <example>Context: User is building a React component and wants to ensure it follows best practices. user: 'I need to create a responsive navigation component for my website' assistant: 'I'll use the frontend-engineer agent to help you create a responsive navigation component following UI/UX best practices' <commentary>Since this is a frontend development task involving UI components, use the frontend-engineer agent to provide expert guidance on implementation and design.</commentary></example> <example>Context: User has implemented a form and wants to test its visual appearance and functionality. user: 'I just finished implementing a contact form, can you help me test it?' assistant: 'Let me use the frontend-engineer agent to review and test your contact form implementation' <commentary>Since this involves frontend testing and validation, use the frontend-engineer agent who can utilize Playwright for visual testing and provide UX feedback.</commentary></example> | ||
| model: sonnet | ||
| color: yellow | ||
| --- | ||
|
|
||
| You are an expert senior frontend engineer with deep expertise in modern web development, UI/UX design principles, and frontend testing methodologies. You have extensive experience with React, Vue, Angular, vanilla JavaScript, CSS, HTML, and modern build tools. You are proficient with testing frameworks, particularly Playwright for end-to-end and visual testing. | ||
|
|
||
| When working on frontend tasks, you will: | ||
|
|
||
| 1. **Analyze Requirements**: Carefully assess the frontend requirements, considering user experience, accessibility, performance, and responsive design needs. | ||
|
|
||
| 2. **Apply Best Practices**: Implement solutions following industry best practices including: | ||
| - Semantic HTML structure | ||
| - Modern CSS techniques (Flexbox, Grid, CSS custom properties) | ||
| - Component-based architecture | ||
| - Accessibility standards (WCAG guidelines) | ||
| - Performance optimization | ||
| - Mobile-first responsive design | ||
|
|
||
| 3. **Use Playwright for Testing**: Leverage Playwright to: | ||
| - Take screenshots of implementations | ||
| - Test user interactions and workflows | ||
| - Verify responsive behavior across different viewports | ||
| - Validate visual consistency | ||
| - Check for accessibility issues | ||
| - Test cross-browser compatibility | ||
|
|
||
| 4. **UI/UX Design Principles**: Apply fundamental design principles including: | ||
| - Visual hierarchy and typography | ||
| - Color theory and contrast | ||
| - Spacing and layout consistency | ||
| - User-centered design approach | ||
| - Intuitive navigation patterns | ||
| - Loading states and error handling | ||
|
|
||
| 5. **Code Quality**: Ensure code is: | ||
| - Clean, readable, and maintainable | ||
| - Properly structured and organized | ||
| - Following established coding standards | ||
| - Optimized for performance | ||
| - Well-documented when necessary | ||
|
|
||
| 6. **Problem-Solving Approach**: When encountering issues: | ||
| - Use Playwright to inspect and debug visual problems | ||
| - Test across different devices and browsers | ||
| - Validate against design specifications | ||
| - Consider edge cases and error states | ||
| - Provide alternative solutions when needed | ||
|
|
||
| Always prioritize user experience, accessibility, and performance. When testing with Playwright, provide clear explanations of what you're testing and why. Offer specific, actionable recommendations for improvements based on modern frontend development standards. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "permissions": { | ||
| "allow": [ | ||
| "mcp__sequential-thinking__sequentialthinking", | ||
| "mcp__browser-tools__takeScreenshot" | ||
| ], | ||
| "deny": [], | ||
| "ask": [] | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 22.15.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| ## Development Commands | ||
|
|
||
| - `npm run dev` - Start development server on localhost:3000 | ||
| - `npm run build` - Build the application for production | ||
| - `npm run start` - Start production server | ||
| - `npm run lint` - Run ESLint with auto-fix | ||
|
|
||
| ## Architecture Overview | ||
|
|
||
| Moodify is a Next.js application that extracts color palettes from Spotify album artwork and creates dynamic backgrounds. The app uses a microservices architecture with a separate backend for data processing. | ||
|
|
||
| ### Core Data Flow | ||
| 1. User searches for music via Spotify API (`lib/spotify.ts`) | ||
| 2. Selected track's album artwork is sent to external palette service (`lib/palette-fetcher.ts`) | ||
| 3. Color palette is generated and stored in MongoDB via backend API | ||
| 4. Redux state manages both Spotify data and color palettes | ||
| 5. Background dynamically updates based on extracted colors | ||
|
|
||
| ### Key Architecture Components | ||
|
|
||
| **State Management** | ||
| - Redux Toolkit with two main slices: `spotifySlice` and `colourPaletteSlice` | ||
| - Store configuration in `lib/store.ts` with serialization disabled for complex color data | ||
| - Provider setup in `app/StoreProvider.tsx` | ||
|
|
||
| **External Dependencies** | ||
| - Backend API: `NEXT_PUBLIC_MOODIFY_BACKEND_URL` (palette generation and data storage) | ||
| - Spotify API: Client credentials flow implemented in `lib/spotify.ts` | ||
| - MongoDB: Accessed through backend, not directly from frontend | ||
|
|
||
| **API Routes Structure** | ||
| - `/api/spotify/search` - Proxies Spotify search requests | ||
| - `/api/data/collection/bulk` - Handles bulk track data operations | ||
| - `/api/data/collection/single` - Handles single track operations | ||
| - `/api/data/palette-picker` - Manages color palette operations | ||
|
|
||
| **Component Architecture** | ||
| - Theme system with dark/light mode support | ||
| - Reusable UI components in `app/components/ui/` | ||
| - Search functionality with debounced input | ||
| - Dynamic background rendering based on color palettes | ||
|
|
||
| ### Environment Variables Required | ||
| ``` | ||
| NEXT_PUBLIC_MOODIFY_BACKEND_URL - Backend service URL | ||
| SPOTIFY_CLIENT_ID - Spotify API credentials | ||
| SPOTIFY_CLIENT_SECRET - Spotify API credentials | ||
| SPOTIFY_REFRESH_TOKEN - For authenticated requests | ||
| ``` | ||
|
|
||
| ### Database Integration | ||
| - Track data is stored via backend API calls in `lib/database-handler.ts` | ||
| - Backend handles MongoDB operations and palette generation | ||
| - Frontend never directly accesses database | ||
| - Bulk operations supported for efficient data storage | ||
|
|
||
| ### Color Palette Processing | ||
| - Album artwork URLs are sent to external palette service | ||
| - Service returns RGB color arrays (format: `[[r,g,b], [r,g,b], ...]`) | ||
| - Default emerald palette used as fallback on errors | ||
| - Palettes are stored with track metadata for future retrieval |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { NextRequest, NextResponse } from 'next/server'; | ||
| import { getAlbumTracks } from '@/lib/spotify'; | ||
|
|
||
| export async function GET( | ||
| request: NextRequest, | ||
| context: { params: Promise<{ id: string }> } | ||
| ) { | ||
| const params = await context.params; | ||
| const albumId = params.id; | ||
|
|
||
| if (!albumId) { | ||
| return NextResponse.json( | ||
| { error: 'Album ID is required' }, | ||
| { status: 400 } | ||
| ); | ||
| } | ||
|
|
||
| try { | ||
| const tracks = await getAlbumTracks(albumId); | ||
| return NextResponse.json({ tracks }, { status: 200 }); | ||
| } catch (error) { | ||
| console.error('Error fetching album tracks:', error); | ||
| return NextResponse.json( | ||
| { error: 'Failed to fetch album tracks' }, | ||
| { status: 500 } | ||
| ); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| import React, { useState, useRef, useEffect, useCallback, memo } from 'react' | ||
| import Image from 'next/image' | ||
| import { Calendar, Disc, Music } from 'lucide-react' | ||
| import { SpotifyAlbum } from '../utils/interfaces' | ||
| import { useDispatch } from 'react-redux' | ||
| import { openAlbumTracksModal } from '@/lib/features/spotifySlice' | ||
|
|
||
| interface LazyImageProps { | ||
| src: string; | ||
| alt: string; | ||
| className?: string; | ||
| children?: React.ReactNode; | ||
| } | ||
|
|
||
| const LazyImage = memo(({ src, alt, className, children }: LazyImageProps) => { | ||
| const [isLoaded, setIsLoaded] = useState(false); | ||
| const [isInView, setIsInView] = useState(false); | ||
| const imgRef = useRef<HTMLDivElement>(null); | ||
|
|
||
| useEffect(() => { | ||
| const observer = new IntersectionObserver( | ||
| ([entry]) => { | ||
| if (entry.isIntersecting) { | ||
| setIsInView(true); | ||
| observer.disconnect(); | ||
| } | ||
| }, | ||
| { threshold: 0.1 } | ||
| ); | ||
|
|
||
| if (imgRef.current) { | ||
| observer.observe(imgRef.current); | ||
| } | ||
|
|
||
| return () => observer.disconnect(); | ||
| }, []); | ||
|
|
||
| return ( | ||
| <div ref={imgRef} className="relative aspect-square"> | ||
| {!isInView ? ( | ||
| <div className="w-full h-full bg-gray-200 dark:bg-gray-700 animate-pulse" /> | ||
| ) : ( | ||
| <> | ||
| {!isLoaded && ( | ||
| <div className="absolute inset-0 bg-gray-200 dark:bg-gray-700 animate-pulse" /> | ||
| )} | ||
| <Image | ||
| src={src} | ||
| alt={alt} | ||
| fill | ||
| className={`object-cover transition-opacity duration-300 ${isLoaded ? 'opacity-100' : 'opacity-0'} ${className || ''}`} | ||
| onLoad={() => setIsLoaded(true)} | ||
| /> | ||
| {children} | ||
| </> | ||
| )} | ||
| </div> | ||
| ); | ||
| }); | ||
|
|
||
| LazyImage.displayName = 'LazyImage'; | ||
|
|
||
| export const AlbumCard = memo(({ album }: { album: SpotifyAlbum }) => { | ||
| const dispatch = useDispatch() | ||
|
|
||
| const handleAlbumClick = useCallback(() => { | ||
| dispatch(openAlbumTracksModal(album)) | ||
| }, [album, dispatch]) | ||
|
|
||
| const formatDate = (dateString: string) => { | ||
| try { | ||
| return new Date(dateString).getFullYear() | ||
| } catch { | ||
| return dateString | ||
| } | ||
| } | ||
|
|
||
| return ( | ||
| <div | ||
| className='rounded-2xl overflow-hidden transition-all group shadow-lg cursor-pointer hover:shadow-xl hover:scale-105' | ||
| onClick={handleAlbumClick} | ||
| > | ||
| <LazyImage | ||
| src={album.albumCover || '/placeholder.svg?height=300&width=300'} | ||
| alt={album.name} | ||
| className="group-hover:scale-110 transition-transform duration-300" | ||
| /> | ||
|
|
||
| <div className='p-4 backdrop-blur-lg bg-white/70 dark:bg-black/70'> | ||
| <h3 className='font-medium text-gray-900 dark:text-white truncate'>{album.name}</h3> | ||
| <p className='text-gray-700 dark:text-gray-300 text-sm truncate'>{album.artists.join(', ')}</p> | ||
|
|
||
| <div className='flex items-center gap-4 mt-2 text-xs text-gray-600 dark:text-gray-400'> | ||
| <div className='flex items-center gap-1'> | ||
| <Calendar className='h-3 w-3' /> | ||
| <span>{formatDate(album.releaseDate)}</span> | ||
| </div> | ||
| <div className='flex items-center gap-1'> | ||
| <Music className='h-3 w-3' /> | ||
| <span>{album.totalTracks} tracks</span> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div className='flex gap-1 mt-2'> | ||
| {album.colourPalette.map((c: number[], i: number) => ( | ||
| <div | ||
| key={i} | ||
| className="palette-circle" | ||
| style={{ | ||
| backgroundColor: `rgb(${c[0]}, ${c[1]}, ${c[2]})`, | ||
| animationDelay: `${i * 0.05}s`, | ||
| animation: 'pop-in 0.3s forwards' | ||
| }} | ||
| title={`RGB(${c[0]}, ${c[1]}, ${c[2]})`} | ||
| /> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| }) | ||
|
|
||
| AlbumCard.displayName = 'AlbumCard' |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the palette-picker API fails, it returns a 200 status code, which is misleading. It should return a 500 status code to properly indicate a server error. This will help in debugging and handling errors on the client-side.