Files
saborflow/js/main.js
Javier Blanco e4f8d9f8f0 Add Google Maps links to schedule venues
Each venue in the schedule table is now a link that opens Google Maps.
Real place page used where found (Caliz, Webe Coffee); search fallback
for the rest. Pin icon appears on hover.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 22:43:47 +07:00

114 lines
6.2 KiB
JavaScript

// ============================================================
// Sabor Flow Da Nang — main.js
// Update SCHEDULE array monthly when the weekly program changes.
// ============================================================
const SCHEDULE = [
{ day: 'Monday', venue: 'Webe Coffee', social: 'BOM', music: '8 Bachata · 1 Salsa · 1 Kizomba', city: 'Da Nang', organizer: 'Luu Phuong & Shai', mapUrl: 'https://maps.app.goo.gl/jvaQgcNt4doYwZ2N7' },
{ day: 'Tuesday', venue: 'La Riva', social: 'Latino Dancing', music: '2 Salsa · 2 Bachata · 2 Kizomba', city: 'Hoi An', organizer: 'David Tavares', mapUrl: 'https://www.google.com/maps/search/?api=1&query=La+Riva+An+Bang+Hoi+An+Vietnam' },
{ day: 'Tuesday', venue: 'Caliz Bar', social: 'Sensual Night', music: '3 Bachata · 2 Salsa · 2 Kizomba', city: 'Da Nang', organizer: 'Daisy Nguyen', mapUrl: 'https://www.google.com/maps/place/C%C3%A1liz+Wine+Bar/@16.0485026,108.2470699,17z' },
{ day: 'Wednesday', venue: 'Ket Fai Bar', social: 'Bachata Kiz Night', music: 'Kizomba 19:30 · Bachata 21:00', city: 'Da Nang', organizer: 'Sean Kim', mapUrl: 'https://www.google.com/maps/search/?api=1&query=Ket+Fai+Bar+Da+Nang+Vietnam' },
{ day: 'Thursday', venue: 'Malibu', social: 'Salsa Nights', music: '2 Salsa · 2 Bachata', city: 'Da Nang', organizer: 'Lucho Giraldes', mapUrl: 'https://www.google.com/maps/search/?api=1&query=Malibu+Beach+Club+Da+Nang+Vietnam' },
{ day: 'Friday', venue: 'An Thuong By Night', social: 'Dance Unity Party', music: '2 Salsa · 2 Bachata · 2 Kizomba', city: 'Da Nang', organizer: 'Nadiya Yagfarova', mapUrl: 'https://www.google.com/maps/search/?api=1&query=An+Thuong+Tourist+Street+Da+Nang+Vietnam' },
{ day: 'Saturday', venue: 'La Riva', social: 'Latino Dancing', music: '2 Salsa · 2 Bachata · 2 Kizomba', city: 'Hoi An', organizer: 'David Tavares', mapUrl: 'https://www.google.com/maps/search/?api=1&query=La+Riva+An+Bang+Hoi+An+Vietnam' },
{ day: 'Saturday', venue: 'An Thuong By Night', social: 'Bachata Party', music: 'Only Bachata', city: 'Da Nang', organizer: 'Vaclav & Kseniya', mapUrl: 'https://www.google.com/maps/search/?api=1&query=An+Thuong+Tourist+Street+Da+Nang+Vietnam' },
{ day: 'Sunday', venue: 'Last Call', social: 'Latin Dance Social', music: '3 Bachata · 2 Salsa', city: 'Da Nang', organizer: 'Vaclav & Kseniya', mapUrl: 'https://www.google.com/maps/search/?api=1&query=Last+Call+Bar+Da+Nang+Vietnam' },
{ day: 'Sunday', venue: 'Corner Bar', social: 'Sunday Latin', music: '3 Bachata · 2 Salsa · 3 Kizomba', city: 'Da Nang', organizer: 'Daisy Nguyen', mapUrl: 'https://www.google.com/maps/search/?api=1&query=Corner+Bar+Da+Nang+Vietnam' },
];
// ---- Navigation ----
function initNav() {
const hamburger = document.getElementById('hamburger');
const navLinks = document.getElementById('nav-links');
if (!hamburger || !navLinks) return;
hamburger.addEventListener('click', () => {
const isOpen = navLinks.classList.toggle('open');
hamburger.setAttribute('aria-expanded', String(isOpen));
});
navLinks.querySelectorAll('a').forEach(link => {
link.addEventListener('click', () => navLinks.classList.remove('open'));
});
}
// ---- Schedule: full table ----
function renderScheduleTable() {
const tbody = document.getElementById('schedule-tbody');
if (!tbody) return;
tbody.innerHTML = SCHEDULE.map(row => `
<tr>
<td data-label="Day">
<span class="day-badge day-${row.day.toLowerCase()}">${row.day}</span>
</td>
<td data-label="Venue" class="venue-name">
${row.mapUrl
? `<a href="${row.mapUrl}" target="_blank" rel="noopener" class="venue-map-link">${row.venue}<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></a>`
: row.venue}
</td>
<td data-label="Social" class="social-name">${row.social}</td>
<td data-label="Music" class="music-text">${row.music}</td>
<td data-label="City"><span class="city-badge">${row.city}</span></td>
<td data-label="Organizer" class="organizer-text">${row.organizer}</td>
</tr>
`).join('');
}
// ---- Home: "Coming up this week" teaser (3 events starting from today) ----
function renderScheduleTeaser() {
const container = document.getElementById('schedule-teaser');
if (!container) return;
const DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const today = DAYS[new Date().getDay()];
const startIdx = DAYS.indexOf(today);
const order = [...DAYS.slice(startIdx), ...DAYS.slice(0, startIdx)];
const sorted = [...SCHEDULE].sort(
(a, b) => order.indexOf(a.day) - order.indexOf(b.day)
);
container.innerHTML = sorted.slice(0, 3).map(row => `
<div class="teaser-card">
<div class="teaser-day">${row.day}</div>
<div class="teaser-social">${row.social}</div>
<div class="teaser-venue">@ ${row.venue}</div>
<div class="teaser-meta">${row.music} &middot; ${row.city}</div>
</div>
`).join('');
}
// ---- Filter pills (studios.html / classes.html) ----
function initFilters() {
const pills = document.querySelectorAll('.filter-pill');
if (!pills.length) return;
pills.forEach(pill => {
pill.addEventListener('click', () => {
pills.forEach(p => p.classList.remove('active'));
pill.classList.add('active');
const filter = pill.dataset.filter;
document.querySelectorAll('.filterable-card').forEach(card => {
if (filter === 'all') {
card.classList.remove('hidden');
} else {
const styles = (card.dataset.styles || '')
.split(',')
.map(s => s.trim().toLowerCase());
card.classList.toggle('hidden', !styles.includes(filter));
}
});
});
});
}
// ---- Init ----
document.addEventListener('DOMContentLoaded', () => {
initNav();
renderScheduleTable();
renderScheduleTeaser();
initFilters();
});