Refactor TrackCard and TrackModal components for improved functionality and styling

- Replaced hash-based modal opening in TrackCard with state management for better control.
- Integrated TrackModal into TrackCard, allowing for direct interaction and improved user experience.
- Updated TrackModal to accept props for track data and theme, enhancing its reusability.
- Refined styling in both components to maintain visual consistency with dynamic theming.
This commit is contained in:
m4x809 2025-10-25 03:26:25 +02:00
parent b93b0c2160
commit 9fad47fc65
Signed by: m4x809
SSH key fingerprint: SHA256:YCoFF78p2DUP94EnCScqLwldjkKDwdKSZq3r8p/6EiU
4 changed files with 155 additions and 161 deletions

View file

@ -4,7 +4,7 @@ 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";
import { useHash } from "@mantine/hooks";
import TrackModal from "./TrackModal";
interface TrackCardProps {
track: Track;
@ -14,11 +14,12 @@ interface TrackCardProps {
export default function TrackCard({ track, index, theme }: TrackCardProps) {
const [isHovered, setIsHovered] = useState(false);
const [_hash, setHash] = useHash();
const [modalOpened, setModalOpened] = useState(false);
return (
<>
<Card
onClick={() => setHash(`trackModal_${track.id}`)}
onClick={() => setModalOpened(true)}
className="backdrop-blur-sm transition-all duration-300"
style={{
background: isHovered ? theme.card.backgroundHover : theme.card.background,
@ -109,5 +110,7 @@ export default function TrackCard({ track, index, theme }: TrackCardProps) {
</Group>
</Group>
</Card>
<TrackModal opened={modalOpened} onClose={() => setModalOpened(false)} track={track} theme={theme} />
</>
);
}

View file

@ -1,72 +1,53 @@
"use client";
import { albums } from "@/lib/list";
import { getSongLink } from "@/lib/songLinks";
import { getThemeColors } from "@/lib/themes";
import { faApple, faSpotify, faYoutube, faYoutubeSquare, IconDefinition } from "@fortawesome/free-brands-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import type { AlbumTheme } from "@/lib/themes";
import type { Track } from "@/lib/ListTypes";
import {
ActionIcon,
Anchor,
Box,
Divider,
Grid,
GridCol,
Group,
Modal,
Stack,
Text,
Title,
Tooltip,
} from "@mantine/core";
import { useDisclosure, useHash } from "@mantine/hooks";
faApple,
faSpotify,
faYoutube,
faYoutubeSquare,
type IconDefinition,
} from "@fortawesome/free-brands-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { ActionIcon, Box, Divider, Grid, GridCol, Group, Modal, Stack, Text, Title, Tooltip } from "@mantine/core";
import Link from "next/link";
export default function TrackModal() {
const [hash, setHash] = useHash();
console.log("🚀 ~ TrackModal.tsx:8 ~ TrackModal ~ hash:", hash);
const close = () => {
setHash("");
};
interface TrackModalProps {
opened: boolean;
onClose: () => void;
track: Track;
theme: AlbumTheme;
}
const album = albums.find((album) => {
return album.id === hash.split("_")[1];
});
const track = album?.tracks.find((track) => {
return track.id === `${hash.split("_")[1]}_${hash.split("_")[2]}`;
});
const songLink = getSongLink(track?.id || "");
console.log("🚀 ~ TrackModal.tsx:25 ~ TrackModal ~ songLink:", songLink);
const theme = getThemeColors(album?.id || "");
export default function TrackModal({ opened, onClose, track, theme }: TrackModalProps) {
const songLink = getSongLink(track.id);
return (
<Modal
opened={hash.startsWith("#trackModal_")}
onClose={close}
centered
opened={opened}
onClose={onClose}
withCloseButton={false}
transitionProps={{ duration: 150, transition: "fade" }}
styles={{
// content: {
// background: theme.background.gradient,
// border: `2px solid ${theme.border.light}`,
// boxShadow: "none",
// },
// header: {
// background: theme.background.gradient,
// border: `2px solid ${theme.border.light}`,
// boxShadow: "none",
// },
body: {
background: theme.background.gradient,
// border: `2px solid ${theme.border.light}`,
boxShadow: "none",
},
}}
>
<Stack>
<Title order={1}>{track?.label}</Title>
<Divider size={"lg"} label={<Title order={3}>Studio Version</Title>} />
<Title order={1}>{track.label}</Title>
<Divider
color={theme.accent.DEFAULT}
size={"lg"}
label={
<Title c={theme.accent.DEFAULT} order={3}>
Studio Version
</Title>
}
/>
<Grid columns={songLink && Object.keys(songLink).length > 0 ? Object.keys(songLink).length : 4}>
{songLink &&
Object.entries(songLink).map(([key, value]) => {
@ -113,11 +94,12 @@ export default function TrackModal() {
return (
<GridCol
span={1}
key={`${track?.id}_${key}`}
key={`${track.id}_${key}`}
style={{ display: "flex", alignItems: "center", justifyContent: "center" }}
>
<Tooltip label={themeColor.tooltip}>
<ActionIcon
tabIndex={-1}
variant="filled"
color={themeColor.color}
size="lg"
@ -133,11 +115,19 @@ export default function TrackModal() {
);
})}
</Grid>
{Array.isArray(track?.emilyLive) && (
{Array.isArray(track.emilyLive) && (
<>
<Divider size={"lg"} label={<Title order={3}>Fan Live Versions</Title>} />
<Divider
color={theme.accent.DEFAULT}
size={"lg"}
label={
<Title c={theme.accent.DEFAULT} order={3}>
Fan Live Versions
</Title>
}
/>
<Stack>
{track.emilyLive.map((live, idx) => (
{track.emilyLive.map((live) => (
<Box style={{ width: "100%" }} key={`emilyLive_${live.url}`}>
<Group justify="space-between" align="center">
<Box style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
@ -148,6 +138,7 @@ export default function TrackModal() {
</Text>
</Box>
<ActionIcon
tabIndex={-1}
variant="filled"
color={"#FF0000"}
size="lg"
@ -165,26 +156,35 @@ export default function TrackModal() {
</>
)}
{track?.lpLive && (
{track.lpLive && (
<>
<Divider size={"lg"} label={<Title order={3}>Linkin Park Live Versions</Title>} />
<Divider
color={theme.accent.DEFAULT}
size={"lg"}
label={
<Title c={theme.accent.DEFAULT} order={3}>
Linkin Park Live Versions
</Title>
}
/>
<Group justify="space-between" align="center">
<Box style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
<Text>
{new Date(track?.lpLive.date).toLocaleDateString("en-US", {
{new Date(track.lpLive.date).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
})}
</Text>
<Text>{track?.lpLive.location}</Text>
<Text>{track.lpLive.location}</Text>
</Box>
<ActionIcon
tabIndex={-1}
variant="filled"
color={"#FF0000"}
size="lg"
component={Link}
href={track?.lpLive.url}
href={track.lpLive.url}
target="_blank"
rel="noopener noreferrer"
>

View file

@ -4,7 +4,6 @@ import { albums } from "../../../lib/list";
import BackButton from "../../../Components/BackButton";
import { getThemeColors } from "@/lib/themes";
import TrackCard from "@/Components/TrackCard";
import TrackModal from "@/Components/TrackModal";
export function generateStaticParams() {
return albums.map((album) => ({
@ -46,7 +45,6 @@ export default async function AlbumDetail({ params }: { params: Promise<{ albumI
viewTransitionName: `album-card-background-${album.id}`,
}}
>
<TrackModal />
<Container size="xl" className="py-12">
{/* Back Button */}
<BackButton theme={theme} />
@ -57,7 +55,6 @@ export default async function AlbumDetail({ params }: { params: Promise<{ albumI
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}`,

View file

@ -22,12 +22,6 @@ export const albums: Album[] = [
location: "Austin, Texas, USA",
author: "Erynn Halvorson",
},
{
url: "https://youtu.be/miQ9Y5UW08dasdasdg",
date: "2025-04-26",
location: "Austin, Texas, USdasdsaA",
author: "Erynn Halvorson",
},
],
lpLive: {
url: "https://www.youtube.com/watch?v=DOKcCl6iKaA",