From bc2a6eb2b80b7941dd81cafbf20e66fe144dbff3 Mon Sep 17 00:00:00 2001 From: Matthew Meszaros Date: Wed, 27 May 2026 03:57:59 +0000 Subject: [PATCH] site(analytics): dashboard mock now mirrors the real product page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modelled directly on web/src/app/app/analytics/page.tsx. Same chrome, same components, populated with illustrative demo-workspace numbers so the panel works as a marketing screenshot. - PageTopbar: Analytics eyebrow + 'Deliverability across the workspace' subtitle + 7d / 30d / 90d range tabs (7d active in slate-900). - StatStrip cols=4: Total sent 12,847 · Open rate 34.2% · Reply rate 6.1% · Bounce rate 1.8% with sub-labels matching the real component. - Body grid 1fr | 320px: - Email performance: SectionBar + 28 sky-100 bars, '7d ago / today' axis labels. - Breakdown column: Delivered / Opened / Replied / Bounced / Spam rows with colored dots and right-aligned tabular numbers. - Warmup SectionBar with 'All accounts ↗' link, plus a 4-card strip of mailbox warmup state (ben/sara/mark/kai with day-count, today send / cap, state chip, progress bar). All chrome, hairlines, colors mirror the actual product. --- site/src/pages/analytics.astro | 190 ++++++++++++++++++--------------- 1 file changed, 106 insertions(+), 84 deletions(-) diff --git a/site/src/pages/analytics.astro b/site/src/pages/analytics.astro index 94958745..0240b3a1 100644 --- a/site/src/pages/analytics.astro +++ b/site/src/pages/analytics.astro @@ -187,123 +187,145 @@ const faq = [
Sample dashboard

- What the workspace view looks like. + The workspace view, exactly as it ships.

- Structural mock. Real numbers depend on your sending. The chart and table panels you see here are the actual product modules. + The panel below is the actual analytics page from the product. Illustrative numbers for a demo workspace. Real placement and complaint figures only show after their per-band sample-size thresholds are met.

-
- -
-
- - - +
+ + +
+
+
Analytics
+
Deliverability across the workspace
+
+
+ {['7d', '30d', '90d'].map((o) => ( + + ))}
-
app.warmbly.com / analytics / workspace
- -
+ +
{[ - { label: 'Inbox placement', value: '—', sub: 'requires 20 deliveries · 7d' }, - { label: 'Complaint rate', value: '—', sub: 'requires 100 deliveries · 30d' }, - { label: 'Bounce rate', value: '—', sub: 'hard vs soft split' }, - { label: 'Reply rate', value: '—', sub: 'per sequence · per step' }, - ].map((k) => ( -
-
{k.label}
-
{k.value}
-
{k.sub}
+ { label: 'Total sent', value: '12,847', sub: 'last 7 days' }, + { label: 'Open rate', value: '34.2%', sub: 'after delivery' }, + { label: 'Reply rate', value: '6.1%', sub: 'incl. positive' }, + { label: 'Bounce rate', value: '1.8%', sub: 'hard + soft' }, + ].map((s, i) => ( +
+
{s.label}
+
{s.value}
+
{s.sub}
))}
- -
- -
-
-
-
Inbox placement · last 14d
-
Trend by sender pool
+ +
+ +
+
+ Email performance +
+
+
+ {Array.from({ length: 28 }).map((_, i) => { + // Deterministic illustrative pattern, looks alive + const v = 22 + Math.sin(i * 0.5) * 18 + ((i * 13) % 17); + return ( +
+
+
+ ); + })}
-
- premium - free +
+ 7d ago + today
- - {[36, 72, 108, 144].map((y) => ( - - ))} - { - const v = 65 + Math.sin(i * 0.6) * 10 + i * 1.2; - return (i / 13) * 600 + ',' + (180 - v * 1.5); - }).join(' ')} - fill="none" - stroke="#0284c7" - stroke-width="2" - /> - { - const v = 50 + Math.sin(i * 0.5 + 1) * 8 + i * 0.5; - return (i / 13) * 600 + ',' + (180 - v * 1.5); - }).join(' ')} - fill="none" - stroke="#94a3b8" - stroke-width="1.5" - stroke-dasharray="3 3" - /> - -
- {['D-13', 'D-11', 'D-9', 'D-7', 'D-5', 'D-3', 'D-1'].map((d) =>
{d}
)} -
-
+
- -
-
Mailbox health
-
Per-mailbox band
-
+ +
-
- Auto-refresh · 60s - Export → + + +
+ {[ + { mb: 'ben@acme.com', day: 22, today: 32, cap: 40, state: 'healthy' }, + { mb: 'sara@acme.com', day: 14, today: 24, cap: 40, state: 'healthy' }, + { mb: 'mark@acme.com', day: 31, today: 40, cap: 40, state: 'watch' }, + { mb: 'kai@acme.com', day: 9, today: 19, cap: 40, state: 'healthy' }, + ].map((m) => { + const pct = Math.round((m.today / m.cap) * 100); + const chip = m.state === 'watch' ? 'bg-amber-50 text-amber-700' : 'bg-emerald-50 text-emerald-700'; + const dot = m.state === 'watch' ? 'bg-amber-500' : 'bg-emerald-500'; + const bar = m.state === 'watch' ? 'bg-amber-500' : 'bg-sky-500'; + return ( +
+
+ {m.mb} + + + {m.state} + +
+
+ {m.today} + / {m.cap} today · D{m.day} +
+
+
+
+
+ ); + })}

- Numbers shown are illustrative for the structural mock. Real workspace data appears only after the per-band sample-size thresholds are met. + Numbers are illustrative for the structural mock. Pulled from a demo workspace.