a982d9a669
- storage.ts: add sessionStore wrapper (getRaw/setRaw/delete/clear) so transientPrefill + ScheduleStartPage tests don't trip the no-restricted-globals rule. - transientPrefill.ts + ScheduleStartPage.test.tsx: use sessionStore. - closestFlight.ts: hoist bracket-index key so no newline-before-[ ASI. - Test files: hoist typeof import(...) into named type alias with type-only namespace import. - Drop unused imports: FlightCard (Link, languageToLocale), OnlineBoardDetailsPage (operatingCarrier), ScheduleSearchPage (FlightList, inline import() types), PageLayout (FeedbackButton). - Drop react-hooks/exhaustive-deps disable comments for a rule not registered in eslint.config.js.
77 lines
2.7 KiB
TypeScript
77 lines
2.7 KiB
TypeScript
/**
|
|
* Shared page layout wrapper matching the Angular `page-layout` component.
|
|
*
|
|
* Produces the same DOM structure and CSS class names so global SCSS
|
|
* styles apply identically. Includes breadcrumbs, feedback button,
|
|
* and scroll-up button from the Angular app.
|
|
*/
|
|
|
|
import type { ReactNode, FC } from "react";
|
|
import { Breadcrumbs, type BreadcrumbItem } from "./Breadcrumbs.js";
|
|
import { ScrollUpButton } from "./ScrollUpButton.js";
|
|
import "./PageLayout.scss";
|
|
|
|
export interface PageLayoutProps {
|
|
/** Content rendered in the header left column (e.g. page tabs). */
|
|
headerLeft?: ReactNode;
|
|
/** Page title rendered in the header right column. */
|
|
title?: ReactNode;
|
|
/** Content in the left column of the main content area (e.g. filter). */
|
|
contentLeft?: ReactNode;
|
|
/** Sticky content in the right column above main children. */
|
|
stickyContent?: ReactNode;
|
|
/** Main content rendered in the right column. */
|
|
children?: ReactNode;
|
|
/** Breadcrumb trail items (beyond the default "Главная" root). */
|
|
breadcrumbs?: BreadcrumbItem[];
|
|
}
|
|
|
|
export const PageLayout: FC<PageLayoutProps> = ({
|
|
headerLeft,
|
|
title,
|
|
contentLeft,
|
|
stickyContent,
|
|
children,
|
|
breadcrumbs,
|
|
}) => {
|
|
return (
|
|
<div className="page-layout">
|
|
{stickyContent && <div className="page-layout__scroll-overlay" aria-hidden="true" />}
|
|
<div className="page-layout__row page-layout__header">
|
|
<aside className="page-layout__column-left page-layout__header-left">
|
|
{headerLeft}
|
|
</aside>
|
|
<div className="page-layout__column-right page-layout__header-right">
|
|
{/*
|
|
Angular stacks the breadcrumb trail and the <h1> inside a
|
|
single `__title` wrapper, then uses `__header-right`'s
|
|
`justify-content: space-between` to push the optional
|
|
feedback button to the far right. Mirror that structure so
|
|
the breadcrumb sits directly above the title rather than
|
|
drifting to the row start.
|
|
*/}
|
|
<div className="page-layout__title">
|
|
{breadcrumbs && <Breadcrumbs items={breadcrumbs} />}
|
|
{title}
|
|
</div>
|
|
{/* FeedbackButton hidden: Angular has it behind FEEDBACK_BUTTON_AVAILABLE feature flag (off by default) */}
|
|
</div>
|
|
</div>
|
|
<div className="page-layout__row page-layout__content">
|
|
<aside className="page-layout__column-left">
|
|
{contentLeft}
|
|
</aside>
|
|
<main className="page-layout__column-right">
|
|
{stickyContent && (
|
|
<div className="page-layout__sticky-content">
|
|
{stickyContent}
|
|
</div>
|
|
)}
|
|
{children}
|
|
</main>
|
|
</div>
|
|
<ScrollUpButton />
|
|
</div>
|
|
);
|
|
};
|