← back to Calendar Agentabrams
public/index.html
91 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Beverly Hills Videos — Posting Calendar</title>
<meta name="description" content="Upcoming Instagram posting schedule for Beverly Hills Videos — Rodeo Drive store films and Beverly Hills restaurant films, every 6 hours.">
<style>
:root{--cream:#f6f3ec;--ink:#15130f;--green:#12281f;--gold:#b8935a;--muted:#8a8577;--line:#e4ded1}
*{box-sizing:border-box}
body{margin:0;background:var(--cream);color:var(--ink);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;-webkit-font-smoothing:antialiased}
.serif{font-family:"Cormorant Garamond","Didot",Georgia,serif}
header{background:var(--green);color:var(--cream);padding:38px 22px 30px;text-align:center}
header .eyebrow{letter-spacing:.32em;font-size:12px;color:var(--gold);text-transform:uppercase}
header h1{font-family:"Cormorant Garamond",Georgia,serif;font-weight:600;font-size:40px;margin:8px 0 6px}
header p{color:#cfc9ba;margin:0;font-size:14px}
.wrap{max-width:820px;margin:0 auto;padding:22px}
.bar{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:16px}
.stats{font-size:13px;color:var(--muted)}
select{padding:7px 10px;border:1px solid var(--line);border-radius:8px;background:#fff;font-size:13px}
.day{margin:22px 0 8px;display:flex;align-items:baseline;gap:10px}
.day h2{font-family:"Cormorant Garamond",Georgia,serif;font-size:22px;margin:0}
.day .sub{color:var(--muted);font-size:12px}
.post{display:flex;align-items:center;gap:14px;background:#fff;border:1px solid var(--line);border-radius:12px;padding:12px 14px;margin:8px 0}
.post.next{border-color:var(--gold);box-shadow:0 0 0 2px rgba(184,147,90,.18)}
.time{font-variant-numeric:tabular-nums;font-weight:600;font-size:15px;min-width:64px;color:var(--green)}
.badge{font-size:11px;letter-spacing:.08em;text-transform:uppercase;padding:3px 9px;border-radius:999px;white-space:nowrap}
.badge.store{background:#efe7d8;color:#8a6a33}
.badge.restaurant{background:#e3ece7;color:#2c5b47}
.meta{flex:1;min-width:0}
.meta .name{font-family:"Cormorant Garamond",Georgia,serif;font-size:20px;line-height:1.15}
.meta .cat{font-size:12px;color:var(--muted)}
.nextchip{margin-left:auto;font-size:10px;letter-spacing:.1em;color:var(--gold);text-transform:uppercase}
footer{text-align:center;color:var(--muted);font-size:12px;padding:26px}
a{color:var(--gold)}
</style>
</head>
<body>
<header>
<div class="eyebrow">Beverly Hills Videos</div>
<h1>Posting Calendar</h1>
<p>Rodeo Drive store films & Beverly Hills dining — one post every 6 hours, on <a href="https://instagram.com/beverlyhillsvideos" style="color:#e8dcc4">@beverlyhillsvideos</a></p>
</header>
<div class="wrap">
<div class="bar">
<div class="stats" id="stats">Loading…</div>
<label>Show <select id="days">
<option value="3">3 days</option>
<option value="7" selected>7 days</option>
<option value="14">14 days</option>
<option value="30">30 days</option>
</select></label>
</div>
<div id="cal"></div>
</div>
<footer id="foot"></footer>
<script>
const fmtDay = d => d.toLocaleDateString(undefined,{weekday:'long',month:'long',day:'numeric'});
const fmtTime = d => d.toLocaleTimeString(undefined,{hour:'numeric',minute:'2-digit'});
async function load(){
const days = document.getElementById('days').value;
const r = await fetch('/api/schedule?days='+days); const j = await r.json();
document.getElementById('stats').textContent =
`${j.stats.stores} store films · ${j.stats.restaurants} restaurant films · ${j.stats.slotsPerDay}×/day`;
const cal = document.getElementById('cal'); cal.innerHTML='';
const byDay = {};
for(const it of j.items){ const d=new Date(it.epoch); const k=d.toDateString(); (byDay[k]=byDay[k]||[]).push(it); }
let first=true;
for(const k of Object.keys(byDay)){
const d=new Date(k);
const hd=document.createElement('div'); hd.className='day';
hd.innerHTML=`<h2 class="serif">${fmtDay(d)}</h2><span class="sub">${byDay[k].length} posts</span>`;
cal.appendChild(hd);
for(const it of byDay[k]){
const el=document.createElement('div'); el.className='post'+(first?' next':'');
el.innerHTML=`<span class="time">${fmtTime(new Date(it.epoch))}</span>
<span class="badge ${it.kind}">${it.kind==='store'?'Store':'Restaurant'}</span>
<span class="meta"><span class="name serif">${it.name}</span><br><span class="cat">${it.category}</span></span>
${first?'<span class="nextchip">next up</span>':''}`;
cal.appendChild(el); first=false;
}
}
document.getElementById('foot').innerHTML =
`Projected schedule · generated ${new Date(j.generatedAt).toLocaleString()} · rotation is round-robin and may shift as posts publish.`;
}
document.getElementById('days').addEventListener('change',load);
load();
</script>
</body>
</html>