Improve Portfolio UX and redesign AnalyzePanel
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

- Move Portfolio tabs directly under subtitle (above filters line)
- Add Health Detail Overlay when clicking health score (like Watchlist)
- Redesign AnalyzePanel: wider (600-680px), larger text, better contrast
- Improved section headers with colored backgrounds
- Larger status indicators and score display
- Better spacing and readability throughout
This commit is contained in:
2025-12-16 15:02:47 +01:00
parent 7d68266745
commit 82619f5506
2 changed files with 307 additions and 142 deletions

View File

@ -30,6 +30,9 @@ import {
Calendar,
Edit3,
CheckCircle,
CheckCircle2,
XCircle,
AlertTriangle,
Copy,
Check,
Navigation,
@ -686,6 +689,9 @@ export default function PortfolioPage() {
// Mobile
const [navDrawerOpen, setNavDrawerOpen] = useState(false)
const [expandedRow, setExpandedRow] = useState<number | null>(null)
// Health detail overlay
const [selectedHealthDomain, setSelectedHealthDomain] = useState<PortfolioDomain | null>(null)
const tier = subscription?.tier || 'scout'
const tierName = subscription?.tier_name || tier
@ -949,9 +955,12 @@ export default function PortfolioPage() {
return (
<button
onClick={() => handleHealthCheck(domain.domain)}
onClick={() => {
setSelectedHealthDomain(domain)
if (!health) handleHealthCheck(domain.domain)
}}
disabled={isChecking}
title={health ? `${cfg.label} • Score ${health.score}/100` : 'Run health check'}
title={health ? `${cfg.label} • Score ${health.score}/100 • Click for details` : 'Run health check'}
className={clsx(
"flex items-center gap-1 px-2 py-1 text-[10px] font-mono uppercase border transition-colors",
cfg.color, cfg.bg, cfg.border,
@ -1109,18 +1118,53 @@ export default function PortfolioPage() {
{/* DESKTOP HEADER */}
<section className="hidden lg:block px-10 pt-10 pb-6">
<div className="flex items-end justify-between gap-8">
<div className="space-y-3">
<div className="flex items-center gap-2">
<div className="w-1.5 h-1.5 bg-accent animate-pulse" />
<span className="text-[10px] font-mono tracking-[0.2em] text-accent uppercase">Portfolio Manager</span>
<div className="flex items-start justify-between gap-8">
<div className="space-y-4">
<div>
<div className="flex items-center gap-2 mb-2">
<div className="w-1.5 h-1.5 bg-accent animate-pulse" />
<span className="text-[10px] font-mono tracking-[0.2em] text-accent uppercase">Portfolio Manager</span>
</div>
<h1 className="font-display text-[2.5rem] leading-[1] tracking-[-0.02em] text-white">
My Portfolio
</h1>
<p className="text-sm text-white/40 font-mono max-w-lg mt-2">
Track your domain investments. Add purchase details, monitor values, verify ownership, and list for sale.
</p>
</div>
{/* TABS - Directly under subtitle */}
<div className="flex gap-2 pt-2">
<button
onClick={() => setActiveTab('assets')}
className={clsx(
'flex items-center gap-2 px-4 py-2.5 border transition-all',
activeTab === 'assets'
? 'border-accent bg-accent/10 text-accent'
: 'border-white/[0.08] text-white/50 hover:text-white hover:bg-white/[0.02]'
)}
>
<Briefcase className="w-4 h-4" />
<span className="text-xs font-bold uppercase tracking-wider">Assets</span>
</button>
<button
onClick={() => setActiveTab('financials')}
className={clsx(
'flex items-center gap-2 px-4 py-2.5 border transition-all',
activeTab === 'financials'
? 'border-orange-500 bg-orange-500/10 text-orange-400'
: 'border-white/[0.08] text-white/50 hover:text-white hover:bg-white/[0.02]'
)}
>
<Wallet className="w-4 h-4" />
<span className="text-xs font-bold uppercase tracking-wider">Financials</span>
{stats.upcoming30dCost > 0 && (
<span className="px-1.5 py-0.5 text-[9px] bg-orange-500/20 text-orange-400 border border-orange-500/30">
${Math.round(stats.upcoming30dCost)}
</span>
)}
</button>
</div>
<h1 className="font-display text-[2.5rem] leading-[1] tracking-[-0.02em] text-white">
My Portfolio
</h1>
<p className="text-sm text-white/40 font-mono max-w-lg">
Track your domain investments. Add purchase details, monitor values, verify ownership, and list for sale.
</p>
</div>
<div className="flex items-center gap-8">
@ -1151,41 +1195,8 @@ export default function PortfolioPage() {
</div>
</section>
{/* TABS - Matching Hunt page style */}
<section className="px-4 lg:px-10 py-4 border-y border-white/[0.08] bg-white/[0.01]">
<div className="flex gap-2 mb-4">
<button
onClick={() => setActiveTab('assets')}
className={clsx(
'flex items-center gap-2 px-4 py-2.5 border transition-all',
activeTab === 'assets'
? 'border-accent bg-accent/10 text-accent'
: 'border-white/[0.08] text-white/50 hover:text-white hover:bg-white/[0.02]'
)}
>
<Briefcase className="w-4 h-4" />
<span className="text-xs font-bold uppercase tracking-wider">Assets</span>
</button>
<button
onClick={() => setActiveTab('financials')}
className={clsx(
'flex items-center gap-2 px-4 py-2.5 border transition-all',
activeTab === 'financials'
? 'border-orange-500 bg-orange-500/10 text-orange-400'
: 'border-white/[0.08] text-white/50 hover:text-white hover:bg-white/[0.02]'
)}
>
<Wallet className="w-4 h-4" />
<span className="text-xs font-bold uppercase tracking-wider">Financials</span>
{stats.upcoming30dCost > 0 && (
<span className="px-1.5 py-0.5 text-[9px] bg-orange-500/20 text-orange-400 border border-orange-500/30">
${Math.round(stats.upcoming30dCost)}
</span>
)}
</button>
</div>
{/* Asset Filters - only show when assets tab active */}
{/* FILTERS BAR - Only for assets tab */}
<section className="hidden lg:block px-10 py-3 border-y border-white/[0.08] bg-white/[0.01]">
{activeTab === 'assets' && (
<div className="flex items-center gap-2 overflow-x-auto">
{[
@ -1209,6 +1220,11 @@ export default function PortfolioPage() {
))}
</div>
)}
{activeTab === 'financials' && (
<div className="text-[10px] font-mono text-white/40 uppercase tracking-wider">
Financial Overview & Renewal Costs
</div>
)}
</section>
{/* TAB CONTENT */}
@ -1744,6 +1760,149 @@ export default function PortfolioPage() {
/>
)}
{/* HEALTH DETAIL OVERLAY */}
{selectedHealthDomain && (
<div
className="fixed inset-0 z-[100] bg-black/80 flex items-center justify-center p-4"
onClick={() => setSelectedHealthDomain(null)}
>
<div
className="w-full max-w-md bg-[#0A0A0A] border border-white/[0.08]"
onClick={e => e.stopPropagation()}
>
{/* Header */}
<div className="px-5 py-4 border-b border-white/[0.08] flex items-center justify-between">
<div>
<div className="text-[10px] font-mono text-white/40 uppercase tracking-wider mb-1">Health Check</div>
<h3 className="text-lg font-bold text-white font-mono">{selectedHealthDomain.domain}</h3>
</div>
<button
onClick={() => setSelectedHealthDomain(null)}
className="p-2 text-white/40 hover:text-white transition-colors"
>
<X className="w-5 h-5" />
</button>
</div>
{/* Body */}
<div className="p-5">
{(() => {
const key = selectedHealthDomain.domain.toLowerCase()
const health = healthByDomain[key]
const isLoading = checkingHealth.has(key)
const cfg = healthConfig[(health?.status as HealthStatus) || 'unknown']
return (
<>
{/* Score Badge */}
<div className="flex items-center gap-3 mb-5">
<div className={clsx(
"px-3 py-1.5 text-sm font-mono font-bold uppercase border",
cfg.bg, cfg.color, cfg.border
)}>
{cfg.label}
</div>
{health?.score !== undefined && (
<span className="text-sm font-mono text-white/60">Score: {health.score}/100</span>
)}
</div>
{/* Checks */}
{health ? (
<div className="space-y-px mb-5 border border-white/[0.08]">
{/* DNS */}
<div className="flex items-center justify-between px-4 py-3 bg-[#020202]">
<span className="text-sm font-mono text-white/70">DNS Resolution</span>
{health.dns?.has_a || health.dns?.has_ns ? (
<div className="flex items-center gap-2">
<CheckCircle2 className="w-5 h-5 text-accent" />
<span className="text-sm font-mono text-accent font-bold">OK</span>
</div>
) : (
<div className="flex items-center gap-2">
<XCircle className="w-5 h-5 text-rose-400" />
<span className="text-sm font-mono text-rose-400 font-bold">FAIL</span>
</div>
)}
</div>
{/* HTTP */}
<div className="flex items-center justify-between px-4 py-3 bg-[#020202]">
<span className="text-sm font-mono text-white/70">HTTP Access</span>
{health.http?.is_reachable ? (
<div className="flex items-center gap-2">
<CheckCircle2 className="w-5 h-5 text-accent" />
<span className="text-sm font-mono text-accent font-bold">OK</span>
</div>
) : (
<div className="flex items-center gap-2">
<XCircle className="w-5 h-5 text-rose-400" />
<span className="text-sm font-mono text-rose-400 font-bold">{health.http?.error?.substring(0, 15) || 'FAIL'}</span>
</div>
)}
</div>
{/* SSL */}
<div className="flex items-center justify-between px-4 py-3 bg-[#020202]">
<span className="text-sm font-mono text-white/70">SSL Certificate</span>
{health.ssl?.has_certificate ? (
<div className="flex items-center gap-2">
<CheckCircle2 className="w-5 h-5 text-accent" />
<span className="text-sm font-mono text-accent font-bold">VALID</span>
</div>
) : (
<div className="flex items-center gap-2">
<XCircle className="w-5 h-5 text-rose-400" />
<span className="text-sm font-mono text-rose-400 font-bold">MISSING</span>
</div>
)}
</div>
{/* Parked Status */}
<div className="flex items-center justify-between px-4 py-3 bg-[#020202]">
<span className="text-sm font-mono text-white/70">Not Parked</span>
{!health.dns?.is_parked && !health.http?.is_parked ? (
<div className="flex items-center gap-2">
<CheckCircle2 className="w-5 h-5 text-accent" />
<span className="text-sm font-mono text-accent font-bold">OK</span>
</div>
) : (
<div className="flex items-center gap-2">
<AlertTriangle className="w-5 h-5 text-amber-400" />
<span className="text-sm font-mono text-amber-400 font-bold">PARKED</span>
</div>
)}
</div>
</div>
) : (
<div className="py-10 text-center text-white/40 text-sm font-mono mb-5 border border-white/[0.08] bg-[#020202]">
{isLoading ? 'Running health check...' : 'Click below to run health check'}
</div>
)}
{/* Run Check Button */}
<button
onClick={() => handleHealthCheck(selectedHealthDomain.domain)}
disabled={isLoading}
className="w-full py-3.5 bg-accent text-black text-sm font-bold uppercase tracking-wider hover:bg-white transition-colors flex items-center justify-center gap-2 disabled:opacity-50"
>
{isLoading ? (
<Loader2 className="w-5 h-5 animate-spin" />
) : (
<>
<RefreshCw className="w-5 h-5" />
{health ? 'Refresh Check' : 'Run Check'}
</>
)}
</button>
</>
)
})()}
</div>
</div>
</div>
)}
{toast && <Toast message={toast.message} type={toast.type} onClose={hideToast} />}
</div>
)

View File

@ -20,6 +20,8 @@ import {
Eye,
ChevronDown,
ChevronUp,
CheckCircle2,
XCircle,
} from 'lucide-react'
import { api } from '@/lib/api'
import { useAnalyzePanelStore } from '@/lib/analyze-store'
@ -32,13 +34,13 @@ import type { AnalyzeResponse, AnalyzeSection, AnalyzeItem } from '@/components/
function getStatusColor(status: string) {
switch (status) {
case 'pass':
return { bg: 'bg-accent/10', text: 'text-accent', border: 'border-accent/30', icon: Check }
return { bg: 'bg-accent/20', text: 'text-accent', border: 'border-accent/40', icon: CheckCircle2 }
case 'warn':
return { bg: 'bg-amber-400/10', text: 'text-amber-300', border: 'border-amber-400/30', icon: AlertTriangle }
return { bg: 'bg-amber-400/20', text: 'text-amber-300', border: 'border-amber-400/40', icon: AlertTriangle }
case 'fail':
return { bg: 'bg-red-500/10', text: 'text-red-400', border: 'border-red-500/30', icon: X }
return { bg: 'bg-red-500/20', text: 'text-red-400', border: 'border-red-500/40', icon: XCircle }
default:
return { bg: 'bg-white/5', text: 'text-white/40', border: 'border-white/10', icon: null }
return { bg: 'bg-white/10', text: 'text-white/50', border: 'border-white/20', icon: null }
}
}
@ -60,15 +62,15 @@ function getSectionIcon(key: string) {
function getSectionColor(key: string) {
switch (key) {
case 'authority':
return 'text-blue-400'
return { text: 'text-blue-400', bg: 'bg-blue-500/10', border: 'border-blue-500/30' }
case 'market':
return 'text-emerald-400'
return { text: 'text-emerald-400', bg: 'bg-emerald-500/10', border: 'border-emerald-500/30' }
case 'risk':
return 'text-amber-400'
return { text: 'text-amber-400', bg: 'bg-amber-500/10', border: 'border-amber-500/30' }
case 'value':
return 'text-violet-400'
return { text: 'text-violet-400', bg: 'bg-violet-500/10', border: 'border-violet-500/30' }
default:
return 'text-white/60'
return { text: 'text-white/60', bg: 'bg-white/5', border: 'border-white/20' }
}
}
@ -203,28 +205,28 @@ export function AnalyzePanel() {
return (
<div className="fixed inset-0 z-[200]">
{/* Backdrop */}
<div className="absolute inset-0 bg-black/80 backdrop-blur-sm" onClick={close} />
<div className="absolute inset-0 bg-black/85 backdrop-blur-md" onClick={close} />
{/* Panel */}
<div className="absolute right-0 top-0 bottom-0 w-full sm:w-[480px] bg-[#050505] border-l border-white/[0.06] flex flex-col overflow-hidden">
{/* Panel - WIDER & MORE READABLE */}
<div className="absolute right-0 top-0 bottom-0 w-full sm:w-[600px] lg:w-[680px] bg-[#0A0A0A] border-l border-white/10 flex flex-col overflow-hidden shadow-2xl">
{/* Header */}
<div className="shrink-0 border-b border-white/[0.06]">
<div className="shrink-0 border-b border-white/10 bg-[#050505]">
{/* Top Bar */}
<div className="px-4 py-3 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-accent/10 border border-accent/20 flex items-center justify-center">
<Shield className="w-5 h-5 text-accent" />
<div className="px-6 py-5 flex items-center justify-between">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-accent/15 border border-accent/30 flex items-center justify-center">
<Shield className="w-6 h-6 text-accent" />
</div>
<div>
<div className="text-xs font-mono text-white/40 uppercase tracking-wider">Analyze</div>
<div className="text-base font-bold text-white font-mono truncate max-w-[200px]">
<div className="text-xs font-mono text-accent uppercase tracking-widest mb-1">Domain Analysis</div>
<div className="text-xl font-bold text-white font-mono truncate max-w-[300px]">
{headerDomain}
</div>
</div>
</div>
<div className="flex items-center gap-1.5">
<div className="flex items-center gap-2">
<button
onClick={async () => {
const ok = await copyToClipboard(headerDomain)
@ -232,48 +234,49 @@ export function AnalyzePanel() {
setTimeout(() => setCopied(false), 1500)
}}
className={clsx(
"w-8 h-8 flex items-center justify-center border transition-all",
copied ? "border-accent bg-accent/10 text-accent" : "border-white/10 text-white/40 hover:text-white"
"w-10 h-10 flex items-center justify-center border transition-all",
copied ? "border-accent bg-accent/20 text-accent" : "border-white/20 text-white/50 hover:text-white hover:bg-white/10"
)}
>
{copied ? <Check className="w-4 h-4" /> : <Copy className="w-4 h-4" />}
{copied ? <Check className="w-5 h-5" /> : <Copy className="w-5 h-5" />}
</button>
<a
href={`https://${encodeURIComponent(headerDomain)}`}
target="_blank"
rel="noopener noreferrer"
className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40 hover:text-white transition-colors"
className="w-10 h-10 flex items-center justify-center border border-white/20 text-white/50 hover:text-white hover:bg-white/10 transition-colors"
>
<ExternalLink className="w-4 h-4" />
<ExternalLink className="w-5 h-5" />
</a>
<button
onClick={refresh}
disabled={loading}
className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40 hover:text-white transition-colors disabled:opacity-50"
className="w-10 h-10 flex items-center justify-center border border-white/20 text-white/50 hover:text-white hover:bg-white/10 transition-colors disabled:opacity-50"
>
<RefreshCw className={clsx('w-4 h-4', loading && 'animate-spin')} />
<RefreshCw className={clsx('w-5 h-5', loading && 'animate-spin')} />
</button>
<button
onClick={close}
className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40 hover:text-white transition-colors"
className="w-10 h-10 flex items-center justify-center border border-white/20 text-white/50 hover:text-white hover:bg-white/10 transition-colors ml-2"
>
<X className="w-4 h-4" />
<X className="w-5 h-5" />
</button>
</div>
</div>
{/* Score Bar */}
{/* Score Bar - LARGER */}
{overallScore && !loading && (
<div className="px-4 pb-3">
<div className="flex items-center gap-3">
<div className="px-6 pb-5">
<div className="flex items-center gap-4 p-4 bg-white/[0.03] border border-white/10">
<div className={clsx(
"text-2xl font-bold font-mono",
"text-4xl font-bold font-mono",
overallScore.score >= 70 ? "text-accent" : overallScore.score >= 40 ? "text-amber-400" : "text-red-400"
)}>
{overallScore.score}
</div>
<div className="flex-1">
<div className="h-1.5 bg-white/5 rounded-full overflow-hidden flex">
<div className="text-xs font-mono text-white/50 uppercase tracking-wider mb-2">Overall Score</div>
<div className="h-3 bg-white/10 overflow-hidden flex">
<div
className="h-full bg-accent transition-all"
style={{ width: `${(overallScore.pass / overallScore.total) * 100}%` }}
@ -288,90 +291,93 @@ export function AnalyzePanel() {
/>
</div>
</div>
<div className="flex items-center gap-2 text-[10px] font-mono">
<span className="text-accent">{overallScore.pass} pass</span>
<span className="text-amber-400">{overallScore.warn} warn</span>
<span className="text-red-400">{overallScore.fail} fail</span>
<div className="flex flex-col gap-1 text-sm font-mono">
<span className="text-accent flex items-center gap-2"><CheckCircle2 className="w-4 h-4" /> {overallScore.pass}</span>
<span className="text-amber-400 flex items-center gap-2"><AlertTriangle className="w-4 h-4" /> {overallScore.warn}</span>
<span className="text-red-400 flex items-center gap-2"><XCircle className="w-4 h-4" /> {overallScore.fail}</span>
</div>
</div>
</div>
)}
{/* Mode Toggle */}
<div className="px-4 pb-3 flex items-center gap-2">
<div className="px-6 pb-4 flex items-center gap-3">
<button
onClick={() => setFastMode(!fastMode)}
className={clsx(
"flex items-center gap-1.5 px-3 py-1.5 text-[10px] font-bold uppercase tracking-wider border transition-all",
"flex items-center gap-2 px-4 py-2 text-sm font-bold uppercase tracking-wider border transition-all",
fastMode
? "border-accent/30 bg-accent/10 text-accent"
: "border-white/10 text-white/40 hover:text-white"
? "border-accent/40 bg-accent/15 text-accent"
: "border-white/20 text-white/50 hover:text-white hover:bg-white/10"
)}
>
<Zap className="w-3 h-3" />
Fast
<Zap className="w-4 h-4" />
Fast Mode
</button>
{data?.cached && (
<span className="text-[10px] font-mono text-white/30 px-2 py-1 border border-white/10">
Cached
<span className="text-sm font-mono text-white/40 px-3 py-2 border border-white/20 bg-white/5">
Cached
</span>
)}
</div>
</div>
{/* Body */}
{/* Body - BETTER SPACING */}
<div className="flex-1 overflow-y-auto">
{loading ? (
<div className="flex items-center justify-center py-20">
<div className="flex items-center justify-center py-24">
<div className="text-center">
<RefreshCw className="w-6 h-6 text-accent animate-spin mx-auto mb-3" />
<div className="text-sm font-mono text-white/40">Analyzing...</div>
<RefreshCw className="w-10 h-10 text-accent animate-spin mx-auto mb-4" />
<div className="text-base font-mono text-white/50">Analyzing domain...</div>
</div>
</div>
) : error ? (
<div className="p-4">
<div className="border border-red-500/20 bg-red-500/5 p-4">
<div className="text-sm font-bold text-red-400 mb-1">Analysis Failed</div>
<div className="text-xs font-mono text-white/40">{error}</div>
<div className="p-6">
<div className="border border-red-500/30 bg-red-500/10 p-6">
<div className="text-lg font-bold text-red-400 mb-2">Analysis Failed</div>
<div className="text-sm font-mono text-white/60">{error}</div>
</div>
</div>
) : !data ? (
<div className="flex items-center justify-center py-20">
<div className="text-sm font-mono text-white/30">No data</div>
<div className="flex items-center justify-center py-24">
<div className="text-base font-mono text-white/40">No data available</div>
</div>
) : (
<div className="p-3 space-y-2">
<div className="p-6 space-y-4">
{visibleSections.map((section) => {
const SectionIcon = getSectionIcon(section.key)
const sectionColor = getSectionColor(section.key)
const sectionStyle = getSectionColor(section.key)
const isExpanded = expandedSections[section.key] !== false
return (
<div key={section.key} className="border border-white/[0.06] bg-[#020202] overflow-hidden">
{/* Section Header */}
<div key={section.key} className={clsx("border overflow-hidden", sectionStyle.border, "bg-[#050505]")}>
{/* Section Header - LARGER */}
<button
onClick={() => toggleSection(section.key)}
className="w-full px-3 py-2.5 flex items-center justify-between hover:bg-white/[0.02] transition-colors"
className={clsx(
"w-full px-5 py-4 flex items-center justify-between transition-colors",
sectionStyle.bg, "hover:brightness-110"
)}
>
<div className="flex items-center gap-2">
<SectionIcon className={clsx("w-4 h-4", sectionColor)} />
<span className="text-xs font-bold uppercase tracking-wider text-white/80">
<div className="flex items-center gap-3">
<SectionIcon className={clsx("w-5 h-5", sectionStyle.text)} />
<span className={clsx("text-sm font-bold uppercase tracking-wider", sectionStyle.text)}>
{section.title}
</span>
<span className="text-[10px] font-mono text-white/30">
{section.items.length}
<span className="text-sm font-mono text-white/40 ml-2">
{section.items.length} checks
</span>
</div>
{isExpanded ? (
<ChevronUp className="w-4 h-4 text-white/30" />
<ChevronUp className="w-5 h-5 text-white/40" />
) : (
<ChevronDown className="w-4 h-4 text-white/30" />
<ChevronDown className="w-5 h-5 text-white/40" />
)}
</button>
{/* Section Items */}
{/* Section Items - BETTER CONTRAST */}
{isExpanded && (
<div className="border-t border-white/[0.04]">
<div className="border-t border-white/10">
{section.items.map((item) => {
const statusStyle = getStatusColor(item.status)
const StatusIcon = statusStyle.icon
@ -379,53 +385,53 @@ export function AnalyzePanel() {
return (
<div
key={item.key}
className="px-3 py-2 border-b border-white/[0.04] last:border-0 hover:bg-white/[0.01] transition-colors"
className="px-5 py-4 border-b border-white/[0.06] last:border-0 hover:bg-white/[0.03] transition-colors"
>
<div className="flex items-start gap-3">
{/* Status Indicator */}
<div className="flex items-start gap-4">
{/* Status Indicator - LARGER */}
<div className={clsx(
"w-6 h-6 flex items-center justify-center shrink-0 mt-0.5",
"w-10 h-10 flex items-center justify-center shrink-0",
statusStyle.bg, statusStyle.border, "border"
)}>
{StatusIcon && <StatusIcon className={clsx("w-3 h-3", statusStyle.text)} />}
{StatusIcon && <StatusIcon className={clsx("w-5 h-5", statusStyle.text)} />}
</div>
{/* Content */}
{/* Content - BETTER READABILITY */}
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between gap-2">
<span className="text-[11px] font-medium text-white/70">
<div className="flex items-center justify-between gap-4 mb-2">
<span className="text-base font-medium text-white">
{item.label}
</span>
<span className="text-[10px] font-mono text-white/30">
<span className="text-xs font-mono text-white/40 uppercase tracking-wider">
{item.source}
</span>
</div>
{/* Value */}
<div className="mt-1">
{/* Value - LARGER TEXT */}
<div>
{isMatrix(item) ? (
<div className="grid grid-cols-3 gap-1">
<div className="grid grid-cols-4 gap-2">
{(item.value as any[]).slice(0, 12).map((row: any) => (
<div
key={String(row.domain)}
className={clsx(
"px-2 py-1 text-[10px] font-mono flex items-center justify-between border",
"px-3 py-2 text-sm font-mono flex items-center justify-between border",
row.status === 'available'
? "border-accent/20 bg-accent/5 text-accent"
: "border-white/5 bg-white/[0.02] text-white/40"
? "border-accent/30 bg-accent/10 text-accent"
: "border-white/10 bg-white/[0.03] text-white/50"
)}
>
<span className="truncate">{String(row.domain)}</span>
{row.status === 'available' && <Check className="w-2.5 h-2.5 shrink-0" />}
{row.status === 'available' && <Check className="w-4 h-4 shrink-0 ml-2" />}
</div>
))}
</div>
) : (
<div className={clsx(
"text-xs font-mono",
item.status === 'pass' ? "text-white/60" :
item.status === 'warn' ? "text-amber-300/80" :
item.status === 'fail' ? "text-red-300/80" : "text-white/40"
"text-base font-mono",
item.status === 'pass' ? "text-white/80" :
item.status === 'warn' ? "text-amber-300" :
item.status === 'fail' ? "text-red-300" : "text-white/50"
)}>
{formatValue(item.value)}
</div>
@ -434,11 +440,11 @@ export function AnalyzePanel() {
{/* Details Toggle */}
{item.details && Object.keys(item.details).length > 0 && (
<details className="mt-2">
<summary className="text-[10px] font-mono text-white/25 cursor-pointer hover:text-white/40 select-none">
View details
<details className="mt-3">
<summary className="text-sm font-mono text-white/40 cursor-pointer hover:text-white/60 select-none">
View raw details
</summary>
<pre className="mt-1.5 text-[9px] font-mono text-white/30 bg-black/40 border border-white/5 p-2 overflow-x-auto rounded">
<pre className="mt-2 text-xs font-mono text-white/50 bg-black/50 border border-white/10 p-4 overflow-x-auto">
{JSON.stringify(item.details, null, 2)}
</pre>
</details>