-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
aca2ada
commit bfe7fbb
Showing
11 changed files
with
505 additions
and
9 deletions.
There are no files selected for viewing
This file contains 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,79 @@ | ||
// SongItem.tsx | ||
import React from "react"; | ||
import Image from "next/image"; | ||
import { Heart } from "lucide-react"; | ||
|
||
interface SongItemProps { | ||
title: string; | ||
artist: string; | ||
genre: string; | ||
duration: string; | ||
isSelected: boolean; | ||
isFavorite: boolean; | ||
onFavoriteToggle: () => void; | ||
onPlay: () => void; | ||
} | ||
|
||
const SongItem: React.FC<SongItemProps> = ({ | ||
title, | ||
genre, | ||
duration, | ||
isSelected, | ||
isFavorite, | ||
onFavoriteToggle, | ||
onPlay, | ||
}) => { | ||
return ( | ||
<div | ||
onClick={onPlay} | ||
className={` | ||
p-4 rounded-[15px] bg-black | ||
hover:bg-primary/10 transition-colors cursor-pointer | ||
${isSelected ? "border border-primary" : ""} | ||
mb-3 | ||
h-[72px] | ||
`} | ||
> | ||
<div className="flex items-center gap-4 h-full"> | ||
{/* Imagen de la canción */} | ||
<div className="w-16 h-16 bg-black rounded-md overflow-hidden relative flex-shrink-0"> | ||
<Image | ||
src="/bg-4.jpg" | ||
alt="Album art" | ||
fill | ||
className="object-cover" | ||
/> | ||
</div> | ||
|
||
{/* Corazón para marcar favorito */} | ||
<Heart | ||
className={`w-5 h-5 cursor-pointer transition-colors border-primary ${ | ||
isFavorite ? "fill-primary" : "text-primary" | ||
}`} | ||
onClick={(e) => { | ||
e.stopPropagation(); | ||
onFavoriteToggle(); | ||
}} | ||
/> | ||
|
||
{/* Contenedor de la canción */} | ||
<div className="flex flex-1 items-center justify-between h-full"> | ||
{/* Título de la canción */} | ||
<div className="flex-1"> | ||
<h3 className="text-white font-bold truncate">{title}</h3> | ||
</div> | ||
|
||
{/* Género */} | ||
<div className="text-white text-center font-bold w-[100px]"> | ||
{genre} | ||
</div> | ||
|
||
{/* Duración */} | ||
<div className="text-white font-bold w-[60px]">{duration}</div> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default SongItem; |
This file contains 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,61 @@ | ||
// SongList.tsx | ||
import React, { useState } from "react"; | ||
import SongItem from "./SongItem"; | ||
import Player from "@/components/ui/Player"; | ||
import { useFilterSongs } from "@/hooks/useFilterSongs"; | ||
import { mockSongs } from "@/data/mockSongs"; | ||
import { Song } from "@/types/ui/Song"; | ||
|
||
interface SongListProps { | ||
searchTerm?: string; | ||
selectedGenre?: string; | ||
} | ||
|
||
export default function SongList({ | ||
searchTerm = "", | ||
selectedGenre = "Todos", | ||
}: SongListProps) { | ||
const [selectedSong, setSelectedSong] = useState<Song | null>(null); | ||
const [isPlaying, setIsPlaying] = useState(false); | ||
const [songs, setSongs] = useState<Song[]>(mockSongs); | ||
|
||
const filteredSongs = useFilterSongs(songs, searchTerm, selectedGenre); | ||
|
||
const handlePlay = (song: Song) => { | ||
setSelectedSong(song); | ||
setIsPlaying(true); | ||
}; | ||
|
||
const toggleFavorite = (songId: string) => { | ||
setSongs((prevSongs) => | ||
prevSongs.map((song) => | ||
song.id === songId ? { ...song, isFavorite: !song.isFavorite } : song | ||
) | ||
); | ||
}; | ||
|
||
return ( | ||
<div className="w-full"> | ||
{filteredSongs.map((song) => ( | ||
<SongItem | ||
key={song.id} | ||
title={song.title} | ||
artist={song.artist} | ||
genre={song.genre} | ||
duration={song.duration} | ||
isFavorite={song.isFavorite} | ||
isSelected={selectedSong?.id === song.id} | ||
onPlay={() => handlePlay(song)} | ||
onFavoriteToggle={() => toggleFavorite(song.id)} | ||
/> | ||
))} | ||
{selectedSong && ( | ||
<Player | ||
currentSong={selectedSong} | ||
isPlaying={isPlaying} | ||
onPlayPause={() => setIsPlaying(!isPlaying)} | ||
/> | ||
)} | ||
</div> | ||
); | ||
} |
This file contains 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,20 @@ | ||
"use client"; | ||
|
||
import React, { ReactNode } from "react"; | ||
|
||
interface ExploreLayoutProps { | ||
children: ReactNode; | ||
} | ||
|
||
const ExploreLayout: React.FC<ExploreLayoutProps> = ({ children }) => { | ||
return ( | ||
<div | ||
className="min-h-screen bg-cover bg-center bg-no-repeat" | ||
style={{ backgroundImage: "url('/bg-1.jpg')" }} | ||
> | ||
<div className="bg-black bg-opacity-70 min-h-screen">{children}</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default ExploreLayout; |
This file contains 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,62 @@ | ||
"use client"; | ||
import GenreButtons from "@/components/ui/GenroButtons"; | ||
import SearchBar from "@/components/ui/SearchBar"; | ||
import SongList from "@/app/(page)/explore/components/SongList"; | ||
import { useState } from "react"; | ||
|
||
export default function ExplorePage() { | ||
const [searchTerm, setSearchTerm] = useState(""); | ||
const [selectedGenre, setSelectedGenre] = useState("Todos"); | ||
|
||
const handleSearchChange = (term: string) => { | ||
setSearchTerm(term); | ||
}; | ||
|
||
const handleGenreChange = (genre: string) => { | ||
setSelectedGenre(genre); | ||
}; | ||
|
||
return ( | ||
<div className="container mx-auto px-4 py-12 max-w-[1300px]"> | ||
<h1 className="text-4xl font-bold mb-12 text-center text-white"> | ||
Explorar | ||
</h1> | ||
<div className="flex flex-col md:flex-row gap-6"> | ||
{/* Pantallas grandes*/} | ||
<div className="hidden md:flex gap-6 w-full"> | ||
<div className="md:w-1/4"> | ||
<div className="flex flex-wrap gap-2 justify-center md:justify-start"> | ||
<GenreButtons | ||
onGenreChange={handleGenreChange} | ||
selectedGenre={selectedGenre} | ||
/> | ||
</div> | ||
</div> | ||
<div className="md:w-3/4"> | ||
<div className="mb-6"> | ||
<SearchBar onSearchChange={handleSearchChange} /> | ||
</div> | ||
<div className="mt-10"> | ||
<SongList searchTerm={searchTerm} selectedGenre={selectedGenre} /> | ||
</div> | ||
</div> | ||
</div> | ||
{/* Mobile*/} | ||
<div className="flex flex-col gap-6 md:hidden"> | ||
<div className="mb-6"> | ||
<SearchBar onSearchChange={handleSearchChange} /> | ||
</div> | ||
<div className="flex flex-wrap gap-2 justify-center"> | ||
<GenreButtons | ||
onGenreChange={handleGenreChange} | ||
selectedGenre={selectedGenre} | ||
/> | ||
</div> | ||
<div className="mt-10"> | ||
<SongList searchTerm={searchTerm} selectedGenre={selectedGenre} /> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains 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,43 @@ | ||
"use client"; | ||
|
||
interface GenreButtonsProps { | ||
onGenreChange: (genre: string) => void; | ||
selectedGenre: string; | ||
} | ||
|
||
const genres = [ | ||
"Todos", | ||
"Electronica", | ||
"Pop", | ||
"Rock", | ||
"Rap", | ||
"K-pop", | ||
"Clásica", | ||
]; | ||
|
||
export default function GenreButtons({ | ||
onGenreChange, | ||
selectedGenre, | ||
}: GenreButtonsProps) { | ||
return ( | ||
<div className="flex flex-wrap gap-4 justify-center md:justify-start"> | ||
{genres.map((genre) => ( | ||
<button | ||
key={genre} | ||
onClick={() => onGenreChange(genre)} | ||
className={` | ||
w-[150px] h-[50px] md:w-[200px] md:h-[60px] rounded-full text-lg font-bold border-2 | ||
transition-all duration-200 | ||
${ | ||
selectedGenre === genre | ||
? "bg-primary text-black border-black" | ||
: "bg-black text-primary border-primary hover:bg-primary hover:text-black hover:border-black" | ||
} | ||
`} | ||
> | ||
{genre} | ||
</button> | ||
))} | ||
</div> | ||
); | ||
} |
This file contains 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
Oops, something went wrong.