feat: add getReferrerDisplayName utility to enhance referrer display in ExportModal and TopReferrers components
This commit is contained in:
@@ -7,6 +7,7 @@ import jsPDF from 'jspdf'
|
||||
import autoTable from 'jspdf-autotable'
|
||||
import type { DailyStat } from './Chart'
|
||||
import { formatNumber, formatDuration } from '@/lib/utils/format'
|
||||
import { getReferrerDisplayName } from '@/lib/utils/icons'
|
||||
import type { TopPage, TopReferrer } from '@/lib/api/stats'
|
||||
|
||||
interface ExportModalProps {
|
||||
@@ -278,7 +279,7 @@ export default function ExportModal({ isOpen, onClose, data, stats, topPages, to
|
||||
doc.text('Top Referrers', 14, finalY)
|
||||
finalY += 5
|
||||
|
||||
const referrersData = topReferrers.slice(0, 10).map(r => [r.referrer, formatNumber(r.pageviews)])
|
||||
const referrersData = topReferrers.slice(0, 10).map(r => [getReferrerDisplayName(r.referrer), formatNumber(r.pageviews)])
|
||||
|
||||
autoTable(doc, {
|
||||
startY: finalY,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { formatNumber } from '@/lib/utils/format'
|
||||
import { getReferrerFavicon, getReferrerIcon } from '@/lib/utils/icons'
|
||||
import { getReferrerDisplayName, getReferrerFavicon, getReferrerIcon } from '@/lib/utils/icons'
|
||||
import { Modal, GlobeIcon } from '@ciphera-net/ui'
|
||||
import { getTopReferrers, TopReferrer } from '@/lib/api/stats'
|
||||
|
||||
@@ -98,7 +98,7 @@ export default function TopReferrers({ referrers, collectReferrers = true, siteI
|
||||
<div key={index} className="flex items-center justify-between h-9 group hover:bg-neutral-50 dark:hover:bg-neutral-800 rounded-lg px-2 -mx-2 transition-colors">
|
||||
<div className="flex-1 truncate text-neutral-900 dark:text-white flex items-center gap-3">
|
||||
{renderReferrerIcon(ref.referrer)}
|
||||
<span className="truncate" title={ref.referrer}>{ref.referrer}</span>
|
||||
<span className="truncate" title={ref.referrer}>{getReferrerDisplayName(ref.referrer)}</span>
|
||||
</div>
|
||||
<div className="text-sm font-semibold text-neutral-600 dark:text-neutral-400 ml-4">
|
||||
{formatNumber(ref.pageviews)}
|
||||
@@ -141,7 +141,7 @@ export default function TopReferrers({ referrers, collectReferrers = true, siteI
|
||||
<div key={index} className="flex items-center justify-between py-2 group hover:bg-neutral-50 dark:hover:bg-neutral-800 rounded-lg px-2 -mx-2 transition-colors">
|
||||
<div className="flex-1 truncate text-neutral-900 dark:text-white flex items-center gap-3">
|
||||
{renderReferrerIcon(ref.referrer)}
|
||||
<span className="truncate" title={ref.referrer}>{ref.referrer}</span>
|
||||
<span className="truncate" title={ref.referrer}>{getReferrerDisplayName(ref.referrer)}</span>
|
||||
</div>
|
||||
<div className="text-sm font-semibold text-neutral-600 dark:text-neutral-400 ml-4">
|
||||
{formatNumber(ref.pageviews)}
|
||||
|
||||
@@ -80,6 +80,69 @@ export function getReferrerIcon(referrerName: string) {
|
||||
|
||||
const REFERRER_NO_FAVICON = ['direct', 'unknown', '']
|
||||
|
||||
/**
|
||||
* Map of referrer hostname (lowercase) to display name for the Top Referrers list.
|
||||
* Unknown hostnames fall back to the original referrer string.
|
||||
*/
|
||||
const REFERRER_DISPLAY_NAMES: Record<string, string> = {
|
||||
'google.com': 'Google',
|
||||
'www.google.com': 'Google',
|
||||
'google.co.uk': 'Google',
|
||||
'google.de': 'Google',
|
||||
'facebook.com': 'Facebook',
|
||||
'www.facebook.com': 'Facebook',
|
||||
'm.facebook.com': 'Facebook',
|
||||
'instagram.com': 'Instagram',
|
||||
'www.instagram.com': 'Instagram',
|
||||
'l.instagram.com': 'Instagram',
|
||||
'twitter.com': 'X',
|
||||
'www.twitter.com': 'X',
|
||||
't.co': 'X',
|
||||
'x.com': 'X',
|
||||
'linkedin.com': 'LinkedIn',
|
||||
'www.linkedin.com': 'LinkedIn',
|
||||
'github.com': 'GitHub',
|
||||
'www.github.com': 'GitHub',
|
||||
'youtube.com': 'YouTube',
|
||||
'www.youtube.com': 'YouTube',
|
||||
'reddit.com': 'Reddit',
|
||||
'www.reddit.com': 'Reddit',
|
||||
'chatgpt.com': 'ChatGPT',
|
||||
'www.chatgpt.com': 'ChatGPT',
|
||||
'ciphera.net': 'Ciphera',
|
||||
'www.ciphera.net': 'Ciphera',
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname for a referrer string (URL or plain hostname), or null if invalid.
|
||||
*/
|
||||
function getReferrerHostname(referrer: string): string | null {
|
||||
if (!referrer || typeof referrer !== 'string') return null
|
||||
const trimmed = referrer.trim()
|
||||
if (REFERRER_NO_FAVICON.includes(trimmed.toLowerCase())) return null
|
||||
try {
|
||||
const url = new URL(trimmed.startsWith('http') ? trimmed : `https://${trimmed}`)
|
||||
return url.hostname.toLowerCase()
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a friendly display name for the referrer (e.g. "Google" instead of "google.com").
|
||||
* Falls back to the original referrer string when no mapping exists.
|
||||
*/
|
||||
export function getReferrerDisplayName(referrer: string): string {
|
||||
if (!referrer || typeof referrer !== 'string') return referrer || ''
|
||||
const trimmed = referrer.trim()
|
||||
if (trimmed === '') return ''
|
||||
const hostname = getReferrerHostname(trimmed)
|
||||
if (!hostname) return trimmed
|
||||
const displayName = REFERRER_DISPLAY_NAMES[hostname]
|
||||
if (displayName) return displayName
|
||||
return trimmed
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a favicon URL for the referrer's domain, or null for non-URL referrers
|
||||
* (e.g. "Direct", "Unknown") so callers can show an icon fallback instead.
|
||||
|
||||
Reference in New Issue
Block a user