Updated metar checking
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { Badge, Box, Divider, Drawer, Group, Tabs, TabsList, Text, Tooltip } from '@mantine/core';
|
||||
import { Airport, AirportCategory } from '@lib/airport.types.ts';
|
||||
import { getMarkerColor, Metar } from '@lib/metar.types.ts';
|
||||
import { forwardRef, useEffect, useState } from 'react';
|
||||
import { forwardRef, ReactNode, useEffect, useState } from 'react';
|
||||
import { getMetars } from '@lib/metar.ts';
|
||||
import { useMediaQuery } from '@mantine/hooks';
|
||||
|
||||
@@ -56,7 +56,9 @@ export default function AirportDrawer({
|
||||
>
|
||||
<Drawer.Content>
|
||||
<Drawer.Header>
|
||||
<Drawer.Title><Text size={'xl'}>{airport.name}</Text></Drawer.Title>
|
||||
<Drawer.Title>
|
||||
<Text size={'xl'}>{airport.name}</Text>
|
||||
</Drawer.Title>
|
||||
<Drawer.CloseButton />
|
||||
</Drawer.Header>
|
||||
<Drawer.Body>
|
||||
@@ -72,7 +74,7 @@ export default function AirportDrawer({
|
||||
padding: '10px'
|
||||
}}
|
||||
>
|
||||
<Badge size="lg" color={metarColor}>
|
||||
<Badge size='lg' color={metarColor}>
|
||||
{metar.flight_category}
|
||||
</Badge>
|
||||
{/*<Text style={{ color: metarColor }}>{metar.flight_category}</Text>*/}
|
||||
@@ -86,10 +88,12 @@ export default function AirportDrawer({
|
||||
<Tabs.Tab value={'info'}>Info</Tabs.Tab>
|
||||
<Tabs.Tab value={'weather'}>Weather</Tabs.Tab>
|
||||
</TabsList>
|
||||
<Tabs.Panel value={'info'}><AirportInfo airport={airport}/></Tabs.Panel>
|
||||
{airport.latest_metar && (
|
||||
<Tabs.Panel value={'weather'}><WeatherInfo metar={airport.latest_metar} /></Tabs.Panel>
|
||||
)}
|
||||
<Tabs.Panel value={'info'}>
|
||||
<AirportInfo airport={airport} />
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel value={'weather'}>
|
||||
<WeatherInfo metar={airport.latest_metar} />
|
||||
</Tabs.Panel>
|
||||
</Tabs>
|
||||
</Box>
|
||||
</Drawer.Body>
|
||||
@@ -98,53 +102,62 @@ export default function AirportDrawer({
|
||||
);
|
||||
}
|
||||
|
||||
function AirportInfo({ airport }: { airport: Airport }) {
|
||||
return (<div>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
padding: 'var(--mantine-spacing-sm) var(--mantine-spacing-lg)',
|
||||
borderTop: '1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5))'
|
||||
}}>
|
||||
<div>
|
||||
<Text size="xs" color="dimmed">
|
||||
ICAO
|
||||
</Text>
|
||||
<Text fw={500} size="sm">
|
||||
{airport.icao}
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text size="xs" color="dimmed">
|
||||
IATA
|
||||
</Text>
|
||||
<Text fw={500} size="sm">
|
||||
{airport.iata}
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text size="xs" color="dimmed">
|
||||
Local
|
||||
</Text>
|
||||
<Text fw={500} size="sm">
|
||||
{airport.local}
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text size="xs" color="dimmed">
|
||||
Category
|
||||
</Text>
|
||||
<Text fw={500} size="sm">
|
||||
{airportCategoryToText(airport.category)}
|
||||
</Text>
|
||||
</div>
|
||||
function AirportInfoSlot({ title, value, units }: { title: string; value: string | number; units?: string }) {
|
||||
return (
|
||||
<div>
|
||||
<Text size='xs' color='dimmed'>
|
||||
{title}
|
||||
</Text>
|
||||
<Text fw={500} size='sm'>
|
||||
{value}
|
||||
{units}
|
||||
</Text>
|
||||
</div>
|
||||
<Divider />
|
||||
</div>);
|
||||
);
|
||||
}
|
||||
|
||||
function WeatherInfo({ metar }: { metar: Metar }) {
|
||||
return <>{metar.raw_text}</>
|
||||
function AirportInfoRow({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignContent: 'center',
|
||||
padding: 'var(--mantine-spacing-sm) var(--mantine-spacing-lg)',
|
||||
borderTop: '1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5))'
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AirportInfo({ airport }: { airport: Airport }) {
|
||||
return (
|
||||
<div>
|
||||
<AirportInfoRow>
|
||||
<AirportInfoSlot title={'ICAO'} value={airport.icao} />
|
||||
<AirportInfoSlot title={'IATA'} value={airport.iata} />
|
||||
<AirportInfoSlot title={'LOCAL'} value={airport.local} />
|
||||
<AirportInfoSlot title={'Category'} value={airportCategoryToText(airport.category)} />
|
||||
</AirportInfoRow>
|
||||
<AirportInfoRow>
|
||||
<AirportInfoSlot title={'Latitude'} value={airport.latitude} units={'°'} />
|
||||
<AirportInfoSlot title={'Longitude'} value={airport.longitude} units={'°'} />
|
||||
<AirportInfoSlot title={'Elevation'} value={airport.elevation_ft} units={' ft'} />
|
||||
Zoom To
|
||||
</AirportInfoRow>
|
||||
<Divider />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function WeatherInfo({ metar }: { metar?: Metar }) {
|
||||
if (metar) {
|
||||
return <>{metar.raw_text}</>;
|
||||
} else {
|
||||
return <>No METAR observation available</>;
|
||||
}
|
||||
}
|
||||
|
||||
function airportCategoryToText(category: AirportCategory): string {
|
||||
@@ -168,20 +181,26 @@ function airportCategoryToText(category: AirportCategory): string {
|
||||
}
|
||||
}
|
||||
|
||||
const TimeSince = forwardRef<HTMLParagraphElement, { date: string }>(
|
||||
({ date }, ref) => {
|
||||
const inputDate = new Date(date);
|
||||
// @ts-expect-error doing arithmetic with dates
|
||||
const seconds = Math.floor((new Date() - inputDate) / 1000);
|
||||
const TimeSince = forwardRef<HTMLParagraphElement, { date: string }>(({ date }, ref) => {
|
||||
const inputDate = new Date(date);
|
||||
// @ts-expect-error doing arithmetic with dates
|
||||
const seconds = Math.floor((new Date() - inputDate) / 1000);
|
||||
|
||||
if (seconds < 60) {
|
||||
const content = seconds + (seconds === 1 ? " second ago" : " seconds ago");
|
||||
return <Text ref={ref} style={{ userSelect: 'none' }} >{content}</Text>;
|
||||
} else {
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const content = minutes + (minutes === 1 ? " minute ago" : " minutes ago");
|
||||
// If more than 60 minutes have passed, set the text color to yellow
|
||||
return <Text ref={ref} style={{ color: minutes >= 60 ? '#fca903' : undefined, userSelect: 'none' }}>{content}</Text>;
|
||||
}
|
||||
if (seconds < 60) {
|
||||
const content = seconds + (seconds === 1 ? ' second ago' : ' seconds ago');
|
||||
return (
|
||||
<Text ref={ref} style={{ userSelect: 'none' }}>
|
||||
{content}
|
||||
</Text>
|
||||
);
|
||||
} else {
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const content = minutes + (minutes === 1 ? ' minute ago' : ' minutes ago');
|
||||
// If more than 60 minutes have passed, set the text color to yellow
|
||||
return (
|
||||
<Text ref={ref} style={{ color: minutes >= 60 ? '#fca903' : undefined, userSelect: 'none' }}>
|
||||
{content}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ export default function AirportMarker({
|
||||
index,
|
||||
airport,
|
||||
setAirport,
|
||||
selectedLayer,
|
||||
selectedLayer
|
||||
}: {
|
||||
index: number;
|
||||
airport: Airport;
|
||||
@@ -28,7 +28,7 @@ export default function AirportMarker({
|
||||
eventHandlers={{
|
||||
click: () => setAirport(airport),
|
||||
mouseover: () => markerRef.current?.openPopup(),
|
||||
mouseout: () => markerRef.current?.closePopup(),
|
||||
mouseout: () => markerRef.current?.closePopup()
|
||||
}}
|
||||
>
|
||||
<Popup closeButton={false} autoPan={false} interactive={false}>
|
||||
|
||||
@@ -155,9 +155,7 @@ export function Header() {
|
||||
)}
|
||||
</Group>
|
||||
)}
|
||||
{isMobile && (
|
||||
<Burger opened={opened} onClick={toggle} size='sm' />
|
||||
)}
|
||||
{isMobile && <Burger opened={opened} onClick={toggle} size='sm' />}
|
||||
</Group>
|
||||
</header>
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user