refactor: Simplify AnalyzePanel to match Hunt page style
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
- Remove colorful section backgrounds and borders - Use monochrome, minimalist styling throughout - Remove "Show raw data" toggle from items - Compact header and score display - Simplified footer with smaller text - Consistent with Hunt pages design language
This commit is contained in:
@ -14,17 +14,11 @@ import {
|
|||||||
Check,
|
Check,
|
||||||
Zap,
|
Zap,
|
||||||
Globe,
|
Globe,
|
||||||
ChevronDown,
|
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
XCircle,
|
XCircle,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
Info,
|
|
||||||
Clock,
|
Clock,
|
||||||
Link2,
|
|
||||||
Search,
|
|
||||||
Eye,
|
|
||||||
Filter,
|
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { api } from '@/lib/api'
|
import { api } from '@/lib/api'
|
||||||
import { useAnalyzePanelStore } from '@/lib/analyze-store'
|
import { useAnalyzePanelStore } from '@/lib/analyze-store'
|
||||||
@ -49,58 +43,54 @@ function getStatusColor(status: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getSectionConfig(key: string) {
|
function getSectionConfig(key: string) {
|
||||||
|
// Minimalist monochrome style matching Hunt pages
|
||||||
|
const base = {
|
||||||
|
bg: 'bg-white/[0.02]',
|
||||||
|
border: 'border-white/[0.08]',
|
||||||
|
color: 'text-white/60'
|
||||||
|
}
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'authority':
|
case 'authority':
|
||||||
return {
|
return {
|
||||||
|
...base,
|
||||||
icon: Shield,
|
icon: Shield,
|
||||||
color: 'text-blue-400',
|
description: 'Age, backlinks, trust signals',
|
||||||
bg: 'bg-blue-500/10',
|
tooltip: 'Authority measures how established and trusted the domain is.'
|
||||||
border: 'border-blue-500/20',
|
|
||||||
description: 'Domain age, backlink profile, and trust signals',
|
|
||||||
tooltip: 'Authority measures how established and trusted the domain is. Older domains with quality backlinks rank better.'
|
|
||||||
}
|
}
|
||||||
case 'market':
|
case 'market':
|
||||||
return {
|
return {
|
||||||
|
...base,
|
||||||
icon: TrendingUp,
|
icon: TrendingUp,
|
||||||
color: 'text-emerald-400',
|
description: 'Search demand, CPC, TLD availability',
|
||||||
bg: 'bg-emerald-500/10',
|
tooltip: 'Market data shows commercial potential.'
|
||||||
border: 'border-emerald-500/20',
|
|
||||||
description: 'Search demand, ad value, and TLD availability',
|
|
||||||
tooltip: 'Market data shows commercial potential. High search volume + CPC = strong buyer intent.'
|
|
||||||
}
|
}
|
||||||
case 'risk':
|
case 'risk':
|
||||||
return {
|
return {
|
||||||
|
...base,
|
||||||
icon: AlertTriangle,
|
icon: AlertTriangle,
|
||||||
color: 'text-amber-400',
|
description: 'Trademarks, blacklists, history',
|
||||||
bg: 'bg-amber-500/10',
|
tooltip: 'Risk checks help avoid legal issues.'
|
||||||
border: 'border-amber-500/20',
|
|
||||||
description: 'Trademark conflicts, blacklists, and history',
|
|
||||||
tooltip: 'Risk checks help avoid legal issues and spam penalties. Always clear before buying.'
|
|
||||||
}
|
}
|
||||||
case 'value':
|
case 'value':
|
||||||
return {
|
return {
|
||||||
|
...base,
|
||||||
icon: DollarSign,
|
icon: DollarSign,
|
||||||
color: 'text-violet-400',
|
description: 'Estimated worth, comparable sales',
|
||||||
bg: 'bg-violet-500/10',
|
tooltip: 'Value estimation based on market data.'
|
||||||
border: 'border-violet-500/20',
|
|
||||||
description: 'Estimated worth and recent comparable sales',
|
|
||||||
tooltip: 'Value estimation based on length, keywords, extension, and actual market sales.'
|
|
||||||
}
|
}
|
||||||
case 'vision':
|
case 'vision':
|
||||||
return {
|
return {
|
||||||
|
...base,
|
||||||
icon: Sparkles,
|
icon: Sparkles,
|
||||||
color: 'text-accent',
|
color: 'text-accent',
|
||||||
bg: 'bg-accent/10',
|
description: 'AI business insights',
|
||||||
border: 'border-accent/20',
|
tooltip: 'AI-powered analysis for this domain.'
|
||||||
description: 'AI business concepts and ideal buyer profiles',
|
|
||||||
tooltip: 'AI-powered analysis suggesting business uses and potential buyers for this domain.'
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
|
...base,
|
||||||
icon: Globe,
|
icon: Globe,
|
||||||
color: 'text-white/50',
|
|
||||||
bg: 'bg-white/5',
|
|
||||||
border: 'border-white/10',
|
|
||||||
description: '',
|
description: '',
|
||||||
tooltip: ''
|
tooltip: ''
|
||||||
}
|
}
|
||||||
@ -295,22 +285,17 @@ export function AnalyzePanel() {
|
|||||||
<div className="absolute right-0 top-0 bottom-0 w-full sm:w-[560px] lg:w-[640px] bg-[#030303] border-l border-white/[0.08] flex flex-col overflow-hidden">
|
<div className="absolute right-0 top-0 bottom-0 w-full sm:w-[560px] lg:w-[640px] bg-[#030303] border-l border-white/[0.08] flex flex-col overflow-hidden">
|
||||||
|
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="shrink-0 border-b border-white/[0.08]">
|
<div className="shrink-0 border-b border-white/[0.06]">
|
||||||
{/* Top Bar */}
|
{/* Top Bar */}
|
||||||
<div className="px-4 py-4 flex items-center justify-between gap-4">
|
<div className="px-4 py-3 flex items-center justify-between gap-4">
|
||||||
<div className="flex items-center gap-3 min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="w-10 h-10 bg-accent/10 border border-accent/20 flex items-center justify-center shrink-0">
|
<div className="text-[9px] font-mono text-white/30 uppercase tracking-wider mb-0.5">Analysis</div>
|
||||||
<Search className="w-5 h-5 text-accent" />
|
<div className="text-base font-bold text-white font-mono truncate">
|
||||||
</div>
|
{headerDomain}
|
||||||
<div className="min-w-0">
|
|
||||||
<div className="text-[10px] font-mono text-accent uppercase tracking-wider">Domain Analysis</div>
|
|
||||||
<div className="text-lg font-bold text-white font-mono truncate">
|
|
||||||
{headerDomain}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-1.5 shrink-0">
|
<div className="flex items-center gap-1 shrink-0">
|
||||||
<button
|
<button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const ok = await copyToClipboard(headerDomain)
|
const ok = await copyToClipboard(headerDomain)
|
||||||
@ -318,134 +303,84 @@ export function AnalyzePanel() {
|
|||||||
setTimeout(() => setCopied(false), 1500)
|
setTimeout(() => setCopied(false), 1500)
|
||||||
}}
|
}}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"w-9 h-9 flex items-center justify-center border transition-all",
|
"w-8 h-8 flex items-center justify-center transition-all",
|
||||||
copied
|
copied ? "text-accent" : "text-white/30 hover:text-white"
|
||||||
? "border-accent/30 bg-accent/10 text-accent"
|
|
||||||
: "border-white/[0.08] text-white/40 hover:text-white hover:bg-white/[0.05]"
|
|
||||||
)}
|
)}
|
||||||
title="Copy domain"
|
title="Copy domain"
|
||||||
>
|
>
|
||||||
{copied ? <Check className="w-4 h-4" /> : <Copy className="w-4 h-4" />}
|
{copied ? <Check className="w-3.5 h-3.5" /> : <Copy className="w-3.5 h-3.5" />}
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a
|
||||||
href={`https://${encodeURIComponent(headerDomain)}`}
|
href={`https://${encodeURIComponent(headerDomain)}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="w-9 h-9 flex items-center justify-center border border-white/[0.08] text-white/40 hover:text-white hover:bg-white/[0.05] transition-colors"
|
className="w-8 h-8 flex items-center justify-center text-white/30 hover:text-white transition-colors"
|
||||||
title="Visit domain"
|
title="Visit domain"
|
||||||
>
|
>
|
||||||
<ExternalLink className="w-4 h-4" />
|
<ExternalLink className="w-3.5 h-3.5" />
|
||||||
</a>
|
</a>
|
||||||
<button
|
<button
|
||||||
onClick={refresh}
|
onClick={refresh}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="w-9 h-9 flex items-center justify-center border border-white/[0.08] text-white/40 hover:text-white hover:bg-white/[0.05] transition-colors disabled:opacity-50"
|
className="w-8 h-8 flex items-center justify-center text-white/30 hover:text-white transition-colors disabled:opacity-50"
|
||||||
title="Refresh analysis"
|
title="Refresh"
|
||||||
>
|
>
|
||||||
<RefreshCw className={clsx('w-4 h-4', loading && 'animate-spin')} />
|
<RefreshCw className={clsx('w-3.5 h-3.5', loading && 'animate-spin')} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={close}
|
onClick={close}
|
||||||
className="w-9 h-9 flex items-center justify-center border border-white/[0.08] text-white/40 hover:text-white hover:bg-white/[0.05] transition-colors ml-1"
|
className="w-8 h-8 flex items-center justify-center text-white/30 hover:text-white transition-colors"
|
||||||
title="Close panel (ESC)"
|
title="Close (ESC)"
|
||||||
>
|
>
|
||||||
<X className="w-4 h-4" />
|
<X className="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Score Bar */}
|
{/* Score Bar - Compact */}
|
||||||
{overallScore && !loading && (
|
{overallScore && !loading && (
|
||||||
<div className="px-4 pb-4">
|
<div className="px-4 pb-3">
|
||||||
<div className="p-4 bg-white/[0.02] border border-white/[0.08]">
|
<div className="flex items-center gap-3">
|
||||||
<div className="flex items-center gap-4">
|
<div
|
||||||
<div
|
className={clsx(
|
||||||
className={clsx(
|
"w-12 h-12 flex items-center justify-center border",
|
||||||
"w-16 h-16 flex items-center justify-center border-2",
|
overallScore.score >= 70 ? "border-accent/30 text-accent" :
|
||||||
overallScore.score >= 70 ? "border-accent bg-accent/10" :
|
overallScore.score >= 40 ? "border-amber-400/30 text-amber-400" : "border-rose-500/30 text-rose-400"
|
||||||
overallScore.score >= 40 ? "border-amber-400 bg-amber-400/10" : "border-rose-500 bg-rose-500/10"
|
)}
|
||||||
)}
|
>
|
||||||
title={`Health Score: ${overallScore.score}/100. ${overallScore.score >= 70 ? 'Excellent - safe to buy' : overallScore.score >= 40 ? 'Moderate - review warnings' : 'Poor - significant issues'}`}
|
<span className="text-xl font-bold font-mono">{overallScore.score}</span>
|
||||||
>
|
</div>
|
||||||
<span className={clsx(
|
<div className="flex-1 min-w-0">
|
||||||
"text-2xl font-bold font-mono",
|
<div className="h-1.5 bg-white/[0.05] overflow-hidden flex mb-2">
|
||||||
overallScore.score >= 70 ? "text-accent" : overallScore.score >= 40 ? "text-amber-400" : "text-rose-400"
|
<div className="h-full bg-accent" style={{ width: `${(overallScore.pass / overallScore.total) * 100}%` }} />
|
||||||
)}>
|
<div className="h-full bg-amber-400" style={{ width: `${(overallScore.warn / overallScore.total) * 100}%` }} />
|
||||||
{overallScore.score}
|
<div className="h-full bg-rose-500" style={{ width: `${(overallScore.fail / overallScore.total) * 100}%` }} />
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex items-center gap-3 text-[10px] font-mono text-white/40">
|
||||||
<div className="flex items-center justify-between mb-2">
|
<span className="text-accent">{overallScore.pass} ok</span>
|
||||||
<div className="text-xs font-bold text-white uppercase tracking-wider">Health Score</div>
|
<span className="text-amber-400">{overallScore.warn} warn</span>
|
||||||
<div className="text-[10px] font-mono text-white/40">
|
<span className="text-rose-400">{overallScore.fail} fail</span>
|
||||||
{overallScore.score >= 70 ? '✓ Good to buy' : overallScore.score >= 40 ? '⚠ Review issues' : '⛔ High risk'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="h-2.5 bg-white/[0.05] overflow-hidden flex mb-2">
|
|
||||||
<div
|
|
||||||
className="h-full bg-accent transition-all"
|
|
||||||
style={{ width: `${(overallScore.pass / overallScore.total) * 100}%` }}
|
|
||||||
title={`${overallScore.pass} passed checks`}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className="h-full bg-amber-400 transition-all"
|
|
||||||
style={{ width: `${(overallScore.warn / overallScore.total) * 100}%` }}
|
|
||||||
title={`${overallScore.warn} warnings`}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className="h-full bg-rose-500 transition-all"
|
|
||||||
style={{ width: `${(overallScore.fail / overallScore.total) * 100}%` }}
|
|
||||||
title={`${overallScore.fail} failed checks`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-4 text-xs font-mono">
|
|
||||||
<span className="text-accent flex items-center gap-1.5" title="Checks passed - no issues found">
|
|
||||||
<CheckCircle2 className="w-3.5 h-3.5" /> {overallScore.pass} passed
|
|
||||||
</span>
|
|
||||||
<span className="text-amber-400 flex items-center gap-1.5" title="Warnings - review before buying">
|
|
||||||
<AlertTriangle className="w-3.5 h-3.5" /> {overallScore.warn} warnings
|
|
||||||
</span>
|
|
||||||
<span className="text-rose-400 flex items-center gap-1.5" title="Failed checks - potential problems">
|
|
||||||
<XCircle className="w-3.5 h-3.5" /> {overallScore.fail} failed
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Controls with Explanations */}
|
{/* Controls - Minimal */}
|
||||||
<div className="px-4 pb-3">
|
<div className="px-4 pb-3 flex items-center gap-2">
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<button
|
||||||
<button
|
onClick={() => setFastMode(!fastMode)}
|
||||||
onClick={() => setFastMode(!fastMode)}
|
className={clsx(
|
||||||
className={clsx(
|
"flex items-center gap-1 px-2 py-1 text-[9px] font-mono uppercase transition-all",
|
||||||
"flex items-center gap-1.5 px-3 py-1.5 text-[10px] font-bold uppercase tracking-wider border transition-all group relative",
|
fastMode ? "text-accent" : "text-white/30 hover:text-white"
|
||||||
fastMode
|
|
||||||
? "border-accent/30 bg-accent/10 text-accent"
|
|
||||||
: "border-white/[0.08] text-white/40 hover:text-white hover:bg-white/[0.05]"
|
|
||||||
)}
|
|
||||||
title="Fast Mode: DNS-only checks (~2 sec). Skips WHOIS/RDAP for speed. Fewer details but instant results."
|
|
||||||
>
|
|
||||||
<Zap className="w-3.5 h-3.5" />
|
|
||||||
Fast Mode
|
|
||||||
</button>
|
|
||||||
{data?.cached && (
|
|
||||||
<span
|
|
||||||
className="text-[10px] font-mono text-white/30 px-2 py-1.5 border border-white/[0.08] bg-white/[0.02] flex items-center gap-1.5 cursor-help"
|
|
||||||
title="Cached Result: Data from previous analysis (saves time). Click refresh ↻ for live data."
|
|
||||||
>
|
|
||||||
<Clock className="w-3 h-3" />
|
|
||||||
Cached Result
|
|
||||||
</span>
|
|
||||||
)}
|
)}
|
||||||
{fastMode && (
|
>
|
||||||
<span className="text-[10px] font-mono text-white/30 italic">
|
<Zap className="w-3 h-3" />
|
||||||
DNS-only, limited details
|
Fast
|
||||||
</span>
|
</button>
|
||||||
)}
|
{data?.cached && (
|
||||||
</div>
|
<span className="text-[9px] font-mono text-white/20">cached</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -479,49 +414,36 @@ export function AnalyzePanel() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={section.key}
|
key={section.key}
|
||||||
className={clsx(
|
className="border border-white/[0.06] overflow-hidden bg-[#020202]"
|
||||||
"border overflow-hidden bg-[#020202]",
|
|
||||||
config.border
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
{/* Section Header */}
|
{/* Section Header */}
|
||||||
<button
|
<button
|
||||||
onClick={() => toggleSection(section.key)}
|
onClick={() => toggleSection(section.key)}
|
||||||
className={clsx(
|
className="w-full px-4 py-3 flex items-center justify-between transition-colors group hover:bg-white/[0.02]"
|
||||||
"w-full px-4 py-3 flex items-center justify-between transition-colors group",
|
|
||||||
config.bg, "hover:brightness-110"
|
|
||||||
)}
|
|
||||||
title={(config as any).tooltip || ''}
|
title={(config as any).tooltip || ''}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className={clsx("w-8 h-8 flex items-center justify-center border", config.border)}>
|
<SectionIcon className="w-4 h-4 text-white/40" />
|
||||||
<SectionIcon className={clsx("w-4 h-4", config.color)} />
|
|
||||||
</div>
|
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<div className="flex items-center gap-2">
|
<span className="text-[11px] font-bold uppercase tracking-wider text-white/70">
|
||||||
<span className={clsx("text-xs font-bold uppercase tracking-wider", config.color)}>
|
{section.title}
|
||||||
{section.title}
|
</span>
|
||||||
</span>
|
<div className="text-[10px] font-mono text-white/30">
|
||||||
<span title={(config as any).tooltip || ''}>
|
|
||||||
<Info className="w-3 h-3 text-white/20 opacity-0 group-hover:opacity-100 transition-opacity" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="text-[10px] font-mono text-white/40 mt-0.5">
|
|
||||||
{config.description}
|
{config.description}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{section.key !== 'vision' && section.items.length > 0 && (
|
{section.key !== 'vision' && section.items.length > 0 && (
|
||||||
<span className="text-[10px] font-mono text-white/40 px-2 py-0.5 bg-white/5 border border-white/[0.06]">
|
<span className="text-[10px] font-mono text-white/30">
|
||||||
{section.items.length} checks
|
{section.items.length}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{section.key === 'vision' && (
|
{section.key === 'vision' && (
|
||||||
<span className="text-[10px] font-mono text-accent px-2 py-0.5 bg-accent/10 border border-accent/20">AI Powered</span>
|
<span className="text-[9px] font-mono text-accent/70 uppercase">AI</span>
|
||||||
)}
|
)}
|
||||||
<ChevronRight className={clsx(
|
<ChevronRight className={clsx(
|
||||||
"w-4 h-4 text-white/30 transition-transform",
|
"w-4 h-4 text-white/20 transition-transform",
|
||||||
isExpanded && "rotate-90"
|
isExpanded && "rotate-90"
|
||||||
)} />
|
)} />
|
||||||
</div>
|
</div>
|
||||||
@ -538,98 +460,55 @@ export function AnalyzePanel() {
|
|||||||
<div className="divide-y divide-white/[0.04]">
|
<div className="divide-y divide-white/[0.04]">
|
||||||
{section.items.map((item) => {
|
{section.items.map((item) => {
|
||||||
const statusStyle = getStatusColor(item.status)
|
const statusStyle = getStatusColor(item.status)
|
||||||
const StatusIcon = statusStyle.icon
|
|
||||||
const tooltip = getItemTooltip(item.key)
|
const tooltip = getItemTooltip(item.key)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={item.key}
|
key={item.key}
|
||||||
className="px-4 py-3.5 hover:bg-white/[0.02] transition-colors group"
|
className="px-4 py-3 hover:bg-white/[0.02] transition-colors group"
|
||||||
title={tooltip || undefined}
|
title={tooltip || undefined}
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-center justify-between gap-4">
|
||||||
{/* Status Indicator */}
|
{/* Label + Source */}
|
||||||
<div className={clsx(
|
<div className="flex items-center gap-2 min-w-0">
|
||||||
"w-9 h-9 flex items-center justify-center shrink-0 border",
|
<span className="text-[11px] font-medium text-white/60 truncate">
|
||||||
statusStyle.bg, statusStyle.border
|
{item.label}
|
||||||
)}>
|
</span>
|
||||||
{StatusIcon && <StatusIcon className={clsx("w-4 h-4", statusStyle.text)} />}
|
{item.source && (
|
||||||
</div>
|
<span className="text-[9px] font-mono text-white/20 uppercase shrink-0">
|
||||||
|
{item.source}
|
||||||
{/* Content */}
|
</span>
|
||||||
<div className="flex-1 min-w-0">
|
|
||||||
<div className="flex items-center justify-between gap-2 mb-1.5">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span className="text-sm font-semibold text-white">
|
|
||||||
{item.label}
|
|
||||||
</span>
|
|
||||||
{tooltip && (
|
|
||||||
<span
|
|
||||||
title={tooltip}
|
|
||||||
className="cursor-help"
|
|
||||||
>
|
|
||||||
<Info className="w-3.5 h-3.5 text-white/20 group-hover:text-white/40 transition-colors" />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{item.source && (
|
|
||||||
<span className="text-[9px] font-mono text-white/30 uppercase px-1.5 py-0.5 bg-white/[0.03] border border-white/[0.06]">
|
|
||||||
{item.source}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Value */}
|
|
||||||
<div>
|
|
||||||
{isMatrix(item) ? (
|
|
||||||
<div className="grid grid-cols-4 gap-1.5 mt-2">
|
|
||||||
{(item.value as any[]).slice(0, 12).map((row: any) => (
|
|
||||||
<div
|
|
||||||
key={String(row.domain)}
|
|
||||||
className={clsx(
|
|
||||||
"px-2 py-1.5 text-[10px] font-mono flex items-center justify-between border",
|
|
||||||
row.status === 'available'
|
|
||||||
? "border-accent/20 bg-accent/5 text-accent"
|
|
||||||
: "border-white/[0.06] bg-white/[0.02] text-white/40"
|
|
||||||
)}
|
|
||||||
title={row.status === 'available' ? '✓ Available for registration' : '✗ Already registered'}
|
|
||||||
>
|
|
||||||
<span className="truncate">.{String(row.domain).split('.').pop()}</span>
|
|
||||||
{row.status === 'available' && <Check className="w-3 h-3 shrink-0 ml-1" />}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className={clsx(
|
|
||||||
"text-base font-mono font-medium",
|
|
||||||
item.status === 'pass' ? "text-accent" :
|
|
||||||
item.status === 'warn' ? "text-amber-400" :
|
|
||||||
item.status === 'fail' ? "text-rose-400" : "text-white/60"
|
|
||||||
)}>
|
|
||||||
{formatValue(item.value)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Inline Explanation for important items */}
|
|
||||||
{tooltip && item.status !== 'pass' && (
|
|
||||||
<div className="mt-1.5 text-[10px] font-mono text-white/30 leading-relaxed">
|
|
||||||
{item.status === 'warn' && '⚠️ '}
|
|
||||||
{item.status === 'fail' && '⛔ '}
|
|
||||||
{tooltip.split('.')[0]}.
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
{/* Details Toggle */}
|
|
||||||
{item.details && Object.keys(item.details).length > 0 && (
|
{/* Value */}
|
||||||
<details className="mt-2">
|
<div className="shrink-0">
|
||||||
<summary className="text-[10px] font-mono text-white/30 cursor-pointer hover:text-white/50 select-none">
|
{isMatrix(item) ? (
|
||||||
Show raw data
|
<div className="flex gap-1">
|
||||||
</summary>
|
{(item.value as any[]).slice(0, 7).map((row: any) => (
|
||||||
<pre className="mt-2 text-[10px] font-mono text-white/40 bg-black/50 border border-white/[0.06] p-3 overflow-x-auto max-h-32">
|
<div
|
||||||
{JSON.stringify(item.details, null, 2)}
|
key={String(row.domain)}
|
||||||
</pre>
|
className={clsx(
|
||||||
</details>
|
"w-6 h-6 flex items-center justify-center text-[9px] font-mono",
|
||||||
|
row.status === 'available'
|
||||||
|
? "bg-accent/10 text-accent"
|
||||||
|
: "bg-white/[0.03] text-white/20"
|
||||||
|
)}
|
||||||
|
title={`${String(row.domain).split('.').pop()}: ${row.status === 'available' ? 'Available' : 'Taken'}`}
|
||||||
|
>
|
||||||
|
.{String(row.domain).split('.').pop()?.slice(0, 2)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<span className={clsx(
|
||||||
|
"text-sm font-mono font-medium",
|
||||||
|
item.status === 'pass' ? "text-accent" :
|
||||||
|
item.status === 'warn' ? "text-amber-400" :
|
||||||
|
item.status === 'fail' ? "text-rose-400" : "text-white/50"
|
||||||
|
)}>
|
||||||
|
{formatValue(item.value)}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -648,29 +527,24 @@ export function AnalyzePanel() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<div className="shrink-0 border-t border-white/[0.08] px-4 py-3 bg-[#020202]">
|
<div className="shrink-0 border-t border-white/[0.06] px-4 py-2 bg-[#020202]">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between text-[9px] font-mono text-white/20">
|
||||||
<div className="text-[10px] font-mono text-white/30">
|
<span>ESC to close</span>
|
||||||
Press ESC to close
|
<div className="flex items-center gap-3">
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<a
|
<a
|
||||||
href={`https://who.is/whois/${encodeURIComponent(headerDomain)}`}
|
href={`https://who.is/whois/${encodeURIComponent(headerDomain)}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-[10px] font-mono text-white/40 hover:text-white transition-colors flex items-center gap-1"
|
className="hover:text-white/50 transition-colors"
|
||||||
>
|
>
|
||||||
<Link2 className="w-3 h-3" />
|
|
||||||
WHOIS
|
WHOIS
|
||||||
</a>
|
</a>
|
||||||
<span className="text-white/10">|</span>
|
|
||||||
<a
|
<a
|
||||||
href={`https://web.archive.org/web/*/${encodeURIComponent(headerDomain)}`}
|
href={`https://web.archive.org/web/*/${encodeURIComponent(headerDomain)}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-[10px] font-mono text-white/40 hover:text-white transition-colors flex items-center gap-1"
|
className="hover:text-white/50 transition-colors"
|
||||||
>
|
>
|
||||||
<Clock className="w-3 h-3" />
|
|
||||||
Archive
|
Archive
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user