From 608476d2412475da3e041a1e843d2ad29aa0dc15 Mon Sep 17 00:00:00 2001 From: Nezumi-2711 Date: Fri, 28 Aug 2026 16:53:07 +0700 Subject: [PATCH] fix: improve the UI --- src/client/components/StatusHistoryBar.tsx | 53 ++++++++++++++-------- src/client/styles.css | 2 + 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/client/components/StatusHistoryBar.tsx b/src/client/components/StatusHistoryBar.tsx index 5ec9f11..3074c91 100644 --- a/src/client/components/StatusHistoryBar.tsx +++ b/src/client/components/StatusHistoryBar.tsx @@ -2,6 +2,8 @@ import type { PublicService } from "../api/status"; const DAY_MS = 24 * 60 * 60 * 1000; const HISTORY_DAYS = 90; +const DAYS_PER_SEGMENT = 2; +const HISTORY_SEGMENTS = HISTORY_DAYS / DAYS_PER_SEGMENT; type HistoryEntry = PublicService["history"][number]; @@ -12,41 +14,52 @@ function dayClass(uptimePct: number | null) { return "is-partial"; } -function dayTitle(day: number, uptimePct: number | null) { - const date = new Intl.DateTimeFormat("en", { +function formatDay(day: number) { + return new Intl.DateTimeFormat("en", { month: "short", day: "numeric", year: "numeric", timeZone: "UTC", }).format(new Date(day)); - return `${date}: ${uptimePct === null ? "No data" : `${uptimePct.toFixed(1)}% uptime`}`; +} + +function segmentTitle(startDay: number, endDay: number, uptimePct: number | null) { + const dateRange = `${formatDay(startDay)} – ${formatDay(endDay)}`; + return `${dateRange}: ${uptimePct === null ? "No data" : `${uptimePct.toFixed(1)}% uptime`}`; } export function StatusHistoryBar({ history }: { history: HistoryEntry[] }) { const historyByDay = new Map(history.map((entry) => [entry.day, entry.uptimePct])); const now = new Date(); const today = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()); - const days = Array.from({ length: HISTORY_DAYS }, (_, index) => { - const day = today - (HISTORY_DAYS - index - 1) * DAY_MS; - return { day, uptimePct: historyByDay.get(day) ?? null }; + const segments = Array.from({ length: HISTORY_SEGMENTS }, (_, index) => { + const startDay = today - (HISTORY_DAYS - index * DAYS_PER_SEGMENT - 1) * DAY_MS; + const endDay = startDay + (DAYS_PER_SEGMENT - 1) * DAY_MS; + const values = Array.from({ length: DAYS_PER_SEGMENT }, (_, dayIndex) => + historyByDay.get(startDay + dayIndex * DAY_MS), + ).filter((value): value is number => value !== undefined && value !== null); + const uptimePct = values.length === 0 + ? null + : Math.round((values.reduce((sum, value) => sum + value, 0) / values.length) * 10) / 10; + return { startDay, endDay, uptimePct }; }); return (
-
- {days.map(({ day, uptimePct }) => ( - - ))} -
- +
+ {segments.map(({ startDay, endDay, uptimePct }) => ( + + ))} +
+
); } diff --git a/src/client/styles.css b/src/client/styles.css index 652185f..c9d9b6c 100644 --- a/src/client/styles.css +++ b/src/client/styles.css @@ -404,6 +404,8 @@ button { color: inherit; } .auth-card { padding: 28px 22px; } .auth-heading h1 { font-size: 27px; } .dashboard-header-inner { height: 62px; } + .status-header-action { min-height: 36px; padding: 6px 14px; } + .public-services-heading .icon-button { flex: 0 0 44px; width: 44px; height: 44px; } .dashboard-main { padding-top: 32px; } .dashboard-intro > div > p:last-child { font-size: 14px; line-height: 1.5; } .panel-heading { min-height: 70px; padding: 14px 16px; }