mirror of
https://github.com/SrIzan10/mainwebsite.git
synced 2026-06-06 00:56:58 +00:00
spotify and about me
This commit is contained in:
11463
package-lock.json
generated
11463
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@
|
||||
"radix-ui": "^1.3.4",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"rehype-document": "^7.0.3",
|
||||
"rehype-external-links": "^3.0.0",
|
||||
"rehype-katex": "^7.0.1",
|
||||
|
||||
153
src/components/BentoSpotify.tsx
Normal file
153
src/components/BentoSpotify.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
// code based on https://github.com/jktrn/enscribe.dev/blob/main/src/components/bento/SpotifyPresence.tsx
|
||||
// which is under copyright.
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import { Skeleton } from "./ui/skeleton"
|
||||
import { FaSpotify } from 'react-icons/fa'
|
||||
import { MoveUpRight } from "lucide-react"
|
||||
|
||||
interface Track {
|
||||
name: string
|
||||
artist: { '#text': string }
|
||||
album: { '#text': string }
|
||||
image: { '#text': string }[]
|
||||
url: string
|
||||
'@attr'?: { nowplaying: string }
|
||||
}
|
||||
|
||||
export default function BentoSpotify() {
|
||||
const [displayData, setDisplayData] = useState<Track | null>(null)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
fetch('https://lastfm-last-played.biancarosa.com.br/enscribe/latest-song')
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
setDisplayData(data.track)
|
||||
setIsLoading(false)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error fetching latest song:', error)
|
||||
setIsLoading(false)
|
||||
})
|
||||
}, [])
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="relative h-full w-full overflow-hidden rounded-lg bg-gradient-to-br from-green-500/10 to-green-600/5">
|
||||
{/* Background Pattern */}
|
||||
<div className="absolute inset-0 opacity-5">
|
||||
<div className="h-full w-full bg-[radial-gradient(circle_at_20%_80%,_theme(colors.green.500)_0%,_transparent_50%)]"></div>
|
||||
</div>
|
||||
|
||||
{/* Spotify Logo */}
|
||||
<div className="absolute right-3 top-3 z-10">
|
||||
<FaSpotify size={24} className="text-green-500" />
|
||||
</div>
|
||||
|
||||
<div className="relative z-10 flex h-full flex-col p-4">
|
||||
{/* Header Skeleton */}
|
||||
<div className="mb-4 flex items-center gap-2">
|
||||
<Skeleton className="h-2 w-2 rounded-full" />
|
||||
<Skeleton className="h-3 w-20" />
|
||||
</div>
|
||||
|
||||
{/* Album Art & Info Skeleton */}
|
||||
<div className="flex flex-1 gap-3">
|
||||
<Skeleton className="h-16 w-16 rounded-lg flex-shrink-0" />
|
||||
|
||||
<div className="flex min-w-0 flex-1 flex-col justify-center gap-2">
|
||||
<Skeleton className="h-4 w-3/4" />
|
||||
<Skeleton className="h-3 w-1/2" />
|
||||
<Skeleton className="h-3 w-2/3" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer Skeleton */}
|
||||
<div className="mt-4 flex items-center justify-between">
|
||||
<Skeleton className="h-1 w-8 rounded-full" />
|
||||
<Skeleton className="h-8 w-8 rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!displayData) return <p>Something absolutely horrible has gone wrong</p>
|
||||
|
||||
const { name: song, artist, album, image, url } = displayData
|
||||
|
||||
return (
|
||||
<div className="relative h-full w-full overflow-hidden rounded-lg bg-gradient-to-br from-green-500/10 to-green-600/5">
|
||||
{/* Background Pattern */}
|
||||
<div className="absolute inset-0 opacity-5">
|
||||
<div className="h-full w-full bg-[radial-gradient(circle_at_20%_80%,_theme(colors.green.500)_0%,_transparent_50%)]"></div>
|
||||
</div>
|
||||
|
||||
{/* Spotify Logo */}
|
||||
<div className="absolute right-3 top-3 z-10">
|
||||
<FaSpotify size={24} className="text-green-500" />
|
||||
</div>
|
||||
|
||||
<div className="relative z-10 flex h-full flex-col p-4">
|
||||
{/* Header */}
|
||||
<div className="mb-4 flex items-center gap-2">
|
||||
<div className="flex h-2 w-2 rounded-full bg-green-500 animate-pulse"></div>
|
||||
<span className="text-xs font-medium text-muted-foreground">
|
||||
{displayData['@attr']?.nowplaying === 'true'
|
||||
? 'NOW PLAYING'
|
||||
: 'LAST PLAYED'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Album Art & Info */}
|
||||
<div className="flex flex-1 gap-3">
|
||||
<div className="relative flex-shrink-0">
|
||||
<img
|
||||
src={image[3]['#text']}
|
||||
alt="Album art"
|
||||
width={64}
|
||||
height={64}
|
||||
className="h-16 w-16 rounded-lg border shadow-lg"
|
||||
/>
|
||||
{displayData['@attr']?.nowplaying === 'true' && (
|
||||
<div className="absolute -bottom-1 -right-1 h-4 w-4 rounded-full bg-green-500 border-2 border-background"></div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex min-w-0 flex-1 flex-col justify-center">
|
||||
<h3 className="mb-1 truncate text-sm font-bold leading-tight">
|
||||
{song}
|
||||
</h3>
|
||||
<p className="truncate text-xs text-muted-foreground">
|
||||
{artist['#text']}
|
||||
</p>
|
||||
<p className="truncate text-xs text-muted-foreground/70">
|
||||
{album['#text']}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="mt-4 flex items-center justify-between">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="h-1 w-8 rounded-full bg-muted">
|
||||
<div className="h-full rounded-full bg-green-500"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
href={url}
|
||||
aria-label="View on last.fm"
|
||||
title="View on last.fm"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex h-8 w-8 items-center justify-center rounded-full bg-secondary/80 text-muted-foreground transition-all duration-200 hover:bg-secondary hover:text-foreground hover:scale-110"
|
||||
>
|
||||
<MoveUpRight size={14} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
13
src/components/ui/skeleton.tsx
Normal file
13
src/components/ui/skeleton.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="skeleton"
|
||||
className={cn("bg-accent animate-pulse rounded-md", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Skeleton }
|
||||
@@ -1,26 +1,31 @@
|
||||
---
|
||||
import PageHead from '@/components/PageHead.astro'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import Link from '@/components/Link.astro'
|
||||
import BentoSpotify from '@/components/BentoSpotify'
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<PageHead slot="head" title="Home" />
|
||||
<section class="p-4">
|
||||
<!-- Mobile: Single column stack, Tablet: 2 columns, Desktop: 3 columns -->
|
||||
<div
|
||||
class="grid w-full grid-cols-1 grid-rows-6 gap-4 md:aspect-[3/2] md:grid-cols-2 md:grid-rows-4 lg:aspect-[4/3] lg:grid-cols-3 lg:grid-rows-3"
|
||||
>
|
||||
<!-- Profile Image -->
|
||||
<div class="bento-item rounded-lg border p-2 md:col-span-2 lg:col-span-2">
|
||||
<div class="bento-item rounded-lg border p-2 md:col-span-2 lg:col-span-2 flex flex-col items-center justify-center relative *:text-center">
|
||||
<img src="https://res.cloudinary.com/mainwebsite/image/upload/v1703593035/bg/Playa_de_Santa_Marina_ae389j.jpg" class="absolute inset-0 object-cover w-full h-full rounded-lg opacity-20" />
|
||||
<img
|
||||
src="https://github.com/SrIzan10.png"
|
||||
class="h-32 w-full rounded object-cover md:h-40"
|
||||
class="rounded-full w-24 h-24 mb-2 relative z-10"
|
||||
/>
|
||||
<p>hi im ethan</p>
|
||||
<p class="relative z-10">Hi! I'm Izan, a student from Málaga, Spain</p>
|
||||
<p class="relative z-10">I mainly do open source work at <Link href="https://sern.dev" external underline>sern</Link> and <Link href="https://hackclub.com" external underline>Hack Club</Link>.</p>
|
||||
<p class="relative z-10">In my free time, I enjoy coding, reading and learning languages.</p>
|
||||
</div>
|
||||
|
||||
<!-- Spotify -->
|
||||
<div class="bento-item rounded-lg border p-2">spotify</div>
|
||||
<div class="bento-item rounded-lg border">
|
||||
<BentoSpotify client:load />
|
||||
</div>
|
||||
|
||||
<!-- Filler -->
|
||||
<div class="bento-item rounded-lg border p-2 md:row-span-2 lg:row-span-2">
|
||||
|
||||
@@ -5238,6 +5238,11 @@ react-dom@19.0.0:
|
||||
dependencies:
|
||||
scheduler "^0.25.0"
|
||||
|
||||
react-icons@^5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.5.0.tgz#8aa25d3543ff84231685d3331164c00299cdfaf2"
|
||||
integrity sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==
|
||||
|
||||
react-refresh@^0.17.0:
|
||||
version "0.17.0"
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53"
|
||||
|
||||
Reference in New Issue
Block a user