Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 3 additions & 113 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@
background: #310E10;
}

/* Album grid */
/* Album section and result count */
.album-section {
min-width: 0;
}
Expand All @@ -235,107 +235,7 @@
text-align: right;
}

.album-displayer {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 24px 18px;
}

.filters-hidden .album-displayer {
grid-template-columns: repeat(4, minmax(0, 1fr));
}

.album-card {
min-width: 0;
overflow: hidden;
color: #310E10;
text-decoration: none;
transition: transform 0.2s ease;
}

.album-card:hover {
transform: translateY(-4px);
}

.album-image {
display: block;
width: 100%;
aspect-ratio: 1 / 1;
object-fit: cover;
border: 1px solid #947268;
background: #947268;
}

.album-placeholder {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
padding: 18px;
background: #74070E;
color: #F4E3B2;
}

.album-card:nth-child(2n) .album-placeholder {
background: #45462A;
}

.album-card:nth-child(3n) .album-placeholder {
background: #947268;
color: #310E10;
}

.placeholder-mark {
font-family: 'Clash Display', sans-serif;
font-size: 2.8rem;
font-weight: 600;
}

.placeholder-title {
max-width: 100%;
font-family: 'Clash Display', sans-serif;
font-size: clamp(1.1rem, 1.7vw, 1.8rem);
font-weight: 600;
overflow-wrap: anywhere;
}

.album-card-info {
padding: 12px 2px 0;
}

.album-card-info h2 {
margin: 0 0 5px;
font-family: 'Clash Display', sans-serif;
font-size: 1.15rem;
line-height: 1.2;
}

.album-artist {
margin: 0 0 10px;
color: #45462A;
font-size: 0.9rem;
}

.album-meta {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 6px;
color: #45462A;
font-size: 0.75rem;
}

/* Empty state and pagination */
.empty-state {
padding: 48px 20px;
border: 1px dashed #947268;
text-align: center;
}

.empty-state h2 {
font-family: 'Clash Display', sans-serif;
}

/* Pagination */
.pagination {
display: flex;
justify-content: center;
Expand All @@ -350,6 +250,7 @@
border-radius: 2px;
background: transparent;
color: #74070E;
cursor: pointer;
}

.pagination button:disabled {
Expand All @@ -367,11 +268,6 @@
grid-template-columns: 200px minmax(0, 1fr);
gap: 20px;
}

.album-displayer,
.filters-hidden .album-displayer {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}

@media (max-width: 650px) {
Expand Down Expand Up @@ -400,12 +296,6 @@
grid-template-columns: minmax(0, 1fr);
}

.album-displayer,
.filters-hidden .album-displayer {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 20px 12px;
}

.results-heading span {
display: none;
}
Expand Down
102 changes: 102 additions & 0 deletions src/components/AlbumCard/AlbumCard.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@

/* Individual album card */

.album-card {
display: block;
min-width: 0;
overflow: hidden;
border: 1px solid #947268;
border-radius: 3px;
padding: 12px;
background: #fff4d5;
color: #310E10;
text-decoration: none;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.album-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgb(49 14 16 / 15%);
}

.album-card:focus-visible {
outline: 2px solid #74070E;
outline-offset: 4px;
}

.album-card:hover {
transform: translateY(-4px);
}

.album-card:focus-visible {
outline: 2px solid #74070E;
outline-offset: 4px;
}

.album-image {
display: block;
width: 100%;
aspect-ratio: 1 / 1;
object-fit: cover;
border: 1px solid #947268;
background: #947268;
}

.album-placeholder {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
padding: 18px;
background: #74070E;
color: #F4E3B2;
}

.album-card:nth-child(2n) .album-placeholder {
background: #45462A;
}

.album-card:nth-child(3n) .album-placeholder {
background: #947268;
color: #310E10;
}

.placeholder-mark {
font-family: 'Clash Display', sans-serif;
font-size: 2.8rem;
font-weight: 600;
}

.placeholder-title {
max-width: 100%;
font-family: 'Clash Display', sans-serif;
font-size: clamp(1.1rem, 1.7vw, 1.8rem);
font-weight: 600;
overflow-wrap: anywhere;
}

.album-card-info {
padding: 12px 2px 0;
}

.album-card-info h2 {
margin: 0 0 5px;
font-family: 'Clash Display', sans-serif;
font-size: 1.15rem;
line-height: 1.2;
}

.album-artist {
margin: 0 0 10px;
color: #45462A;
font-size: 0.9rem;
}

.album-meta {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 6px;
color: #45462A;
font-size: 0.75rem;
}
41 changes: 41 additions & 0 deletions src/components/AlbumCard/AlbumCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Link } from 'react-router-dom'
import type { Album } from '../../types/album'
import './AlbumCard.css'

interface AlbumCardProps {
album: Album
}

function AlbumCard({ album }: AlbumCardProps) {
return (
<Link
to={`/album/${album.id}`}
className="album-card"
key={album.id}
>
{album.coverUrl ? (
<img
className="album-image"
src={album.coverUrl}
alt={`${album.title} album cover`}
/>
) : (
<div className="album-image album-placeholder">
<span className="placeholder-mark">C.</span>
<span className="placeholder-title">{album.title}</span>
</div>
)}

<div className="album-card-info">
<h2>{album.title}</h2>
<p className="album-artist">{album.artist}</p>
<div className="album-meta">
<span>{album.releaseYear}</span>
<span>{album.genre.join(' / ')}</span>
</div>
</div>
</Link>
)
}

export default AlbumCard
39 changes: 39 additions & 0 deletions src/components/AlbumList/AlbumList.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

/* Album grid */
.album-displayer {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 24px 18px;
}

/* More space when filters are hidden */
.filters-hidden .album-displayer {
grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* Empty search results */
.empty-state {
padding: 48px 20px;
border: 1px dashed #947268;
text-align: center;
}

.empty-state h2 {
font-family: 'Clash Display', sans-serif;
}

/* Smaller screens */
@media (max-width: 1050px) {
.album-displayer,
.filters-hidden .album-displayer {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}

@media (max-width: 650px) {
.album-displayer,
.filters-hidden .album-displayer {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 20px 12px;
}
}
29 changes: 29 additions & 0 deletions src/components/AlbumList/AlbumList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

import type { Album } from '../../types/album'
import AlbumCard from '../AlbumCard/AlbumCard'
import './AlbumList.css'

interface AlbumListProps {
albums: Album[]
}

function AlbumList({ albums }: AlbumListProps) {
if (albums.length === 0) {
return (
<div className="empty-state">
<h2>No albums found</h2>
<p>Try another search or clear your filters.</p>
</div>
)
}

return (
<div className="album-displayer">
{albums.map((album) => (
<AlbumCard key={album.id} album={album} />
))}
</div>
)
}

export default AlbumList
Loading