diff --git a/pics/515AxpWj0QL._UF894,1000_QL80_.jpg b/pics/515AxpWj0QL._UF894,1000_QL80_.jpg new file mode 100644 index 0000000..977b5c6 Binary files /dev/null and b/pics/515AxpWj0QL._UF894,1000_QL80_.jpg differ diff --git a/pics/81GU366NSiL._UF1000,1000_QL80_.jpg b/pics/81GU366NSiL._UF1000,1000_QL80_.jpg new file mode 100644 index 0000000..1f72963 Binary files /dev/null and b/pics/81GU366NSiL._UF1000,1000_QL80_.jpg differ diff --git a/pics/ab67616d0000b27302c1331a8a44330610dd4cbe.jpeg b/pics/ab67616d0000b27302c1331a8a44330610dd4cbe.jpeg new file mode 100644 index 0000000..f16276f Binary files /dev/null and b/pics/ab67616d0000b27302c1331a8a44330610dd4cbe.jpeg differ diff --git a/pics/ab67616d0000b2731df28c6164bc1bf01e304daa.jpeg b/pics/ab67616d0000b2731df28c6164bc1bf01e304daa.jpeg new file mode 100644 index 0000000..6d7c4f0 Binary files /dev/null and b/pics/ab67616d0000b2731df28c6164bc1bf01e304daa.jpeg differ diff --git a/pics/ab67616d0000b27364ba6b515bb7a9c2a0de8f90.jpeg b/pics/ab67616d0000b27364ba6b515bb7a9c2a0de8f90.jpeg new file mode 100644 index 0000000..8db6973 Binary files /dev/null and b/pics/ab67616d0000b27364ba6b515bb7a9c2a0de8f90.jpeg differ diff --git a/pics/ab67616d0000b273bc6b0bc222552902755ee599.jpeg b/pics/ab67616d0000b273bc6b0bc222552902755ee599.jpeg new file mode 100644 index 0000000..862c09e Binary files /dev/null and b/pics/ab67616d0000b273bc6b0bc222552902755ee599.jpeg differ diff --git a/pics/ab67616d0000b273d2675cb6847d1b1da9fc28a3.jpeg b/pics/ab67616d0000b273d2675cb6847d1b1da9fc28a3.jpeg new file mode 100644 index 0000000..4bb5d5e Binary files /dev/null and b/pics/ab67616d0000b273d2675cb6847d1b1da9fc28a3.jpeg differ diff --git a/src/App.css b/src/App.css index 393b616..a9848f4 100644 --- a/src/App.css +++ b/src/App.css @@ -6,7 +6,17 @@ } .app-header { - margin-bottom: 24px; + background-color: #fce4ec; + padding: 24px; + text-align: center; + margin: -24px -24px 24px -24px; +} + +.app-header h1 { + color: #c2185b; + font-family: Georgia, serif; + font-size: 32px; + margin: 0; } .app-content { @@ -27,6 +37,116 @@ min-width: 0; } +.song-controls { + display: flex; + gap: 12px; + margin-bottom: 24px; +} + +.sidebar button, +.sidebar select { + background-color: #fce4ec; + width: 100%; + padding: 8px 12px; + border: none; + cursor: pointer; + transition: background-color 0.2s; + display: inline-flex; + align-items: center; +} + +.sidebar button:hover { + background-color: #f48fb1; +} + +.sidebar button:active { + background-color: #f48fb1; +} + +.sidebar button.active { + background-color: #f48fb1; +} + +.sidebar ul { + list-style: none; + padding: 0; +} + +.sidebar li { + margin-bottom: 8px; +} + +.sidebar > section > div { + margin-bottom: 16px; +} + +.song-controls { + align-items: center; +} + +.song-controls button { + padding: 8px 12px; + border: none; + cursor: pointer; + transition: background-color 0.2s; + display: inline-flex; + align-items: center; +} + +.song-controls nav { + display: flex; + gap: 12px; +} + +.song-controls nav button { + background-color: #e0e0e0; + padding: 8px 16px; +} + +.song-controls nav button:hover { + background-color: #b3b3b3; +} + +.song-controls nav button:active { + background-color: #b3b3b3; +} + +.song-controls nav button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.song-lyrics-wrapper { + margin-top: 16px; +} + +.song-lyrics { + margin: 0; +} + +.song-lyrics-stanza { + margin: 0 0 1.5em; +} + +.song-lyrics-stanza:last-child { + margin-bottom: 0; +} + +.song-lyrics-line { + display: block; +} + +.song-album-art { + margin-top: 24px; +} + +.song-album-art img { + display: block; + width: min(100%, 320px); + height: auto; + border-radius: 4px; +} + @media (max-width: 768px) { .app { padding: 16px; diff --git a/src/App.tsx b/src/App.tsx index be860e4..b2f86a7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -51,21 +51,22 @@ function App() {
- handleToggleFavorites(currentSong.id)}/> +
+ handleToggleFavorites(currentSong.id)}/> + setCurrentSongIndex(currentSongIndex - 1)} + onNext={() => setCurrentSongIndex(currentSongIndex + 1)} + /> +
- setCurrentSongIndex(currentSongIndex - 1)} - onNext={() => setCurrentSongIndex(currentSongIndex + 1)} - /> -
diff --git a/src/components/LyricsDisplay.tsx b/src/components/LyricsDisplay.tsx new file mode 100644 index 0000000..2a3964d --- /dev/null +++ b/src/components/LyricsDisplay.tsx @@ -0,0 +1,27 @@ +import { parseLyrics } from '../utils/formatLyrics' + +type LyricsDisplayProps = { + lyrics: string +} + +export function LyricsDisplay({ lyrics }: LyricsDisplayProps) { + const stanzas = parseLyrics(lyrics) + + if (!stanzas.length) { + return null + } + + return ( +
+ {stanzas.map((stanza, stanzaIndex) => ( +

+ {stanza.lines.map((line, lineIndex) => ( + + {line} + + ))} +

+ ))} +
+ ) +} diff --git a/src/components/SongCard.tsx b/src/components/SongCard.tsx index 2db4850..a3797d5 100644 --- a/src/components/SongCard.tsx +++ b/src/components/SongCard.tsx @@ -1,5 +1,7 @@ import type { Song } from '../data/songs' +import { getAlbumImage } from '../data/albumImages' import { useLyrics } from '../hooks/useLyrics' +import { LyricsDisplay } from './LyricsDisplay' type SongCardProps = { song: Song @@ -8,20 +10,29 @@ type SongCardProps = { export function SongCard({ song }: SongCardProps) { const { data, isLoading, error } = useLyrics(song.artist, song.title) - + const albumImage = getAlbumImage(song.album) + return (

{song.title}

-

{song.artist}

-

{song.album}

+

Artist: {song.artist}

+

Album: {song.album}

-
-

{isLoading ? 'Laster…' : error || data?.error ? 'Fant ingen sangtekst for denne sangen' : data?.lyrics}

+
+ {isLoading ? ( +

Laster…

+ ) : error || data?.error ? ( +

Fant ingen sangtekst for denne sangen

+ ) : data?.lyrics ? ( + + ) : null}
-
-

Bilde vises her

-
+ {albumImage && ( +
+ {`Albumomslag: +
+ )}
) diff --git a/src/components/SongList.tsx b/src/components/SongList.tsx index fbfb0b3..8c7d071 100644 --- a/src/components/SongList.tsx +++ b/src/components/SongList.tsx @@ -3,9 +3,10 @@ import type { Song } from '../data/songs' type SongListProps = { songs: Song[] onSelectSong: (song: Song) => void + currentSong: Song } -export function SongList({songs, onSelectSong}: SongListProps) { +export function SongList({songs, onSelectSong, currentSong}: SongListProps) { return (

@@ -15,7 +16,7 @@ export function SongList({songs, onSelectSong}: SongListProps) {