Group audits within each category by sub-group (e.g., "Names and
Labels", "Contrast") with small uppercase headers, matching the
pagespeed.web.dev layout.
- Hero: 4 equal 90px ScoreGauges in a row with screenshot on right
- Diagnostics: each category card gets a 56px gauge header with score
and issue count, matching pagespeed.web.dev's category sections
- Legend and metadata moved to footer bar in hero card
Use direct API fetch for polling instead of mutateLatest() which was
causing the page to flicker and clear data every 5 seconds. SWR cache
is only updated once when new results arrive.
- Hero card: large performance gauge + compact inline scores + screenshot
- Single metrics card with 2x3 grid and colored status dots
- Flat diagnostics list sorted by impact with severity indicators
- ScoreGauge accepts size prop for flexible gauge sizing
- Unicode severity markers (triangle/square/circle) per audit
- Page screenshot thumbnail next to score gauges
- Expandable audit rows with description and detail items table
- Shows URLs, HTML snippets, wasted bytes/ms for each failing element
- AuditRow component replaces flat diagnostic rows
- PageSpeed API client with types for config, checks, and audits
- SWR hooks: usePageSpeedConfig, usePageSpeedLatest, usePageSpeedHistory
- GaugeIcon added to sidebar under Infrastructure group
Rewrites uptime page from 978 to ~370 lines. Removes all monitor CRUD
UI (modals, monitor list, selection state). Adds enable/disable toggle
and empty state. Reads the single auto-managed monitor.
Features (scroll, 404, outbound, downloads, frustration, storage, ttl)
are saved to site.script_features JSONB column on every toggle change.
Values are read from the site object on load.
Backend returns timestamps already bucketed in site timezone but as
UTC values. Using getUTCHours/getUTCMinutes prevents the browser
from adding its local timezone offset.
Added formatLabel prop to XAxis component. When viewing Today (hour
or minute interval), X-axis shows "2:00 PM" instead of "Mar 22".
Tooltip shows time for intra-day, date for multi-day.
handlePasswordSubmit now calls POST /public/sites/:id/auth which
sets an HttpOnly cookie. All subsequent API calls authenticate via
cookie automatically — no password in URLs, no captcha state needed
for data fetching. Simplifies share page state management.
Used refs for password/captcha values so loadDashboard doesn't
recreate on every keystroke. Password is only sent to API on
explicit form submit. Also fixes stale captcha state in closures.
Public dashboard endpoints use password auth, not session tokens.
A 401 on /public/ should surface to the caller (for password prompt),
not trigger a token refresh that fails and shows "Session expired".
- Shows green "Password set" badge when a password is active
- Simplified placeholder to "Enter new password"
- Added helper text explaining current password persists
- Added "Remove password protection" link for easy removal
- Cleaned up dark-mode toggle styling
Uses @icons-pack/react-simple-icons for available brands (Google,
Facebook, Instagram, GitHub, YouTube, Reddit, etc.) and inline SVGs
for brands missing from the package (X, LinkedIn, OpenAI, Bing).
All icons now show actual brand logos with correct colors.
Google's favicon service returns wrong/low-quality icons for known
services. Now all major platforms, search engines, and AI assistants
use their Phosphor icon directly. Favicons only fetched for unknown
domains.
Integrated 21st.dev AreaChart component with animated crosshair,
spring-based tooltip, and date ticker. Uses brand orange for the
line/fill with dark-only CSS variables.