84 lines
5.7 KiB
HTML
84 lines
5.7 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Release</title>
|
||
<style>
|
||
:root{--primary:#ff5db1;--accent:#46d18a;--bg:#0c0c0e;--panel:#141418;--text:#f0f0f2;--mut:#8a8a98;--line:#26262c;--radius:12px;--font:system-ui}
|
||
*{box-sizing:border-box}
|
||
html,body{margin:0;background:var(--bg);color:var(--text);font-family:var(--font),system-ui,sans-serif}
|
||
a{color:inherit;text-decoration:none}
|
||
header{display:flex;align-items:center;gap:16px;padding:14px 22px;border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--bg);z-index:10}
|
||
.logo{font-weight:800;font-size:20px}.logo b{color:var(--primary)}.logo img{height:30px;vertical-align:middle}
|
||
nav.menu{display:flex;gap:16px;flex:1}nav.menu a{color:var(--mut);font-size:14px}nav.menu a:hover{color:var(--text)}
|
||
button,.btn{cursor:pointer;border:0;border-radius:9px;font:600 14px var(--font),system-ui;padding:11px 16px;background:var(--primary);color:#10070c}
|
||
.ghost{background:var(--panel);color:var(--text);border:1px solid var(--line)}
|
||
.wrap{max-width:1080px;margin:0 auto;padding:24px}
|
||
.crumb{color:var(--mut);font-size:13px;margin-bottom:14px}.crumb a:hover{color:var(--text)}
|
||
.top{display:grid;grid-template-columns:340px 1fr;gap:28px}
|
||
.cov{width:100%;aspect-ratio:1;object-fit:cover;border-radius:var(--radius);background:#222;border:1px solid var(--line)}
|
||
h1{font-size:26px;margin:0 0 2px}.artist{font-size:18px;color:var(--mut);margin-bottom:14px}
|
||
.meta{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:14px}
|
||
.pill{background:var(--panel);border:1px solid var(--line);border-radius:20px;padding:4px 11px;font-size:12px;color:var(--mut)}
|
||
.copies{margin:16px 0}
|
||
.copy{display:flex;align-items:center;gap:12px;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:12px 14px;margin-bottom:8px}
|
||
.copy .cd{flex:1}.copy .pr{font-size:20px;font-weight:800;color:var(--primary)}
|
||
.sec{margin-top:26px}.sec h3{font-size:15px;border-bottom:1px solid var(--line);padding-bottom:6px}
|
||
table{width:100%;border-collapse:collapse;font-size:14px}td{padding:6px 4px;border-bottom:1px solid var(--line)}
|
||
.muted{color:var(--mut)}.desc{color:#c8c8d0;line-height:1.6;font-size:14px;white-space:pre-wrap}
|
||
@media(max-width:760px){.top{grid-template-columns:1fr}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header>
|
||
<a class="logo" href="/records" id="logo">Record<b>God</b></a>
|
||
<nav class="menu" id="menu"></nav>
|
||
</header>
|
||
<div class="wrap" id="app"><div class="muted">loading…</div></div>
|
||
<script>
|
||
const $=s=>document.querySelector(s);
|
||
const esc=s=>(s||'').replace(/[&<>"]/g,c=>({'&':'&','<':'<','>':'>','"':'"'}[c]));
|
||
const money=n=>n==null?'':'$'+Number(n).toFixed(2);
|
||
const RID=(location.pathname.match(/\/release\/(\d+)/)||[])[1] || new URLSearchParams(location.search).get('id');
|
||
let CFG={};
|
||
|
||
async function boot(){
|
||
CFG=await fetch('/shop/config').then(r=>r.json()).catch(()=>({}));
|
||
const t=CFG.theme||{}, R=document.documentElement.style;
|
||
for(const [k,v] of Object.entries({'--primary':t.primary,'--accent':t.accent,'--bg':t.bg,'--panel':t.panel,'--text':t.text,'--font':t.font})) if(v) R.setProperty(k,v);
|
||
if(t.radius) R.setProperty('--radius',t.radius+'px');
|
||
if(t.logo) $('#logo').innerHTML=`<img src="${esc(t.logo)}">`;
|
||
$('#menu').innerHTML=(CFG.menu||[]).map(m=>`<a href="${esc(m.href||'#')}">${esc(m.label||'')}</a>`).join('');
|
||
render();
|
||
}
|
||
async function render(){
|
||
if(!RID){ $('#app').innerHTML='<div class="muted">no release</div>'; return; }
|
||
const d=await fetch('/shop/release/'+RID).then(r=>r.json());
|
||
const r=d.release;
|
||
const show=k=>(CFG.product_page||['cover','title','artist','price','condition','genre','tracklist','cart']).includes(k);
|
||
if(!r){ $('#app').innerHTML=`<div class="muted">release ${esc(RID)} not found</div>`; return; }
|
||
const meta=[]; if(show('label')&&r.label)meta.push(r.label); if(show('format')&&r.format)meta.push(r.format);
|
||
if(show('country')&&r.country)meta.push(r.country); if(show('year')&&r.year)meta.push(r.year);
|
||
const tags=[]; if(show('genre')&&r.genre)tags.push(...r.genre.split(', ')); if(r.style)tags.push(...r.style.split(', '));
|
||
const buy=c=> c.product_url ? `<a class="btn" href="${esc(c.product_url)}" target="_blank">Buy online</a>` : `<span class="muted">in store</span>`;
|
||
$('#app').innerHTML=`
|
||
<div class="crumb"><a href="/records">Records</a> › ${esc(r.artist||'')}</div>
|
||
<div class="top">
|
||
<div>${show('cover')?`<img class="cov" src="/img/r/${r.id}" onerror="this.style.visibility='hidden'">`:''}</div>
|
||
<div>
|
||
${show('title')?`<h1>${esc(r.title||'')}</h1>`:''}${show('artist')?`<div class="artist">${esc(r.artist||'')}</div>`:''}
|
||
<div class="meta">${meta.map(m=>`<span class="pill">${esc(String(m))}</span>`).join('')}</div>
|
||
<div class="meta">${tags.map(t=>`<span class="pill">${esc(t)}</span>`).join('')}</div>
|
||
${show('cart')||show('price')?`<div class="copies">${(d.copies||[]).map(c=>`<div class="copy">
|
||
<div class="cd"><div class="pr">${money(c.price)}</div><div class="muted">${esc(c.condition||'')}${c.sleeve_cond?' / '+esc(c.sleeve_cond):''} · ${esc(c.sku)}</div></div>${buy(c)}</div>`).join('')||'<div class="muted">no copies in stock</div>'}</div>`:''}
|
||
</div>
|
||
</div>
|
||
${show('tracklist')&&d.tracks.length?`<div class="sec"><h3>Tracklist</h3><table>${d.tracks.map(t=>`<tr><td class="muted" style="width:40px">${esc(t.position||'')}</td><td>${esc(t.title||'')}</td><td class="muted" style="width:50px;text-align:right">${esc(t.duration||'')}</td></tr>`).join('')}</table></div>`:''}
|
||
${show('description')&&r.notes?`<div class="sec"><h3>Notes</h3><div class="desc">${esc(r.notes)}</div></div>`:''}`;
|
||
}
|
||
boot();
|
||
</script>
|
||
</body>
|
||
</html>
|