refactor: comprehensive frontend review — consistency, a11y, code quality

- Replace event dispatchers with BookingContext (Hero, Header, FloatingContact)
- Add focus trap hook for modals (SignupModal, NewsModal)
- Extract shared components: CollapsibleSection, ConfirmDialog, PriceField, AdminSkeleton
- Add delete confirmation dialog to ArrayEditor
- Replace hardcoded colors (#050505, #0a0a0a, #c9a96e, #2ecc71) with theme tokens
- Add CSS variables --color-surface-deep/dark for consistent dark surfaces
- Improve contrast: muted text neutral-500 → neutral-400 in dark mode
- Fix modal z-index hierarchy (modals z-60, header z-50, floats z-40)
- Consolidate duplicate formatDate → shared formatting.ts
- Add useMemo to TeamProfile groupMap computation
- Fix typography: responsive price text in Pricing section
- Add ARIA labels/expanded to FAQ, OpenDay, ArrayEditor grip handles
- Hide number input spinners globally
- Reorder admin sidebar: Dashboard → SEO → Bookings → site section order
- Use shared PriceField in Open Day editor
- Fix schedule grid first time slot (09:00) clipped by container
- Fix pre-existing type errors (bookings, hero, db interfaces)
This commit is contained in:
2026-03-26 19:45:37 +03:00
parent ec08f8e8d5
commit 76307e298b
32 changed files with 613 additions and 319 deletions
+8 -6
View File
@@ -95,8 +95,10 @@ function timeToMinutes(timeStr: string): number {
return t.h * 60 + t.m;
}
const GRID_TOP_PAD = 8; // px — space so the first time label isn't clipped
function minutesToY(minutes: number): number {
return ((minutes - HOUR_START * 60) / 60) * HOUR_HEIGHT;
return ((minutes - HOUR_START * 60) / 60) * HOUR_HEIGHT + GRID_TOP_PAD;
}
function yToMinutes(y: number): number {
@@ -927,12 +929,12 @@ function CalendarGrid({
{/* Time grid */}
<div className="flex">
{/* Time labels */}
<div className="w-14 shrink-0 relative" style={{ height: `${TOTAL_HOURS * HOUR_HEIGHT}px` }}>
<div className="w-14 shrink-0 relative" style={{ height: `${TOTAL_HOURS * HOUR_HEIGHT + GRID_TOP_PAD}px` }}>
{hours.slice(0, -1).map((h) => (
<div
key={h}
className="absolute left-0 right-0 text-right pr-2 text-xs text-neutral-500"
style={{ top: `${(h - HOUR_START) * HOUR_HEIGHT - 6}px` }}
style={{ top: `${(h - HOUR_START) * HOUR_HEIGHT + GRID_TOP_PAD - 6}px` }}
>
{String(h).padStart(2, "0")}:00
</div>
@@ -951,7 +953,7 @@ function CalendarGrid({
key={day.day}
ref={(el) => { columnRefs.current[di] = el; }}
className={`flex-1 border-l border-white/10 relative ${drag ? "cursor-grabbing" : "cursor-pointer"}`}
style={{ height: `${TOTAL_HOURS * HOUR_HEIGHT}px` }}
style={{ height: `${TOTAL_HOURS * HOUR_HEIGHT + GRID_TOP_PAD}px` }}
onMouseMove={(e) => {
if (drag) return;
// Ignore if hovering over a class block
@@ -978,7 +980,7 @@ function CalendarGrid({
<div
key={h}
className="absolute left-0 right-0 border-t border-white/5"
style={{ top: `${(h - HOUR_START) * HOUR_HEIGHT}px` }}
style={{ top: `${(h - HOUR_START) * HOUR_HEIGHT + GRID_TOP_PAD}px` }}
/>
))}
{/* Half-hour lines */}
@@ -986,7 +988,7 @@ function CalendarGrid({
<div
key={`${h}-30`}
className="absolute left-0 right-0 border-t border-white/[0.02]"
style={{ top: `${(h - HOUR_START) * HOUR_HEIGHT + HOUR_HEIGHT / 2}px` }}
style={{ top: `${(h - HOUR_START) * HOUR_HEIGHT + HOUR_HEIGHT / 2 + GRID_TOP_PAD}px` }}
/>
))}