Changeset 9c1dcc7 for frontend/src/pages


Ignore:
Timestamp:
02/07/26 19:52:09 (5 months ago)
Author:
Filip Gavrilovski <filipgavrilovski28@…>
Branches:
main
Children:
8675f75
Parents:
8a47b30
Message:

add experimental video miniplayer

Location:
frontend/src/pages
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • frontend/src/pages/LandingPage.tsx

    r8a47b30 r9c1dcc7  
    11import { useEffect, useRef, useState } from "react";
     2import { useNavigate } from "react-router-dom";
    23import axiosInstance from "../api/axiosInstance";
    34import AlbumResult from "../components/search/AlbumResult";
    45import SongResult from "../components/search/SongResult";
    56import UserResult from "../components/search/UserResult";
     7import { usePlayer } from "../context/playerContext";
    68import type {
    79        Album,
     
    1113} from "../utils/types";
    1214
     15// Convert a regular YouTube URL to an embeddable URL
     16const toEmbedUrl = (url: string): string => {
     17        try {
     18                const parsed = new URL(url);
     19                if (
     20                        (parsed.hostname === "www.youtube.com" ||
     21                                parsed.hostname === "youtube.com") &&
     22                        parsed.searchParams.has("v")
     23                ) {
     24                        return `https://www.youtube.com/embed/${parsed.searchParams.get("v")}`;
     25                }
     26                if (parsed.hostname === "youtu.be") {
     27                        return `https://www.youtube.com/embed${parsed.pathname}`;
     28                }
     29                return url;
     30        } catch {
     31                return url;
     32        }
     33};
     34
    1335const CATEGORIES: { value: SearchCategory; label: string }[] = [
    1436        { value: "songs", label: "Songs" },
     
    1941
    2042const LandingPage = () => {
     43        const navigate = useNavigate();
     44        const { play, currentSong } = usePlayer();
    2145        const [songs, setSongs] = useState<Song[]>([]);
    2246        const [loading, setLoading] = useState<boolean>(true);
     
    327351                                                                                        <div
    328352                                                                                                key={song.id}
     353                                                                                                onClick={() => navigate(`/songs/${song.id}`)}
    329354                                                                                                className="bg-[#282828] rounded-xl overflow-hidden cursor-pointer shadow-lg transition-all duration-300 ease-in-out hover:-translate-y-2 hover:shadow-2xl group"
    330355                                                                                        >
     
    340365                                                                                                        />
    341366                                                                                                        <div className="absolute top-0 left-0 w-full h-full bg-black/60 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300">
    342                                                                                                                 <div className="w-15 h-15 rounded-full bg-[#1db954] flex items-center justify-center text-2xl text-black shadow-[0_4px_12px_rgba(29,185,84,0.5)]">
    343                                                                                                                         ▶
    344                                                                                                                 </div>
     367                                                                                                                {song.link ? (
     368                                                                                                                        <button
     369                                                                                                                                onClick={(e) => {
     370                                                                                                                                        e.stopPropagation();
     371                                                                                                                                        play({
     372                                                                                                                                                id: song.id,
     373                                                                                                                                                title: song.title,
     374                                                                                                                                                artist: song.releasedBy,
     375                                                                                                                                                cover: song.cover,
     376                                                                                                                                                embedUrl: toEmbedUrl(song.link!),
     377                                                                                                                                        });
     378                                                                                                                                }}
     379                                                                                                                                className={`w-14 h-14 rounded-full flex items-center justify-center text-xl shadow-[0_4px_12px_rgba(29,185,84,0.5)] transition-all cursor-pointer ${
     380                                                                                                                                        currentSong?.id === song.id
     381                                                                                                                                                ? "bg-white text-[#1db954]"
     382                                                                                                                                                : "bg-[#1db954] text-black hover:scale-105"
     383                                                                                                                                }`}
     384                                                                                                                                aria-label={
     385                                                                                                                                        currentSong?.id === song.id
     386                                                                                                                                                ? "Now playing"
     387                                                                                                                                                : "Play song"
     388                                                                                                                                }
     389                                                                                                                        >
     390                                                                                                                                {currentSong?.id === song.id ? (
     391                                                                                                                                        <svg
     392                                                                                                                                                className="w-6 h-6"
     393                                                                                                                                                fill="currentColor"
     394                                                                                                                                                viewBox="0 0 24 24"
     395                                                                                                                                        >
     396                                                                                                                                                <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
     397                                                                                                                                        </svg>
     398                                                                                                                                ) : (
     399                                                                                                                                        <svg
     400                                                                                                                                                className="w-6 h-6"
     401                                                                                                                                                fill="currentColor"
     402                                                                                                                                                viewBox="0 0 24 24"
     403                                                                                                                                        >
     404                                                                                                                                                <path d="M8 5v14l11-7z" />
     405                                                                                                                                        </svg>
     406                                                                                                                                )}
     407                                                                                                                        </button>
     408                                                                                                                ) : (
     409                                                                                                                        <div className="w-14 h-14 rounded-full bg-[#1db954] flex items-center justify-center text-xl text-black shadow-[0_4px_12px_rgba(29,185,84,0.5)]">
     410                                                                                                                                ▶
     411                                                                                                                        </div>
     412                                                                                                                )}
    345413                                                                                                        </div>
    346414                                                                                                </div>
  • frontend/src/pages/SongDetail.tsx

    r8a47b30 r9c1dcc7  
    33import axiosInstance from "../api/axiosInstance";
    44import { useAuth } from "../context/authContext";
     5import { usePlayer } from "../context/playerContext";
    56import type { SongDetail as SongDetailType } from "../utils/types";
    67
     
    6263        const { id } = useParams<{ id: string }>();
    6364        const { user } = useAuth();
     65        const { play, currentSong } = usePlayer();
    6466        const [song, setSong] = useState<SongDetailType | null>(null);
    6567        const [loading, setLoading] = useState(true);
     
    7274                                const response = await axiosInstance.get(`/songs/${id}/details`);
    7375                                setSong(response.data);
     76                                // Don't autoplay - user must click play button
    7477                        } catch (err) {
    7578                                console.error("Error fetching song details:", err);
     
    207210
    208211                                                {/* Action buttons */}
    209                                                 {/* todo: add add to playlist button */}
    210212                                                <div className="flex items-center gap-3 mt-4">
     213                                                        {/* Play button */}
     214                                                        {song.link && (
     215                                                                <button
     216                                                                        onClick={() =>
     217                                                                                play({
     218                                                                                        id: song.id,
     219                                                                                        title: song.title,
     220                                                                                        artist: song.releasedBy,
     221                                                                                        cover: song.cover,
     222                                                                                        embedUrl: toEmbedUrl(song.link!),
     223                                                                                })
     224                                                                        }
     225                                                                        className={`flex items-center gap-2 px-6 py-3 rounded-full text-sm font-semibold transition-all cursor-pointer ${
     226                                                                                currentSong?.id === song.id
     227                                                                                        ? "bg-white text-[#1db954]"
     228                                                                                        : "bg-[#1db954] text-black hover:bg-[#1ed760] hover:scale-105"
     229                                                                        }`}
     230                                                                >
     231                                                                        {currentSong?.id === song.id ? (
     232                                                                                <>
     233                                                                                        <svg
     234                                                                                                className="w-5 h-5"
     235                                                                                                fill="currentColor"
     236                                                                                                viewBox="0 0 24 24"
     237                                                                                        >
     238                                                                                                <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
     239                                                                                        </svg>
     240                                                                                        Now Playing
     241                                                                                </>
     242                                                                        ) : (
     243                                                                                <>
     244                                                                                        <svg
     245                                                                                                className="w-5 h-5"
     246                                                                                                fill="currentColor"
     247                                                                                                viewBox="0 0 24 24"
     248                                                                                        >
     249                                                                                                <path d="M8 5v14l11-7z" />
     250                                                                                        </svg>
     251                                                                                        Play Song
     252                                                                                </>
     253                                                                        )}
     254                                                                </button>
     255                                                        )}
     256
    211257                                                        {user && (
    212258                                                                <button
     
    248294                                </div>
    249295
    250                                 {/* YouTube embed */}
     296                                {/* Play button — plays in persistent mini-player */}
    251297                                {song.link && (
    252298                                        <section className="mb-10">
    253                                                 <div className="rounded-xl overflow-hidden shadow-lg aspect-video bg-black">
    254                                                         <iframe
    255                                                                 src={toEmbedUrl(song.link)}
    256                                                                 title={song.title}
    257                                                                 className="w-full h-full"
    258                                                                 allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
    259                                                                 allowFullScreen
    260                                                         />
    261                                                 </div>
     299                                                {currentSong?.id === song.id ? (
     300                                                        <div className="bg-[#1a1a2e]/60 rounded-xl p-4 flex items-center gap-3">
     301                                                                <div className="w-10 h-10 rounded-full bg-[#1db954] flex items-center justify-center text-black animate-pulse">
     302                                                                        <svg
     303                                                                                className="w-5 h-5"
     304                                                                                fill="currentColor"
     305                                                                                viewBox="0 0 24 24"
     306                                                                        >
     307                                                                                <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
     308                                                                        </svg>
     309                                                                </div>
     310                                                                <p className="text-[#1db954] font-medium">
     311                                                                        Now playing in mini-player below
     312                                                                </p>
     313                                                        </div>
     314                                                ) : (
     315                                                        <button
     316                                                                onClick={() =>
     317                                                                        play({
     318                                                                                id: song.id,
     319                                                                                title: song.title,
     320                                                                                artist: song.releasedBy,
     321                                                                                cover: song.cover,
     322                                                                                embedUrl: toEmbedUrl(song.link!),
     323                                                                        })
     324                                                                }
     325                                                                className="w-full bg-[#1a1a2e]/60 hover:bg-[#1a1a2e]/80 rounded-xl p-4 flex items-center gap-3 transition-colors cursor-pointer group"
     326                                                        >
     327                                                                <div className="w-10 h-10 rounded-full bg-[#1db954] flex items-center justify-center text-black group-hover:scale-105 transition-transform">
     328                                                                        <svg
     329                                                                                className="w-5 h-5"
     330                                                                                fill="currentColor"
     331                                                                                viewBox="0 0 24 24"
     332                                                                        >
     333                                                                                <path d="M8 5v14l11-7z" />
     334                                                                        </svg>
     335                                                                </div>
     336                                                                <p className="text-white font-medium">Play this song</p>
     337                                                        </button>
     338                                                )}
    262339                                        </section>
    263340                                )}
Note: See TracChangeset for help on using the changeset viewer.