feat: add actionable CTAs to all dashboard empty states
- Campaigns: "Build a UTM URL" opens UTM builder modal directly - Pages/Referrers/Locations/Technology: "Install tracking script" links to /installation - Matches existing CTA pattern from GoalStats
This commit is contained in:
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|||||||
|
|
||||||
### Improved
|
### Improved
|
||||||
|
|
||||||
|
- **Actionable empty states.** When a dashboard section has no data yet, you now get a direct action — like "Install tracking script" or "Build a UTM URL" — instead of just passive text. Gets you set up faster.
|
||||||
- **Animated numbers across the dashboard.** Stats like visitors, pageviews, bounce rate, and visit duration now smoothly count up or down when you switch date ranges, apply filters, or when real-time visitor counts change — instead of just jumping to the new value.
|
- **Animated numbers across the dashboard.** Stats like visitors, pageviews, bounce rate, and visit duration now smoothly count up or down when you switch date ranges, apply filters, or when real-time visitor counts change — instead of just jumping to the new value.
|
||||||
- **Inline bar charts on dashboard lists.** Pages, referrers, locations, technology, and campaigns now show subtle proportional bars behind each row, making it easier to compare values at a glance without reading numbers.
|
- **Inline bar charts on dashboard lists.** Pages, referrers, locations, technology, and campaigns now show subtle proportional bars behind each row, making it easier to compare values at a glance without reading numbers.
|
||||||
- **Redesigned Top Paths.** The Top Paths section on the Journeys page has been completely rebuilt — from bulky cards to a clean, compact list with inline bars that matches the rest of Pulse. Long path sequences are truncated so they stay readable.
|
- **Redesigned Top Paths.** The Top Paths section on the Journeys page has been completely rebuilt — from bulky cards to a clean, compact list with inline bars that matches the rest of Pulse. Long path sequences are truncated so they stay readable.
|
||||||
|
|||||||
@@ -206,13 +206,13 @@ export default function Campaigns({ siteId, dateRange, filters, onFilter }: Camp
|
|||||||
<p className="text-sm text-neutral-500 dark:text-neutral-400 max-w-xs">
|
<p className="text-sm text-neutral-500 dark:text-neutral-400 max-w-xs">
|
||||||
Add UTM parameters to your links to see campaign performance here.
|
Add UTM parameters to your links to see campaign performance here.
|
||||||
</p>
|
</p>
|
||||||
<Link
|
<button
|
||||||
href="/installation"
|
onClick={() => setIsBuilderOpen(true)}
|
||||||
className="inline-flex items-center gap-2 text-sm font-medium text-brand-orange hover:text-brand-orange/90 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange/20 rounded"
|
className="inline-flex items-center gap-2 text-sm font-medium text-brand-orange hover:text-brand-orange/90 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange/20 rounded cursor-pointer"
|
||||||
>
|
>
|
||||||
Learn more
|
Build a UTM URL
|
||||||
<ArrowRightIcon className="w-4 h-4" />
|
<ArrowRightIcon className="w-4 h-4" />
|
||||||
</Link>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import { logger } from '@/lib/utils/logger'
|
|||||||
import { formatNumber } from '@ciphera-net/ui'
|
import { formatNumber } from '@ciphera-net/ui'
|
||||||
import { useTabListKeyboard } from '@/lib/hooks/useTabListKeyboard'
|
import { useTabListKeyboard } from '@/lib/hooks/useTabListKeyboard'
|
||||||
import { TopPage, getTopPages, getEntryPages, getExitPages } from '@/lib/api/stats'
|
import { TopPage, getTopPages, getEntryPages, getExitPages } from '@/lib/api/stats'
|
||||||
|
import Link from 'next/link'
|
||||||
import { Files, FrameCornersIcon } from '@phosphor-icons/react'
|
import { Files, FrameCornersIcon } from '@phosphor-icons/react'
|
||||||
import { Modal, ArrowUpRightIcon, LayoutDashboardIcon } from '@ciphera-net/ui'
|
import { Modal, ArrowUpRightIcon, ArrowRightIcon, LayoutDashboardIcon } from '@ciphera-net/ui'
|
||||||
import { ListSkeleton } from '@/components/skeletons'
|
import { ListSkeleton } from '@/components/skeletons'
|
||||||
import VirtualList from './VirtualList'
|
import VirtualList from './VirtualList'
|
||||||
import { type DimensionFilter } from '@/lib/filters'
|
import { type DimensionFilter } from '@/lib/filters'
|
||||||
@@ -199,6 +200,13 @@ export default function ContentStats({ topPages, entryPages, exitPages, domain,
|
|||||||
<p className="text-sm text-neutral-500 dark:text-neutral-400 max-w-xs">
|
<p className="text-sm text-neutral-500 dark:text-neutral-400 max-w-xs">
|
||||||
Your most visited pages will appear here as traffic arrives.
|
Your most visited pages will appear here as traffic arrives.
|
||||||
</p>
|
</p>
|
||||||
|
<Link
|
||||||
|
href="/installation"
|
||||||
|
className="inline-flex items-center gap-2 text-sm font-medium text-brand-orange hover:text-brand-orange/90 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange/20 rounded"
|
||||||
|
>
|
||||||
|
Install tracking script
|
||||||
|
<ArrowRightIcon className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import iso3166 from 'iso-3166-2'
|
|||||||
|
|
||||||
const DottedMap = dynamic(() => import('./DottedMap'), { ssr: false })
|
const DottedMap = dynamic(() => import('./DottedMap'), { ssr: false })
|
||||||
const Globe = dynamic(() => import('./Globe'), { ssr: false })
|
const Globe = dynamic(() => import('./Globe'), { ssr: false })
|
||||||
import { Modal, GlobeIcon } from '@ciphera-net/ui'
|
import Link from 'next/link'
|
||||||
|
import { Modal, GlobeIcon, ArrowRightIcon } from '@ciphera-net/ui'
|
||||||
import { ListSkeleton } from '@/components/skeletons'
|
import { ListSkeleton } from '@/components/skeletons'
|
||||||
import VirtualList from './VirtualList'
|
import VirtualList from './VirtualList'
|
||||||
import { ShieldCheck, Detective, Broadcast, MapPin, FrameCornersIcon } from '@phosphor-icons/react'
|
import { ShieldCheck, Detective, Broadcast, MapPin, FrameCornersIcon } from '@phosphor-icons/react'
|
||||||
@@ -280,6 +281,13 @@ export default function Locations({ countries, cities, regions, geoDataLevel = '
|
|||||||
<p className="text-sm text-neutral-500 dark:text-neutral-400 max-w-xs">
|
<p className="text-sm text-neutral-500 dark:text-neutral-400 max-w-xs">
|
||||||
Visitor locations will appear here based on anonymous geographic data.
|
Visitor locations will appear here based on anonymous geographic data.
|
||||||
</p>
|
</p>
|
||||||
|
<Link
|
||||||
|
href="/installation"
|
||||||
|
className="inline-flex items-center gap-2 text-sm font-medium text-brand-orange hover:text-brand-orange/90 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange/20 rounded"
|
||||||
|
>
|
||||||
|
Install tracking script
|
||||||
|
<ArrowRightIcon className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import { logger } from '@/lib/utils/logger'
|
|||||||
import { formatNumber } from '@ciphera-net/ui'
|
import { formatNumber } from '@ciphera-net/ui'
|
||||||
import { useTabListKeyboard } from '@/lib/hooks/useTabListKeyboard'
|
import { useTabListKeyboard } from '@/lib/hooks/useTabListKeyboard'
|
||||||
import { getBrowserIcon, getOSIcon, getDeviceIcon } from '@/lib/utils/icons'
|
import { getBrowserIcon, getOSIcon, getDeviceIcon } from '@/lib/utils/icons'
|
||||||
|
import Link from 'next/link'
|
||||||
import { Monitor, DeviceMobile, FrameCornersIcon } from '@phosphor-icons/react'
|
import { Monitor, DeviceMobile, FrameCornersIcon } from '@phosphor-icons/react'
|
||||||
import { Modal, GridIcon } from '@ciphera-net/ui'
|
import { Modal, GridIcon, ArrowRightIcon } from '@ciphera-net/ui'
|
||||||
import { ListSkeleton } from '@/components/skeletons'
|
import { ListSkeleton } from '@/components/skeletons'
|
||||||
import VirtualList from './VirtualList'
|
import VirtualList from './VirtualList'
|
||||||
import { getBrowsers, getOS, getDevices, getScreenResolutions } from '@/lib/api/stats'
|
import { getBrowsers, getOS, getDevices, getScreenResolutions } from '@/lib/api/stats'
|
||||||
@@ -223,6 +224,13 @@ export default function TechSpecs({ browsers, os, devices, screenResolutions, co
|
|||||||
<p className="text-sm text-neutral-500 dark:text-neutral-400 max-w-xs">
|
<p className="text-sm text-neutral-500 dark:text-neutral-400 max-w-xs">
|
||||||
Browser, OS, and device information will appear as visitors arrive.
|
Browser, OS, and device information will appear as visitors arrive.
|
||||||
</p>
|
</p>
|
||||||
|
<Link
|
||||||
|
href="/installation"
|
||||||
|
className="inline-flex items-center gap-2 text-sm font-medium text-brand-orange hover:text-brand-orange/90 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange/20 rounded"
|
||||||
|
>
|
||||||
|
Install tracking script
|
||||||
|
<ArrowRightIcon className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import { logger } from '@/lib/utils/logger'
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import { formatNumber } from '@ciphera-net/ui'
|
import { formatNumber } from '@ciphera-net/ui'
|
||||||
import { getReferrerDisplayName, getReferrerFavicon, getReferrerIcon, mergeReferrersByDisplayName } from '@/lib/utils/icons'
|
import { getReferrerDisplayName, getReferrerFavicon, getReferrerIcon, mergeReferrersByDisplayName } from '@/lib/utils/icons'
|
||||||
|
import Link from 'next/link'
|
||||||
import { ArrowSquareOut, FrameCornersIcon } from '@phosphor-icons/react'
|
import { ArrowSquareOut, FrameCornersIcon } from '@phosphor-icons/react'
|
||||||
import { Modal, GlobeIcon } from '@ciphera-net/ui'
|
import { Modal, GlobeIcon, ArrowRightIcon } from '@ciphera-net/ui'
|
||||||
import { ListSkeleton } from '@/components/skeletons'
|
import { ListSkeleton } from '@/components/skeletons'
|
||||||
import VirtualList from './VirtualList'
|
import VirtualList from './VirtualList'
|
||||||
import { getTopReferrers, TopReferrer } from '@/lib/api/stats'
|
import { getTopReferrers, TopReferrer } from '@/lib/api/stats'
|
||||||
@@ -155,6 +156,13 @@ export default function TopReferrers({ referrers, collectReferrers = true, siteI
|
|||||||
<p className="text-sm text-neutral-500 dark:text-neutral-400 max-w-xs">
|
<p className="text-sm text-neutral-500 dark:text-neutral-400 max-w-xs">
|
||||||
Traffic sources will appear here when visitors come from external sites.
|
Traffic sources will appear here when visitors come from external sites.
|
||||||
</p>
|
</p>
|
||||||
|
<Link
|
||||||
|
href="/installation"
|
||||||
|
className="inline-flex items-center gap-2 text-sm font-medium text-brand-orange hover:text-brand-orange/90 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange/20 rounded"
|
||||||
|
>
|
||||||
|
Install tracking script
|
||||||
|
<ArrowRightIcon className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user