Skip to content

Commit

Permalink
Add Explore page #27
Browse files Browse the repository at this point in the history
  • Loading branch information
Jhonatanjacome07 committed Dec 2, 2024
1 parent aca2ada commit bfe7fbb
Show file tree
Hide file tree
Showing 11 changed files with 505 additions and 9 deletions.
79 changes: 79 additions & 0 deletions frontend/src/app/(page)/explore/components/SongItem.tsx
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;
61 changes: 61 additions & 0 deletions frontend/src/app/(page)/explore/components/SongList.tsx
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>
);
}
20 changes: 20 additions & 0 deletions frontend/src/app/(page)/explore/layout.tsx
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;
62 changes: 62 additions & 0 deletions frontend/src/app/(page)/explore/page.tsx
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>
);
}
43 changes: 43 additions & 0 deletions frontend/src/components/ui/GenroButtons.tsx
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>
);
}
22 changes: 13 additions & 9 deletions frontend/src/components/ui/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { usePathname } from "next/navigation";

const navLinks: NavLink[] = [
{ label: "Inicio", href: "/" },
{ label: "Explorar", href: "/explorar" },
{ label: "Explorar", href: "/explore" },
];

const Header = () => {
Expand Down Expand Up @@ -40,20 +40,22 @@ const Header = () => {
<Link
key={label}
href={href}
className={`text-xl transition-colors ${pathname === href
className={`text-xl transition-colors ${
pathname === href
? "text-primary"
: "text-white hover:text-primary"
}`}
}`}
>
{label}
</Link>
))}
<Link
href="/profile"
className={`text-3xl transition-colors ${pathname === "/profile"
className={`text-3xl transition-colors ${
pathname === "/profile"
? "text-primary"
: "text-white hover:text-primary"
}`}
}`}
>
<UserCircle className="w-8 h-8" />
</Link>
Expand Down Expand Up @@ -96,21 +98,23 @@ const Header = () => {
<Link
key={label}
href={href}
className={`text-2xl transition-colors ${pathname === href
className={`text-2xl transition-colors ${
pathname === href
? "text-primary"
: "text-white hover:text-primary"
}`}
}`}
onClick={toggleMenu}
>
{label}
</Link>
))}
<Link
href="/profile"
className={`transition-colors ${pathname === "/profile"
className={`transition-colors ${
pathname === "/profile"
? "text-primary"
: "text-white hover:text-primary"
}`}
}`}
onClick={toggleMenu}
>
<UserCircle className="w-12 h-12" />
Expand Down
Loading

0 comments on commit bfe7fbb

Please sign in to comment.