Refactor AlbumCard and BackButton components for improved theming and styling

- Updated AlbumCard to use a div wrapper instead of Card for layout, enhancing styling with dynamic theme colors.
- Improved BackButton to accept a theme prop, allowing for dynamic styling on hover.
- Adjusted layout.tsx to remove unnecessary imports and streamline the MantineProvider usage.
- Enhanced album detail page with new theming and styling for better visual consistency.
- Added Spotify URLs for tracks in the album list for better integration with music services.
This commit is contained in:
m4x809 2025-10-25 01:33:08 +02:00
parent a8097d84fc
commit 6ce4950d54
Signed by: m4x809
SSH key fingerprint: SHA256:YCoFF78p2DUP94EnCScqLwldjkKDwdKSZq3r8p/6EiU
7 changed files with 620 additions and 240 deletions

View file

@ -23,37 +23,63 @@ export default function AlbumCard({ album }: { album: Album }) {
const theme = getThemeColors(album.id); const theme = getThemeColors(album.id);
return ( return (
<div
style={{
border: `1px solid ${theme.border.DEFAULT}`,
boxShadow: `0 4px 20px ${theme.primary.DEFAULT}20`,
overflow: "hidden",
borderRadius: "8px",
}}
className="group relative col-span-1 cursor-pointer rounded-lg transition-all duration-300 hover:scale-105 hover:shadow-2xl"
>
<Card <Card
component={Link} component={Link}
href={`/album/${album.id}`} href={`/album/${album.id}`}
className="group col-span-1 cursor-pointer border border-gray-700 backdrop-blur-sm transition-all duration-300 hover:scale-105 hover:bg-gray-800/70 hover:shadow-2xl hover:shadow-black/20"
style={{ style={{
background: `linear-gradient(to bottom, ${theme.bg})`, background: theme.background.gradient,
viewTransitionName: `album-card-background-${album.id}`,
}} }}
> >
<Box className="relative overflow-hidden rounded-lg"> <Box
className="relative overflow-hidden rounded-lg"
style={{
border: `2px solid ${theme.border.light}`,
borderRadius: "8px",
padding: "2px",
background: theme.background.secondary,
viewTransitionName: `album-card-image-${album.id}`,
}}
>
<Box>
<Image <Image
src={image} src={image}
alt={label} alt={label}
radius="md" radius="md"
className="aspect-square w-full object-cover transition-transform duration-500 group-hover:scale-110" className="aspect-square w-full object-cover transition-transform duration-500 group-hover:scale-110"
style={{ viewTransitionName: `album-card-image-${album.id}` }}
/> />
<Box className="absolute inset-0 bg-linear-to-t from-black/80 via-transparent to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
</Box> </Box>
</Box>
<Box className="space-y-3 p-4"> <Box className="space-y-3 p-4">
<Text <Text
size="xl" size="xl"
fw={700} fw={700}
className="text-white transition-colors group-hover:text-purple-300" className="transition-colors"
style={{ viewTransitionName: `album-card-title-${album.id}` }} style={{
viewTransitionName: `album-card-title-${album.id}`,
color: theme.text.primary,
}}
> >
{label} {label}
</Text> </Text>
<Text size="sm" className="text-gray-400" style={{ viewTransitionName: `album-card-release-date-${album.id}` }}> <Text
Released:{" "} size="sm"
style={{
viewTransitionName: `album-card-release-date-${album.id}`,
color: theme.text.secondary,
}}
>
<span style={{ color: theme.accent.DEFAULT, fontWeight: 600 }}>Released: </span>
{new Date(releaseDate).toLocaleDateString("en-US", { {new Date(releaseDate).toLocaleDateString("en-US", {
year: "numeric", year: "numeric",
month: "long", month: "long",
@ -62,21 +88,43 @@ export default function AlbumCard({ album }: { album: Album }) {
</Text> </Text>
<Group gap="xs"> <Group gap="xs">
<Badge color="purple" variant="light" size="sm" className="bg-purple-500/20 text-purple-300"> <Badge
size="sm"
variant="filled"
style={{
background: theme.primary.DEFAULT,
color: theme.text.contrast,
}}
>
{songs.count} Songs {songs.count} Songs
</Badge> </Badge>
{songs.emilyLiveSongs > 0 && ( {songs.emilyLiveSongs > 0 && (
<Badge color="pink" variant="light" size="sm" className="bg-pink-500/20 text-pink-300"> <Badge
size="sm"
variant="filled"
style={{
background: theme.badges.liveEmily,
color: theme.text.contrast,
}}
>
{songs.emilyLiveSongs} Emily Live {songs.emilyLiveSongs} Emily Live
</Badge> </Badge>
)} )}
{songs.lpLiveSongs > 0 && ( {songs.lpLiveSongs > 0 && (
<Badge color="blue" variant="light" size="sm" className="bg-blue-500/20 text-blue-300"> <Badge
size="sm"
variant="filled"
style={{
background: theme.badges.liveLP,
color: theme.text.contrast,
}}
>
{songs.lpLiveSongs} LP Live {songs.lpLiveSongs} LP Live
</Badge> </Badge>
)} )}
</Group> </Group>
</Box> </Box>
</Card> </Card>
</div>
); );
} }

View file

@ -2,15 +2,31 @@
import { Button } from "@mantine/core"; import { Button } from "@mantine/core";
import { Link } from "next-view-transitions"; import { Link } from "next-view-transitions";
import type { AlbumTheme } from "@/lib/themes";
export default function BackButton() { interface BackButtonProps {
theme?: AlbumTheme;
}
export default function BackButton({ theme }: BackButtonProps) {
return ( return (
<Button <Button
component={Link} component={Link}
href="/" href="/"
variant="subtle" variant="subtle"
color="gray" className="mb-8 transition-all duration-200"
className="mb-8 text-gray-300 hover:bg-gray-800 hover:text-white" style={{
color: theme?.text.secondary || "#d1d5db",
backgroundColor: "transparent",
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = theme?.card.background || "rgba(31, 41, 55, 0.5)";
e.currentTarget.style.color = theme?.text.primary || "#ffffff";
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = "transparent";
e.currentTarget.style.color = theme?.text.secondary || "#d1d5db";
}}
> >
Back to Albums Back to Albums
</Button> </Button>

View file

@ -0,0 +1,110 @@
"use client";
import { Card, Group, Text, Badge, Box } from "@mantine/core";
import { useState } from "react";
import type { AlbumTheme } from "@/lib/themes";
import type { Track } from "@/lib/ListTypes";
interface TrackCardProps {
track: Track;
index: number;
theme: AlbumTheme;
}
export default function TrackCard({ track, index, theme }: TrackCardProps) {
const [isHovered, setIsHovered] = useState(false);
return (
<Card
className="backdrop-blur-sm transition-all duration-300"
style={{
background: isHovered ? theme.card.backgroundHover : theme.card.background,
border: `1px solid ${isHovered ? theme.border.light : theme.card.border}`,
cursor: "pointer",
// transform: isHovered ? "translateY(-2px)" : "translateY(0)",
boxShadow: isHovered ? `0 8px 24px ${theme.primary.DEFAULT}30` : "none",
}}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<Group justify="space-between" align="center">
<Group gap="md">
<Box
style={{
minWidth: "40px",
height: "40px",
display: "flex",
alignItems: "center",
justifyContent: "center",
background: theme.primary.DEFAULT,
borderRadius: "8px",
fontWeight: 700,
fontSize: "18px",
color: theme.text.contrast,
boxShadow: `0 4px 12px ${theme.primary.DEFAULT}60`,
}}
>
{index + 1}
</Box>
<Text size="lg" fw={500} style={{ color: theme.text.primary }}>
{track.label}
</Text>
</Group>
<Group gap="md">
<Text
size="sm"
fw={500}
style={{
color: theme.text.muted,
fontFamily: "monospace",
background: theme.background.tertiary,
padding: "4px 12px",
borderRadius: "6px",
}}
>
{track.duration}
</Text>
<Group gap="xs">
{track.studioUrl && (
<Badge
size="sm"
variant="filled"
style={{
background: theme.badges.studio,
color: theme.text.contrast,
}}
>
Studio
</Badge>
)}
{track.emilyLiveUrl && (
<Badge
size="sm"
variant="filled"
style={{
background: theme.badges.liveEmily,
color: theme.text.contrast,
}}
>
Emily Live
</Badge>
)}
{track.lpLiveUrl && (
<Badge
size="sm"
variant="filled"
style={{
background: theme.badges.liveLP,
color: theme.text.contrast,
}}
>
LP Live
</Badge>
)}
</Group>
</Group>
</Group>
</Card>
);
}

View file

@ -1,8 +1,9 @@
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { Box, Container, Title, Text, Group, Badge, Card, Image, Stack, Grid, GridCol } from "@mantine/core"; import { Box, Container, Title, Text, Image, Stack, Grid, GridCol } from "@mantine/core";
import { albums } from "../../../lib/list"; import { albums } from "../../../lib/list";
import BackButton from "../../../Components/BackButton"; import BackButton from "../../../Components/BackButton";
import { getThemeColors } from "@/lib/themes"; import { getThemeColors } from "@/lib/themes";
import TrackCard from "@/Components/TrackCard";
export function generateStaticParams() { export function generateStaticParams() {
return albums.map((album) => ({ return albums.map((album) => ({
@ -34,95 +35,96 @@ export default async function AlbumDetail({ params }: { params: Promise<{ albumI
notFound(); notFound();
} }
// Theme colors based on album
const theme = getThemeColors(albumId); const theme = getThemeColors(albumId);
return ( return (
<Box className="min-h-screen"> <Box
className="min-h-screen"
style={{
background: theme.background.gradient,
viewTransitionName: `album-card-background-${album.id}`,
}}
>
<Container size="xl" className="py-12"> <Container size="xl" className="py-12">
{/* Back Button */} {/* Back Button */}
<BackButton /> <BackButton theme={theme} />
<Grid columns={5} gutter={"xl"}> <Grid columns={5} gutter={"xl"} className="mb-12">
<GridCol span={"content"}> <GridCol span={"content"}>
<Box
style={{
border: `3px solid ${theme.border.light}`,
borderRadius: "8px",
padding: "4px",
background: theme.background.secondary,
boxShadow: `0 8px 32px ${theme.primary.DEFAULT}40`,
viewTransitionName: `album-card-image-${album.id}`,
}}
>
<Image <Image
src={album.image} src={album.image}
alt={album.label} alt={album.label}
h={200} h={200}
w={200} w={200}
className="aspect-square!" className="aspect-square!"
style={{ viewTransitionName: `album-card-image-${album.id}` }} style={{
borderRadius: "4px",
}}
/> />
</Box>
</GridCol> </GridCol>
<GridCol span={"auto"}> <GridCol span={"auto"}>
<Title <Title
order={1} order={1}
className="text-6xl font-bold text-white" className="mb-3 text-6xl font-bold"
style={{ viewTransitionName: `album-card-title-${album.id}` }} style={{
viewTransitionName: `album-card-title-${album.id}`,
color: theme.text.primary,
textShadow: `0 0 20px ${theme.primary.DEFAULT}80`,
}}
> >
{album.label} {album.label}
</Title> </Title>
<Text size="xl" className="text-gray-400" style={{ viewTransitionName: `album-card-release-date-${album.id}` }}> <Text
Released:{" "} size="xl"
className="mb-4"
style={{
viewTransitionName: `album-card-release-date-${album.id}`,
color: theme.text.secondary,
}}
>
<span style={{ color: theme.accent.DEFAULT, fontWeight: 600 }}>Released: </span>
{new Date(album.releaseDate).toLocaleDateString("en-US", { {new Date(album.releaseDate).toLocaleDateString("en-US", {
year: "numeric", year: "numeric",
month: "long", month: "long",
day: "numeric", day: "numeric",
})} })}
</Text> </Text>
<Text className="text-gray-400">{album.description}</Text> <Text size="md" style={{ color: theme.text.muted, lineHeight: 1.6 }}>
{album.description}
</Text>
</GridCol> </GridCol>
</Grid> </Grid>
{/* Track List */} {/* Track List */}
{album.tracks.length > 0 && ( {album.tracks.length > 0 && (
<Box> <Box>
<Title order={2} className="mb-6 text-3xl font-bold text-white"> <Title
order={2}
className="mb-6 text-3xl font-bold"
style={{
color: theme.text.primary,
borderBottom: `2px solid ${theme.border.light}`,
paddingBottom: "12px",
}}
>
Track List Track List
</Title> </Title>
<Stack gap="sm"> <Stack gap="xs" pt={"md"} pb={50}>
{album.tracks.map((track, index) => ( {album.tracks.map((track, index) => (
<Card <TrackCard key={track.id} track={track} index={index} theme={theme} />
key={track.id}
className="border border-gray-700 bg-gray-800/30 backdrop-blur-sm transition-all duration-200 hover:bg-gray-800/50"
>
<Group justify="space-between" align="center">
<Group gap="md">
<Text size="lg" fw={600} style={{ color: theme.primary }} className="min-w-8">
{index + 1}
</Text>
<Text size="lg" className="text-white">
{track.label}
</Text>
</Group>
<Group gap="md">
<Text size="sm" className="text-gray-400">
{track.duration}
</Text>
<Group gap="xs">
{track.studioUrl && (
<Badge size="sm" color="green" variant="light">
Studio
</Badge>
)}
{track.emilyLiveUrl && (
<Badge size="sm" color="pink" variant="light">
Emily Live
</Badge>
)}
{track.lpLiveUrl && (
<Badge size="sm" color="blue" variant="light">
LP Live
</Badge>
)}
</Group>
</Group>
</Group>
</Card>
))} ))}
</Stack> </Stack>
</Box> </Box>

View file

@ -1,6 +1,6 @@
import "@mantine/core/styles.css"; import "@mantine/core/styles.css";
import "../index.css"; import "../index.css";
import { MantineProvider, ColorSchemeScript } from "@mantine/core"; import { MantineProvider } from "@mantine/core";
import { ViewTransitions } from "next-view-transitions"; import { ViewTransitions } from "next-view-transitions";
import { Nunito } from "next/font/google"; import { Nunito } from "next/font/google";

View file

@ -273,111 +273,135 @@ export const albums: Album[] = [
}, },
], ],
}, },
// { {
// id: "minutes-to-midnight", id: "minutes-to-midnight",
// label: "Minutes to Midnight", label: "Minutes to Midnight",
// releaseDate: "2007-05-14", releaseDate: "2007-05-14",
// image: "/minutes_to_midnight.jpg", image: "/minutes_to_midnight.jpg",
// url: "/minutes-to-midnight", url: "/minutes-to-midnight",
// description: description:
// "Minutes to Midnight is the third studio album by American rock band Linkin Park, released on May 14, 2007, by Warner Bros. Records. The album marked a departure from the band's previous nu-metal sound, incorporating more alternative rock and experimental elements.", "Minutes to Midnight is the third studio album by American rock band Linkin Park, released on May 14, 2007, by Warner Bros. Records. The album marked a departure from the band's previous nu-metal sound, incorporating more alternative rock and experimental elements.",
// tracks: [ tracks: [
// { {
// id: "minutes-to-midnight-1", id: "minutes-to-midnight-1",
// label: "Wake", label: "Wake",
// duration: "01:40", duration: "01:40",
// studioUrl: null, studioUrl: null,
// emilyLiveUrl: null, emilyLiveUrl: null,
// lpLiveUrl: null, lpLiveUrl: null,
// },
// { __SPOTIFY_URL__: "https://open.spotify.com/track/0GkuKdv0osuL9QhfnXqVNP?si=0491e2d35b0a4e12",
// id: "minutes-to-midnight-2", },
// label: "Given Up", {
// duration: "03:09", id: "minutes-to-midnight-2",
// studioUrl: null, label: "Given Up",
// emilyLiveUrl: null, duration: "03:09",
// lpLiveUrl: null, studioUrl: null,
// }, emilyLiveUrl: null,
// { lpLiveUrl: null,
// id: "minutes-to-midnight-3",
// label: "Leave Out All the Rest", __SPOTIFY_URL__: "https://open.spotify.com/track/1fLlRApgzxWweF1JTf8yM5?si=9b22e697bdd640e8",
// duration: "03:29", },
// studioUrl: null, {
// emilyLiveUrl: null, id: "minutes-to-midnight-3",
// lpLiveUrl: null, label: "Leave Out All the Rest",
// }, duration: "03:29",
// { studioUrl: null,
// id: "minutes-to-midnight-4", emilyLiveUrl: null,
// label: "Bleed It Out", lpLiveUrl: null,
// duration: "02:44",
// studioUrl: null, __SPOTIFY_URL__: "https://open.spotify.com/track/0sp00HSXkQyqTa6QqM0O8V?si=c9ad349e7f164919",
// emilyLiveUrl: null, },
// lpLiveUrl: null, {
// }, id: "minutes-to-midnight-4",
// { label: "Bleed It Out",
// id: "minutes-to-midnight-5", duration: "02:44",
// label: "Shadow of the Day", studioUrl: null,
// duration: "04:49", emilyLiveUrl: null,
// studioUrl: null, lpLiveUrl: null,
// emilyLiveUrl: null,
// lpLiveUrl: null, __SPOTIFY_URL__: "https://open.spotify.com/track/0UFDKFqW2oGspYeYqo9wjA?si=2f4e310a85674523",
// }, },
// { {
// id: "minutes-to-midnight-6", id: "minutes-to-midnight-5",
// label: "What I've Done", label: "Shadow of the Day",
// duration: "03:25", duration: "04:49",
// studioUrl: null, studioUrl: null,
// emilyLiveUrl: null, emilyLiveUrl: null,
// lpLiveUrl: null, lpLiveUrl: null,
// },
// { __SPOTIFY_URL__: "https://open.spotify.com/track/0OYcEfskah1egYHjYRvbg1?si=e7fe66722b7544d9",
// id: "minutes-to-midnight-7", },
// label: "Hands Held High", {
// duration: "03:53", id: "minutes-to-midnight-6",
// studioUrl: null, label: "What I've Done",
// emilyLiveUrl: null, duration: "03:25",
// lpLiveUrl: null, studioUrl: null,
// }, emilyLiveUrl: null,
// { lpLiveUrl: null,
// id: "minutes-to-midnight-8",
// label: "No More Sorrow", __SPOTIFY_URL__: "https://open.spotify.com/track/18lR4BzEs7e3qzc0KVkTpU?si=f04a6e933aab4ba0",
// duration: "03:41", },
// studioUrl: null, {
// emilyLiveUrl: null, id: "minutes-to-midnight-7",
// lpLiveUrl: null, label: "Hands Held High",
// }, duration: "03:53",
// { studioUrl: null,
// id: "minutes-to-midnight-9", emilyLiveUrl: null,
// label: "Valentine's Day", lpLiveUrl: null,
// duration: "03:16",
// studioUrl: null, __SPOTIFY_URL__: "https://open.spotify.com/track/0m7mTaFGMiKI3rBJpYknip?si=e382b6252c7c427a",
// emilyLiveUrl: null, },
// lpLiveUrl: null, {
// }, id: "minutes-to-midnight-8",
// { label: "No More Sorrow",
// id: "minutes-to-midnight-10", duration: "03:41",
// label: "In Between", studioUrl: null,
// duration: "03:16", emilyLiveUrl: null,
// studioUrl: null, lpLiveUrl: null,
// emilyLiveUrl: null,
// lpLiveUrl: null, __SPOTIFY_URL__: "https://open.spotify.com/track/4CWhc9FaMMfBTt4ANjfbOf?si=dd3a00c6453c4737",
// }, },
// { {
// id: "minutes-to-midnight-11", id: "minutes-to-midnight-9",
// label: "In Pieces", label: "Valentine's Day",
// duration: "03:38", duration: "03:16",
// studioUrl: null, studioUrl: null,
// emilyLiveUrl: null, emilyLiveUrl: null,
// lpLiveUrl: null, lpLiveUrl: null,
// },
// { __SPOTIFY_URL__: "https://open.spotify.com/track/2vfshZvISOKy2Je7wQBWOV?si=51d75042da314fa4",
// id: "minutes-to-midnight-12", },
// label: "The Little Things Give You Away", {
// duration: "06:23", id: "minutes-to-midnight-10",
// studioUrl: null, label: "In Between",
// emilyLiveUrl: null, duration: "03:16",
// lpLiveUrl: null, studioUrl: null,
// }, emilyLiveUrl: null,
// ], lpLiveUrl: null,
// },
__SPOTIFY_URL__: "https://open.spotify.com/track/2ysXuQd8uOfSMZcMRR5Ux4?si=3ae5e92155874795",
},
{
id: "minutes-to-midnight-11",
label: "In Pieces",
duration: "03:38",
studioUrl: null,
emilyLiveUrl: null,
lpLiveUrl: null,
__SPOTIFY_URL__: "https://open.spotify.com/track/7jeI6EdY0elPSNz80mAKS8?si=983410366a774f68",
},
{
id: "minutes-to-midnight-12",
label: "The Little Things Give You Away",
duration: "06:23",
studioUrl: null,
emilyLiveUrl: null,
lpLiveUrl: null,
__SPOTIFY_URL__: "https://open.spotify.com/track/7jeI6EdY0elPSNz80mAKS8?si=679b76c359004769",
},
],
},
]; ];

View file

@ -1,25 +1,205 @@
export const getThemeColors = (albumId: string) => { export interface AlbumTheme {
// Primary color palette
primary: {
DEFAULT: string;
light: string;
dark: string;
100: string;
500: string;
900: string;
};
// Secondary color palette
secondary: {
DEFAULT: string;
light: string;
dark: string;
};
// Accent colors
accent: {
DEFAULT: string;
light: string;
dark: string;
};
// Background variations
background: {
primary: string;
secondary: string;
tertiary: string;
gradient: string;
};
// Text colors
text: {
primary: string;
secondary: string;
muted: string;
contrast: string;
};
// Border colors
border: {
DEFAULT: string;
light: string;
focus: string;
};
// Badge colors
badges: {
studio: string;
liveEmily: string;
liveLP: string;
};
// Card styling
card: {
background: string;
backgroundHover: string;
border: string;
};
}
const themes: Record<string, AlbumTheme> = {
"hybrid-theory": {
primary: {
DEFAULT: "#47090E",
light: "#95121d",
dark: "#1F0506",
100: "#f6b3b8",
500: "#47090E",
900: "#0f0203",
},
secondary: {
DEFAULT: "#8C786C",
light: "#bbaea7",
dark: "#554841",
},
accent: {
DEFAULT: "#ec6672",
light: "#f6b3b8",
dark: "#95121d",
},
background: {
primary: "#050404",
secondary: "#1F0506",
tertiary: "#3D3D39",
gradient: "linear-gradient(135deg, #050404 0%, #47090E 50%, #1F0506 100%)",
},
text: {
primary: "#e8e4e2",
secondary: "#d2c9c4",
muted: "#a49389",
contrast: "#ffffff",
},
border: {
DEFAULT: "#3D3D39",
light: "#8C786C",
focus: "#47090E",
},
badges: {
studio: "#95121d",
liveEmily: "#ec6672",
liveLP: "#8C786C",
},
card: {
background: "rgba(61, 61, 57, 0.3)",
backgroundHover: "rgba(71, 9, 14, 0.4)",
border: "#3D3D39",
},
},
meteora: {
primary: {
DEFAULT: "#8B7B65",
light: "#9A8B71",
dark: "#55493C",
100: "#ebe8e2",
500: "#8B7B65",
900: "#1c1914",
},
secondary: {
DEFAULT: "#9A8B71",
light: "#c2b9a9",
dark: "#7c6f58",
},
accent: {
DEFAULT: "#bbb0a1",
light: "#d6d0c6",
dark: "#a4917e",
},
background: {
primary: "#241C16",
secondary: "#32271F",
tertiary: "#55493C",
gradient: "linear-gradient(135deg, #241C16 0%, #32271F 50%, #55493C 100%)",
},
text: {
primary: "#e8e5e0",
secondary: "#d2cac0",
muted: "#a49682",
contrast: "#ffffff",
},
border: {
DEFAULT: "#55493C",
light: "#8B7B65",
focus: "#9A8B71",
},
badges: {
studio: "#8B7B65",
liveEmily: "#bbb0a1",
liveLP: "#9A8B71",
},
card: {
background: "rgba(85, 73, 60, 0.3)",
backgroundHover: "rgba(139, 123, 101, 0.4)",
border: "#55493C",
},
},
"minutes-to-midnight": {
primary: {
DEFAULT: "#77716F",
light: "#A09D9C",
dark: "#292527",
100: "#fafafa",
500: "#77716F",
900: "#181716",
},
secondary: {
DEFAULT: "#A09D9C",
light: "#c6c4c4",
dark: "#615e5d",
},
accent: {
DEFAULT: "#928d8b",
light: "#b3b1b0",
dark: "#5f5a59",
},
background: {
primary: "#292527",
secondary: "#2f2d2d",
tertiary: "#474443",
gradient: "linear-gradient(135deg, #292527 0%, #474443 50%, #5f5a59 100%)",
},
text: {
primary: "#F2F1F0",
secondary: "#d9d8d7",
muted: "#b3b1b0",
contrast: "#FEFFFC",
},
border: {
DEFAULT: "#474443",
light: "#77716F",
focus: "#A09D9C",
},
badges: {
studio: "#77716F",
liveEmily: "#928d8b",
liveLP: "#A09D9C",
},
card: {
background: "rgba(71, 68, 67, 0.3)",
backgroundHover: "rgba(119, 113, 111, 0.4)",
border: "#474443",
},
},
};
export const getThemeColors = (albumId: string): AlbumTheme => {
return themes[albumId] || themes["hybrid-theory"]; return themes[albumId] || themes["hybrid-theory"];
}; };
const themes: Record<string, { primary: string; secondary: string; accent: string; bg: string }> = { export type Theme = AlbumTheme;
"hybrid-theory": {
primary: "#ff6b35",
secondary: "#f7931e",
accent: "#ff1744",
bg: "from-orange-900 via-red-900 to-orange-800",
},
meteora: {
primary: "#8b5cf6",
secondary: "#a855f7",
accent: "#ec4899",
bg: "from-purple-900 via-pink-900 to-purple-800",
},
"minutes-to-midnight": {
primary: "#1e40af",
secondary: "#3b82f6",
accent: "#06b6d4",
bg: "from-slate-900 via-blue-900 to-slate-800",
},
};
export type Theme = (typeof themes)["hybrid-theory"];