diff --git a/src/features/online-board/components/OnlineBoardFilter.tsx b/src/features/online-board/components/OnlineBoardFilter.tsx index c1fc1bc8..c94b8e15 100644 --- a/src/features/online-board/components/OnlineBoardFilter.tsx +++ b/src/features/online-board/components/OnlineBoardFilter.tsx @@ -44,7 +44,7 @@ export const OnlineBoardFilter: FC = () => { const routeParams = useParams<{ lang: string }>(); const lang = routeParams.lang ?? "ru"; - const [activeTab, setActiveTab] = useState("flight"); + const [activeTab, setActiveTab] = useState("route"); // Flight number fields const [flightNumber, setFlightNumber] = useState(""); diff --git a/src/features/online-board/components/OnlineBoardStartPage.tsx b/src/features/online-board/components/OnlineBoardStartPage.tsx index 132342da..e728e192 100644 --- a/src/features/online-board/components/OnlineBoardStartPage.tsx +++ b/src/features/online-board/components/OnlineBoardStartPage.tsx @@ -41,9 +41,7 @@ export const OnlineBoardStartPage: FC = () => { {t("BOARD.TITLE")} } - breadcrumbs={[ - { label: t("BOARD.TITLE") }, - ]} + breadcrumbs={[]} contentLeft={ <> diff --git a/src/features/schedule/components/ScheduleStartPage.tsx b/src/features/schedule/components/ScheduleStartPage.tsx index c6c0db1c..3cee8041 100644 --- a/src/features/schedule/components/ScheduleStartPage.tsx +++ b/src/features/schedule/components/ScheduleStartPage.tsx @@ -295,9 +295,7 @@ export const ScheduleStartPage: FC = () => { {t("SCHEDULE.TITLE")} } - breadcrumbs={[ - { label: t("SCHEDULE.TITLE"), url: `/${lang}/schedule` }, - ]} + breadcrumbs={[]} contentLeft={ <> {scheduleFilter} diff --git a/src/routes/error/[code]/page.scss b/src/routes/error/[code]/page.scss index bf97ea41..637171d4 100644 --- a/src/routes/error/[code]/page.scss +++ b/src/routes/error/[code]/page.scss @@ -12,8 +12,10 @@ display: flex; padding: 2rem; - & > * + * { - margin-left: 2rem; + // Match Angular: v-spacing(2rem) + h-spacing(2rem) + & > *:not(:last-child) { + margin-right: 2rem; + margin-bottom: 2rem; } @include screen.desktop { @@ -25,16 +27,16 @@ @include screen.mobile { flex-direction: column; - & > * + * { - margin-left: 0; - margin-top: 2rem; + & > *:not(:last-child) { + margin-right: 0; + margin-bottom: 2rem; } } } &__illustration { - flex: 0 0 30%; - min-height: 300px; + // Match Angular: flex: 30% (equivalent to flex: 0 1 30%) + flex: 30%; background-position: bottom; background-repeat: no-repeat; background-size: contain; @@ -48,21 +50,19 @@ &__code { font-size: 8rem; color: #a3a3a3; - line-height: 1; - margin: 0; } &__title { font-size: 3rem; color: colors.$text-color; - margin: 0; } &__content { - flex: 1 1 70%; + // Match Angular: flex: 70% + v-spacing(1rem) + flex: 70%; - & > * + * { - margin-top: 1rem; + & > *:not(:last-child) { + margin-bottom: 1rem; } @include screen.mobile { @@ -76,20 +76,85 @@ line-height: 1.5; } + // Search input — matches Angular error-page-search + &__search { + width: 100%; + + @include screen.desktop { + width: 17rem; + } + + margin-bottom: 1rem; + + &-control { + position: relative; + } + + &-icon { + position: absolute; + top: 0; + right: 0; + background: no-repeat; + background-image: url("/assets/img/icon--search.svg"); + width: 2.25rem; + height: 2.25rem; + background-position: center; + cursor: pointer; + + &:hover { + background-image: url("/assets/img/icon--search-blue.svg"); + } + } + + input { + font-size: 0.875rem; + box-sizing: border-box; + width: 100%; + height: 2.25rem; + padding: 0.25rem 0.5rem; + border: 1px solid #dfdfdf; + background: #fff; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + transition: all 0.2s; + outline: 0 solid transparent; + border-radius: 0.1875rem; + position: relative; + top: 0; + left: 0; + + &:focus { + border: 1px solid #b7d3f3; + box-shadow: 0 0.0625rem 0.1875rem #cad6e5; + } + } + } + &__actions { display: flex; padding: 2rem 0; flex-wrap: wrap; - gap: 1rem; + + // Match Angular: h-spacing(1rem) on gt-mobile + @include screen.desktop { + & > *:not(:last-child) { + margin-right: 1rem; + } + } @include screen.mobile { - flex-direction: column; + flex-wrap: wrap; + + & > *:not(:last-child) { + margin-bottom: 1rem; + } } } &__btn { height: 35px; - display: inline-flex; + display: flex; align-items: center; justify-content: center; padding: 0 1.5rem; diff --git a/src/routes/error/[code]/page.tsx b/src/routes/error/[code]/page.tsx index c06453c3..142e2dc5 100644 --- a/src/routes/error/[code]/page.tsx +++ b/src/routes/error/[code]/page.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import { useParams } from "@modern-js/runtime/router"; import { createI18nInstance } from "@/i18n/config.js"; import { resolveLocaleFromPath, type Language } from "@/i18n/resolver.js"; @@ -52,9 +52,11 @@ const FALLBACK_CONFIG: ErrorConfig = { export default function ErrorPage(): JSX.Element { const { code } = useParams<{ code: string }>(); const config = (code ? ERROR_CONFIG[code] : undefined) ?? FALLBACK_CONFIG; + const searchRef = useRef(null); // Attempt to detect locale from referrer or default to "ru" const [translations, setTranslations] = useState | null>(null); + const [searchTerm, setSearchTerm] = useState(""); useEffect(() => { const pathname = typeof window !== "undefined" ? window.location.pathname : ""; @@ -73,6 +75,15 @@ export default function ErrorPage(): JSX.Element { }); }, [config]); + const handleSearch = () => { + if (searchTerm) { + window.open( + `https://www.aeroflot.ru/search?text=${encodeURIComponent(searchTerm)}`, + "_blank", + ); + } + }; + // Show content immediately (with hardcoded Russian fallback for SSR), // then replace with i18n translations on the client const title = translations?.title ?? config.titleKey; @@ -92,6 +103,21 @@ export default function ErrorPage(): JSX.Element {
{code ?? "?"}
{title}
{description}
+
+
+ setSearchTerm(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && handleSearch()} + /> +
+
+