Files
acm-austin-website/sessionize.html
T
2026-09-23 13:53:30 -05:00

94 lines
9.3 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="ACM Austin speakers and sessions powered by Sessionize.">
<title>ACM Austin | Speakers & Sessions</title>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-V67H9T0WJ0"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-V67H9T0WJ0');
</script>
<link rel="icon" type="image/png" href="photos/logos/acm-small.png">
<link rel="apple-touch-icon" href="photos/logos/acm.png">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = { theme: { extend: {
colors: { navy: '#071525', ink: '#10253d', electric: '#2dd4ff', lime: '#c8f169', mist: '#edf4f7' },
fontFamily: { sans: ['Plus Jakarta Sans', 'ui-sans-serif', 'sans-serif'], mono: ['IBM Plex Mono', 'monospace'] }
}}};
</script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
</head>
<body class="bg-mist font-sans text-ink antialiased">
<header class="bg-navy text-white">
<nav class="mx-auto flex max-w-7xl items-center justify-between px-6 py-5 lg:px-8" aria-label="Main navigation">
<a href="index.html" class="flex items-center gap-3 font-bold tracking-tight"><img class="h-10 w-10 rounded-lg bg-white object-contain p-1" src="photos/logos/acm-small.png" alt="ACM Austin logo"><span>ACM <span class="text-electric">Austin</span></span></a>
<div class="flex items-center gap-5 text-sm text-slate-300"><a href="index.html#events" class="hover:text-white">Events</a><a href="index.html#community" class="hover:text-white">Community</a><a href="https://sessionize.com/austin-acm-meetup/" target="_blank" rel="noopener" class="rounded-full bg-lime px-4 py-2 font-bold text-navy hover:bg-white">Submit a talk ↗</a></div>
</nav>
</header>
<main>
<section class="bg-navy px-6 pb-16 pt-12 text-white lg:px-8 lg:pb-20 lg:pt-20"><div class="mx-auto max-w-7xl"><p class="font-mono text-xs uppercase tracking-[.2em] text-electric">Sessionize / ACM Austin</p><h1 class="mt-4 max-w-3xl text-5xl font-extrabold tracking-tight sm:text-6xl">Speakers who share the <span class="text-electric">real work.</span></h1><p class="mt-6 max-w-2xl text-lg leading-8 text-slate-300">Explore the talks and practitioners shaping our monthly engineering community.</p></div></section>
<section class="mx-auto max-w-7xl px-6 py-16 lg:px-8"><div id="status" class="rounded-xl border border-slate-200 bg-white p-5 text-sm text-slate-600" role="status">Loading the Sessionize program...</div><div class="mt-12"><div class="flex flex-wrap items-end justify-between gap-5"><div><p class="font-mono text-xs uppercase tracking-[.2em] text-cyan-600">The people</p><h2 class="mt-3 text-3xl font-extrabold tracking-tight text-navy">Speaker directory</h2></div><a href="https://sessionize.com/austin-acm-meetup/" target="_blank" rel="noopener" class="rounded-full border border-ink px-5 py-3 text-sm font-bold text-navy hover:border-cyan-600 hover:text-cyan-700">View on Sessionize ↗</a></div><div id="speakers" class="mt-8 grid gap-5 sm:grid-cols-2 lg:grid-cols-4"></div></div><section class="mt-16 border-t border-slate-200 pt-12"><div class="flex flex-wrap items-center justify-between gap-6"><div><p class="font-mono text-xs uppercase tracking-[.2em] text-cyan-600">Past speakers</p><h2 class="mt-2 text-2xl font-extrabold tracking-tight text-navy">Request your certificate</h2><p class="mt-3 max-w-2xl text-sm leading-6 text-slate-600">If you spoke in person at an event, submit the certificate request and email chair Akshay Canodia at <a class="font-semibold text-cyan-700 hover:text-navy" href="mailto:akshaycanodia@gmail.com">akshaycanodia@gmail.com</a> to receive your certificate.</p></div><a href="https://credsverse.com/forms/221af5a9-da36-4f98-89a4-fdb17fd749c6" target="_blank" rel="noopener" class="rounded-full bg-navy px-5 py-3 text-sm font-bold text-white hover:bg-ink">Submit certificate request ↗</a></div></section><div class="mt-20"><p class="font-mono text-xs uppercase tracking-[.2em] text-cyan-600">The program</p><h2 class="mt-3 text-3xl font-extrabold tracking-tight text-navy">Sessions</h2><div id="sessions" class="mt-8 grid gap-5 lg:grid-cols-2" hidden></div></div></section>
</main>
<footer class="bg-navy px-6 py-8 text-sm text-slate-400 lg:px-8"><div class="mx-auto flex max-w-7xl flex-wrap items-center justify-between gap-4"><div class="flex items-center gap-3"><img class="h-8 w-8 rounded-md bg-white object-contain p-1" src="photos/logos/acm-small.png" alt="ACM Austin logo"><span>© 2026 ACM Austin · A joint ACM / IEEE chapter</span></div><a href="index.html" class="font-bold text-electric hover:text-white">Back to ACM Austin home</a></div></footer>
<script>
// Keep this endpoint in one place so a regenerated Sessionize ID is easy to swap.
const SESSIONIZE_ENDPOINT = 'https://sessionize.com/api/v2/f8cooe5l/view/All';
const status = document.querySelector('#status');
const sessionsTarget = document.querySelector('#sessions');
const speakersTarget = document.querySelector('#speakers');
const escapeHtml = value => String(value || '').replace(/[&<>'"]/g, character => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#039;', '"': '&quot;' }[character]));
const dateLabel = value => value ? new Intl.DateTimeFormat('en-US', { weekday: 'short', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }).format(new Date(value)) : 'Schedule coming soon';
function speakerName(speaker) {
return [speaker.firstName, speaker.lastName].filter(Boolean).join(' ') || speaker.name || 'ACM Austin speaker';
}
function sessionSpeakerNames(session, speakerLookup) {
const references = session.speakers || session.speakerIds || session.speaker || [];
const list = Array.isArray(references) ? references : [references];
return list.map(reference => {
if (typeof reference === 'object') return speakerName(reference);
return speakerLookup.get(reference) || speakerLookup.get(String(reference)) || '';
}).filter(Boolean);
}
function renderSessions(sessions, speakers) {
if (!sessions.length) return;
const speakerLookup = new Map(speakers.flatMap(speaker => [[speaker.id, speakerName(speaker)], [String(speaker.id), speakerName(speaker)]]));
sessionsTarget.innerHTML = sessions.map(session => { const names = sessionSpeakerNames(session, speakerLookup); return `<article class="rounded-2xl border border-slate-200 bg-white p-6 shadow-sm"><div class="flex flex-wrap items-center justify-between gap-3"><span class="font-mono text-xs uppercase tracking-wider text-cyan-700">${escapeHtml(session.categoryItems?.[0]?.name || 'Session')}</span><span class="font-mono text-xs text-slate-500">${dateLabel(session.startsAt || session.startTime)}</span></div><h3 class="mt-4 text-xl font-bold leading-snug text-navy">${escapeHtml(session.title || session.name || 'Untitled session')}</h3>${names.length ? `<p class="mt-2 text-sm font-semibold text-cyan-700">${escapeHtml(names.join(' · '))}</p>` : ''}<p class="mt-3 text-sm leading-6 text-slate-600">${escapeHtml(session.description || session.tagline || 'Session details coming soon.')}</p><p class="mt-5 font-mono text-xs text-slate-500">${escapeHtml(session.room?.name || session.room || '')}</p></article>`; }).join('');
sessionsTarget.hidden = false;
}
function renderSpeakers(speakers) {
speakersTarget.innerHTML = speakers.length ? speakers.map(speaker => `<article class="rounded-2xl border border-slate-200 bg-white p-5"><img class="aspect-square w-full rounded-xl bg-mist object-cover" src="${escapeHtml(speaker.profilePicture || 'photos/images/placeholder_profile.svg')}" alt="${escapeHtml(speakerName(speaker))}"><h3 class="mt-4 font-bold text-navy">${escapeHtml(speakerName(speaker))}</h3><p class="mt-1 text-sm leading-6 text-slate-500">${escapeHtml(speaker.tagLine || speaker.bio || 'ACM Austin community speaker')}</p></article>`).join('') : '<p class="text-slate-600">Speaker profiles will appear here as the program is published.</p>';
}
fetch(SESSIONIZE_ENDPOINT).then(response => { if (!response.ok) throw new Error(`Sessionize returned ${response.status}`); return response.json(); }).then(data => {
const sessions = data.sessions || data.sessionList || [];
const speakers = data.speakers || data.speakerList || [];
renderSessions(sessions, speakers);
renderSpeakers(speakers);
status.textContent = `Loaded ${sessions.length} sessions and ${speakers.length} speakers from Sessionize.`;
status.className = 'rounded-xl border border-emerald-200 bg-emerald-50 p-5 text-sm text-emerald-800';
}).catch(error => {
status.innerHTML = `The live Sessionize feed is temporarily unavailable. <a class="font-bold underline" href="https://sessionize.com/austin-acm-meetup/" target="_blank" rel="noopener">View the program on Sessionize ↗</a>`;
status.title = error.message;
renderSpeakers([]);
});
</script>
</body>
</html>