diff --git a/ui/src/app/airport/[icao]/page.tsx b/ui/src/app/airport/[icao]/page.tsx index 6aad27f..9513297 100644 --- a/ui/src/app/airport/[icao]/page.tsx +++ b/ui/src/app/airport/[icao]/page.tsx @@ -1,14 +1,31 @@ -import { getAirport } from '@/api/airport'; -import Link from 'next/link'; +'use client'; -export default async function Page({ params }: { params: { icao: string } }) { - const { data: airport } = await getAirport({ icao: params.icao }); - return ( - <> -
-

{airport.full_name}

- Back -
- - ); +import { getAirport } from '@/api/airport'; +import { Airport } from '@/api/airport.types'; +import Link from 'next/link'; +import { useEffect, useState } from 'react'; + +export default function Page({ params }: { params: { icao: string } }) { + const [airport, setAirport] = useState(undefined); + + useEffect(() => { + async function loadAirport() { + const { data: airport } = await getAirport({ icao: params.icao }); + setAirport(airport); + } + loadAirport(); + }, []); + + if (airport) { + return ( + <> +
+

{airport.full_name}

+ Back +
+ + ); + } else { + return <>; + } } diff --git a/ui/src/app/page.tsx b/ui/src/app/page.tsx index 5685dc2..4761a4e 100644 --- a/ui/src/app/page.tsx +++ b/ui/src/app/page.tsx @@ -3,4 +3,5 @@ import Metar from '@/components/Metars'; export default function Page() { return ; + // return <>; } diff --git a/ui/src/components/Metars/MapTiles.tsx b/ui/src/components/Metars/MapTiles.tsx index e051acf..e1a490b 100644 --- a/ui/src/components/Metars/MapTiles.tsx +++ b/ui/src/components/Metars/MapTiles.tsx @@ -8,7 +8,7 @@ import { useEffect, useState } from 'react'; import ReactDOMServer from 'react-dom/server'; import { Marker, TileLayer, Tooltip, useMap, useMapEvents } from 'react-leaflet'; import MetarModal from './MetarModal'; -import { BsCircle, BsCircleFill } from 'react-icons/bs'; +import { Avatar, MantineProvider } from '@mantine/core'; export default function MapTiles() { const [isOpen, setIsOpen] = useState(false); @@ -60,20 +60,10 @@ export default function MapTiles() { } function iconSize() { - if (zoomLevel <= 4) { - return 'text-xs'; - } else if (zoomLevel <= 5) { - return 'text-sm'; - } else if (zoomLevel <= 6) { - return 'text-base'; - } else if (zoomLevel <= 7) { - return 'text-lg'; - } else if (zoomLevel <= 9) { - return 'text-2xl'; - } else if (zoomLevel <= 11) { - return 'text-3xl'; - } else if (zoomLevel >= 12) { - return 'text-4xl'; + if (zoomLevel <= 5) { + return 'xs'; + } else { + return 'sm'; } } @@ -81,46 +71,56 @@ export default function MapTiles() { if (airport.metar?.flight_category == 'VFR') { return new DivIcon({ html: ReactDOMServer.renderToString( -
- - V -
+ + + V + + ), className: 'metar-marker-icon' }); } else if (airport.metar?.flight_category == 'MVFR') { return new DivIcon({ html: ReactDOMServer.renderToString( -
- - M -
+ + + M + + ), className: 'metar-marker-icon' }); } else if (airport.metar?.flight_category == 'IFR') { return new DivIcon({ html: ReactDOMServer.renderToString( -
- - I -
+ + + I + + ), className: 'metar-marker-icon' }); } else if (airport.metar?.flight_category == 'LIFR') { return new DivIcon({ html: ReactDOMServer.renderToString( -
- - L -
+ + + L + + ), className: 'metar-marker-icon' }); } else { return new DivIcon({ - html: ReactDOMServer.renderToString(), + html: ReactDOMServer.renderToString( + + + U + + + ), className: 'metar-marker-icon' }); } diff --git a/ui/src/components/Metars/MetarMap.tsx b/ui/src/components/Metars/MetarMap.tsx index fb5310c..0360c5b 100644 --- a/ui/src/components/Metars/MetarMap.tsx +++ b/ui/src/components/Metars/MetarMap.tsx @@ -2,8 +2,9 @@ import { MapContainer } from 'react-leaflet'; import MapTiles from './MapTiles'; +import './metars.css'; -export default function Map({ className = '' }: { className?: string }) { +export default function Map() { return ( <> diff --git a/ui/src/components/Metars/MetarModal.tsx b/ui/src/components/Metars/MetarModal.tsx index ef0e8c7..76ed111 100644 --- a/ui/src/components/Metars/MetarModal.tsx +++ b/ui/src/components/Metars/MetarModal.tsx @@ -5,9 +5,16 @@ import { Metar } from '@/api/metar.types'; import { FaArrowsSpin, FaLocationArrow } from 'react-icons/fa6'; import Link from 'next/link'; import { AiFillStar, AiOutlineStar } from 'react-icons/ai'; -import { BsFillCloudRainFill, BsFillCloudRainHeavyFill, BsFillCloudSleetFill, BsFillCloudSnowFill, BsQuestionLg } from 'react-icons/bs'; +import { + BsFillCloudRainFill, + BsFillCloudRainHeavyFill, + BsFillCloudSleetFill, + BsFillCloudSnowFill, + BsQuestionLg +} from 'react-icons/bs'; import { useState } from 'react'; import { Grid, Modal, Tooltip } from '@mantine/core'; +import './metars.css'; interface MetarModalProps { airport: Airport; @@ -23,31 +30,17 @@ export default function MetarModal({ airport, isOpen, onClose }: MetarModalProps } return ( - - - {airport.icao} {airport.full_name} - - {isFavorite ? ( - handleFavorite(false)} - /> - ) : ( - handleFavorite(true)} - /> - )} - - } - opened={isOpen} - onClose={onClose} - className='select-none' - > + + + + {airport.icao} {airport.full_name} + + {isFavorite ? ( + handleFavorite(false)} /> + ) : ( + handleFavorite(true)} /> + )} +

