polish UI/UX color bands, add install-heatmap command

This commit is contained in:
Francis Cao
2026-05-19 12:11:48 -07:00
parent 6de5adaefc
commit afab485874
3 changed files with 24 additions and 13 deletions
+1
View File
@@ -41,6 +41,7 @@
"postbuild": "node scripts/postbuild.js",
"test": "vitest run",
"test:watch": "vitest",
"install-heatmap": "playwright install chromium",
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
"seed-data": "tsx scripts/seed-data.ts",
@@ -408,18 +408,18 @@ function ScrollHeatmapView({
for (let depth = 0; depth < 100; depth += SCROLL_BUCKET_SIZE) {
const reached = Math.max(0, totalSessions - dropped);
const ratio = totalSessions ? reached / totalSessions : 0;
dropped += sessionsByDepth.get(depth) ?? 0;
const nextReached = Math.max(0, totalSessions - dropped);
const ratio = totalSessions ? nextReached / totalSessions : 0;
if (reached > 0) {
bands.push({
fromPct: depth,
toPct: Math.min(100, depth + SCROLL_BUCKET_SIZE),
reached,
reached: nextReached,
ratio,
});
}
dropped += sessionsByDepth.get(depth) ?? 0;
}
return (
@@ -481,10 +481,10 @@ function ScrollHeatmapView({
height: `${Math.max(0, band.toPct - band.fromPct)}%`,
background: `hsla(${hue}, 90%, 55%, ${0.12 + intensity * 0.45})`,
}}
title={`${band.fromPct}% depth • ${formatLongNumber(band.reached)} sessions reached`}
title={`${band.toPct}% depth • ${formatLongNumber(band.reached)} sessions reached`}
>
<span className={styles.scrollBandLabel}>
{band.fromPct}% depth {Math.round(intensity * 100)}% reached
{band.toPct}% depth {Math.round(intensity * 100)}% reached
</span>
</div>
);
+17 -7
View File
@@ -4,9 +4,9 @@ import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
import prisma from '@/lib/prisma';
import type { QueryFilters } from '@/lib/types';
import {
type HeatmapSnapshotImage,
ensureHeatmapSnapshot,
shouldSkipSnapshot,
type HeatmapSnapshotImage,
} from './ensureHeatmapSnapshot';
const FUNCTION_NAME = 'getHeatmap';
@@ -86,7 +86,7 @@ async function relationalQuery(
const { startDate, endDate, urlPath, mode = 'click' } = parameters;
const eventType = mode === 'scroll' ? HEATMAP_EVENT_TYPE.scroll : HEATMAP_EVENT_TYPE.click;
const filterContext = getRelationalHeatmapFilterContext(websiteId, parameters);
const clickPageFilter =
const pageFilter =
mode === 'click'
? `
and x is not null
@@ -98,7 +98,12 @@ async function relationalQuery(
and viewport_w is not null
and viewport_h is not null
`
: '';
: `
and scroll_pct is not null
and page_w is not null
and page_h is not null
and viewport_w is not null
`;
const rawPages: HeatmapPage[] = await rawQuery(
`
@@ -111,7 +116,7 @@ async function relationalQuery(
where h.website_id = {{websiteId::uuid}}
and h.event_type = {{eventType}}
and h.created_at between {{startDate}} and {{endDate}}
${clickPageFilter}
${pageFilter}
group by h.url_path
order by sessions desc, count desc
limit ${PAGE_LIMIT}
@@ -267,7 +272,7 @@ async function clickhouseQuery(
const { startDate, endDate, urlPath, mode = 'click' } = parameters;
const eventType = mode === 'scroll' ? HEATMAP_EVENT_TYPE.scroll : HEATMAP_EVENT_TYPE.click;
const filterContext = getClickhouseHeatmapFilterContext(websiteId, parameters);
const clickPageFilter =
const pageFilter =
mode === 'click'
? `
and x is not null
@@ -279,7 +284,12 @@ async function clickhouseQuery(
and viewport_w is not null
and viewport_h is not null
`
: '';
: `
and scroll_pct is not null
and page_w is not null
and page_h is not null
and viewport_w is not null
`;
const pageRows = await rawQuery<
{ urlPath: string; count: string | number; sessions: string | number }[]
@@ -294,7 +304,7 @@ async function clickhouseQuery(
where h.website_id = {websiteId:UUID}
and h.event_type = {eventType:UInt8}
and h.created_at between {startDate:DateTime64} and {endDate:DateTime64}
${clickPageFilter}
${pageFilter}
group by h.url_path
order by sessions desc, count desc
limit ${PAGE_LIMIT}