fix(widgets): restore compact v1 surfaces (#6710)
This commit is contained in:
1 parent
1b2f1bd720
commit
643ecf3df7
105 files changed
+1603
-1285
No files matched your search
@@ -10,12 +10,20 @@ import { formatStatsSpeed } from "./helpers";
|
||||
import { SectionLabel } from "./section-label";
|
||||
import { SpeedStatCard } from "./speed-stat-card";
|
||||
|
||||
export function AveragesSection({ stats, width = 500 }: { stats: SpeedtestTrackerStats; width?: number }) {
|
||||
export function AveragesSection({
|
||||
stats,
|
||||
width = 500,
|
||||
compactSurface = false,
|
||||
}: {
|
||||
stats: SpeedtestTrackerStats;
|
||||
width?: number;
|
||||
compactSurface?: boolean;
|
||||
}) {
|
||||
const t = useI18n("widget.speedtestTracker");
|
||||
|
||||
return (
|
||||
<Stack gap={6} h="100%">
|
||||
<SectionLabel>
|
||||
<SectionLabel uppercase={compactSurface}>
|
||||
{t("averages")} · {t("tests", { count: stats.total_results.toString() })}
|
||||
</SectionLabel>
|
||||
<SimpleGrid cols={width < 220 ? 1 : 3} spacing="xs" style={{ flex: 1, gridTemplateRows: "1fr" }}>
|
||||
@@ -25,6 +33,7 @@ export function AveragesSection({ stats, width = 500 }: { stats: SpeedtestTracke
|
||||
value={formatStatsSpeed(stats.download)}
|
||||
label={t("avgDownload")}
|
||||
compact
|
||||
legacySurface={compactSurface}
|
||||
/>
|
||||
<SpeedStatCard
|
||||
icon={IconArrowUp}
|
||||
@@ -32,6 +41,7 @@ export function AveragesSection({ stats, width = 500 }: { stats: SpeedtestTracke
|
||||
value={formatStatsSpeed(stats.upload)}
|
||||
label={t("avgUpload")}
|
||||
compact
|
||||
legacySurface={compactSurface}
|
||||
/>
|
||||
<SpeedStatCard
|
||||
icon={IconWaveSine}
|
||||
@@ -39,6 +49,7 @@ export function AveragesSection({ stats, width = 500 }: { stats: SpeedtestTracke
|
||||
value={`${stats.ping.avg.toFixed(1)} ms`}
|
||||
label={t("avgPing")}
|
||||
compact
|
||||
legacySurface={compactSurface}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IntegrationErrorIndicator } from "../common/integration-error-indicator
|
||||
import { getUsableWidgetQueryData } from "../common/query-state";
|
||||
import { WidgetEmptyState } from "../common/empty-state";
|
||||
import { AveragesSection } from "./averages";
|
||||
import { combineSpeedtestDashboards, getAvailableSpeedtestDashboards, getCompactSections } from "./helpers";
|
||||
import { combineSpeedtestDashboards, getAvailableSpeedtestDashboards } from "./helpers";
|
||||
import { LatestResultSection } from "./latest-result";
|
||||
import { RecentResultsSection } from "./recent-results";
|
||||
|
||||
@@ -51,16 +51,19 @@ export default function SpeedtestTrackerWidget({
|
||||
const advancedSectionWidth = width >= 720 ? width / 2 : width;
|
||||
|
||||
const latest = showLatestResult && combined.latestResult && (
|
||||
<LatestResultSection result={combined.latestResult} width={isAdvanced ? advancedSectionWidth : width} />
|
||||
<LatestResultSection
|
||||
result={combined.latestResult}
|
||||
width={isAdvanced ? advancedSectionWidth : width}
|
||||
compactSurface={!isAdvanced}
|
||||
/>
|
||||
);
|
||||
const averages = showStats && combined.stats && (
|
||||
<AveragesSection stats={combined.stats} width={isAdvanced ? advancedSectionWidth : width} />
|
||||
<AveragesSection
|
||||
stats={combined.stats}
|
||||
width={isAdvanced ? advancedSectionWidth : width}
|
||||
compactSurface={!isAdvanced}
|
||||
/>
|
||||
);
|
||||
const compactSections = getCompactSections(height, {
|
||||
latest: Boolean(latest),
|
||||
chart: hasChart,
|
||||
averages: Boolean(averages),
|
||||
});
|
||||
|
||||
if (displayMode === "advanced") {
|
||||
const sourceColumns = successfulDashboards.length > 1 && width >= 900 ? 2 : 1;
|
||||
@@ -136,15 +139,15 @@ export default function SpeedtestTrackerWidget({
|
||||
{successfulDashboards.map(({ integrationName }) => integrationName).join(" · ")}
|
||||
</Text>
|
||||
)}
|
||||
{(compactSections.latest || compactSections.averages) && (
|
||||
{(latest || averages) && (
|
||||
<Stack gap="sm" style={{ flex: 1, minHeight: 0 }}>
|
||||
{compactSections.latest && <div style={{ flex: 1, minHeight: 0 }}>{latest}</div>}
|
||||
{compactSections.averages && <div style={{ flex: 1, minHeight: 0 }}>{averages}</div>}
|
||||
{latest && <div style={{ flex: 1, minHeight: 0 }}>{latest}</div>}
|
||||
{averages && <div style={{ flex: 1, minHeight: 0 }}>{averages}</div>}
|
||||
</Stack>
|
||||
)}
|
||||
{compactSections.chart && (
|
||||
{hasChart && (
|
||||
<div style={{ flex: 2, minHeight: 0 }}>
|
||||
<RecentResultsSection results={recentFiltered} showPingGraph={showPingGraph} />
|
||||
<RecentResultsSection results={recentFiltered} showPingGraph={showPingGraph} uppercaseLabels />
|
||||
</div>
|
||||
)}
|
||||
{noSectionsEnabled && (
|
||||
|
||||
@@ -10,7 +10,15 @@ import { formatResultSpeed } from "./helpers";
|
||||
import { SectionLabel } from "./section-label";
|
||||
import { SpeedStatCard } from "./speed-stat-card";
|
||||
|
||||
export function LatestResultSection({ result, width = 500 }: { result: SpeedtestTrackerResult; width?: number }) {
|
||||
export function LatestResultSection({
|
||||
result,
|
||||
width = 500,
|
||||
compactSurface = false,
|
||||
}: {
|
||||
result: SpeedtestTrackerResult;
|
||||
width?: number;
|
||||
compactSurface?: boolean;
|
||||
}) {
|
||||
const t = useI18n("widget.speedtestTracker");
|
||||
const locale = useCurrentIntlLocale();
|
||||
const timestamp = Intl.DateTimeFormat(locale, {
|
||||
@@ -25,7 +33,7 @@ export function LatestResultSection({ result, width = 500 }: { result: Speedtest
|
||||
return (
|
||||
<Stack gap={6} h="100%">
|
||||
<Group justify="space-between" align="center" wrap="nowrap">
|
||||
<SectionLabel>{t("latestResult")}</SectionLabel>
|
||||
<SectionLabel uppercase={compactSurface}>{t("latestResult")}</SectionLabel>
|
||||
<Text size="xs" c="dimmed" truncate title={timestamp} style={{ minWidth: 0 }}>
|
||||
{timestamp}
|
||||
</Text>
|
||||
@@ -36,18 +44,21 @@ export function LatestResultSection({ result, width = 500 }: { result: Speedtest
|
||||
color="blue"
|
||||
value={formatResultSpeed(result, "download")}
|
||||
label={t("download")}
|
||||
legacySurface={compactSurface}
|
||||
/>
|
||||
<SpeedStatCard
|
||||
icon={IconArrowUp}
|
||||
color="teal"
|
||||
value={formatResultSpeed(result, "upload")}
|
||||
label={t("upload")}
|
||||
legacySurface={compactSurface}
|
||||
/>
|
||||
<SpeedStatCard
|
||||
icon={IconWaveSine}
|
||||
color="orange"
|
||||
value={result.ping !== null ? `${result.ping.toFixed(1)} ms` : "—"}
|
||||
label={t("ping")}
|
||||
legacySurface={compactSurface}
|
||||
/>
|
||||
{result.healthy !== null && (
|
||||
<SpeedStatCard
|
||||
@@ -55,6 +66,7 @@ export function LatestResultSection({ result, width = 500 }: { result: Speedtest
|
||||
color={result.healthy ? "green" : "red"}
|
||||
value={result.healthy ? t("healthy") : t("unhealthy")}
|
||||
label={t("status")}
|
||||
legacySurface={compactSurface}
|
||||
/>
|
||||
)}
|
||||
</SimpleGrid>
|
||||
|
||||
@@ -114,30 +114,40 @@ function formatTooltipDate(label: number | string | undefined, locale: string):
|
||||
export function RecentResultsSection({
|
||||
results,
|
||||
showPingGraph,
|
||||
uppercaseLabels = false,
|
||||
}: {
|
||||
results: SpeedtestTrackerResult[];
|
||||
showPingGraph: boolean;
|
||||
uppercaseLabels?: boolean;
|
||||
}) {
|
||||
const t = useI18n("widget.speedtestTracker");
|
||||
|
||||
return (
|
||||
<Stack gap={4} h="100%" style={{ minHeight: 0 }}>
|
||||
<SectionLabel>{t("recentResults")}</SectionLabel>
|
||||
<SectionLabel uppercase={uppercaseLabels}>{t("recentResults")}</SectionLabel>
|
||||
<div style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column", gap: 4 }}>
|
||||
<SpeedSubChart results={results} showLabel={showPingGraph} />
|
||||
{showPingGraph && <PingSubChart results={results} />}
|
||||
<SpeedSubChart results={results} showLabel={showPingGraph} uppercaseLabels={uppercaseLabels} />
|
||||
{showPingGraph && <PingSubChart results={results} uppercaseLabels={uppercaseLabels} />}
|
||||
</div>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
function SpeedSubChart({ results, showLabel }: { results: SpeedtestTrackerResult[]; showLabel: boolean }) {
|
||||
function SpeedSubChart({
|
||||
results,
|
||||
showLabel,
|
||||
uppercaseLabels,
|
||||
}: {
|
||||
results: SpeedtestTrackerResult[];
|
||||
showLabel: boolean;
|
||||
uppercaseLabels: boolean;
|
||||
}) {
|
||||
const t = useI18n("widget.speedtestTracker");
|
||||
const { ref, height } = useElementSize<HTMLDivElement>();
|
||||
|
||||
return (
|
||||
<div style={{ flex: 2, minHeight: 0, display: "flex", flexDirection: "column", gap: 2 }}>
|
||||
{showLabel && <SectionLabel>{t("recentResultsSpeed")}</SectionLabel>}
|
||||
{showLabel && <SectionLabel uppercase={uppercaseLabels}>{t("recentResultsSpeed")}</SectionLabel>}
|
||||
<div ref={ref} style={{ flex: 1, minHeight: 0 }}>
|
||||
{height > 0 && <SpeedHistoryChart results={results} height={height} />}
|
||||
</div>
|
||||
@@ -145,13 +155,13 @@ function SpeedSubChart({ results, showLabel }: { results: SpeedtestTrackerResult
|
||||
);
|
||||
}
|
||||
|
||||
function PingSubChart({ results }: { results: SpeedtestTrackerResult[] }) {
|
||||
function PingSubChart({ results, uppercaseLabels }: { results: SpeedtestTrackerResult[]; uppercaseLabels: boolean }) {
|
||||
const t = useI18n("widget.speedtestTracker");
|
||||
const { ref, height } = useElementSize<HTMLDivElement>();
|
||||
|
||||
return (
|
||||
<div style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column", gap: 2 }}>
|
||||
<SectionLabel>{t("recentResultsPing")}</SectionLabel>
|
||||
<SectionLabel uppercase={uppercaseLabels}>{t("recentResultsPing")}</SectionLabel>
|
||||
<div ref={ref} style={{ flex: 1, minHeight: 0 }}>
|
||||
{height > 0 && <PingHistoryChart results={results} height={height} />}
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { Text } from "@mantine/core";
|
||||
|
||||
export function SectionLabel({ children }: { children: ReactNode }) {
|
||||
export function SectionLabel({ children, uppercase = false }: { children: ReactNode; uppercase?: boolean }) {
|
||||
return (
|
||||
<Text size="xs" fw={600} c="dimmed">
|
||||
<Text
|
||||
size="xs"
|
||||
fw={600}
|
||||
c="dimmed"
|
||||
tt={uppercase ? "uppercase" : undefined}
|
||||
style={{ letterSpacing: uppercase ? "0.05em" : undefined }}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
);
|
||||
|
||||
@@ -13,9 +13,17 @@ export interface SpeedStatCardProps {
|
||||
value: string;
|
||||
label: string;
|
||||
compact?: boolean;
|
||||
legacySurface?: boolean;
|
||||
}
|
||||
|
||||
export function SpeedStatCard({ icon: Icon, color, value, label, compact = false }: SpeedStatCardProps) {
|
||||
export function SpeedStatCard({
|
||||
icon: Icon,
|
||||
color,
|
||||
value,
|
||||
label,
|
||||
compact = false,
|
||||
legacySurface = false,
|
||||
}: SpeedStatCardProps) {
|
||||
const { ref, height, width } = useElementSize<HTMLDivElement>();
|
||||
const board = useRequiredBoard();
|
||||
const isWide = width > height + 20;
|
||||
@@ -23,7 +31,8 @@ export function SpeedStatCard({ icon: Icon, color, value, label, compact = false
|
||||
const surfaceColor = `var(--mantine-color-${color}-filled)`;
|
||||
const accentColor = `var(--mantine-color-${color}-5)`;
|
||||
const surfaceAlpha = compact ? 0.1 : 0.14;
|
||||
const surfaceBackground = `rgb(from ${surfaceColor} r g b / calc(var(--opacity, 1) * ${surfaceAlpha}))`;
|
||||
const modernBackground = `rgb(from ${surfaceColor} r g b / calc(var(--opacity, 1) * ${surfaceAlpha}))`;
|
||||
const surfaceBackground = legacySurface ? `var(--mantine-color-${color}-light)` : modernBackground;
|
||||
const surfaceBorder = "rgb(from var(--mantine-color-default-border) r g b / calc(var(--opacity, 1) * 0.45))";
|
||||
|
||||
return (
|
||||
@@ -32,7 +41,7 @@ export function SpeedStatCard({ icon: Icon, color, value, label, compact = false
|
||||
ref={ref}
|
||||
p={compact ? "xs" : "sm"}
|
||||
radius={board.itemRadius}
|
||||
withBorder
|
||||
withBorder={!legacySurface}
|
||||
bg={surfaceBackground}
|
||||
h="100%"
|
||||
style={{ flex: 1, minWidth: 0, borderColor: surfaceBorder }}
|
||||
|
||||
Reference in new issue
Block a user