/**
* config.js - A modular configuration component for the SL Transport Departures app
* Allows changing settings on the fly, such as orientation (portrait/landscape)
*/
class ConfigManager {
constructor(options = {}) {
// Default options
this.options = {
configButtonId: 'config-button',
configModalId: 'config-modal',
saveToLocalStorage: true,
defaultOrientation: 'normal',
defaultDarkMode: 'auto', // 'auto', 'on', or 'off'
...options
};
// Add updateBackgroundPreview function
this.updateBackgroundPreview = function() {
const preview = document.getElementById('background-preview');
const imageUrl = document.getElementById('background-image-url').value;
if (preview) {
if (imageUrl && imageUrl.trim() !== '') {
preview.innerHTML = `
`;
} else {
preview.innerHTML = '
Instructions: Click on a marker to select a transit stop. Zoom and pan to explore the map.
`;
document.body.appendChild(mapModal);
// Wait for DOM to be ready
await new Promise(resolve => setTimeout(resolve, 100));
// Initialize map centered on Stockholm
const map = L.map('map-container').setView([59.3293, 18.0686], 13);
// Add OpenStreetMap tiles
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
maxZoom: 19
}).addTo(map);
// Close handlers
const closeMap = () => {
map.remove();
document.body.removeChild(mapModal);
};
mapModal.querySelector('.map-modal-close').addEventListener('click', closeMap);
mapModal.querySelector('#map-close-button').addEventListener('click', closeMap);
mapModal.addEventListener('click', (e) => {
if (e.target === mapModal) closeMap();
});
// Load transit stops - search for common Stockholm areas
const loadSitesOnMap = async () => {
try {
// Start with focused search to avoid too many markers
const searchTerms = ['Ambassaderna'];
const allSites = new Map();
for (const term of searchTerms) {
try {
const response = await fetch(`/api/sites/search?q=${encodeURIComponent(term)}`);
const data = await response.json();
console.log(`Search "${term}" returned:`, data);
if (data.sites) {
data.sites.forEach(site => {
// Only add sites with valid coordinates from API
const lat = site.lat || site.latitude;
const lon = site.lon || site.longitude;
if (lat && lon && !isNaN(parseFloat(lat)) && !isNaN(parseFloat(lon))) {
if (!allSites.has(site.id)) {
allSites.set(site.id, {
id: site.id,
name: site.name,
lat: parseFloat(lat),
lon: parseFloat(lon)
});
}
} else {
console.log(`Site ${site.id} (${site.name}) missing coordinates, skipping`);
}
});
}
} catch (err) {
console.error(`Error searching for ${term}:`, err);
}
}
// Add known site with coordinates as fallback
const knownSites = [
{ id: '1411', name: 'Ambassaderna', lat: 59.3293, lon: 18.0686 }
];
knownSites.forEach(site => {
if (!allSites.has(site.id)) {
allSites.set(site.id, site);
}
});
const sitesArray = Array.from(allSites.values());
console.log(`Loading ${sitesArray.length} sites on map with coordinates:`, sitesArray);
if (sitesArray.length > 0) {
const markers = [];
sitesArray.forEach(site => {
const lat = site.lat;
const lon = site.lon;
if (!lat || !lon || isNaN(lat) || isNaN(lon)) {
console.warn(`Invalid coordinates for site ${site.id}, skipping`);
return;
}
// Create custom icon
const customIcon = L.divIcon({
className: 'custom-marker',
html: `