const locationInput = document.querySelector('#location-input');
const latitudeInput = document.querySelector('#latitude-input');
const longitudeInput = document.querySelector('#longitude-input');
const options = document.querySelector('#location-options');
let locationTimer;
if (locationInput) {
locationInput.addEventListener('input', () => {
latitudeInput.value = '';
longitudeInput.value = '';
clearTimeout(locationTimer);
const query = locationInput.value.trim();
if (query.length < 3) { options.hidden = true; return; }
locationTimer = setTimeout(async () => {
try {
const response = await fetch(`/api/locations?q=${encodeURIComponent(query)}`);
const places = await response.json();
options.replaceChildren();
places.forEach(place => {
const button = document.createElement('button');
button.type = 'button';
button.textContent = place.label;
button.addEventListener('click', () => {
locationInput.value = place.label;
latitudeInput.value = place.latitude;
longitudeInput.value = place.longitude;
options.hidden = true;
});
options.append(button);
});
if (places.length === 0) {
const message = document.createElement('div');
message.className = 'location-message';
message.textContent = 'No geographic locations found. Try a suburb, town, or postcode.';
options.append(message);
}
options.hidden = false;
} catch (_) { options.hidden = true; }
}, 300);
});
document.addEventListener('click', event => { if (!event.target.closest('.location-field')) options.hidden = true; });
}
const tagToggle = document.querySelector('#tag-toggle');
const tagOptions = document.querySelector('#tag-options');
if (tagToggle && tagOptions) {
tagToggle.addEventListener('click', () => { tagOptions.hidden = !tagOptions.hidden; });
tagOptions.addEventListener('change', () => {
const count = tagOptions.querySelectorAll('input:checked').length;
tagToggle.textContent = count ? `${count} selected` : 'All types';
});
document.addEventListener('click', event => {
if (!event.target.closest('.tag-field')) tagOptions.hidden = true;
});
}
const tabs = document.querySelectorAll('.tab');
let map;
tabs.forEach(tab => tab.addEventListener('click', () => {
tabs.forEach(item => item.classList.toggle('active', item === tab));
document.querySelectorAll('.view-panel').forEach(panel => panel.classList.toggle('active', panel.id === tab.dataset.view));
if (tab.dataset.view === 'map-view') initialiseMap();
}));
const eventRows = [...document.querySelectorAll('[data-event-start]')];
const visibleCount = document.querySelector('#visible-event-count');
const clearDay = document.querySelector('#clear-day');
const dayEmpty = document.querySelector('#day-empty');
const rangeStatus = document.querySelector('#range-status');
let rangeStart = '';
let rangeEnd = '';
function formatDay(dayKey) {
return new Date(`${dayKey}T00:00:00`).toLocaleDateString(undefined, { day: 'numeric', month: 'short' });
}
function filterToRange(startDay, endDay = startDay) {
let count = 0;
eventRows.forEach(row => {
row.hidden = Boolean(startDay) && (row.dataset.eventStart > endDay || row.dataset.eventEnd < startDay);
if (!row.hidden) count += 1;
});
document.querySelectorAll('.calendar-day').forEach(day => {
const inRange = Boolean(startDay) && day.dataset.day >= startDay && day.dataset.day <= endDay;
day.classList.toggle('selected', inRange);
day.classList.toggle('range-start', day.dataset.day === startDay);
day.classList.toggle('range-end', day.dataset.day === endDay && endDay !== startDay);
});
if (visibleCount) visibleCount.textContent = count;
if (clearDay) clearDay.hidden = !startDay;
if (dayEmpty) dayEmpty.hidden = count !== 0;
}
document.querySelectorAll('.calendar-day').forEach(day => day.addEventListener('click', event => {
event.preventDefault();
const clicked = day.dataset.day;
if (!rangeStart || rangeEnd) {
rangeStart = clicked;
rangeEnd = '';
filterToRange(rangeStart);
if (rangeStatus) rangeStatus.textContent = `${formatDay(rangeStart)} selected · choose an end date`;
} else {
rangeEnd = clicked;
if (rangeEnd < rangeStart) [rangeStart, rangeEnd] = [rangeEnd, rangeStart];
filterToRange(rangeStart, rangeEnd);
if (rangeStatus) rangeStatus.textContent = `${formatDay(rangeStart)} – ${formatDay(rangeEnd)}`;
document.querySelector('#event-list')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}));
if (clearDay) clearDay.addEventListener('click', event => {
event.preventDefault(); rangeStart = ''; rangeEnd = ''; filterToRange('');
if (rangeStatus) rangeStatus.textContent = 'Select a start date';
});
function initialiseMap() {
if (map || !window.maplibregl) return;
const events = JSON.parse(document.querySelector('#map-events').textContent);
const center = events.length ? [events[0].longitude, events[0].latitude] : [150.8931, -34.4278];
map = new maplibregl.Map({ container: 'events-map', style: { version: 8, sources: { osm: { type: 'raster', tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'], tileSize: 256, attribution: '© OpenStreetMap contributors' } }, layers: [{ id: 'osm', type: 'raster', source: 'osm' }] }, center, zoom: 12 });
map.addControl(new maplibregl.NavigationControl(), 'top-right');
const bounds = new maplibregl.LngLatBounds();
events.forEach(event => {
const popup = new maplibregl.Popup({ offset: 20 }).setHTML(`${escapeHtml(event.title)}
${escapeHtml(event.venue)}
View event`);
new maplibregl.Marker({ color: '#dd5b32' }).setLngLat([event.longitude, event.latitude]).setPopup(popup).addTo(map);
bounds.extend([event.longitude, event.latitude]);
});
if (events.length > 1) map.fitBounds(bounds, { padding: 60, maxZoom: 14 });
}
function escapeHtml(value) {
const node = document.createElement('div'); node.textContent = value; return node.innerHTML;
}