This commit is contained in:
2025-09-19 19:33:53 -04:00
parent 8844ee75fe
commit 84312d0b50
36 changed files with 799 additions and 694 deletions

View File

@@ -1,12 +1,12 @@
/* Set up Flexbox layout */
.App {
display: flex;
flex-direction: column;
html, body, #root {
height: 100%;
}
.map-wrapper {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
.leaflet-container {

View File

@@ -6,7 +6,6 @@ import markerIcon2x from 'leaflet/dist/images/marker-icon-2x.png';
import markerIcon from 'leaflet/dist/images/marker-icon.png';
import markerShadow from 'leaflet/dist/images/marker-shadow.png';
import L from 'leaflet';
import { Header } from '@components/Header';
import AirportLayer from '@components/AirportLayer.tsx';
import { useEffect, useState } from 'react';
import { Airport } from '@lib/airport.types.ts';
@@ -16,7 +15,6 @@ import { IconBuildingAirport, IconRadar } from '@tabler/icons-react';
import { GroupControl } from '@components/GroupControl.tsx';
import { AirportDrawer } from '@components/AirportDrawer';
import { LocateControl } from '@components/LocateControl.tsx';
import { Footer } from '@components/Footer';
// Fix Leaflet's default icon path issues with Webpack
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
@@ -91,57 +89,54 @@ function App() {
}
return (
<div className='App'>
<Header />
<div className='map-wrapper'>
<MapContainer
className='leaflet-container'
attributionControl={false}
center={defaultCenter}
zoom={defaultZoom}
minZoom={3}
maxZoom={19}
maxBounds={[
[-85.06, -181],
[85.06, 181]
<div className='map-wrapper' style={{ flex: 1, minHeight: 0 }}>
<MapContainer
style={{ height: '100%', width: '100%' }}
className='leaflet-container'
attributionControl={false}
center={defaultCenter}
zoom={defaultZoom}
minZoom={3}
maxZoom={19}
maxBounds={[
[-85.06, -181],
[85.06, 181]
]}
scrollWheelZoom={true}
zoomControl={false}
markerZoomAnimation={false}
>
<AirportDrawer airport={airport} setAirport={setAirport} />
<LayersControl>
{layerMap.map((layer, index) => (
<LayersControl.BaseLayer key={index} checked={selectedLayerIndex === `${index}`} name={layer.name}>
<TileLayer url={layer.url} />
</LayersControl.BaseLayer>
))}
</LayersControl>
<ScaleControl />
{rainViewerUrl && showRadar && <TileLayer url={rainViewerUrl} opacity={0.5} zIndex={10} />}
<ZoomControl position={'bottomright'} />
<AirportLayer setAirport={setAirport} selectedLayer={selectedLayer} showNoMetar={showNoMetar} />
<BaseLayerChangeHandler />
<LocateControl />
<GroupControl
buttons={[
{
title: 'Toggle radar',
active: showRadar,
onClick: toggleRadar,
icon: <IconRadar />
},
{
title: 'Toggle nonMETAR airports',
active: showNoMetar,
onClick: toggleShowNoMetar,
icon: <IconBuildingAirport />
}
]}
scrollWheelZoom={true}
zoomControl={false}
markerZoomAnimation={false}
>
<AirportDrawer airport={airport} setAirport={setAirport} />
<LayersControl>
{layerMap.map((layer, index) => (
<LayersControl.BaseLayer key={index} checked={selectedLayerIndex === `${index}`} name={layer.name}>
<TileLayer url={layer.url} />
</LayersControl.BaseLayer>
))}
</LayersControl>
<ScaleControl />
{rainViewerUrl && showRadar && <TileLayer url={rainViewerUrl} opacity={0.5} zIndex={10} />}
<ZoomControl position={'bottomright'} />
<AirportLayer setAirport={setAirport} selectedLayer={selectedLayer} showNoMetar={showNoMetar} />
<BaseLayerChangeHandler />
<LocateControl />
<GroupControl
buttons={[
{
title: 'Toggle radar',
active: showRadar,
onClick: toggleRadar,
icon: <IconRadar />
},
{
title: 'Toggle nonMETAR airports',
active: showNoMetar,
onClick: toggleShowNoMetar,
icon: <IconBuildingAirport />
}
]}
/>
</MapContainer>
</div>
<Footer />
/>
</MapContainer>
</div>
);
}

View File

@@ -1,4 +1,3 @@
import { Header } from '@components/Header';
import { useUserContext } from '@components/context/UserContext.tsx';
import { AirportTable } from '@components/AirportTable';
import { AirportDrop } from '@components/AirportDrop';
@@ -13,7 +12,6 @@ export function Administration() {
return (
<>
<Header />
<AirportTable />
<AirportDrop />
</>

View File

@@ -71,7 +71,7 @@ export function AirportDrawer({
onClose={() => setAirport(null)}
withinPortal
zIndex={1000}
styles={{ root: { padding: 0, margin: 0, width: 0, height: 0, backgroundColor: 'red' } }}
styles={{ root: { padding: 0, margin: 0, width: 0, height: 0 } }}
padding='md'
size={isMobile ? '100%' : 'md'}
position='left'

View File

@@ -1,9 +1,11 @@
.footer {
background: #32495f;
height: 48px;
background: #2b2d31;
border-top: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
}
.inner {
height: 48px;
display: flex;
justify-content: space-between;
align-items: center;

View File

@@ -40,7 +40,7 @@ export function Footer() {
</a>
</Text>
<Divider orientation={'vertical'} />
<Text size='sm'>© {new Date().getFullYear()} Aviation Data</Text>
<Text size='sm'>© {new Date().getFullYear()} bensherriff.com</Text>
</Group>
{!isMobile && (
<Group gap='xs' justify='flex-end' wrap='nowrap'>

View File

@@ -2,7 +2,7 @@
height: 56px;
padding: 0 16px 0 16px;
/*background-color: var(--mantine-color-body);*/
background: #32495f;
background: #2b2d31;
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
}

View File

@@ -1,4 +1,4 @@
import { Avatar, Box, Burger, Button, Group, Text } from '@mantine/core';
import { Avatar, Box, Burger, Button, Drawer, Group, Text } from '@mantine/core';
import { useDisclosure, useMediaQuery, useToggle } from '@mantine/hooks';
import classes from './Header.module.css';
import { HeaderModal } from '@components/Header/HeaderModal.tsx';
@@ -146,7 +146,7 @@ export function Header() {
<Group justify='space-between' h='100%'>
<Group align='center' gap='xs'>
<Link to='/'>
<Avatar src='/logo.svg' alt='logo' onClick={toggle} />
<Avatar src='/logo.svg' alt='logo' />
</Link>
<Text size={'xl'}>Aviation Data</Text>
</Group>
@@ -173,6 +173,21 @@ export function Header() {
</Group>
</header>
</Box>
<Drawer.Root
opened={opened}
onClose={toggle}
zIndex={1001}
padding="md"
size="40%"
position="right"
>
<Drawer.Overlay />
<Drawer.Content>
<Drawer.Body>
test
</Drawer.Body>
</Drawer.Content>
</Drawer.Root>
<HeaderModal type={modalType} toggle={modalToggle} login={loginUser} register={registerUser} />
</>
);

View File

@@ -0,0 +1,29 @@
import { AppShell } from '@mantine/core';
import { Outlet } from 'react-router';
import { Header } from '@components/Header';
import { Footer } from '@components/Footer';
export function MainLayout() {
return (
<AppShell padding={0} mih={'100dvh'}>
<AppShell.Header>
<Header />
</AppShell.Header>
<AppShell.Main p={0} style={{ display: 'flex', minHeight: 0 }}>
<div
style={{
display: 'flex',
flexDirection: 'column',
flex: 1,
minHeight: 0
}}
>
<Outlet />
</div>
</AppShell.Main>
<AppShell.Footer>
<Footer />
</AppShell.Footer>
</AppShell>
);
}

View File

@@ -1,4 +1,3 @@
import { Header } from '@components/Header';
import { useUserContext } from '@components/context/UserContext.tsx';
import { NotFound } from '@components/NotFound';
@@ -11,7 +10,6 @@ export function Profile() {
return (
<>
<Header />
Todo: profile {user?.firstName}
</>
);

View File

@@ -1,3 +1,4 @@
import 'leaflet/dist/leaflet.css';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
@@ -9,6 +10,7 @@ import { BrowserRouter, Route, Routes } from 'react-router';
import { Profile } from '@components/Profile.tsx';
import { Administration } from '@components/Administration.tsx';
import { NotFound } from '@components/NotFound';
import { MainLayout } from '@components/MainLayout.tsx';
const theme = createTheme({
fontFamily: 'Inter, sans-serif'
@@ -21,9 +23,11 @@ createRoot(document.getElementById('root')!).render(
<Notifications zIndex={2000} />
<UserProvider>
<Routes>
<Route path='/' element={<App />} />
<Route path='/profile' element={<Profile />} />
<Route path='/administration' element={<Administration />} />
<Route path="/" element={<MainLayout />}>
<Route index element={<App />} />
<Route path='profile' element={<Profile />} />
<Route path='administration' element={<Administration />} />
</Route>
<Route path='*' element={<NotFound />} />
</Routes>
</UserProvider>