From 5a03e1f9a5361b98b5ad16c65889e367d6a5322c Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Tue, 24 Mar 2026 21:17:21 +0100 Subject: [PATCH] fix: skeleton loading states match actual page layouts - PageSpeed: show 4 gauge rings, screenshot, legend, metrics grid, trend chart - Uptime: match real layout with status card, 90-day bar, 4-col detail grid - Remove duplicate local skeletons in behavior components, use shared library - Strip light-mode classes from dark-only app --- app/sites/[id]/pagespeed/page.tsx | 74 +++++++++++----- .../behavior/FrustrationByPageTable.tsx | 21 +---- .../behavior/FrustrationSummaryCards.tsx | 19 +---- components/behavior/FrustrationTrend.tsx | 17 +--- components/skeletons.tsx | 85 ++++++++++++------- 5 files changed, 114 insertions(+), 102 deletions(-) diff --git a/app/sites/[id]/pagespeed/page.tsx b/app/sites/[id]/pagespeed/page.tsx index 4eb5f27..8e5de27 100644 --- a/app/sites/[id]/pagespeed/page.tsx +++ b/app/sites/[id]/pagespeed/page.tsx @@ -868,35 +868,67 @@ function AuditItem({ item }: { item: Record }) { // * Skeleton loading state function PageSpeedSkeleton() { return ( -
-
-
-
-
- {/* Hero skeleton */} -
-
-
-
-
-
-
+
+ {/* Header — title + subtitle + toggle buttons */} +
+
+
+
+
+
+
+
+
-
+
- {/* Metrics skeleton */} -
-
-
+ + {/* Score overview — 4 gauge circles + screenshot */} +
+
+
+ {[...Array(4)].map((_, i) => ( +
+
+
+
+ ))} +
+
+
+ {/* Legend bar */} +
+
+
+
+
+
+
+
+
+ + {/* Metrics card — 6 metrics in 3-col grid */} +
+
+
{[...Array(6)].map((_, i) => ( -
-
-
+
+
+
+
+
+
))}
+ + {/* Score trend chart placeholder */} +
+
+
+
) } diff --git a/components/behavior/FrustrationByPageTable.tsx b/components/behavior/FrustrationByPageTable.tsx index 2331228..d419a2a 100644 --- a/components/behavior/FrustrationByPageTable.tsx +++ b/components/behavior/FrustrationByPageTable.tsx @@ -3,30 +3,13 @@ import { formatNumber } from '@ciphera-net/ui' import { Files } from '@phosphor-icons/react' import type { FrustrationByPage } from '@/lib/api/stats' +import { TableSkeleton } from '@/components/skeletons' interface FrustrationByPageTableProps { pages: FrustrationByPage[] loading: boolean } -function SkeletonRows() { - return ( -
- {Array.from({ length: 5 }).map((_, i) => ( -
-
-
-
-
-
-
-
-
- ))} -
- ) -} - export default function FrustrationByPageTable({ pages, loading }: FrustrationByPageTableProps) { const hasData = pages.length > 0 const maxTotal = Math.max(...pages.map(p => p.total), 1) @@ -43,7 +26,7 @@ export default function FrustrationByPageTable({ pages, loading }: FrustrationBy

{loading ? ( - + ) : hasData ? (
{/* Header */} diff --git a/components/behavior/FrustrationSummaryCards.tsx b/components/behavior/FrustrationSummaryCards.tsx index 6f7cf48..185be21 100644 --- a/components/behavior/FrustrationSummaryCards.tsx +++ b/components/behavior/FrustrationSummaryCards.tsx @@ -1,6 +1,7 @@ 'use client' import type { FrustrationSummary } from '@/lib/api/stats' +import { StatCardSkeleton } from '@/components/skeletons' interface FrustrationSummaryCardsProps { data: FrustrationSummary | null @@ -39,25 +40,13 @@ function ChangeIndicator({ change }: { change: ReturnType }) { ) } -function SkeletonCard() { - return ( -
-
-
-
-
-
-
- ) -} - export default function FrustrationSummaryCards({ data, loading }: FrustrationSummaryCardsProps) { if (loading || !data) { return (
- - - + + +
) } diff --git a/components/behavior/FrustrationTrend.tsx b/components/behavior/FrustrationTrend.tsx index 18fb8f6..e364f15 100644 --- a/components/behavior/FrustrationTrend.tsx +++ b/components/behavior/FrustrationTrend.tsx @@ -8,26 +8,13 @@ import { type ChartConfig, } from '@/components/charts' import type { FrustrationSummary } from '@/lib/api/stats' +import { WidgetSkeleton } from '@/components/skeletons' interface FrustrationTrendProps { summary: FrustrationSummary | null loading: boolean } -function SkeletonCard() { - return ( -
-
-
-
-
-
-
-
-
- ) -} - const LABELS: Record = { rage_clicks: 'Rage Clicks', dead_clicks: 'Dead Clicks', @@ -70,7 +57,7 @@ function CustomTooltip({ active, payload }: { active?: boolean; payload?: Array< } export default function FrustrationTrend({ summary, loading }: FrustrationTrendProps) { - if (loading || !summary) return + if (loading || !summary) return const hasData = summary.rage_clicks > 0 || summary.dead_clicks > 0 || summary.prev_rage_clicks > 0 || summary.prev_dead_clicks > 0 diff --git a/components/skeletons.tsx b/components/skeletons.tsx index 52d6e92..76e740e 100644 --- a/components/skeletons.tsx +++ b/components/skeletons.tsx @@ -1,10 +1,10 @@ /** * Reusable skeleton loading primitives and composites for Pulse. * All skeletons follow the design-system pattern: - * animate-pulse + bg-neutral-100 dark:bg-neutral-800 + rounded + * animate-pulse + bg-neutral-800 + rounded */ -const SK = 'animate-pulse bg-neutral-100 dark:bg-neutral-800' +const SK = 'animate-pulse bg-neutral-800' export { useMinimumLoading, useSkeletonFade } from './useMinimumLoading' @@ -71,7 +71,7 @@ export function TableSkeleton({ rows = 7, cols = 5 }: { rows?: number; cols?: nu export function WidgetSkeleton() { return ( -
+
@@ -90,7 +90,7 @@ export function WidgetSkeleton() { export function StatCardSkeleton() { return ( -
+
@@ -101,7 +101,7 @@ export function StatCardSkeleton() { export function ChartSkeleton() { return ( -
+
{Array.from({ length: 4 }).map((_, i) => ( @@ -157,7 +157,7 @@ export function DashboardSkeleton() { {/* Campaigns table */}
-
+
@@ -187,7 +187,7 @@ export function JourneysSkeleton() { {/* Sankey area */} {/* Top paths table */} -
+
@@ -200,28 +200,49 @@ export function JourneysSkeleton() { export function UptimeSkeleton() { return (
-
- - - + {/* Header */} +
+
+ + +
+
- {/* Overall status */} - - {/* Monitor cards */} -
- {Array.from({ length: 3 }).map((_, i) => ( -
-
-
- - - -
- -
- + {/* Overall status card */} +
+
+
+ + +
- ))} +
+ + +
+
+
+ {/* 90-day uptime bar */} +
+ + +
+ + +
+
+ {/* Monitor details + chart + checks */} +
+ {/* 4-col detail grid */} +
+ {Array.from({ length: 4 }).map((_, i) => ( +
+ + +
+ ))} +
+
) @@ -263,7 +284,7 @@ export function FunnelsListSkeleton() {
{Array.from({ length: 3 }).map((_, i) => ( -
+
@@ -308,7 +329,7 @@ export function NotificationsListSkeleton() { return (
{Array.from({ length: 6 }).map((_, i) => ( -
+
@@ -343,7 +364,7 @@ export function GoalsListSkeleton() { return (
{Array.from({ length: 3 }).map((_, i) => ( -
+
@@ -387,7 +408,7 @@ export function BehaviorSkeleton() { {/* Summary cards (3 cols) */}
{Array.from({ length: 3 }).map((_, i) => ( -
+
@@ -403,7 +424,7 @@ export function BehaviorSkeleton() { {/* By-page table */}
-
+