Release 0.14.0-alpha #42
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|||||||
|
|
||||||
### Improved
|
### Improved
|
||||||
|
|
||||||
|
- **Scroll Depth is now a radar chart.** The Scroll Depth panel has been redesigned from a bar chart into a radar chart. The four scroll milestones (25%, 50%, 75%, 100%) are plotted as axes, with the filled shape showing how far visitors are getting through your pages at a glance.
|
||||||
- **Polished Goals & Events panel.** The Goals & Events block on your dashboard got a visual refresh to match the style of the Pages, Referrers, and Locations panels. Events are now ranked with a number on the left, counts are shown in a consistent style, and hovering any row reveals what percentage of total events that action accounts for — sliding in smoothly from the right.
|
- **Polished Goals & Events panel.** The Goals & Events block on your dashboard got a visual refresh to match the style of the Pages, Referrers, and Locations panels. Events are now ranked with a number on the left, counts are shown in a consistent style, and hovering any row reveals what percentage of total events that action accounts for — sliding in smoothly from the right.
|
||||||
- **Smarter bot protection.** The security checks on shared dashboard access and organization settings now use action-specific tokens tied to each page. A token earned on one page can't be reused on another, making it harder for automated tools to bypass the captcha.
|
- **Smarter bot protection.** The security checks on shared dashboard access and organization settings now use action-specific tokens tied to each page. A token earned on one page can't be reused on another, making it harder for automated tools to bypass the captcha.
|
||||||
- **More resilient under Redis outages.** If the caching layer goes down temporarily, Pulse now continues enforcing rate limits using an in-memory fallback instead of letting all traffic through unchecked. This prevents one infrastructure hiccup from snowballing into a bigger problem.
|
- **More resilient under Redis outages.** If the caching layer goes down temporarily, Pulse now continues enforcing rate limits using an in-memory fallback instead of letting all traffic through unchecked. This prevents one infrastructure hiccup from snowballing into a bigger problem.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { formatNumber } from '@ciphera-net/ui'
|
import { PolarAngleAxis, PolarGrid, Radar, RadarChart, Tooltip } from 'recharts'
|
||||||
import { BarChartIcon } from '@ciphera-net/ui'
|
import { BarChartIcon } from '@ciphera-net/ui'
|
||||||
import type { GoalCountStat } from '@/lib/api/stats'
|
import type { GoalCountStat } from '@/lib/api/stats'
|
||||||
|
|
||||||
@@ -22,6 +22,11 @@ export default function ScrollDepth({ goalCounts, totalPageviews }: ScrollDepthP
|
|||||||
|
|
||||||
const hasData = scrollCounts.size > 0 && totalPageviews > 0
|
const hasData = scrollCounts.size > 0 && totalPageviews > 0
|
||||||
|
|
||||||
|
const chartData = THRESHOLDS.map((threshold) => ({
|
||||||
|
label: `${threshold}%`,
|
||||||
|
value: totalPageviews > 0 ? Math.round(((scrollCounts.get(threshold) ?? 0) / totalPageviews) * 100) : 0,
|
||||||
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 rounded-2xl p-6 h-full flex flex-col">
|
<div className="bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 rounded-2xl p-6 h-full flex flex-col">
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
@@ -31,36 +36,37 @@ export default function ScrollDepth({ goalCounts, totalPageviews }: ScrollDepthP
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{hasData ? (
|
{hasData ? (
|
||||||
<div className="space-y-3 flex-1 min-h-[200px]">
|
<div className="flex-1 min-h-[200px] flex items-center justify-center">
|
||||||
{THRESHOLDS.map((threshold) => {
|
<RadarChart
|
||||||
const count = scrollCounts.get(threshold) ?? 0
|
width={260}
|
||||||
const pct = totalPageviews > 0 ? Math.round((count / totalPageviews) * 100) : 0
|
height={220}
|
||||||
const barWidth = Math.max(pct, 2)
|
data={chartData}
|
||||||
|
margin={{ top: 10, right: 20, bottom: 10, left: 20 }}
|
||||||
return (
|
>
|
||||||
<div key={threshold} className="space-y-1">
|
<PolarGrid stroke="#404040" />
|
||||||
<div className="flex items-center justify-between text-sm">
|
<PolarAngleAxis
|
||||||
<span className="font-medium text-neutral-900 dark:text-white">
|
dataKey="label"
|
||||||
{threshold}%
|
tick={{ fill: '#a3a3a3', fontSize: 12, fontWeight: 500 }}
|
||||||
</span>
|
/>
|
||||||
<div className="flex items-center gap-2">
|
<Tooltip
|
||||||
<span className="text-neutral-500 dark:text-neutral-400 tabular-nums">
|
cursor={false}
|
||||||
{formatNumber(count)}
|
contentStyle={{
|
||||||
</span>
|
backgroundColor: '#171717',
|
||||||
<span className="font-semibold text-brand-orange tabular-nums w-12 text-right">
|
border: '1px solid #404040',
|
||||||
{pct}%
|
borderRadius: 8,
|
||||||
</span>
|
fontSize: 12,
|
||||||
</div>
|
color: '#fff',
|
||||||
</div>
|
}}
|
||||||
<div className="h-2 rounded-full bg-neutral-100 dark:bg-neutral-800 overflow-hidden">
|
formatter={(value: number) => [`${value}%`, 'Reached']}
|
||||||
<div
|
/>
|
||||||
className="h-full rounded-full bg-brand-orange transition-all duration-500"
|
<Radar
|
||||||
style={{ width: `${barWidth}%` }}
|
dataKey="value"
|
||||||
/>
|
stroke="#FD5E0F"
|
||||||
</div>
|
fill="#FD5E0F"
|
||||||
</div>
|
fillOpacity={0.25}
|
||||||
)
|
dot={{ r: 4, fill: '#FD5E0F', fillOpacity: 1, strokeWidth: 0 }}
|
||||||
})}
|
/>
|
||||||
|
</RadarChart>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex-1 min-h-[200px] flex flex-col items-center justify-center text-center px-6 py-8 gap-4">
|
<div className="flex-1 min-h-[200px] flex flex-col items-center justify-center text-center px-6 py-8 gap-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user