mymusics

retro MySpace-style music player
Log | Files | Refs | README

commit e0949777fb94e0d6b3f232182c4e0f51ec350fb4
parent 210ba5cbd5ee59aba77c2fa6a3ee74b25d67cb0e
Author: Pablo Murad <pblmrd@gmail.com>
Date:   Wed, 20 May 2026 21:30:21 -0300

getting better

Diffstat:
Msrc/App.css | 97++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/components/EmbedSnippet.tsx | 11+++++++++--
Msrc/components/TrackSearch.tsx | 2+-
Msrc/pages/Home.tsx | 46++++++++++++++++++++++++----------------------
4 files changed, 123 insertions(+), 33 deletions(-)

diff --git a/src/App.css b/src/App.css @@ -1,5 +1,5 @@ .page { - max-width: 880px; + max-width: 960px; margin: 0 auto; padding: 2rem 1.25rem 4rem; } @@ -46,13 +46,57 @@ .main { display: grid; - gap: 1.5rem; + gap: 1.25rem; +} + +.main-home { + gap: 1.25rem; +} + +.main-sidebar { + display: flex; + flex-direction: column; + gap: 1.25rem; + min-width: 0; } @media (min-width: 720px) { - .main { - grid-template-columns: 1fr 1fr; - align-items: start; + .main-home { + grid-template-columns: minmax(0, 1fr) minmax(0, 1.12fr); + grid-template-areas: + "sidebar player" + "embed embed"; + align-items: stretch; + gap: 1.25rem 1.5rem; + } + + .main-sidebar { + grid-area: sidebar; + min-height: 100%; + } + + .main-home .now-playing { + grid-area: player; + display: flex; + flex-direction: column; + } + + .main-home .main-embed { + grid-area: embed; + } + + .main-home .history { + flex: 1; + display: flex; + flex-direction: column; + min-height: 12rem; + } + + .main-home .history-list { + flex: 1; + max-height: none; + min-height: 6rem; + overflow-y: auto; } } @@ -390,10 +434,14 @@ .history-list { margin: 0; padding-left: 1.1rem; - max-height: 22rem; + max-height: 14rem; overflow: auto; } +.main-home .history h2 { + margin-bottom: 0.75rem; +} + .history-list li { margin-bottom: 0.45rem; font-size: 0.92rem; @@ -455,10 +503,14 @@ } .footer { - margin-top: 2.5rem; + margin-top: 1.75rem; text-align: center; } +.page:has(.main-home) .footer { + margin-top: 1.5rem; +} + .footer code { font-size: 0.85em; color: color-mix(in srgb, var(--accent-cyan) 78%, var(--accent) 22%); @@ -644,6 +696,13 @@ padding: 1.25rem 1.25rem 1.5rem; } +.main-home .main-embed.embed-snippet { + max-width: none; + width: 100%; + margin: 0.25rem 0 0; + padding: 1.15rem 1.25rem 1.35rem; +} + .page-about .embed-snippet { margin-top: 1.75rem; } @@ -675,6 +734,12 @@ border-radius: 10px; resize: vertical; min-height: 8rem; + max-height: 10rem; + box-sizing: border-box; +} + +.main-home .embed-snippet-code { + max-height: 7.5rem; } .embed-snippet-copy { @@ -718,7 +783,11 @@ } .track-search { - margin-bottom: 1rem; + margin-bottom: 0; +} + +.card--search { + flex-shrink: 0; } .track-search-input { @@ -769,6 +838,18 @@ margin-bottom: 0.75rem; } +@media (min-width: 600px) { + .embed-snippet-options { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.5rem 1rem; + } + + .embed-snippet-start { + grid-column: 1 / -1; + } +} + .embed-snippet-start { display: flex; flex-direction: column; diff --git a/src/components/EmbedSnippet.tsx b/src/components/EmbedSnippet.tsx @@ -26,7 +26,11 @@ function buildIframeSnippet(opts: { ></iframe>`; } -export function EmbedSnippet() { +type Props = { + className?: string; +}; + +export function EmbedSnippet({ className }: Props = {}) { const [copied, setCopied] = useState(false); const [autoplay, setAutoplay] = useState(true); const [compact, setCompact] = useState(false); @@ -63,7 +67,10 @@ export function EmbedSnippet() { }, [code]); return ( - <section className="embed-snippet card" aria-label="Embed this player"> + <section + className={["embed-snippet", "card", className].filter(Boolean).join(" ")} + aria-label="Embed this player" + > <h2 className="embed-snippet-title">Embed on your site</h2> <p className="embed-snippet-lead muted"> Paste this HTML wherever you want the player. Optional query params:{" "} diff --git a/src/components/TrackSearch.tsx b/src/components/TrackSearch.tsx @@ -49,7 +49,7 @@ export function TrackSearch({ onSelect, disabled }: Props) { ); return ( - <section className="track-search card" aria-label="Search tracks"> + <section className="track-search card card--search" aria-label="Search tracks"> <h2>Search</h2> <input type="search" diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx @@ -69,8 +69,29 @@ export default function Home() { ) : null} <SiteHeader nav="home" /> - <main className="main"> - <TrackSearch onSelect={(id) => void loadTrackById(id)} disabled={!!healthWarn} /> + <main className="main main-home"> + <div className="main-sidebar"> + <TrackSearch onSelect={(id) => void loadTrackById(id)} disabled={!!healthWarn} /> + + <aside className="card history" aria-label="Recently played"> + <h2>History</h2> + <ol className="history-list"> + {history.map((t, idx) => ( + <li key={`${t.id}-${idx}-${t.title}`}> + <button + type="button" + className="history-hit" + onClick={() => void loadTrackById(t.id)} + > + <span className="h-artist">{t.artist}</span> + <span className="sep">—</span> + <span className="h-title">{t.title}</span> + </button> + </li> + ))} + </ol> + </aside> + </div> <article className="card now-playing"> <header className="card-head"> @@ -148,28 +169,9 @@ export default function Home() { <PlayerAttribution /> </article> - <aside className="card history" aria-label="Recently played"> - <h2>History</h2> - <ol className="history-list"> - {history.map((t, idx) => ( - <li key={`${t.id}-${idx}-${t.title}`}> - <button - type="button" - className="history-hit" - onClick={() => void loadTrackById(t.id)} - > - <span className="h-artist">{t.artist}</span> - <span className="sep">—</span> - <span className="h-title">{t.title}</span> - </button> - </li> - ))} - </ol> - </aside> + <EmbedSnippet className="main-embed" /> </main> - <EmbedSnippet /> - <footer className="footer"> <small className="muted">Developed by Pablo Murad — 2026</small> </footer>