mobile ui
This commit is contained in:
@ -19,6 +19,10 @@ document.getElementById('sortSelect').addEventListener('change', (e) => {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initMap();
|
||||
initPrivacyModal();
|
||||
initMobilePopup();
|
||||
initPriceInputs();
|
||||
|
||||
console.log('Kleinanzeigen Karten-Suche initialized');
|
||||
console.log('API Base URL:', API_BASE_URL);
|
||||
console.log('Mobile view:', window.innerWidth < 768);
|
||||
});
|
||||
@ -46,11 +46,21 @@ function addMarker(listing) {
|
||||
|
||||
const marker = L.marker([listing.lat, listing.lon]).addTo(AppState.map);
|
||||
|
||||
const imageHtml = listing.image
|
||||
? `<img src="${listing.image}" style="width: 100%; max-height: 150px; object-fit: cover; margin: 8px 0;" alt="${listing.title}">`
|
||||
: '';
|
||||
// Check if mobile
|
||||
const isMobile = window.innerWidth < 768;
|
||||
|
||||
const popupContent = `
|
||||
if (isMobile) {
|
||||
// On mobile: open fullscreen popup
|
||||
marker.on('click', () => {
|
||||
showMobilePopup(listing);
|
||||
});
|
||||
} else {
|
||||
// On desktop: use regular leaflet popup
|
||||
const imageHtml = listing.image
|
||||
? `<img src="${listing.image}" style="width: 100%; max-height: 150px; object-fit: cover; margin: 8px 0;" alt="${listing.title}">`
|
||||
: '';
|
||||
|
||||
const popupContent = `
|
||||
<div style="min-width: 200px; 8px;">
|
||||
<strong style="font-size: 14px;">${listing.title}</strong><br>
|
||||
${imageHtml}
|
||||
@ -59,12 +69,43 @@ function addMarker(listing) {
|
||||
<a href="${listing.url}" target="_blank" style="color: #0066cc; text-decoration: none; font-weight: 600;">Link öffnen →</a>
|
||||
</div>
|
||||
`;
|
||||
marker.bindPopup(popupContent);
|
||||
marker.bindPopup(popupContent);
|
||||
|
||||
marker.on('click', () => {
|
||||
AppState.selectedListingId = listing.id;
|
||||
highlightSelectedListing();
|
||||
});
|
||||
marker.on('click', () => {
|
||||
AppState.selectedListingId = listing.id;
|
||||
highlightSelectedListing();
|
||||
});
|
||||
}
|
||||
|
||||
AppState.markers.push(marker);
|
||||
}
|
||||
|
||||
function showMobilePopup(listing) {
|
||||
const popup = document.getElementById('mobilePopup');
|
||||
const content = document.getElementById('mobilePopupContent');
|
||||
|
||||
const imageHtml = listing.image
|
||||
? `<img src="${listing.image}" class="popup-image" alt="${listing.title}">`
|
||||
: '';
|
||||
|
||||
const dateStr = listing.date_added ? new Date(listing.date_added).toLocaleDateString('de-DE') : 'Unbekannt';
|
||||
|
||||
content.innerHTML = `
|
||||
${imageHtml}
|
||||
<div class="popup-title">${listing.title}</div>
|
||||
<div class="popup-price">${listing.price} €</div>
|
||||
<div class="popup-meta">
|
||||
<div class="popup-meta-item">
|
||||
<span class="popup-meta-icon">📍</span>
|
||||
<span>${listing.address || listing.zip_code}</span>
|
||||
</div>
|
||||
<div class="popup-meta-item">
|
||||
<span class="popup-meta-icon">📅</span>
|
||||
<span>${dateStr}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a href="${listing.url}" target="_blank" class="popup-link">Inserat auf Kleinanzeigen.de öffnen</a>
|
||||
`;
|
||||
|
||||
popup.classList.add('show');
|
||||
}
|
||||
109
web/js/ui.js
109
web/js/ui.js
@ -18,35 +18,55 @@ function showStatus(message, type = 'loading') {
|
||||
}
|
||||
|
||||
function updateProgress(current, total) {
|
||||
const progressInfo = document.getElementById('progressInfo');
|
||||
const progressFill = progressInfo.querySelector('.progress-fill');
|
||||
const progressText = progressInfo.querySelector('.progress-text');
|
||||
const etaText = progressInfo.querySelector('.eta-text');
|
||||
const isMobile = window.innerWidth < 768;
|
||||
|
||||
if (total === 0) {
|
||||
progressInfo.classList.remove('active');
|
||||
return;
|
||||
}
|
||||
if (isMobile) {
|
||||
// Mobile progress bar
|
||||
const progressInfo = document.getElementById('progressInfo');
|
||||
const progressFill = progressInfo.querySelector('.progress-fill-mobile');
|
||||
const progressText = progressInfo.querySelector('.progress-text-mobile');
|
||||
|
||||
progressInfo.classList.add('active');
|
||||
const percentage = (current / total) * 100;
|
||||
progressFill.style.width = percentage + '%';
|
||||
progressText.textContent = `Inserate werden geladen: ${current}/${total}`;
|
||||
if (total === 0) {
|
||||
progressInfo.classList.remove('active');
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate ETA
|
||||
if (AppState.scrapeStartTime && current > 0) {
|
||||
const elapsed = (Date.now() - AppState.scrapeStartTime) / 1000;
|
||||
const avgTimePerListing = elapsed / current;
|
||||
const remaining = total - current;
|
||||
const etaSeconds = Math.round(avgTimePerListing * remaining);
|
||||
progressInfo.classList.add('active');
|
||||
const percentage = (current / total) * 100;
|
||||
progressFill.style.width = percentage + '%';
|
||||
progressText.textContent = `${current}/${total} Inserate`;
|
||||
} else {
|
||||
// Desktop progress bar
|
||||
const progressInfo = document.getElementById('progressInfoDesktop');
|
||||
const progressFill = progressInfo.querySelector('.progress-fill');
|
||||
const progressText = progressInfo.querySelector('.progress-text');
|
||||
const etaText = progressInfo.querySelector('.eta-text');
|
||||
|
||||
const minutes = Math.floor(etaSeconds / 60);
|
||||
const seconds = etaSeconds % 60;
|
||||
if (total === 0) {
|
||||
progressInfo.classList.remove('active');
|
||||
return;
|
||||
}
|
||||
|
||||
if (minutes > 0) {
|
||||
etaText.textContent = `Noch ca. ${minutes}m ${seconds}s`;
|
||||
} else {
|
||||
etaText.textContent = `Noch ca. ${seconds}s`;
|
||||
progressInfo.classList.add('active');
|
||||
const percentage = (current / total) * 100;
|
||||
progressFill.style.width = percentage + '%';
|
||||
progressText.textContent = `Inserate werden geladen: ${current}/${total}`;
|
||||
|
||||
// Calculate ETA
|
||||
if (AppState.scrapeStartTime && current > 0) {
|
||||
const elapsed = (Date.now() - AppState.scrapeStartTime) / 1000;
|
||||
const avgTimePerListing = elapsed / current;
|
||||
const remaining = total - current;
|
||||
const etaSeconds = Math.round(avgTimePerListing * remaining);
|
||||
|
||||
const minutes = Math.floor(etaSeconds / 60);
|
||||
const seconds = etaSeconds % 60;
|
||||
|
||||
if (minutes > 0) {
|
||||
etaText.textContent = `Noch ca. ${minutes}m ${seconds}s`;
|
||||
} else {
|
||||
etaText.textContent = `Noch ca. ${seconds}s`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -70,6 +90,9 @@ function formatDate(dateString) {
|
||||
}
|
||||
|
||||
function renderResults(listings) {
|
||||
// Only render on desktop
|
||||
if (window.innerWidth < 768) return;
|
||||
|
||||
const resultsList = document.getElementById('resultsList');
|
||||
const resultsCount = document.querySelector('.results-count');
|
||||
|
||||
@ -165,4 +188,42 @@ function initPrivacyModal() {
|
||||
modal.classList.remove('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Mobile popup
|
||||
function initMobilePopup() {
|
||||
const closeBtn = document.getElementById('mobilePopupClose');
|
||||
const popup = document.getElementById('mobilePopup');
|
||||
|
||||
closeBtn.addEventListener('click', () => {
|
||||
popup.classList.remove('show');
|
||||
});
|
||||
}
|
||||
|
||||
// Format price inputs with € suffix
|
||||
function initPriceInputs() {
|
||||
const minPrice = document.getElementById('minPrice');
|
||||
const maxPrice = document.getElementById('maxPrice');
|
||||
|
||||
function formatPriceInput(input) {
|
||||
input.addEventListener('blur', (e) => {
|
||||
if (e.target.value) {
|
||||
// Store the numeric value
|
||||
const value = e.target.value.replace(/[^\d]/g, '');
|
||||
if (value) {
|
||||
e.target.dataset.value = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
input.addEventListener('focus', (e) => {
|
||||
// Show only numeric value when focused
|
||||
if (e.target.dataset.value) {
|
||||
e.target.value = e.target.dataset.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
formatPriceInput(minPrice);
|
||||
formatPriceInput(maxPrice);
|
||||
}
|
||||
Reference in New Issue
Block a user