{airport.metar && } diff --git a/ui/src/components/Metars/index.tsx b/ui/src/components/Metars/index.tsx index abd98e3..dc6c4a2 100644 --- a/ui/src/components/Metars/index.tsx +++ b/ui/src/components/Metars/index.tsx @@ -1,7 +1,7 @@ import { Metar } from '@/api/metar.types'; import dynamic from 'next/dynamic'; -export default async function Metar({ className = '' }: { className?: string }) { +export default async function Metar() { const Map = dynamic(() => import('@/components/Metars/MetarMap'), { loading: () => (
@@ -12,5 +12,5 @@ export default async function Metar({ className = '' }: { className?: string }) ), ssr: false }); - return ; + return ; } diff --git a/ui/src/components/Metars/metars.css b/ui/src/components/Metars/metars.css new file mode 100644 index 0000000..0755991 --- /dev/null +++ b/ui/src/components/Metars/metars.css @@ -0,0 +1,18 @@ +/* https://stackoverflow.com/questions/55291179/how-to-overlay-content-on-react-leaflet-z-index-problem */ +.leaflet-control { z-index: 0 !important} +.leaflet-pane { z-index: 0 !important} +.leaflet-top, .leaflet-bottom {z-index: 0 !important} + +.modal { + user-select: none; +} + +.modal .title { + display: flex; + width: 100%; + justify-content: space-between; +} + +.modal .star { + cursor: pointer; +} \ No newline at end of file diff --git a/ui/src/components/Topbar/index.tsx b/ui/src/components/Topbar/index.tsx index 17df695..7b190be 100644 --- a/ui/src/components/Topbar/index.tsx +++ b/ui/src/components/Topbar/index.tsx @@ -4,13 +4,14 @@ import Link from 'next/link'; import { AiOutlineUser } from 'react-icons/ai'; import { useState } from 'react'; import { getAirports } from '@/api/airport'; -import { useRouter } from 'next/navigation'; +// import { useRouter } from 'next/navigation'; import { Autocomplete, Avatar } from '@mantine/core'; +import './topbar.css'; export default function Topbar() { const [searchValue, setSearchValue] = useState(''); const [airports, setAirports] = useState<{ key: string; value: string; label: string }[]>([]); - const router = useRouter(); + // const router = useRouter(); async function onChange(value: string) { setSearchValue(value); @@ -24,28 +25,30 @@ export default function Topbar() { ); } - function onClick(value: string) { - router.push(`/airport/${value}`); - } + // function onClick(value: string) { + // router.push(`/airport/${value}`); + // } return ( -