feat(builder): P1 page editor — live preview now renders a REAL release from the catalog (real covers/tracklist) so block-arranging is WYSIWYG; + View-live link
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
fcc3d7b2ff
commit
386343cdd3
@ -70,6 +70,7 @@
|
|||||||
<div class="t">Record<b>God</b> · storefront builder</div>
|
<div class="t">Record<b>God</b> · storefront builder</div>
|
||||||
<div class="sp"></div>
|
<div class="sp"></div>
|
||||||
<span id="status"></span>
|
<span id="status"></span>
|
||||||
|
<a class="ghost" href="/records" target="_blank" style="text-decoration:none;color:#2a2a30">View live ↗</a>
|
||||||
<button class="ghost" onclick="resetDefaults()">Reset</button>
|
<button class="ghost" onclick="resetDefaults()">Reset</button>
|
||||||
<button class="btn" onclick="save()">Save</button>
|
<button class="btn" onclick="save()">Save</button>
|
||||||
</header>
|
</header>
|
||||||
@ -81,6 +82,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
const $=s=>document.querySelector(s);
|
const $=s=>document.querySelector(s);
|
||||||
|
const esc=s=>(s==null?'':String(s)).replace(/[&<>"]/g,c=>({'&':'&','<':'<','>':'>','"':'"'}[c]));
|
||||||
let TOKEN=localStorage.getItem('rg_token')||'';
|
let TOKEN=localStorage.getItem('rg_token')||'';
|
||||||
let cfg=null, palette=null, defaults=null, surface='card';
|
let cfg=null, palette=null, defaults=null, surface='card';
|
||||||
const hdr=()=>({'Authorization':'Bearer '+TOKEN,'Content-Type':'application/json'});
|
const hdr=()=>({'Authorization':'Bearer '+TOKEN,'Content-Type':'application/json'});
|
||||||
@ -92,7 +94,7 @@ async function signin(){
|
|||||||
localStorage.setItem('rg_token',TOKEN);
|
localStorage.setItem('rg_token',TOKEN);
|
||||||
const d=await r.json(); cfg=d.config; palette=d.palette; defaults=d.defaults;
|
const d=await r.json(); cfg=d.config; palette=d.palette; defaults=d.defaults;
|
||||||
$('#gate').style.display='none'; $('#app').style.display='grid';
|
$('#gate').style.display='none'; $('#app').style.display='grid';
|
||||||
renderEditor(); renderPreview();
|
await loadSamples(); renderEditor(); renderPreview();
|
||||||
}
|
}
|
||||||
function resetDefaults(){ cfg=JSON.parse(JSON.stringify(defaults)); renderEditor(); renderPreview(); }
|
function resetDefaults(){ cfg=JSON.parse(JSON.stringify(defaults)); renderEditor(); renderPreview(); }
|
||||||
|
|
||||||
@ -161,32 +163,41 @@ async function importBrand(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---------- preview ----------
|
// ---------- preview ----------
|
||||||
const SAMPLE=[
|
let SAMPLE=[], PAGE=null; // real releases pulled from the live catalog
|
||||||
{t:'Hounds of Love',a:'Kate Bush',p:'42.00',c:'NM',g:'Art Pop',h:320},
|
async function loadSamples(){
|
||||||
{t:'Midnight Marauders',a:'A Tribe Called Quest',p:'55.00',c:'VG+',g:'Hip Hop',h:32},
|
try{
|
||||||
{t:'Selected Ambient Works 85-92',a:'Aphex Twin',p:'38.50',c:'VG',g:'Electronic',h:175},
|
const b=await fetch('/shop/browse?sort=new').then(r=>r.json());
|
||||||
{t:'Rumours',a:'Fleetwood Mac',p:'29.95',c:'VG+',g:'Rock',h:265},
|
SAMPLE=(b.items||[]).slice(0,8).map(r=>({id:r.release_id,t:r.title,a:r.artist,
|
||||||
];
|
p:r.price!=null?Number(r.price).toFixed(2):'',g:(r.genre||'').split(', ')[0],y:r.year,copies:r.copies}));
|
||||||
const cover=(r,cls='pv-cover')=>`<div class="${cls}" style="background:linear-gradient(135deg,hsl(${r.h} 50% 38%),hsl(${(r.h+40)%360} 45% 28%))"></div>`;
|
if(SAMPLE[0]){ const d=await fetch('/shop/release/'+SAMPLE[0].id).then(r=>r.json());
|
||||||
const cardEl={cover:r=>cover(r),title:r=>`<div class="pv-title">${r.t}</div>`,artist:r=>`<div class="pv-artist">${r.a}</div>`,
|
PAGE=Object.assign({}, SAMPLE[0], d.release||{}, {tracks:d.tracks||[], copies:d.copies||[]}); }
|
||||||
price:r=>`<div class="pv-price">$${r.p}</div>`,condition:r=>`<span class="pv-pill">${r.c}</span>`,genre:r=>`<span class="pv-pill">${r.g}</span>`,
|
}catch(e){}
|
||||||
format:()=>`<span class="pv-pill">LP</span>`,year:()=>`<span class="pv-pill">1985</span>`,stock_badge:()=>`<span class="pv-pill ok">in stock</span>`,
|
if(!SAMPLE.length) SAMPLE=[{t:'Sample Record',a:'Various Artists',p:'29.95',g:'Electronic',y:1990}];
|
||||||
|
}
|
||||||
|
const cover=(r,cls='pv-cover')=> r&&r.id
|
||||||
|
? `<img class="${cls}" src="/img/r/${r.id}" style="object-fit:cover" onerror="this.style.background='linear-gradient(135deg,#444,#222)';this.removeAttribute('src')">`
|
||||||
|
: `<div class="${cls}" style="background:linear-gradient(135deg,#444,#222)"></div>`;
|
||||||
|
const cardEl={cover:r=>cover(r),title:r=>`<div class="pv-title">${esc(r.t)}</div>`,artist:r=>`<div class="pv-artist">${esc(r.a)}</div>`,
|
||||||
|
price:r=>`<div class="pv-price">$${r.p}</div>`,condition:()=>`<span class="pv-pill">VG+</span>`,genre:r=>`<span class="pv-pill">${esc(r.g)}</span>`,
|
||||||
|
format:()=>`<span class="pv-pill">LP</span>`,year:r=>`<span class="pv-pill">${r.y||''}</span>`,stock_badge:()=>`<span class="pv-pill ok">in stock</span>`,
|
||||||
wishlist:()=>`<button class="pv-ghost">♡</button>`,cart:()=>`<button class="pv-btn">Add to cart</button>`};
|
wishlist:()=>`<button class="pv-ghost">♡</button>`,cart:()=>`<button class="pv-btn">Add to cart</button>`};
|
||||||
const pageEl={cover:r=>cover(r,'pv-bigcover'),gallery:r=>cover(r,'pv-bigcover'),title:r=>`<h1 class="pv-h1">${r.t}</h1>`,artist:r=>`<div class="pv-artist big">${r.a}</div>`,
|
const pageEl={cover:r=>cover(r,'pv-bigcover'),gallery:r=>cover(r,'pv-bigcover'),title:r=>`<h1 class="pv-h1">${esc(r.t||r.title)}</h1>`,artist:r=>`<div class="pv-artist big">${esc(r.a||r.artist)}</div>`,
|
||||||
label:()=>`<div class="pv-meta">Label · 4AD</div>`,price:r=>`<div class="pv-price big">$${r.p}</div>`,condition:r=>`<div class="pv-meta">Condition · ${r.c}</div>`,
|
label:r=>r.label?`<div class="pv-meta">Label · ${esc(r.label)}</div>`:'',price:r=>`<div class="pv-price big">$${r.p}</div>`,condition:()=>`<div class="pv-meta">Condition · VG+</div>`,
|
||||||
genre:r=>`<span class="pv-pill">${r.g}</span> `,format:()=>`<div class="pv-meta">Format · Vinyl LP</div>`,year:()=>`<div class="pv-meta">Year · 1985</div>`,
|
genre:r=>(r.genre||r.g||'').split(', ').filter(Boolean).map(g=>`<span class="pv-pill">${esc(g)}</span> `).join(''),
|
||||||
country:()=>`<div class="pv-meta">Country · UK</div>`,tracklist:()=>`<div class="pv-tracks">1. Running Up That Hill<br>2. Hounds of Love<br>3. The Big Sky<br>4. Mother Stands for Comfort</div>`,
|
format:r=>r.format?`<div class="pv-meta">Format · ${esc(r.format)}</div>`:'',year:r=>r.year||r.y?`<div class="pv-meta">Year · ${r.year||r.y}</div>`:'',
|
||||||
cart:()=>`<button class="pv-btn big">Add to cart</button>`,wishlist:()=>`<button class="pv-ghost">♡ Wishlist</button>`,
|
country:r=>r.country?`<div class="pv-meta">Country · ${esc(r.country)}</div>`:'',
|
||||||
description:()=>`<div class="pv-meta">A landmark 1985 art-pop record, first pressing, sleeve VG+.</div>`,
|
tracklist:r=>`<div class="pv-tracks">${(r.tracks||[]).slice(0,10).map(t=>`${esc(t.position||'')} ${esc(t.title||'')}`).join('<br>')||'<span style="opacity:.5">no tracklist</span>'}</div>`,
|
||||||
related:()=>`<div class="pv-meta" style="margin-top:14px">You may also like · 4 more →</div>`,dealgod_value:()=>`<div class="pv-dg">DealGod value · $48 · target $44 · buy-opportunity nearby</div>`};
|
cart:()=>`<button class="pv-btn big">Buy online</button>`,wishlist:()=>`<button class="pv-ghost">♡ Wishlist</button>`,
|
||||||
|
description:r=>r.notes?`<div class="pv-meta">${esc(String(r.notes).slice(0,220))}</div>`:'',
|
||||||
|
related:()=>`<div class="pv-meta" style="margin-top:14px">You may also like →</div>`,dealgod_value:()=>`<div class="pv-dg">DealGod value · cross-store market</div>`};
|
||||||
|
|
||||||
function renderPreview(){
|
function renderPreview(){
|
||||||
const t=cfg.theme, pv=$('#pv');
|
const t=cfg.theme, pv=$('#pv');
|
||||||
pv.style.setProperty('--p',t.primary);pv.style.setProperty('--a',t.accent);pv.style.setProperty('--bg',t.bg);
|
pv.style.setProperty('--p',t.primary);pv.style.setProperty('--a',t.accent);pv.style.setProperty('--bg',t.bg);
|
||||||
pv.style.setProperty('--pn',t.panel);pv.style.setProperty('--tx',t.text);pv.style.setProperty('--r',(t.radius??12)+'px');pv.style.setProperty('--font',t.font||'system-ui');
|
pv.style.setProperty('--pn',t.panel);pv.style.setProperty('--tx',t.text);pv.style.setProperty('--r',(t.radius??12)+'px');pv.style.setProperty('--font',t.font||'system-ui');
|
||||||
const logo=t.logo?`<img class="pv-logo" src="${t.logo}" onerror="this.replaceWith(Object.assign(document.createElement('span'),{className:'pv-logo txt',textContent:'RecordGod'}))">`:`<span class="pv-logo txt">RecordGod</span>`;
|
const logo=t.logo?`<img class="pv-logo" src="${t.logo}" onerror="this.replaceWith(Object.assign(document.createElement('span'),{className:'pv-logo txt',textContent:'RecordGod'}))">`:`<span class="pv-logo txt">RecordGod</span>`;
|
||||||
const nav=cfg.menu.map(m=>`<a href="#">${m.label}</a>`).join('');
|
const nav=cfg.menu.map(m=>`<a href="#">${esc(m.label)}</a>`).join('');
|
||||||
const r=SAMPLE[0];
|
const r=PAGE||SAMPLE[0]||{};
|
||||||
pv.innerHTML=`<div class="lbl">Storefront preview · live</div><div class="pv-shop">
|
pv.innerHTML=`<div class="lbl">Storefront preview · live</div><div class="pv-shop">
|
||||||
<div class="pv-head">${logo}<nav class="pv-nav">${nav}</nav><button class="pv-btn">Cart</button></div>
|
<div class="pv-head">${logo}<nav class="pv-nav">${nav}</nav><button class="pv-btn">Cart</button></div>
|
||||||
<div class="pv-grid" style="grid-template-columns:repeat(${t.cardCols??4},1fr)">
|
<div class="pv-grid" style="grid-template-columns:repeat(${t.cardCols??4},1fr)">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user