fix: phase 1 bugs — CSS tokens, pluralization, error handling, cross-platform tests
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
- Add missing --space-1 CSS token used by filter and detail components - Fix active nav link losing styles on hover (CSS specificity) - Correct Russian day pluralization (21 день, 22 дня, 25 дней) - Show filter error banner even when stale race data is present - Add cross-env for Windows-compatible npm test - Add global JSON error handler in Express for malformed request bodies - Replace stateless mock DB with in-memory store for correct DELETE/UPDATE behavior Made-with: Cursor
This commit is contained in:
@@ -70,6 +70,22 @@ export function splitRacesByDate(races: Race[], now: Date = new Date()): { upcom
|
||||
};
|
||||
}
|
||||
|
||||
function pluralizeDays(n: number): string {
|
||||
const mod10 = n % 10;
|
||||
const mod100 = n % 100;
|
||||
|
||||
if (mod100 >= 11 && mod100 <= 19) {
|
||||
return "дней";
|
||||
}
|
||||
if (mod10 === 1) {
|
||||
return "день";
|
||||
}
|
||||
if (mod10 >= 2 && mod10 <= 4) {
|
||||
return "дня";
|
||||
}
|
||||
return "дней";
|
||||
}
|
||||
|
||||
export function getRaceCountdownLabel(date: string, now: Date = new Date()): string {
|
||||
const today = new Date(now);
|
||||
today.setHours(0, 0, 0, 0);
|
||||
@@ -80,13 +96,7 @@ export function getRaceCountdownLabel(date: string, now: Date = new Date()): str
|
||||
if (days <= 0) {
|
||||
return "сегодня";
|
||||
}
|
||||
if (days === 1) {
|
||||
return "через 1 день";
|
||||
}
|
||||
if (days < 5) {
|
||||
return `через ${days} дня`;
|
||||
}
|
||||
return `через ${days} дней`;
|
||||
return `через ${days} ${pluralizeDays(days)}`;
|
||||
}
|
||||
|
||||
export function isCloseDistance(left: number, right: number): boolean {
|
||||
|
||||
@@ -145,6 +145,12 @@ export function RacesPage(): JSX.Element {
|
||||
<h1 className="page__title">Календарь стартов</h1>
|
||||
<p className="page__subtitle">Будущие и прошедшие старты в одном месте.</p>
|
||||
|
||||
{errorMessage && !isLoading ? (
|
||||
<p className="page__subtitle page__subtitle--error" role="alert" style={{ marginTop: "var(--space-4)" }}>
|
||||
{errorMessage}
|
||||
</p>
|
||||
) : null}
|
||||
|
||||
<div className="races-filter" role="search" aria-label="Фильтр по дате">
|
||||
<label className="races-filter__field">
|
||||
<span className="races-filter__label">Год</span>
|
||||
|
||||
@@ -64,7 +64,9 @@ a {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.app-shell__link--active {
|
||||
.app-shell__link--active,
|
||||
.app-shell__link--active:hover,
|
||||
.app-shell__link--active:focus-visible {
|
||||
color: var(--color-surface);
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
--font-size-caption: 0.875rem;
|
||||
--line-height-base: 1.5;
|
||||
|
||||
--space-1: 0.25rem;
|
||||
--space-2: 0.5rem;
|
||||
--space-3: 0.75rem;
|
||||
--space-4: 1rem;
|
||||
|
||||
Reference in New Issue
Block a user