fix(referrers): replace low-res Google favicon globe with proper icons

Detect Google's 16x16 default globe fallback via naturalWidth on load
and fall back to Phosphor icons. Add Chrome icon for googlechrome.github.io,
CursorClick for Direct, and abbreviation support (ig, fb, yt).
This commit is contained in:
Usman Baig
2026-03-23 12:23:10 +01:00
parent 31471792f8
commit 508bb006a8
2 changed files with 26 additions and 6 deletions

View File

@@ -2,7 +2,6 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { logger } from '@/lib/utils/logger' import { logger } from '@/lib/utils/logger'
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 Link from 'next/link'
@@ -48,14 +47,21 @@ export default function TopReferrers({ referrers, collectReferrers = true, siteI
const useFavicon = faviconUrl && !faviconFailed.has(referrer) const useFavicon = faviconUrl && !faviconFailed.has(referrer)
if (useFavicon) { if (useFavicon) {
return ( return (
<Image // eslint-disable-next-line @next/next/no-img-element
<img
src={faviconUrl} src={faviconUrl}
alt="" alt=""
width={20} width={20}
height={20} height={20}
className="w-5 h-5 flex-shrink-0 rounded object-contain" className="w-5 h-5 flex-shrink-0 rounded object-contain"
onError={() => setFaviconFailed((prev) => new Set(prev).add(referrer))} onError={() => setFaviconFailed((prev) => new Set(prev).add(referrer))}
unoptimized onLoad={(e) => {
// Google's favicon service returns a 16x16 default globe when no real favicon exists
const img = e.currentTarget
if (img.naturalWidth <= 16) {
setFaviconFailed((prev) => new Set(prev).add(referrer))
}
}}
/> />
) )
} }

View File

@@ -6,6 +6,7 @@ import {
DeviceTablet, DeviceTablet,
Desktop, Desktop,
Link, Link,
CursorClick,
} from '@phosphor-icons/react' } from '@phosphor-icons/react'
import { import {
SiGoogle, SiGoogle,
@@ -122,12 +123,16 @@ const SI = { size: 16 } as const
export function getReferrerIcon(referrerName: string) { export function getReferrerIcon(referrerName: string) {
if (!referrerName) return <Globe className="text-neutral-400" /> if (!referrerName) return <Globe className="text-neutral-400" />
const lower = referrerName.toLowerCase() const lower = referrerName.toLowerCase()
// Direct traffic
if (lower === 'direct') return <CursorClick className="text-neutral-500" />
// Browsers as referrers (e.g. googlechrome.com, firefox.com)
if (lower.includes('googlechrome') || lower.includes('chrome')) return <img src="/icons/browsers/chrome.svg" alt="Chrome" width={16} height={16} className="inline-block" />
// Social / platforms // Social / platforms
if (lower.includes('google') && !lower.includes('gemini')) return <SiGoogle size={SI.size} color="#4285F4" /> if (lower.includes('google') && !lower.includes('gemini')) return <SiGoogle size={SI.size} color="#4285F4" />
if (lower.includes('facebook')) return <SiFacebook size={SI.size} color="#0866FF" /> if (lower.includes('facebook') || lower === 'fb') return <SiFacebook size={SI.size} color="#0866FF" />
if (lower.includes('twitter') || lower.includes('t.co') || lower.includes('x.com')) return <XIcon /> if (lower.includes('twitter') || lower.includes('t.co') || lower.includes('x.com')) return <XIcon />
if (lower.includes('linkedin')) return <LinkedInIcon /> if (lower.includes('linkedin')) return <LinkedInIcon />
if (lower.includes('instagram')) return <SiInstagram size={SI.size} color="#E4405F" /> if (lower.includes('instagram') || lower === 'ig') return <SiInstagram size={SI.size} color="#E4405F" />
if (lower.includes('github')) return <SiGithub size={SI.size} color="#fff" /> if (lower.includes('github')) return <SiGithub size={SI.size} color="#fff" />
if (lower.includes('youtube')) return <SiYoutube size={SI.size} color="#FF0000" /> if (lower.includes('youtube')) return <SiYoutube size={SI.size} color="#FF0000" />
if (lower.includes('reddit')) return <SiReddit size={SI.size} color="#FF4500" /> if (lower.includes('reddit')) return <SiReddit size={SI.size} color="#FF4500" />
@@ -183,6 +188,10 @@ const REFERRER_DISPLAY_OVERRIDES: Record<string, string> = {
threads: 'Threads', threads: 'Threads',
tumblr: 'Tumblr', tumblr: 'Tumblr',
quora: 'Quora', quora: 'Quora',
ig: 'Instagram',
fb: 'Facebook',
yt: 'YouTube',
googlechrome: 'Google Chrome',
't.co': 'X', 't.co': 'X',
'x.com': 'X', 'x.com': 'X',
// AI assistants and search tools // AI assistants and search tools
@@ -239,7 +248,12 @@ export function getReferrerDisplayName(referrer: string): string {
const trimmed = referrer.trim() const trimmed = referrer.trim()
if (trimmed === '') return '' if (trimmed === '') return ''
const hostname = getReferrerHostname(trimmed) const hostname = getReferrerHostname(trimmed)
if (!hostname) return trimmed if (!hostname) {
// Plain names without a dot (e.g. "Ig", "Direct") — check override map before returning raw
const overrideByPlain = REFERRER_DISPLAY_OVERRIDES[trimmed.toLowerCase()]
if (overrideByPlain) return overrideByPlain
return trimmed
}
const overrideByHostname = REFERRER_DISPLAY_OVERRIDES[hostname] const overrideByHostname = REFERRER_DISPLAY_OVERRIDES[hostname]
if (overrideByHostname) return overrideByHostname if (overrideByHostname) return overrideByHostname
const label = getReferrerLabel(hostname) const label = getReferrerLabel(hostname)