Updated UI

This commit is contained in:
2025-04-11 16:26:18 -04:00
parent d6412625d5
commit 05b5ceafe2
10 changed files with 135 additions and 34 deletions

View File

@@ -29,3 +29,39 @@ body,
height: 100%;
width: 100%;
}
.map-button {
position: absolute;
right: 12px;
z-index: 1000;
color: #000;
background: #fff;
border-radius: 3px;
border: 1px solid #ccc;
border-bottom-width: 2px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
height: 30px;
width: 30px;
text-align: center;
line-height: 30px; /* Vertically center text */
font-weight: bold;
cursor: pointer;
user-select: none;
transition: background-color 0.2s, color 0.2s;
}
.map-button.active {
background-color: #228be6;
color: #fff;
}
.map-button.active:hover {
background-color: #187ed7;
}
.map-button:hover {
background: #e6e6e6;
}

View File

@@ -1,4 +1,4 @@
import { MapContainer, TileLayer, ZoomControl } from 'react-leaflet';
import { LayersControl, MapContainer, TileLayer, useMapEvents, ZoomControl } from 'react-leaflet';
import '@mantine/core/styles.css';
import 'leaflet/dist/leaflet.css';
import './App.css';
@@ -12,8 +12,8 @@ import { useEffect, useState } from 'react';
import { Airport } from '@lib/airport.types.ts';
import AirportDrawer from '@components/AirportDrawer.tsx';
import { getWeatherMapUrl } from '@lib/rainViewer.ts';
import { Switch } from '@mantine/core';
import { IconRadar } from '@tabler/icons-react';
import Cookies from 'js-cookie';
// Fix Leaflet's default icon path issues with Webpack
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
@@ -26,13 +26,19 @@ L.Icon.Default.mergeOptions({
});
const openStreetMapUrl = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
const lightLayerUrl = 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png';
const darkLayerUrl = 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png';
// const dark1Url = 'https://maps.rainviewer.com/data/v3/5/10/11.pbf';
// const dark2Url = 'https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/tile/2/0/3.pbf';
const defaultZoom = 6;
const defaultCenter: L.LatLngExpression = [38.944444, -77.455833];
function App() {
const [airport, setAirport] = useState<Airport | null>(null);
const [rainViewerUrl, setRainViewerUrl] = useState<string | null>(null);
const [showRadar, setShowRadar] = useState<boolean>(false);
const initialRadarValue = Cookies.get('showRadar') === 'true';
const [showRadar, setShowRadar] = useState<boolean>(initialRadarValue);
const [baseLayer, setBaseLayer] = useState<string>(Cookies.get('selectedBaseLayer') || 'Open Street Map');
useEffect(() => {
if (showRadar) {
@@ -40,7 +46,25 @@ function App() {
setRainViewerUrl(url);
});
}
}, [showRadar])
}, [showRadar]);
function toggleRadar() {
setShowRadar(prev => {
const newValue = !prev;
Cookies.set('showRadar', newValue.toString(), { expires: 7 });
return newValue;
});
}
function BaseLayerChangeHandler() {
useMapEvents({
baselayerchange: (e) => {
setBaseLayer(e.name);
Cookies.set('selectedBaseLayer', e.name, { expires: 7 });
}
});
return null;
}
return (
<div className='App'>
@@ -61,23 +85,27 @@ function App() {
scrollWheelZoom={true}
zoomControl={false}
>
<LayersControl>
<LayersControl.BaseLayer checked={baseLayer === 'Open Street Map'} name={'Open Street Map'}>
<TileLayer url={openStreetMapUrl} />
</LayersControl.BaseLayer>
<LayersControl.BaseLayer checked={baseLayer === 'Carto Light'} name={'Carto Light'}>
<TileLayer url={lightLayerUrl} />
</LayersControl.BaseLayer>
<LayersControl.BaseLayer checked={baseLayer === 'Carto Dark'} name={'Carto Dark'}>
<TileLayer url={darkLayerUrl} />
</LayersControl.BaseLayer>
</LayersControl>
{rainViewerUrl && showRadar && <TileLayer url={rainViewerUrl} opacity={0.5} zIndex={5} />}
<ZoomControl position={'bottomright'} />
<TileLayer url={openStreetMapUrl} />
{ rainViewerUrl && showRadar && (
<TileLayer url={rainViewerUrl} opacity={0.5} zIndex={5} />
)}
<AirportLayer setAirport={setAirport} />
<BaseLayerChangeHandler />
</MapContainer>
<div style={{
position: 'absolute', top: '100px', right: '10px', zIndex: 1000, backgroundColor: '#fff',
borderRadius: '8px', boxShadow: '0 2px 6px rgba(0,0,0,0.15)', padding: '10px'
}}>
<Switch
label="Radar"
checked={showRadar}
onChange={(event) => setShowRadar(event.currentTarget.checked)}
/>
</div>
<IconRadar
onClick={toggleRadar}
style={{ bottom: '80px' }}
className={`map-button ${showRadar ? 'active' : ''}`}
/>
</div>
</div>
);

View File

@@ -84,9 +84,9 @@ export default function AirportLayer({ setAirport }: { setAirport: (airport: Air
return (
<>
{sortedAirports.map((airport, index) => {
return <AirportMarker airport={airport} index={index} setAirport={setAirport} />;
})}
{sortedAirports.map((airport, index) => (
<AirportMarker key={index} airport={airport} index={index} setAirport={setAirport} />
))}
</>
);
}

View File

@@ -126,9 +126,6 @@ export function Header() {
return false;
}
console.log(Cookies.get('logged_in'));
console.log(Cookies.get('session'));
return (
<>
<Box>

View File

@@ -13,22 +13,19 @@ async function getWeatherMaps(): Promise<WeatherMaps | undefined> {
}
}
// const rainViewerUrl = 'https://tilecache.rainviewer.com/v2/radar/1744386000/256/{z}/{x}/{y}/2/1_1.png';
// const rainViewerUrl = 'https://tilecache.rainviewer.com/v2/radar/1744386000/256/10/290/391/2/1_1.png'
// https://api.rainviewer.com/public/weather-maps.json
export async function getWeatherMapUrl(): Promise<string | null> {
const weatherMaps = await getWeatherMaps();
if (weatherMaps != undefined) {
let url = weatherMaps.host;
// url = 'https://cdn.rainviewer.com';
let latest = "";
if (weatherMaps.radar.nowcast.length > 0) {
latest = weatherMaps.radar.nowcast[weatherMaps.radar.nowcast.length - 1].path;
} else if (weatherMaps.radar.past.length > 0) {
if (weatherMaps.radar.past.length > 0) {
latest = weatherMaps.radar.past[weatherMaps.radar.past.length - 1].path;
} else {
return null;
}
url += latest + "/256/{z}/{x}/{y}/2/1_1.png";
// url += latest + "/256/{z}/{x}/{y}/255/1_1_1_0.webp";
return url;
} else {
return null;