From f2661768b000c3bb89229ed5da16b715b8bdd3a8 Mon Sep 17 00:00:00 2001 From: gnezim Date: Sun, 19 Apr 2026 14:35:13 +0300 Subject: [PATCH] Match Angular day-tabs UI + fix flights-map SEO key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rebuild DayTabs to mirror Angular's flat single-line tab strip: one label per tab ('17 апр.' siblings, '19 апреля' active), 48px tall, 7 tabs per page, brand blue label on light-blue background with white active cell. Single Intl.DateTimeFormat call keeps Russian months in genitive case. Drop the 60px sticky-content offset to 20px so the date strip aligns with the left filter column (both already sticky at top:20px). Correct SEO.FLIGHTS_MAP translation key to SEO.FLIGHTS-MAP.MAIN — the underscored path never existed in the locale files, so the browser tab title on /{lang}/flights-map fell back to the raw key. --- src/features/flights-map/seo.test.ts | 6 +- src/features/flights-map/seo.ts | 4 +- .../components/DayTabs/DayTabButton.test.tsx | 8 +- .../components/DayTabs/DayTabButton.tsx | 14 +- .../components/DayTabs/DayTabs.scss | 128 +++++++++--------- src/ui/layout/PageLayout.scss | 2 +- 6 files changed, 81 insertions(+), 81 deletions(-) diff --git a/src/features/flights-map/seo.test.ts b/src/features/flights-map/seo.test.ts index 736ddd95..87dff492 100644 --- a/src/features/flights-map/seo.test.ts +++ b/src/features/flights-map/seo.test.ts @@ -14,11 +14,11 @@ const CANONICAL = "https://www.aeroflot.ru"; // --------------------------------------------------------------------------- describe("buildFlightsMapSeo", () => { - it("uses FLIGHTS_MAP translation keys", () => { + it("uses FLIGHTS-MAP.MAIN translation keys", () => { const result = buildFlightsMapSeo(stubT, "ru", CANONICAL); - expect(result.title).toBe("SEO.FLIGHTS_MAP.TITLE"); - expect(result.description).toBe("SEO.FLIGHTS_MAP.DESCRIPTION"); + expect(result.title).toBe("SEO.FLIGHTS-MAP.MAIN.TITLE"); + expect(result.description).toBe("SEO.FLIGHTS-MAP.MAIN.DESCRIPTION"); }); it("sets canonical to /{locale}/flights-map", () => { diff --git a/src/features/flights-map/seo.ts b/src/features/flights-map/seo.ts index 4d4909bc..5bf162ca 100644 --- a/src/features/flights-map/seo.ts +++ b/src/features/flights-map/seo.ts @@ -37,8 +37,8 @@ export function buildFlightsMapSeo( locale: string, canonicalOrigin: string, ): SeoHeadProps { - const title = t("SEO.FLIGHTS_MAP.TITLE"); - const description = t("SEO.FLIGHTS_MAP.DESCRIPTION"); + const title = t("SEO.FLIGHTS-MAP.MAIN.TITLE"); + const description = t("SEO.FLIGHTS-MAP.MAIN.DESCRIPTION"); const canonical = `${canonicalOrigin}/${locale}${PATH_WITHOUT_LOCALE}`; return { diff --git a/src/features/online-board/components/DayTabs/DayTabButton.test.tsx b/src/features/online-board/components/DayTabs/DayTabButton.test.tsx index a4f2cace..ab51639f 100644 --- a/src/features/online-board/components/DayTabs/DayTabButton.test.tsx +++ b/src/features/online-board/components/DayTabs/DayTabButton.test.tsx @@ -9,11 +9,11 @@ describe("DayTabButton", () => { expect(screen.getByTestId("day-tab-20260416")).toBeTruthy(); }); - it("renders weekday, day number, and month", () => { + it("renders day number and month in a single label", () => { render( {}} />); - expect(screen.getByText("16")).toBeTruthy(); - expect(screen.getByText(/Apr/i)).toBeTruthy(); - expect(screen.getByText(/Thu/i)).toBeTruthy(); + const label = screen.getByTestId("day-tab-20260416").textContent ?? ""; + expect(label).toMatch(/16/); + expect(label).toMatch(/Apr/i); }); it("calls onClick with date when enabled", () => { diff --git a/src/features/online-board/components/DayTabs/DayTabButton.tsx b/src/features/online-board/components/DayTabs/DayTabButton.tsx index b04010a6..55102d75 100644 --- a/src/features/online-board/components/DayTabs/DayTabButton.tsx +++ b/src/features/online-board/components/DayTabs/DayTabButton.tsx @@ -18,11 +18,11 @@ export const DayTabButton: FC = ({ onClick, }) => { const d = parseYyyymmdd(date); - const weekday = new Intl.DateTimeFormat(locale, { weekday: "short" }).format(d); - const day = new Intl.DateTimeFormat(locale, { day: "numeric" }).format(d); - // Angular shows the selected tab with the full month name ('18 апреля'), - // siblings with the abbreviated form ('19 апр.'). Mirror that. - const month = new Intl.DateTimeFormat(locale, { + // Single format call keeps Russian month in the correct genitive + // case ('19 апреля' rather than '19 апрель'), matching Angular's + // ngx-translate output. + const label = new Intl.DateTimeFormat(locale, { + day: "numeric", month: isActive ? "long" : "short", }).format(d); @@ -44,9 +44,7 @@ export const DayTabButton: FC = ({ if (!isDisabled) onClick(date); }} > - {weekday} - {day} - {month} + {label} ); }; diff --git a/src/features/online-board/components/DayTabs/DayTabs.scss b/src/features/online-board/components/DayTabs/DayTabs.scss index 1eb242ac..292cfdaf 100644 --- a/src/features/online-board/components/DayTabs/DayTabs.scss +++ b/src/features/online-board/components/DayTabs/DayTabs.scss @@ -1,11 +1,67 @@ +// Matches Angular's date-tabs row. Single flat row, 48px tall, 7 tabs per +// page flanked by 50px carousel arrows. Active tab has white bg + dark +// text; siblings have light-blue bg + brand link-blue label. + +.day-tabs-wrap { + margin-bottom: 8px; +} + +.day-tabs { + display: flex; + align-items: stretch; + height: 48px; + border-radius: 8px 8px 0 0; + overflow: hidden; + background: #fff; + + &__arrow { + width: 50px; + flex-shrink: 0; + background: #fff; + border: none; + cursor: pointer; + color: #657282; + font-size: 20px; + line-height: 1; + padding: 0; + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } + } + + &__list { + flex: 1; + display: grid; + grid-template-columns: repeat(7, 1fr); + min-width: 0; + } + + @media (max-width: 768px) { + display: none; + } +} + .day-tab { - padding: 12px 8px; - text-align: center; + display: flex; + align-items: center; + justify-content: center; + padding: 16px 0 15px; + background: #f3f9ff; + color: #1b62b4; + font-size: 12px; + font-weight: 500; + border: 0; + border-right: 1px solid #d1dcea; + border-bottom: 1px solid #d1dcea; cursor: pointer; - background: #e8f0f7; - color: #2060c0; - border: none; - border-right: 1px solid #d0dae5; + text-align: center; + white-space: nowrap; + + &__label { + display: inline-block; + } &:last-child { border-right: none; @@ -13,33 +69,15 @@ &--active { background: #fff; - color: #1a3a5c; - font-weight: 600; + color: #333; + border-bottom-color: #fff; + cursor: default; } &--disabled { opacity: 0.5; cursor: not-allowed; } - - // Angular's tabs size each line small: weekday 11px, day number 16px, - // month 12px. Active tab keeps everything the same size but switches to - // #333 and weight 500; siblings stay in the brand link blue. - &__weekday { - font-size: 11px; - display: block; - } - - &__day { - font-size: 16px; - font-weight: 500; - display: block; - } - - &__month { - font-size: 12px; - display: block; - } } .day-select { @@ -54,39 +92,3 @@ border: 1px solid #d0dae5; } } - -.day-tabs-wrap { - margin-bottom: 8px; -} - -.day-tabs { - display: flex; - align-items: stretch; - background: #e8f0f7; - border-radius: 8px 8px 0 0; - - &__arrow { - width: 48px; - flex-shrink: 0; - background: transparent; - border: none; - cursor: pointer; - color: #2060c0; - font-size: 20px; - - &:disabled { - opacity: 0.3; - cursor: not-allowed; - } - } - - &__list { - flex: 1; - display: grid; - grid-template-columns: repeat(7, 1fr); - } - - @media (max-width: 768px) { - display: none; - } -} diff --git a/src/ui/layout/PageLayout.scss b/src/ui/layout/PageLayout.scss index 0a9bf46b..d674456d 100644 --- a/src/ui/layout/PageLayout.scss +++ b/src/ui/layout/PageLayout.scss @@ -133,7 +133,7 @@ @include screen.gt-mobile { position: sticky; z-index: 1000; - top: 60px; + top: 20px; } } }