fix: restructure PageLayout to match Angular's two-row header/content layout

- Convert PageLayout from single-row to two-row structure (header row + content row)
- Move tabs to headerLeft prop to appear in proper header row
- Update all page components (OnlineBoardStartPage, ScheduleStartPage, search pages, detail pages)
- Update SCSS to use page-layout__row and page-layout__column-left/right classes
- Ensure pixel-perfect layout parity with Angular version
This commit is contained in:
gnezim
2026-04-06 10:43:23 +03:00
parent 7eebdf3c4b
commit b181440e6f
9 changed files with 133 additions and 4689 deletions
-4636
View File
File diff suppressed because it is too large Load Diff
@@ -1,24 +1,84 @@
.page-layout {
// Header row - with tabs (left) and title (right)
.page-layout__row {
display: flex;
flex-direction: row;
align-items: flex-start;
width: 100%;
max-width: 1440px;
margin: 0 auto;
padding: 32px 24px;
margin: 0 auto 20px;
padding: 32px 24px 0;
gap: 0;
@media (max-width: 1050px) {
flex-direction: column;
padding: 20px 24px;
padding: 20px 24px 0;
margin-bottom: 0;
}
@media (max-width: 768px) {
padding: 10px 16px;
padding: 10px 16px 0;
}
}
.page-layout__left {
// Header row
.page-layout__header {
padding: 0;
@media (max-width: 1050px) {
margin-bottom: 20px;
}
}
// Content row
.page-layout__content {
padding: 0 24px;
@media (max-width: 1050px) {
padding: 0 24px;
}
@media (max-width: 768px) {
padding: 0 16px;
}
}
// Left column in header (tabs)
.page-layout__header-left {
position: relative;
flex-shrink: 0;
width: 285px;
margin-right: 1.5%;
z-index: 1001;
@media (max-width: 1300px) {
width: calc(23.875% * 1.04);
}
@media (max-width: 1050px) {
position: relative;
width: 100%;
margin-right: 0;
margin-bottom: 20px;
}
}
// Right column in header (title)
.page-layout__header-right {
display: flex;
flex-direction: column;
width: calc(100% - 285px - 1.5%);
position: relative;
@media (max-width: 1300px) {
width: calc(100% - calc(23.875% * 1.04) - 1.5%);
}
@media (max-width: 1050px) {
width: 100%;
}
}
// Left column in content (filter)
.page-layout__column-left {
position: sticky;
top: 20px;
flex-shrink: 0;
@@ -39,7 +99,8 @@
}
}
.page-layout__right {
// Right column in content (main)
.page-layout__column-right {
display: flex;
flex-direction: column;
width: calc(100% - 285px - 1.5%);
@@ -54,20 +115,20 @@
}
}
.page-layout__header {
position: relative;
z-index: 1001;
padding-top: 0;
margin-bottom: 20px;
}
// Title styling
.page-layout__title {
margin-bottom: 20px;
font-size: 24px;
font-weight: 600;
@media (max-width: 1050px) {
margin-bottom: 10px;
font-size: 20px;
}
}
.page-layout__sticky {
// Sticky content (day tabs, etc)
.page-layout__sticky-content {
position: sticky;
top: 0;
background: white;
@@ -76,6 +137,7 @@
margin-bottom: 20px;
}
.page-layout__content {
// Main content area
.page-layout__content-main {
flex: 1;
}
@@ -19,18 +19,31 @@ export const PageLayout: React.FC<PageLayoutProps> = ({
className,
}) => {
return (
<div className={`page-layout ${className || ''}`}>
<div className="page-layout__left">
{contentLeft}
</div>
<div className="page-layout__right">
{headerLeft && <div className="page-layout__header">{headerLeft}</div>}
{title && <div className="page-layout__title">{title}</div>}
{stickyContent && <div className="page-layout__sticky">{stickyContent}</div>}
<div className="page-layout__content">
{children}
<>
{/* Header Row - matches Angular page-layout__row page-layout__header */}
{headerLeft && (
<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">
{title && <div className="page-layout__title">{title}</div>}
</div>
</div>
)}
{/* Content Row - matches Angular page-layout__row page-layout__content */}
<div className={`page-layout__row page-layout__content ${className || ''}`}>
<aside className="page-layout__column-left">
{contentLeft}
</aside>
<main className="page-layout__column-right">
{stickyContent && <div className="page-layout__sticky-content">{stickyContent}</div>}
<div className="page-layout__content-main">
{children}
</div>
</main>
</div>
</div>
</>
)
}
@@ -78,18 +78,20 @@ export const FlightDetailsPage: React.FC = () => {
if (error || !flight) {
return (
<div className="flight-details-page" data-testid="flight-details-page">
<PageTabs />
<PageEmptyList message={error || 'Flight not found'} />
<PageLayout
headerLeft={<PageTabs />}
>
<PageEmptyList message={error || 'Flight not found'} />
</PageLayout>
</div>
)
}
return (
<div className="flight-details-page" data-testid="flight-details-page">
<PageTabs />
<PageLayout
headerLeft={
headerLeft={<PageTabs />}
title={
<Button
icon="pi pi-arrow-left"
label={t('SHARED.BACK')}
@@ -97,19 +97,21 @@ export const OnlineBoardSearchPage: React.FC = () => {
if (error) {
return (
<div className="online-board-search-page" data-testid="online-board-search-page">
<PageTabs />
<PageEmptyList message={error} />
<PageLayout
headerLeft={<PageTabs />}
>
<PageEmptyList message={error} />
</PageLayout>
</div>
)
}
return (
<div className="online-board-search-page" data-testid="online-board-search-page">
<PageTabs />
<PageLoader isLoading={loading} />
<PageLayout
headerLeft={<PageTabs />}
contentLeft={
<OnlineBoardFilter
initialSearchParams={
@@ -14,9 +14,9 @@ export const OnlineBoardStartPage: React.FC = () => {
return (
<div className="online-board-start-page" data-testid="online-board-start-page">
<PageTabs />
<PageLayout
headerLeft={<PageTabs />}
title={<h1 className="online-board-start-page__page-title">{t('BOARD.TITLE')}</h1>}
contentLeft={<OnlineBoardFilter />}
stickyContent={
<DayTabs
@@ -31,9 +31,6 @@ export const OnlineBoardStartPage: React.FC = () => {
<Link to="/">{t('SHARED.MAIN')}</Link>
</div>
{/* Main Title */}
<h1 className="online-board-start-page__title">{t('BOARD.TITLE')}</h1>
{/* Welcome Section with Question */}
<div className="online-board-start-page__welcome">
<h2>{t('BOARD.BOARD-START')}</h2>
@@ -81,18 +81,20 @@ export const ScheduleFlightDetailsPage: React.FC = () => {
if (error || !flight) {
return (
<div className="schedule-flight-details-page" data-testid="schedule-flight-details-page">
<PageTabs />
<PageEmptyList message={error || 'Flight not found'} />
<PageLayout
headerLeft={<PageTabs />}
>
<PageEmptyList message={error || 'Flight not found'} />
</PageLayout>
</div>
)
}
return (
<div className="schedule-flight-details-page" data-testid="schedule-flight-details-page">
<PageTabs />
<PageLayout
headerLeft={
headerLeft={<PageTabs />}
title={
<Button
icon="pi pi-arrow-left"
label={t('SHARED.BACK')}
@@ -90,19 +90,21 @@ export const ScheduleSearchPage: React.FC = () => {
if (error) {
return (
<div className="schedule-search-page" data-testid="schedule-search-page">
<PageTabs />
<PageEmptyList message={error} />
<PageLayout
headerLeft={<PageTabs />}
>
<PageEmptyList message={error} />
</PageLayout>
</div>
)
}
return (
<div className="schedule-search-page" data-testid="schedule-search-page">
<PageTabs />
<PageLoader isLoading={loading} />
<PageLayout
headerLeft={<PageTabs />}
contentLeft={<ScheduleFilter />}
stickyContent={
<div className="schedule-search-page__week-tabs" data-testid="week-tabs">
@@ -11,9 +11,9 @@ export const ScheduleStartPage: React.FC = () => {
return (
<div className="schedule-start-page" data-testid="schedule-start-page">
<PageTabs />
<PageLayout
headerLeft={<PageTabs />}
title={<h1 className="schedule-start-page__page-title">{t('SCHEDULE.TITLE')}</h1>}
contentLeft={<ScheduleFilter />}
>
<div className="schedule-start-page__content">