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
95 changes: 69 additions & 26 deletions webdev-prosjekt1/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,43 @@ body {
display: flex;
gap: 10px;

width: calc(100% - 96px);
max-width: 1400px;
width: 100%;
max-width: 1020px;

margin: 14px auto 0;
margin-left: 64px;
margin-right: 64px;
padding: 0 24px;
}

@media (max-width: 700px) {
.main-header {
padding: 16px 24px 12px;
}

.app-title-text {
font-size: 40px;
}

.search-section {
max-width: 100%;
padding: 0 12px;
}

.hero-section {
width: calc(100% - 48px);
}

.hero-art {
width: 320px;
min-height: 380px;
}

.hero-art img {
max-width: 290px;
}

.art-glow {
width: 230px;
}
}

.hero-section {
Expand Down Expand Up @@ -135,34 +166,46 @@ body {
filter: blur(45px);
}

.card-list {
width: 100%;
list-style: none;
padding: 0;
margin: 0;

@media (max-width: 700px) {
.main-header {
padding: 16px 24px 12px;
}
display: flex;
flex-direction: column;
gap: 12px;
}

.app-title-text {
font-size: 40px;
}
.results-section {
max-width: 1400px;
width: calc(100% - 96px);

.search-controls {
width: calc(100% - 48px);
}
margin: 20px auto 0;
padding: 0 0 60px;

.hero-section {
width: calc(100% - 48px);
}
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
align-items: start;
}

.hero-art {
width: 320px;
min-height: 380px;
@media (max-width: 900px) {
.results-section {
grid-template-columns: 1fr;
width: calc(100% - 48px);
}
}

.hero-art img {
max-width: 290px;
}
.results-group {
display: flex;
flex-direction: column;
gap: 14px;
}

.art-glow {
width: 230px;
}
.results-heading {
margin: 0;
color: var(--primary_color);
font-size: 1.4rem;
letter-spacing: 0.04em;
}
49 changes: 42 additions & 7 deletions webdev-prosjekt1/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { useState } from 'react';
import './App.css';
import './variables.css';
import { Button } from './components/Button';
import { Searchbar } from './components/Searchbar';
import { TrackCard } from './components/TrackCard';
import { AlbumCard } from './components/AlbumCard';
import { ArtistCard } from './components/ArtistCard';
import filterIcon from './assets/filter.png';
import musicWizImage from './assets/musicwiz.png';
import logoImage from './assets/music-wiz-logo.png';
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { search } from './api/spotify';

function App() {
const [query, setQuery] = useState('');
const hasSearched = query.trim().length > 0;

const handleSearch = (nextQuery: string) => {
setQuery(nextQuery);
Expand Down Expand Up @@ -54,12 +58,43 @@ function App() {
<Button content={<><img src={filterIcon} alt='' /> <span>Filter</span></>} />
</section>

<section className='hero-section'>
<figure className='hero-art'>
<div className='art-glow' />
<img src={musicWizImage} alt='A musical wizard' />
</figure>
</section>
{hasSearched ? (
<section className='results-section'>
<div className='results-group'>
<h2 className='results-heading'>Tracks</h2>
<ul className='card-list'>
{results?.tracks.map((track) => (
<TrackCard key={track.id} track={track} />
))}
</ul>
</div>

<div className='results-group'>
<h2 className='results-heading'>Albums</h2>
<ul className='card-list'>
{results?.albums.map((album) => (
<AlbumCard key={album.id} album={album} />
))}
</ul>
</div>

<div className='results-group'>
<h2 className='results-heading'>Artists</h2>
<ul className='card-list'>
{results?.artists.map((artist) => (
<ArtistCard key={artist.id} artist={artist} />
))}
</ul>
</div>
</section>
) : (
<section className='hero-section'>
<figure className='hero-art'>
<div className='art-glow' />
<img src={musicWizImage} alt='A musical wizard' />
</figure>
</section>
)}
</main>
</>
);
Expand Down
31 changes: 31 additions & 0 deletions webdev-prosjekt1/src/components/AlbumCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import './TrackCard.css';
import type { Album } from '../api/types';
import musicwizimage from '../assets/musicwiz.png';

type AlbumCardProps = {
album: Album;
}

export const AlbumCard = ({ album }: AlbumCardProps) => {
const image = album.images[0]?.url ?? musicwizimage;
const artistNames = album.artists.map((artist) => artist.name).join(', ');
const year = album.release_date.slice(0, 4);

return (
<li className="search-result-card">
<div className='card-image-wrapper'>
<img src={image} alt="" className='card-image'/>
</div>

<div className='card-info-container'>
<div className='title-and-artist'>
<h3 className='card-header'>{album.name}</h3>
<span className='artist-name'>{artistNames}</span>
</div>
<div className='duration-display-container'>
<span className='duration-display'>{year}</span>
</div>
</div>
</li>
)
}
3 changes: 3 additions & 0 deletions webdev-prosjekt1/src/components/ArtistCard.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.artist-image-wrapper {
border-radius: 50%;
}
27 changes: 27 additions & 0 deletions webdev-prosjekt1/src/components/ArtistCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import './TrackCard.css';
import './ArtistCard.css';
import type { Artist } from '../api/types';
import musicwizimage from '../assets/musicwiz.png';

type ArtistCardProps = {
artist: Artist;
}

export const ArtistCard = ({ artist }: ArtistCardProps) => {
const image = artist.images[0]?.url ?? musicwizimage;

return (
<li className="search-result-card artist-card">
<div className='card-image-wrapper artist-image-wrapper'>
<img src={image} alt="" className='card-image'/>
</div>

<div className='card-info-container'>
<div className='title-and-artist'>
<h3 className='card-header'>{artist.name}</h3>
<span className='artist-name'>Artist</span>
</div>
</div>
</li>
)
}
5 changes: 5 additions & 0 deletions webdev-prosjekt1/src/components/Card.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.search-result-card {
background-color: aliceblue;
display: grid;
grid-template-columns: 1fr 2fr;
}
14 changes: 14 additions & 0 deletions webdev-prosjekt1/src/components/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import './Card.css';
import type { ReactNode } from "react";

type CardContent = {
content: ReactNode;
}

export const Card = ({ content }: CardContent) => {
return (
<li className="search-result-card">
{content}
</li>
)
}
57 changes: 57 additions & 0 deletions webdev-prosjekt1/src/components/TrackCard.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
.search-result-card {
display: flex;
padding: 0.3rem;

width: 100%;

border-radius: 0.5rem;

background-color: rgb(43, 43, 43);
}

.card-image {
aspect-ratio: 1 / 1;
width: 100%;
height: 100%;
}

.card-image-wrapper {
max-width: 60px;
border-radius: 0.5rem;
overflow: hidden;
}

.card-info-container {
display: flex;
justify-content: space-between;
width: 100%;

padding: 0.3rem 1rem;
}

.title-and-artist {
display: flex;
flex-direction: column;
justify-content: center;

gap: 0.7rem;
}

.card-header {
width: 100%;
margin: 0;

font-size: 1rem;
}

.artist-name {
width: 100%;

font-size: 0.8rem;
}

.duration-display-container {
display: flex;
align-items: center;
justify-content: center;
}
37 changes: 37 additions & 0 deletions webdev-prosjekt1/src/components/TrackCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import './TrackCard.css';
import type { Track } from '../api/types';
import musicwizimage from '../assets/musicwiz.png';

type TrackCardProps = {
track: Track;
}

const formatDuration = (durationMs: number) => {
const totalSeconds = Math.round(durationMs / 1000);
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
}

export const TrackCard = ({ track }: TrackCardProps) => {
const image = track.album.images[0]?.url ?? musicwizimage;
const artistNames = track.artists.map((artist) => artist.name).join(', ');

return (
<li className="search-result-card">
<div className='card-image-wrapper'>
<img src={image} alt="" className='card-image'/>
</div>

<div className='card-info-container'>
<div className='title-and-artist'>
<h3 className='card-header'>{track.name}</h3>
<span className='artist-name'>{artistNames}</span>
</div>
<div className='duration-display-container'>
<span className='duration-display'>{formatDuration(track.duration_ms)}</span>
</div>
</div>
</li>
)
}