Fix city-input + date-picker styling + remove extra Schedule section

Live-report issues (user-driven smoke test):

1. Schedule city input shown with a thick default PrimeReact border
   (no such border on Board). Root cause: CityAutocomplete's outer
   wrapper carries the border via box-shadow, but the inner .p-inputtext
   still had PrimeReact's 'border: 1px solid #a6a6a6' from the shared
   prime-styles.scss. Angular silences it with a global 'city-autocomplete
   input.p-inputtext { border: none; box-shadow: none }' rule. Added
   the same reset to our shared CityAutocomplete.scss + killed the
   PrimeReact focus shadow so only one border remains.

2. Clear-X button hidden on Board + Map (visible only on Schedule).
   Root cause: a legacy Angular-port rule in _layout.scss
   '.p-accordion .p-accordion-content button.button-clear { display: none }'
   beat our '.city-autocomplete__input--has-value .button-clear { display: block }'
   on specificity — Board's CityAutocomplete sits inside the accordion
   filter. Removed the legacy rule (it targeted an Angular-only close
   affordance that doesn't exist in the React app); if we re-add such
   an element later it'll need a distinct class.

3. Date-picker placeholder 'ДД.ММ.ГГГГ - ДД.ММ.ГГГГ' truncated because
   the ScheduleStartPage inherits 16px font. Stepped calendar font down
   to 14px (matches Angular's base body .p-inputtext) + added right
   padding so the trigger icon doesn't sit on top of the placeholder.

4. Schedule start page showed a 'Возможности расписания' info section
   (TZ Table 9 Title5+Title6) that the Angular reference
   (ClientApp/.../schedule-start-page.component.html) has commented out.
   Followed Angular — removed the block. Kept i18n keys for future work.
   Updated the two corresponding assertion tests to check the block is
   NOT rendered (parity with Angular).

Also during the same session, there was a sub-bug introduced in the
first SCSS edit (I accidentally nested .button-clear inside
:focus-within, inverting display state). Fixed by moving the rule back
under __input directly.

2044 unit tests pass, typecheck clean. Live retest across all three
sections (Board / Schedule / Map): X appears only when city is filled,
inner input shows single clean border, Schedule calendar placeholder
fits, 'Возможности расписания' no longer renders.
This commit is contained in:
2026-04-22 03:53:11 +03:00
parent c18b4b212e
commit 678cde3ed2
5 changed files with 51 additions and 73 deletions
@@ -346,6 +346,15 @@
}
}
// PrimeReact Calendar input — step the font down from the start-page's
// 16px so the full 'ДД.ММ.ГГГГ - ДД.ММ.ГГГГ' placeholder fits in the
// narrow left-column width. Matches Angular's `body .p-inputtext`
// baseline of 14px for calendar inputs.
.p-calendar input.p-inputtext {
font-size: fonts.$font-size-m !important;
padding-right: 2rem; // leave room for the trigger icon on the right
}
// Swap button — match Angular's flat style
.change-container {
display: flex;
@@ -169,16 +169,22 @@ describe("ScheduleStartPage", () => {
expect(screen.getByText("SCHEDULE.SCHEDULE-START-TITLE4-DESCRIPTION")).toBeTruthy();
});
it("4.1.7-R-info-block-2a: renders 'Купить билет' capabilities block (TITLE5)", () => {
// TZ Table 9 prescribes a second 'Возможности расписания' info section
// (Title5 'Купить билет' + Title6 'Расписание'), but the Angular
// reference baseline has that block commented out — the infos are
// redundant with the OB start-page's capability tiles. Following
// Angular: assert the block is *not* rendered. If business later
// requires it, flip these to positive assertions.
it("4.1.7-R-info-block-2a: 'Купить билет' capabilities block (TITLE5) hidden (Angular parity)", () => {
render(<ScheduleStartPage />);
expect(screen.getByText("SCHEDULE.SCHEDULE-START-TITLE5")).toBeTruthy();
expect(screen.getByText("SCHEDULE.SCHEDULE-START-TITLE5-DESCRIPTION")).toBeTruthy();
expect(screen.queryByText("SCHEDULE.SCHEDULE-START-TITLE5")).toBeNull();
expect(screen.queryByText("SCHEDULE.SCHEDULE-START-TITLE5-DESCRIPTION")).toBeNull();
});
it("4.1.7-R-info-block-2b: renders 'Расписание' capabilities block (TITLE6)", () => {
it("4.1.7-R-info-block-2b: 'Расписание' capabilities block (TITLE6) hidden (Angular parity)", () => {
render(<ScheduleStartPage />);
expect(screen.getByText("SCHEDULE.SCHEDULE-START-TITLE6")).toBeTruthy();
expect(screen.getByText("SCHEDULE.SCHEDULE-START-TITLE6-DESCRIPTION")).toBeTruthy();
expect(screen.queryByText("SCHEDULE.SCHEDULE-START-TITLE6")).toBeNull();
expect(screen.queryByText("SCHEDULE.SCHEDULE-START-TITLE6-DESCRIPTION")).toBeNull();
});
it("4.1.7-R-popular: renders PopularRequestsPanel for request handling", () => {
@@ -586,23 +586,14 @@ export const ScheduleStartPage: FC = () => {
</div>
</div>
<h3>{t("SCHEDULE.POPULAR-CHAPTERS")}</h3>
<div className="titles-container">
<div className="title title5">
<a>{t("SCHEDULE.SCHEDULE-START-TITLE5")}</a>
<div>
{t("SCHEDULE.SCHEDULE-START-TITLE5-DESCRIPTION")}
</div>
</div>
<div className="title title6">
<a>{t("SCHEDULE.SCHEDULE-START-TITLE6")}</a>
<div>
{t("SCHEDULE.SCHEDULE-START-TITLE6-DESCRIPTION")}
</div>
</div>
</div>
{/*
TZ Table 9 prescribes a second info section "Возможности расписания"
(Title5 + Title6), but the Angular reference baseline has it commented
out (see `ClientApp/.../schedule-start-page.component.html`). Following
Angular here — the block duplicates the "Купить билет / Расписание"
info already shown in the OB start-page table and breaks the visual
rhythm. The i18n keys are retained for future work if needed.
*/}
<PopularRequestsPanel onRequestClick={handlePopularRequestClick} />
</section>
+7 -50
View File
@@ -313,56 +313,13 @@ body {
}
}
// Accordion button-clear (adapted from PrimeNG p-accordion element selector)
.p-accordion .p-accordion-content button.button-clear {
display: none;
position: absolute;
right: $buttons-width;
top: 0px;
bottom: 0px;
width: $buttons-width !important;
border: none;
border-radius: 0;
background: rgb(255, 255, 255);
background: linear-gradient(270deg, rgba(255, 255, 255, 1) 80%, rgba(255, 255, 255, 0) 100%);
.p-button-label {
background-image: url('/assets/img/close.svg');
background-repeat: no-repeat;
background-size: 10px 10px;
height: 100%;
background-position: center center;
transition-duration: 0.2s;
position: relative;
&:before {
display: none;
position: absolute;
content: '';
top: 0;
left: 0;
bottom: 0;
width: 1px;
background-color: $border-input;
}
}
&-opened {
.p-button-label {
transform: rotate(180deg);
}
}
&:hover {
background-color: $white !important;
.p-button-label {
&:before {
display: block;
}
}
}
}
// Removed: legacy Angular-port rule `.p-accordion .p-accordion-content button.button-clear`
// that forced `display: none` and specific positioning. In React we reuse
// `.button-clear` as the shared "X" for CityAutocomplete + OnlineBoardFilter
// flight-number input; the legacy rule was defeating our `--has-value`
// show-rule by specificity and hiding the X on city inputs inside the
// accordion-based OnlineBoard filter. If we re-introduce a p-accordion
// close affordance, give it a distinct class.
.app-show-debug {
display: inline-flex;
@@ -36,6 +36,21 @@
flex: 1;
}
// Reset the inner PrimeReact input's native border — the outer
// __input div carries the border+shadow already (Angular parity via
// the global `city-autocomplete input.p-inputtext` reset rule).
input.p-inputtext {
border: none !important;
box-shadow: none !important;
}
// Also drop PrimeReact's blue focus shadow on the inner input
// when it is focused, so the outer box-shadow stays as the only
// visible border.
input.p-inputtext:focus {
box-shadow: none !important;
}
.button-clear {
display: none;
width: 32px;