diff --git a/frontend/src/components/HUDleftPoints.jsx b/frontend/src/components/HUDleftPoints.jsx index 96060f0..8902e64 100644 --- a/frontend/src/components/HUDleftPoints.jsx +++ b/frontend/src/components/HUDleftPoints.jsx @@ -444,21 +444,31 @@ function LogoBlock() { {showSortMenu && ( -
{/* Temperature sorting */}
@@ -636,6 +646,20 @@ function LogoBlock() { .boxwithpoints div::-webkit-scrollbar { display: none; } + .sort-menu::-webkit-scrollbar { + width: 8px; + } + .sort-menu::-webkit-scrollbar-track { + background: ${theme === 'light' ? 'rgba(0,0,0,0.1)' : 'rgba(255,255,255,0.1)'}; + border-radius: 10px; + } + .sort-menu::-webkit-scrollbar-thumb { + background: ${theme === 'light' ? 'rgba(0,0,0,0.3)' : 'rgba(255,255,255,0.3)'}; + border-radius: 10px; + } + .sort-menu::-webkit-scrollbar-thumb:hover { + background: ${theme === 'light' ? 'rgba(0,0,0,0.5)' : 'rgba(255,255,255,0.5)'}; + } ` }} /> {filteredList.map((item, index) => ( diff --git a/frontend/src/components/MapComponent.jsx b/frontend/src/components/MapComponent.jsx index 2099a61..fa4bd95 100644 --- a/frontend/src/components/MapComponent.jsx +++ b/frontend/src/components/MapComponent.jsx @@ -298,13 +298,31 @@ export default function MapComponent() { timeDifferences.push(`${diffHours}h gap`); } - // Create graph container + // Create graph container with responsive dimensions const graphContainer = document.createElement('div'); - graphContainer.style.width = '600px'; - graphContainer.style.height = '420px'; - graphContainer.style.padding = '15px'; + graphContainer.className = 'historical-data-container'; + + // Detect mobile viewport + const isMobile = window.innerWidth <= 768; + const isSmallMobile = window.innerWidth <= 480; + + // Set responsive dimensions + if (isSmallMobile) { + graphContainer.style.width = '340px'; + graphContainer.style.height = '300px'; + graphContainer.style.padding = '8px'; + } else if (isMobile) { + graphContainer.style.width = '450px'; + graphContainer.style.height = '350px'; + graphContainer.style.padding = '10px'; + } else { + graphContainer.style.width = '600px'; + graphContainer.style.height = '420px'; + graphContainer.style.padding = '15px'; + } + graphContainer.style.backgroundColor = window.globalTheme === 'dark' ? '#1a1a1a' : '#ffffff'; - graphContainer.style.borderRadius = '12px'; + graphContainer.style.borderRadius = isMobile ? '8px' : '12px'; graphContainer.style.boxShadow = window.globalTheme === 'dark' ? '0 8px 32px rgba(0,0,0,0.5)' : '0 8px 32px rgba(0,0,0,0.15)'; @@ -313,8 +331,18 @@ export default function MapComponent() { const canvas = document.createElement('canvas'); canvas.style.width = '100%'; canvas.style.height = 'calc(100% - 40px)'; - canvas.width = 570; - canvas.height = 380; + + // Set canvas dimensions based on screen size + if (isSmallMobile) { + canvas.width = 320; + canvas.height = 240; + } else if (isMobile) { + canvas.width = 420; + canvas.height = 290; + } else { + canvas.width = 570; + canvas.height = 380; + } graphContainer.appendChild(canvas); console.log('Creating chart with time-based data:', timeBasedData); @@ -346,11 +374,11 @@ export default function MapComponent() { display: true, text: `Historical Data for ${name}`, font: { - size: 18, + size: isSmallMobile ? 14 : (isMobile ? 16 : 18), weight: 'bold' }, color: window.globalTheme === 'dark' ? '#fff' : '#333', - padding: 20 + padding: isSmallMobile ? 10 : (isMobile ? 15 : 20) }, legend: { display: false @@ -385,26 +413,35 @@ export default function MapComponent() { type: 'linear', // Use linear instead of time to avoid adapter issues position: 'bottom', title: { - display: true, + display: !isSmallMobile, // Hide title on very small screens text: 'Date & Time', color: window.globalTheme === 'dark' ? '#fff' : '#333', font: { - size: 14, + size: isSmallMobile ? 10 : (isMobile ? 12 : 14), weight: 'bold' } }, ticks: { color: window.globalTheme === 'dark' ? '#ccc' : '#666', - maxRotation: 45, + maxRotation: isMobile ? 45 : 45, font: { - size: 10 + size: isSmallMobile ? 8 : (isMobile ? 9 : 10) }, - maxTicksLimit: 5, // Limit to prevent overcrowding + maxTicksLimit: isSmallMobile ? 3 : (isMobile ? 4 : 5), // Fewer ticks on mobile callback: function(value) { // The value here is the actual timestamp (milliseconds) const date = new Date(value); if (isNaN(date.getTime())) return ''; // Invalid date - return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); + + // Mobile-friendly date formatting + if (isSmallMobile) { + return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); + } else if (isMobile) { + return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) + '\n' + + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); + } else { + return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); + } } }, grid: { @@ -413,18 +450,18 @@ export default function MapComponent() { }, y: { title: { - display: true, + display: !isSmallMobile, // Hide title on very small screens text: `Temperature (°${currentUnit})`, color: window.globalTheme === 'dark' ? '#fff' : '#333', font: { - size: 14, + size: isSmallMobile ? 10 : (isMobile ? 12 : 14), weight: 'bold' } }, ticks: { color: window.globalTheme === 'dark' ? '#ccc' : '#666', font: { - size: 11 + size: isSmallMobile ? 8 : (isMobile ? 9 : 11) }, callback: function(value) { return `${value}°${currentUnit}`; @@ -448,12 +485,14 @@ export default function MapComponent() { marker.chartData = sortedData; marker.chartContainer = graphContainer; // Store reference to the container - // Open popup + // Open popup with responsive sizing const popup = L.popup({ offset: popupOffset, - maxWidth: 650, - maxHeight: 470, - className: 'custom-popup' + maxWidth: isSmallMobile ? 360 : (isMobile ? 480 : 650), + maxHeight: isSmallMobile ? 320 : (isMobile ? 370 : 470), + className: 'custom-popup mobile-optimized-popup', + autoPan: true, + autoPanPadding: [10, 10] }) .setLatLng([lat, lon]) .setContent(graphContainer) @@ -466,6 +505,25 @@ export default function MapComponent() { console.log('Chart resized'); } }, 100); + + // Add resize handler for mobile orientation changes + const handleResize = () => { + if (chart && chart.resize) { + setTimeout(() => { + chart.resize(); + console.log('Chart resized after orientation change'); + }, 200); + } + }; + + window.addEventListener('resize', handleResize); + window.addEventListener('orientationchange', handleResize); + + // Store cleanup function for the resize handlers + marker._resizeCleanup = () => { + window.removeEventListener('resize', handleResize); + window.removeEventListener('orientationchange', handleResize); + }; }); // Add keyboard accessibility AFTER the click handler @@ -574,6 +632,10 @@ export default function MapComponent() { // Clear existing markers before adding new ones markersRef.current.forEach(({ marker }) => { + // Clean up resize handlers if they exist + if (marker._resizeCleanup) { + marker._resizeCleanup(); + } map.removeLayer(marker); }); markersRef.current = []; diff --git a/frontend/src/components/TempFilterModal.jsx b/frontend/src/components/TempFilterModal.jsx index 99daf68..712267d 100644 --- a/frontend/src/components/TempFilterModal.jsx +++ b/frontend/src/components/TempFilterModal.jsx @@ -224,7 +224,7 @@ function TempFilterModal({ backgroundColor: theme === 'light' ? '#34c759' : '#30D158', border: 'none', borderRadius: '0.35rem', - color: '#fff', + color: 'black', cursor: 'pointer', fontSize: '0.85rem', fontWeight: '600', diff --git a/frontend/src/styles/MapView.css b/frontend/src/styles/MapView.css index d524fd8..6b38098 100644 --- a/frontend/src/styles/MapView.css +++ b/frontend/src/styles/MapView.css @@ -176,4 +176,107 @@ .temp-label[data-temp-category="hot"] { border-left: 4px solid #ff3b30 !important; -} \ No newline at end of file + +} + +/* Mobile-optimized popup styles */ +.mobile-optimized-popup .leaflet-popup-content-wrapper { + border-radius: 8px !important; + overflow: hidden !important; +} + +.mobile-optimized-popup .leaflet-popup-content { + margin: 0 !important; + padding: 0 !important; + width: auto !important; + height: auto !important; +} + +.historical-data-container { + position: relative !important; + overflow: hidden !important; + box-sizing: border-box !important; +} + +/* Mobile responsive adjustments */ +@media (max-width: 768px) { + .leaflet-popup-content-wrapper { + max-width: 95vw !important; + max-height: 70vh !important; + } + + .mobile-optimized-popup .leaflet-popup-content-wrapper { + border-radius: 6px !important; + } + + .historical-data-container { + min-height: 280px !important; + } + + + /* Adjust popup close button for mobile */ + .leaflet-popup-close-button { + padding: 8px !important; + font-size: 18px !important; + width: 32px !important; + height: 32px !important; + line-height: 16px !important; + } +} + +@media (max-width: 568px) { + /* Move legend further up on small mobile devices */ + .legend { + top: 36% !important; + } +} + +@media (max-width: 480px) { + .leaflet-popup-content-wrapper { + max-width: 98vw !important; + max-height: 60vh !important; + } + + .mobile-optimized-popup .leaflet-popup-content-wrapper { + border-radius: 4px !important; + } + + .historical-data-container { + min-height: 240px !important; + } + + + + /* Make popup close button more touch-friendly */ + .leaflet-popup-close-button { + padding: 10px !important; + font-size: 20px !important; + width: 36px !important; + height: 36px !important; + line-height: 16px !important; + background: rgba(0, 0, 0, 0.1) !important; + border-radius: 50% !important; + } + + .leaflet-popup-close-button:hover { + background: rgba(0, 0, 0, 0.2) !important; + } +} + +/* Touch-friendly chart interactions */ +@media (pointer: coarse) { + .historical-data-container canvas { + touch-action: pan-x pan-y !important; + } +} + +/* Landscape orientation adjustments for mobile */ +@media (max-width: 768px) and (orientation: landscape) { + .historical-data-container { + max-height: 50vh !important; + } + + .leaflet-popup-content-wrapper { + max-height: 60vh !important; + } +}