This commit is contained in:
Carl-Gerhard Lindesvärd
2026-03-09 14:20:15 +01:00
parent 0f9e5f6e93
commit df0258f532
12 changed files with 186 additions and 76 deletions

View File

@@ -8,7 +8,7 @@ interface SparklineBarsProps {
data: { date: string; pageviews: number }[];
}
const gap = 1;
const defaultGap = 1;
const height = 24;
const width = 100;
@@ -38,7 +38,16 @@ function SparklineBars({ data }: SparklineBarsProps) {
}
const max = Math.max(...data.map((d) => d.pageviews), 1);
const total = data.length;
const barW = Math.max(2, Math.floor((width - gap * (total - 1)) / total));
// Compute bar width to fit SVG width; reduce gap if needed so barW >= 1 when possible
let gap = defaultGap;
let barW = Math.floor((width - gap * (total - 1)) / total);
if (barW < 1 && total > 1) {
gap = 0;
barW = Math.floor((width - gap * (total - 1)) / total);
}
if (barW < 1) {
barW = 1;
}
const trend = getTrendDirection(data);
const trendColor =
trend === '↑'
@@ -71,9 +80,9 @@ function SparklineBars({ data }: SparklineBarsProps) {
<Tooltiper
content={
trend === '↑'
? 'Upgoing trend'
? 'Upward trend'
: trend === '↓'
? 'Downgoing trend'
? 'Downward trend'
: 'Stable trend'
}
>

View File

@@ -103,6 +103,16 @@ export function useColumns({
if (prev == null) {
return <span className="text-muted-foreground"></span>;
}
if (prev === 0) {
return (
<div className="flex items-center gap-2">
<span className="font-mono text-sm tabular-nums">
{number.short(row.original.sessions)}
</span>
<span className="text-muted-foreground">new</span>
</div>
);
}
const pct = ((row.original.sessions - prev) / prev) * 100;
const isPos = pct >= 0;
@@ -112,15 +122,12 @@ export function useColumns({
<span className="font-mono text-sm tabular-nums">
{number.short(row.original.sessions)}
</span>
{prev === 0 && <span className="text-muted-foreground">new</span>}
{prev > 0 && (
<span
className={`font-mono text-sm tabular-nums ${isPos ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}`}
>
{isPos ? '+' : ''}
{pct.toFixed(1)}%
</span>
)}
<span
className={`font-mono text-sm tabular-nums ${isPos ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}`}
>
{isPos ? '+' : ''}
{pct.toFixed(1)}%
</span>
</div>
);
},

View File

@@ -26,7 +26,12 @@ export function PagesTable({ projectId }: PagesTableProps) {
const pagesQuery = useQuery(
trpc.event.pages.queryOptions(
{ projectId, cursor: 1, take: 1000, search: undefined, range, interval },
{
projectId,
search: debouncedSearch ?? undefined,
range,
interval,
},
{ placeholderData: keepPreviousData },
),
);
@@ -44,7 +49,7 @@ export function PagesTable({ projectId }: PagesTableProps) {
range,
startDate: startDate ?? undefined,
endDate: endDate ?? undefined,
limit: 1000,
limit: 10_000,
},
{ enabled: isGscConnected },
),
@@ -88,22 +93,11 @@ export function PagesTable({ projectId }: PagesTableProps) {
}));
}, [pagesQuery.data, gscMap]);
const filteredData = useMemo(() => {
if (!debouncedSearch) return rawData;
const q = debouncedSearch.toLowerCase();
return rawData.filter(
(p) =>
p.path.toLowerCase().includes(q) ||
p.origin.toLowerCase().includes(q) ||
(p.title ?? '').toLowerCase().includes(q),
);
}, [rawData, debouncedSearch]);
const columns = useColumns({ projectId, isGscConnected, previousMap });
const { table } = useTable({
columns,
data: filteredData,
data: rawData,
loading: pagesQuery.isLoading,
pageSize: 50,
name: 'pages',
@@ -133,7 +127,9 @@ export function PagesTable({ projectId }: PagesTableProps) {
: 'Integrate our web SDK to your site to get pages here.',
}}
onRowClick={(row) => {
if (!isGscConnected) return;
if (!isGscConnected) {
return;
}
const page = row.original;
pushModal('PageDetails', {
type: 'page',