diff --git a/src/features/flights-map/components/FlightsMapStartPage.scss b/src/features/flights-map/components/FlightsMapStartPage.scss new file mode 100644 index 00000000..3536126a --- /dev/null +++ b/src/features/flights-map/components/FlightsMapStartPage.scss @@ -0,0 +1,136 @@ +@use "../../../styles/variables" as vars; +@use "../../../styles/fonts" as fonts; +@use "../../../styles/colors" as colors; +@use "../../../styles/screen" as screen; +@use "../../../styles/shadows" as shadows; + +.flights-map-start-page { + section.frame { + padding: 0; + overflow: hidden; + } + + .page-title { + width: auto; + display: inline-block; + max-width: 100%; + white-space: normal !important; + } + + h1.text--white { + @include fonts.font-overflow(); + + @include screen.smTablet { + font-size: fonts.$font-size-xxxl--tablet; + margin-bottom: vars.$space-m + vars.$space-s; + overflow: visible; + white-space: normal; + } + + @include screen.mobile { + font-size: fonts.$font-size-xxxl--mobile; + margin-bottom: vars.$space-m + vars.$space-s; + margin-top: vars.$space-m; + overflow: visible; + white-space: normal; + } + } + + .flights-map-start { + &__map-wrapper { + position: relative; + min-height: 500px; + } + + &__map { + width: 100%; + height: 500px; + } + + &__loader, + &__error, + &__empty { + padding: vars.$space-xl; + text-align: center; + color: colors.$light-gray; + } + + &__error { + color: colors.$red; + } + } +} + +// Filter panel styling for content-left column +.flights-map-filter { + @include shadows.box-shadow-small; + background-color: colors.$white; + border-radius: vars.$border-radius; + padding: vars.$space-xl; + display: flex; + flex-direction: column; + gap: vars.$space-m; + + &__field { + display: flex; + flex-direction: column; + gap: vars.$space-s; + + label { + @include fonts.font-small(colors.$gray); + margin-bottom: vars.$label-margin-bottom; + } + + input[type="text"], + input[type="date"] { + @include shadows.control-border-shadow(); + height: vars.$standard-button-height; + padding: 0 vars.$space-l; + padding-left: vars.$space-m !important; + font-size: fonts.$font-size-l; + font-weight: fonts.$font-regular; + color: colors.$text-color; + width: 100%; + transition-duration: 0.2s; + @include fonts.font-overflow(); + + &:focus { + outline: none; + border-color: colors.$blue-light; + box-shadow: 0 0 0 0.2em colors.$focus-shadow; + } + } + } + + &__exchange { + align-self: center; + width: vars.$standard-button-height; + height: vars.$standard-button-height; + background: colors.$white; + @include shadows.control-border-shadow(); + cursor: pointer; + font-size: 20px; + display: flex; + align-items: center; + justify-content: center; + transition-duration: 0.2s; + + &:hover { + border-color: colors.$blue-light; + } + } + + &__toggles { + display: flex; + flex-direction: column; + gap: vars.$space-s; + + label { + display: flex; + align-items: center; + gap: vars.$space-s; + cursor: pointer; + @include fonts.font-small(colors.$gray); + } + } +} diff --git a/src/features/flights-map/components/FlightsMapStartPage.tsx b/src/features/flights-map/components/FlightsMapStartPage.tsx index d6809a5b..aa3e4bec 100644 --- a/src/features/flights-map/components/FlightsMapStartPage.tsx +++ b/src/features/flights-map/components/FlightsMapStartPage.tsx @@ -4,10 +4,15 @@ * Manages filter state, drives the map and calendar hooks, and renders * the filter panel + map canvas + loading/empty overlays. * + * Uses PageLayout for the two-column layout matching the Angular version. + * * @module */ import { type FC, lazy, Suspense, useState, useCallback, useMemo } from "react"; +import { useTranslation } from "@/i18n/provider.js"; +import { PageLayout } from "@/ui/layout/PageLayout.js"; +import { PageTabs } from "@/ui/layout/PageTabs.js"; import { ClientOnly } from "./ClientOnly.js"; import { FlightsMapFilter } from "./FlightsMapFilter.js"; import { useFlightsMapSearch } from "../hooks/useFlightsMapSearch.js"; @@ -20,6 +25,7 @@ import type { IMapMarker, IMapPolyline, } from "../types.js"; +import "./FlightsMapStartPage.scss"; const MapCanvas = lazy(() => import("./MapCanvas.js").then((m) => ({ default: m.MapCanvas })), @@ -54,6 +60,7 @@ function addMonthsYyyymmdd(base: string, months: number): string { export const FlightsMapStartPage: FC = () => { const env = getEnv(); + const { t } = useTranslation(); const [filterState, setFilterState] = useState({ connections: false, @@ -121,72 +128,84 @@ export const FlightsMapStartPage: FC = () => { const tileUrl = `${env.API_BASE_URL}/tiles/{z}/{x}/{y}.png`; return ( -
-

Flight Map

- - - -
- - Loading map... -
- } - > - - Loading map... -
- } - > - - - - - {loading && ( -
- Loading routes... -
- )} - - {!loading && error && ( -
- Failed to load routes. Please try again. -
- )} - - {!loading && - !error && - searchParams !== null && - routes.length === 0 && ( -
+ + } + title={ +

+ {t("FLIGHTS-MAP.TITLE")} +

+ } + contentLeft={ + + } + > +
+
+ + Loading map... +
+ } > - No directions found. -
- )} - + + Loading map... + + } + > + + + + + {loading && ( +
+ Loading routes... +
+ )} + + {!loading && error && ( +
+ Failed to load routes. Please try again. +
+ )} + + {!loading && + !error && + searchParams !== null && + routes.length === 0 && ( +
+ No directions found. +
+ )} + + + ); };