mirror of
https://github.com/FranP-code/spooky-spotify-showcase.git
synced 2025-10-13 00:02:36 +00:00
Spookify switch
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { use, useEffect, useState } from "react";
|
||||||
import Tilt from "react-parallax-tilt";
|
import Tilt from "react-parallax-tilt";
|
||||||
import { TrackByAlbum } from "./spotify-data";
|
import { TrackByAlbum } from "./spotify-data";
|
||||||
import { api } from "@/trpc/react";
|
import { api } from "@/trpc/react";
|
||||||
@@ -11,17 +11,22 @@ ring2.register();
|
|||||||
quantum.register();
|
quantum.register();
|
||||||
|
|
||||||
export default function AlbumShowcase({
|
export default function AlbumShowcase({
|
||||||
|
spookify,
|
||||||
album,
|
album,
|
||||||
position,
|
position,
|
||||||
tracks,
|
tracks,
|
||||||
}: TrackByAlbum) {
|
}: TrackByAlbum & { spookify: boolean }) {
|
||||||
const imageSource = album.images[0]
|
const imageSource = album.images[0]
|
||||||
? album.images[0].url
|
? album.images[0].url
|
||||||
: "https://via.placeholder.com/150";
|
: "https://via.placeholder.com/150";
|
||||||
|
|
||||||
const [showSpookyImage, setShowSpookyImage] = useState(false);
|
const [showSpookyImage, setShowSpookyImage] = useState(spookify);
|
||||||
const [spookyImageLoaded, setSpookyImageLoaded] = useState(false);
|
const [spookyImageLoaded, setSpookyImageLoaded] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setShowSpookyImage(spookify);
|
||||||
|
}, [spookify]);
|
||||||
|
|
||||||
const entry = api.entry.get.useQuery({
|
const entry = api.entry.get.useQuery({
|
||||||
type: "album",
|
type: "album",
|
||||||
name: album.name,
|
name: album.name,
|
||||||
@@ -72,14 +77,17 @@ export default function AlbumShowcase({
|
|||||||
)?.match(/https:\/\/res.cloudinary.com\/[^"]+/);
|
)?.match(/https:\/\/res.cloudinary.com\/[^"]+/);
|
||||||
|
|
||||||
const spookyImageSource = spookyImageMatch ? spookyImageMatch[0] : null;
|
const spookyImageSource = spookyImageMatch ? spookyImageMatch[0] : null;
|
||||||
|
console.log(spookyImageSource);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={() => setShowSpookyImage(!showSpookyImage)}
|
|
||||||
key={album.id}
|
key={album.id}
|
||||||
className="flex w-full flex-wrap gap-3 rounded-xl bg-white bg-opacity-10 p-5 backdrop-blur-lg backdrop-filter"
|
className="flex w-full flex-wrap gap-3 rounded-xl bg-white bg-opacity-10 p-5 backdrop-blur-lg backdrop-filter"
|
||||||
>
|
>
|
||||||
<div className="cursor-pointer">
|
<div
|
||||||
|
onClick={() => setShowSpookyImage(!showSpookyImage)}
|
||||||
|
className="cursor-pointer"
|
||||||
|
>
|
||||||
<Tilt tiltMaxAngleX={10} tiltMaxAngleY={10} transitionSpeed={200}>
|
<Tilt tiltMaxAngleX={10} tiltMaxAngleY={10} transitionSpeed={200}>
|
||||||
<img
|
<img
|
||||||
className="h-36 w-36 cursor-pointer rounded"
|
className="h-36 w-36 cursor-pointer rounded"
|
||||||
@@ -99,7 +107,7 @@ export default function AlbumShowcase({
|
|||||||
src={spookyImageSource}
|
src={spookyImageSource}
|
||||||
alt={album.name}
|
alt={album.name}
|
||||||
onLoad={() => {
|
onLoad={() => {
|
||||||
if (!spookyImageLoaded && generateSpookyImage.data) {
|
if (!spookyImageLoaded) {
|
||||||
setSpookyImageLoaded(true);
|
setSpookyImageLoaded(true);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -120,7 +128,7 @@ export default function AlbumShowcase({
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<l-ring-2 size="100" speed="1.75" color="white"></l-ring-2>
|
<l-ring-2 size="100" speed="1.75" color="white"></l-ring-2>
|
||||||
<p className="text-center">Generating...</p>
|
<p className="text-center">Getting image...</p>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,17 +10,23 @@ ring2.register();
|
|||||||
quantum.register();
|
quantum.register();
|
||||||
|
|
||||||
export default function ArtistShowcase({
|
export default function ArtistShowcase({
|
||||||
|
spookify,
|
||||||
images,
|
images,
|
||||||
name,
|
name,
|
||||||
id,
|
id,
|
||||||
}: {
|
}: {
|
||||||
|
spookify: boolean;
|
||||||
images: { url: string }[];
|
images: { url: string }[];
|
||||||
name: string;
|
name: string;
|
||||||
id: string;
|
id: string;
|
||||||
}) {
|
}) {
|
||||||
const [showSpookyImage, setShowSpookyImage] = useState(false);
|
const [showSpookyImage, setShowSpookyImage] = useState(spookify);
|
||||||
const [spookyImageLoaded, setSpookyImageLoaded] = useState(false);
|
const [spookyImageLoaded, setSpookyImageLoaded] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setShowSpookyImage(spookify);
|
||||||
|
}, [spookify]);
|
||||||
|
|
||||||
const imageSource = images[0]
|
const imageSource = images[0]
|
||||||
? images[0].url
|
? images[0].url
|
||||||
: "https://via.placeholder.com/150";
|
: "https://via.placeholder.com/150";
|
||||||
|
|||||||
49
src/app/_components/showcase.tsx
Normal file
49
src/app/_components/showcase.tsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import Switch from "./switch";
|
||||||
|
import AlbumShowcase from "./album-showcase";
|
||||||
|
import ArtistShowcase from "./artist-showcase";
|
||||||
|
|
||||||
|
export function Showcase({
|
||||||
|
tracksByAlbum,
|
||||||
|
artists,
|
||||||
|
}: {
|
||||||
|
tracksByAlbum: Record<string, any>;
|
||||||
|
artists: any[];
|
||||||
|
}) {
|
||||||
|
const [spookify, setSpookify] = useState(false);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex gap-2 self-start">
|
||||||
|
<label className="flex items-center gap-2 text-lg font-semibold leading-6 text-white">
|
||||||
|
Spookify
|
||||||
|
</label>
|
||||||
|
<Switch isChecked={spookify} setIsChecked={setSpookify} />
|
||||||
|
</div>
|
||||||
|
<h3>Tracks by album</h3>
|
||||||
|
{Object.values(tracksByAlbum)
|
||||||
|
.sort((a, b) => b.position - a.position)
|
||||||
|
.map(
|
||||||
|
(album, index) =>
|
||||||
|
!index && <AlbumShowcase spookify={spookify} {...album} />,
|
||||||
|
)}
|
||||||
|
<h3>Artists images</h3>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
justifyContent: "space-evenly",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{[artists[0]].map((artist) => {
|
||||||
|
return (
|
||||||
|
<ArtistShowcase spookify={spookify} key={artist.id} {...artist} />
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Showcase;
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
import SpotifyWebApi from "spotify-web-api-node";
|
import SpotifyWebApi from "spotify-web-api-node";
|
||||||
import AlbumShowcase from "./album-showcase";
|
import Showcase from "./showcase";
|
||||||
import ArtistShowcase from "./artist-showcase";
|
|
||||||
import { TRPCReactProvider } from "@/trpc/react";
|
|
||||||
|
|
||||||
const TRACKS_LIMIT = 20;
|
const TRACKS_LIMIT = 20;
|
||||||
const ARTISTS_LIMIT = 21;
|
const ARTISTS_LIMIT = 21;
|
||||||
@@ -141,12 +139,12 @@ export default async function SpotifyData({
|
|||||||
</div> */}
|
</div> */}
|
||||||
|
|
||||||
{/* TODO CHECK IF NEEDED */}
|
{/* TODO CHECK IF NEEDED */}
|
||||||
<TRPCReactProvider>
|
{/* <TRPCReactProvider>
|
||||||
<h3>Tracks by album</h3>
|
<h3>Tracks by album</h3>
|
||||||
{Object.values(tracksByAlbum)
|
{Object.values(tracksByAlbum)
|
||||||
.sort((a, b) => b.position - a.position)
|
.sort((a, b) => b.position - a.position)
|
||||||
.map((album, index) => !index && <AlbumShowcase {...album} />)}
|
.map((album, index) => !index && <AlbumShowcase {...album} />)}
|
||||||
</TRPCReactProvider>
|
</TRPCReactProvider> */}
|
||||||
|
|
||||||
{/* <h3>Albums images</h3>
|
{/* <h3>Albums images</h3>
|
||||||
<div
|
<div
|
||||||
@@ -175,7 +173,7 @@ export default async function SpotifyData({
|
|||||||
})}
|
})}
|
||||||
</div> */}
|
</div> */}
|
||||||
|
|
||||||
<h3>Artists images</h3>
|
{/* <h3>Artists images</h3>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -183,10 +181,12 @@ export default async function SpotifyData({
|
|||||||
justifyContent: "space-evenly",
|
justifyContent: "space-evenly",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{artists.map((artist) => {
|
{[artists[0]].map((artist) => {
|
||||||
return <ArtistShowcase key={artist.id} {...artist} />;
|
return <ArtistShowcase key={artist.id} {...artist} />;
|
||||||
})}
|
})}
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
|
<Showcase tracksByAlbum={tracksByAlbum} artists={artists} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/app/_components/switch.tsx
Normal file
41
src/app/_components/switch.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"use client";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
const Switch = ({
|
||||||
|
isChecked,
|
||||||
|
setIsChecked,
|
||||||
|
}: {
|
||||||
|
isChecked: boolean;
|
||||||
|
setIsChecked: (isChecked: boolean) => void;
|
||||||
|
}) => {
|
||||||
|
const handleCheckboxChange = () => {
|
||||||
|
setIsChecked(!isChecked);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<label className={`flex cursor-pointer select-none items-center`}>
|
||||||
|
<div className="relative">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={isChecked}
|
||||||
|
onChange={handleCheckboxChange}
|
||||||
|
className="sr-only"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={`box block h-8 w-14 rounded-full ${
|
||||||
|
isChecked ? "bg-purple-800" : "bg-gray-700"
|
||||||
|
}`}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
className={`absolute left-1 top-1 flex h-6 w-6 items-center justify-center rounded-full bg-orange-500 transition ${
|
||||||
|
isChecked ? "translate-x-full" : ""
|
||||||
|
} `}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Switch;
|
||||||
@@ -39,7 +39,7 @@ export default async function Home({
|
|||||||
return (
|
return (
|
||||||
<HydrateClient>
|
<HydrateClient>
|
||||||
<main className="justify-centerbg-gradient-to-r flex min-h-screen flex-col items-center bg-gradient-to-r from-slate-900 to-slate-700 text-slate-200">
|
<main className="justify-centerbg-gradient-to-r flex min-h-screen flex-col items-center bg-gradient-to-r from-slate-900 to-slate-700 text-slate-200">
|
||||||
<div className="container flex flex-col items-center justify-center gap-8 px-4 py-16">
|
<div className="container flex flex-col items-center justify-center gap-8 px-4 pb-16 pt-8">
|
||||||
{userIsLogged ? (
|
{userIsLogged ? (
|
||||||
<SpotifyData
|
<SpotifyData
|
||||||
accessToken={access_token as string}
|
accessToken={access_token as string}
|
||||||
|
|||||||
Reference in New Issue
Block a user