diff --git a/components/dashboard/ExportModal.tsx b/components/dashboard/ExportModal.tsx index bd0da91..86ccd64 100644 --- a/components/dashboard/ExportModal.tsx +++ b/components/dashboard/ExportModal.tsx @@ -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, diff --git a/components/dashboard/TopReferrers.tsx b/components/dashboard/TopReferrers.tsx index 4974f5d..05add44 100644 --- a/components/dashboard/TopReferrers.tsx +++ b/components/dashboard/TopReferrers.tsx @@ -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
{renderReferrerIcon(ref.referrer)} - {ref.referrer} + {getReferrerDisplayName(ref.referrer)}
{formatNumber(ref.pageviews)} @@ -141,7 +141,7 @@ export default function TopReferrers({ referrers, collectReferrers = true, siteI
{renderReferrerIcon(ref.referrer)} - {ref.referrer} + {getReferrerDisplayName(ref.referrer)}
{formatNumber(ref.pageviews)} diff --git a/lib/utils/icons.tsx b/lib/utils/icons.tsx index 7e93641..0293253 100644 --- a/lib/utils/icons.tsx +++ b/lib/utils/icons.tsx @@ -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 = { + '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.