feat: Enhanced domain status icons with color coding + UI polish
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

STATUS ICONS:
- CircleCheck (emerald) = Available - ready to hunt
- Radio (cyan, pulsing) = Monitoring - actively watching
- CircleAlert (amber, pulsing) = Expiring soon - urgent
- CircleX (gray) = Registered - taken

VISUAL IMPROVEMENTS:
- Status icons with colored backgrounds and ring effects
- Pulsing animation for monitoring and expiring domains
- Stats cards with vibrant color accents (emerald, cyan, amber, violet)
- Icon badges in stat cards for better visual hierarchy
- Gradient quick-links section
- Increased max-width consistency (max-w-5xl)
- More padding (pt-28/32, pb-20/24)
- Rounded-2xl for modern card look
- Hover effects with color transitions

COLORS:
- Emerald for positive/available
- Cyan for monitoring/active
- Amber for warnings/expiring
- Violet for investments
- Rose for negative/loss
This commit is contained in:
yves.gugger
2025-12-09 09:23:33 +01:00
parent b1d6e92590
commit 5360c4938c

View File

@ -36,6 +36,10 @@ import {
Globe,
ArrowUpRight,
ArrowDownRight,
Radio,
CircleCheck,
CircleX,
CircleAlert,
} from 'lucide-react'
import clsx from 'clsx'
import Link from 'next/link'
@ -370,12 +374,59 @@ export default function DashboardPage() {
const isProOrHigher = tierName === 'Professional' || tierName === 'Enterprise' || tierName === 'Trader' || tierName === 'Tycoon'
const isEnterprise = tierName === 'Enterprise' || tierName === 'Tycoon'
// Get domain status with icon
const getDomainStatus = (domain: any) => {
const exp = formatExpirationDate(domain.expiration_date)
if (domain.is_available) {
return {
icon: CircleCheck,
label: 'Available',
color: 'text-emerald-400',
bg: 'bg-emerald-400/10',
ring: 'ring-emerald-400/30',
pulse: false
}
}
if (exp?.urgent) {
return {
icon: CircleAlert,
label: 'Expiring',
color: 'text-amber-400',
bg: 'bg-amber-400/10',
ring: 'ring-amber-400/30',
pulse: true
}
}
if (domain.notify_on_available) {
return {
icon: Radio,
label: 'Monitoring',
color: 'text-cyan-400',
bg: 'bg-cyan-400/10',
ring: 'ring-cyan-400/30',
pulse: true
}
}
return {
icon: CircleX,
label: 'Registered',
color: 'text-foreground-subtle',
bg: 'bg-foreground/5',
ring: 'ring-foreground/10',
pulse: false
}
}
return (
<div className="min-h-screen bg-background flex flex-col">
<Header />
<main className="flex-1 pt-24 pb-16 px-4 sm:px-6">
<div className="max-w-6xl mx-auto">
<main className="flex-1 pt-28 sm:pt-32 pb-20 sm:pb-24 px-4 sm:px-6">
<div className="max-w-5xl mx-auto">
{/* Header */}
<div className="flex flex-col sm:flex-row sm:items-end sm:justify-between gap-4 mb-8">
<div>
@ -409,28 +460,42 @@ export default function DashboardPage() {
</div>
{/* Tabs */}
<div className="flex items-center gap-1 p-1 bg-background-secondary border border-border rounded-xl w-fit mb-8">
<div className="flex items-center gap-1 p-1.5 bg-background-secondary/70 backdrop-blur-sm border border-border rounded-2xl w-fit mb-10">
<button
onClick={() => setActiveTab('watchlist')}
className={clsx(
"flex items-center gap-2 px-4 py-2 text-ui-sm font-medium rounded-lg transition-all",
activeTab === 'watchlist' ? "bg-foreground text-background" : "text-foreground-muted hover:text-foreground"
"flex items-center gap-2.5 px-5 py-2.5 text-ui font-medium rounded-xl transition-all duration-200",
activeTab === 'watchlist'
? "bg-foreground text-background shadow-lg"
: "text-foreground-muted hover:text-foreground hover:bg-foreground/5"
)}
>
<Eye className="w-4 h-4" />
Watchlist
{domains.length > 0 && <span className="text-ui-xs px-1.5 py-0.5 bg-background/20 rounded">{domains.length}</span>}
{domains.length > 0 && (
<span className={clsx(
"text-ui-xs px-2 py-0.5 rounded-md",
activeTab === 'watchlist' ? "bg-background/20" : "bg-foreground/10"
)}>{domains.length}</span>
)}
</button>
<button
onClick={() => setActiveTab('portfolio')}
className={clsx(
"flex items-center gap-2 px-4 py-2 text-ui-sm font-medium rounded-lg transition-all",
activeTab === 'portfolio' ? "bg-foreground text-background" : "text-foreground-muted hover:text-foreground"
"flex items-center gap-2.5 px-5 py-2.5 text-ui font-medium rounded-xl transition-all duration-200",
activeTab === 'portfolio'
? "bg-foreground text-background shadow-lg"
: "text-foreground-muted hover:text-foreground hover:bg-foreground/5"
)}
>
<Briefcase className="w-4 h-4" />
Portfolio
{portfolio.length > 0 && <span className="text-ui-xs px-1.5 py-0.5 bg-background/20 rounded">{portfolio.length}</span>}
{portfolio.length > 0 && (
<span className={clsx(
"text-ui-xs px-2 py-0.5 rounded-md",
activeTab === 'portfolio' ? "bg-background/20" : "bg-foreground/10"
)}>{portfolio.length}</span>
)}
</button>
</div>
@ -447,21 +512,49 @@ export default function DashboardPage() {
<div className="space-y-6">
{/* Stats Row */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
<div className="p-4 bg-background-secondary border border-border rounded-xl">
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-1">Tracked</p>
<p className="text-2xl font-display text-foreground">{domains.length}</p>
<div className="p-5 bg-background-secondary/50 border border-border rounded-2xl hover:border-foreground/20 transition-colors">
<div className="flex items-center gap-2 mb-2">
<div className="w-6 h-6 rounded-md bg-foreground/10 flex items-center justify-center">
<Eye className="w-3.5 h-3.5 text-foreground-muted" />
</div>
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider">Tracked</p>
</div>
<p className="text-3xl font-display text-foreground">{domains.length}</p>
</div>
<div className="p-4 bg-accent/5 border border-accent/20 rounded-xl">
<p className="text-ui-xs text-accent/70 uppercase tracking-wider mb-1">Available</p>
<p className="text-2xl font-display text-accent">{availableCount}</p>
<div className="p-5 bg-emerald-500/5 border border-emerald-500/20 rounded-2xl hover:border-emerald-500/40 transition-colors">
<div className="flex items-center gap-2 mb-2">
<div className="w-6 h-6 rounded-md bg-emerald-500/20 flex items-center justify-center">
<CircleCheck className="w-3.5 h-3.5 text-emerald-400" />
</div>
<p className="text-ui-xs text-emerald-400/80 uppercase tracking-wider">Available</p>
</div>
<p className="text-3xl font-display text-emerald-400">{availableCount}</p>
</div>
<div className="p-4 bg-background-secondary border border-border rounded-xl">
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-1">Registered</p>
<p className="text-2xl font-display text-foreground">{domains.length - availableCount}</p>
<div className="p-5 bg-cyan-500/5 border border-cyan-500/20 rounded-2xl hover:border-cyan-500/40 transition-colors">
<div className="flex items-center gap-2 mb-2">
<div className="w-6 h-6 rounded-md bg-cyan-500/20 flex items-center justify-center">
<Radio className="w-3.5 h-3.5 text-cyan-400" />
</div>
<p className="text-ui-xs text-cyan-400/80 uppercase tracking-wider">Monitoring</p>
</div>
<p className="text-3xl font-display text-cyan-400">{domains.filter(d => d.notify_on_available).length}</p>
</div>
<div className={clsx("p-4 border rounded-xl", expiringCount > 0 ? "bg-warning/5 border-warning/20" : "bg-background-secondary border-border")}>
<p className={clsx("text-ui-xs uppercase tracking-wider mb-1", expiringCount > 0 ? "text-warning/70" : "text-foreground-muted")}>Expiring</p>
<p className={clsx("text-2xl font-display", expiringCount > 0 ? "text-warning" : "text-foreground")}>{expiringCount}</p>
<div className={clsx(
"p-5 border rounded-2xl transition-colors",
expiringCount > 0
? "bg-amber-500/5 border-amber-500/20 hover:border-amber-500/40"
: "bg-background-secondary/50 border-border hover:border-foreground/20"
)}>
<div className="flex items-center gap-2 mb-2">
<div className={clsx(
"w-6 h-6 rounded-md flex items-center justify-center",
expiringCount > 0 ? "bg-amber-500/20" : "bg-foreground/10"
)}>
<CircleAlert className={clsx("w-3.5 h-3.5", expiringCount > 0 ? "text-amber-400" : "text-foreground-muted")} />
</div>
<p className={clsx("text-ui-xs uppercase tracking-wider", expiringCount > 0 ? "text-amber-400/80" : "text-foreground-muted")}>Expiring</p>
</div>
<p className={clsx("text-3xl font-display", expiringCount > 0 ? "text-amber-400" : "text-foreground")}>{expiringCount}</p>
</div>
</div>
@ -486,73 +579,102 @@ export default function DashboardPage() {
{/* Domain Table */}
{domains.length === 0 ? (
<div className="text-center py-16 border border-dashed border-border rounded-xl">
<Eye className="w-10 h-10 text-foreground-subtle mx-auto mb-4" />
<p className="text-body text-foreground-muted">No domains yet</p>
<p className="text-body-sm text-foreground-subtle">Add your first domain above</p>
<div className="text-center py-20 border border-dashed border-border/50 rounded-2xl bg-background-secondary/20">
<div className="w-14 h-14 bg-foreground/5 rounded-2xl flex items-center justify-center mx-auto mb-5">
<Eye className="w-7 h-7 text-foreground-subtle" />
</div>
<p className="text-body-lg text-foreground-muted mb-1">No domains tracked yet</p>
<p className="text-body-sm text-foreground-subtle">Add your first domain above to start monitoring</p>
</div>
) : (
<div className="border border-border rounded-xl overflow-hidden">
<div className="border border-border rounded-2xl overflow-hidden bg-background-secondary/30">
<table className="w-full">
<thead className="bg-background-secondary">
<thead className="bg-background-secondary/80 backdrop-blur-sm">
<tr className="border-b border-border">
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-4 py-3">Domain</th>
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-4 py-3 hidden sm:table-cell">Status</th>
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-4 py-3 hidden lg:table-cell">Expiration</th>
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-4 py-3 hidden md:table-cell">Last Check</th>
<th className="text-right text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-4 py-3">Actions</th>
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4">Domain</th>
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4 hidden sm:table-cell">Status</th>
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4 hidden lg:table-cell">Expiration</th>
<th className="text-left text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4 hidden md:table-cell">Last Check</th>
<th className="text-right text-ui-xs font-medium text-foreground-muted uppercase tracking-wider px-5 py-4">Actions</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tbody className="divide-y divide-border/50">
{domains.map((domain) => {
const exp = formatExpirationDate(domain.expiration_date)
const status = getDomainStatus(domain)
const StatusIcon = status.icon
return (
<tr key={domain.id} className="group hover:bg-background-secondary/50 transition-colors">
<td className="px-4 py-3">
<div className="flex items-center gap-3">
<div className={clsx("w-2 h-2 rounded-full", domain.is_available ? "bg-accent" : "bg-foreground-subtle")} />
<span className="font-mono text-body-sm text-foreground">{domain.name}</span>
<tr key={domain.id} className="group hover:bg-background-secondary/60 transition-all duration-200">
<td className="px-5 py-4">
<div className="flex items-center gap-3.5">
<div className={clsx(
"relative w-8 h-8 rounded-lg flex items-center justify-center ring-1",
status.bg, status.ring
)}>
<StatusIcon className={clsx("w-4 h-4", status.color)} />
{status.pulse && (
<span className={clsx(
"absolute inset-0 rounded-lg animate-ping opacity-30",
status.bg
)} />
)}
</div>
<div>
<span className="font-mono text-body-sm font-medium text-foreground">{domain.name}</span>
<p className={clsx("text-ui-xs mt-0.5 sm:hidden", status.color)}>{status.label}</p>
</div>
</div>
</td>
<td className="px-4 py-3 hidden sm:table-cell">
<span className={clsx("text-ui-xs px-2 py-1 rounded-full", domain.is_available ? "text-accent bg-accent/10" : "text-foreground-muted bg-foreground/5")}>
{domain.is_available ? 'Available' : 'Registered'}
<td className="px-5 py-4 hidden sm:table-cell">
<span className={clsx(
"inline-flex items-center gap-1.5 text-ui-xs px-2.5 py-1 rounded-full font-medium",
status.bg, status.color
)}>
{status.label}
</span>
</td>
<td className="px-4 py-3 hidden lg:table-cell">
<td className="px-5 py-4 hidden lg:table-cell">
{exp ? (
<span className={clsx("text-body-sm flex items-center gap-1", exp.urgent ? "text-warning" : "text-foreground-subtle")}>
<span className={clsx(
"text-body-sm flex items-center gap-1.5",
exp.urgent ? "text-amber-400 font-medium" : "text-foreground-subtle"
)}>
<Calendar className="w-3.5 h-3.5" />{exp.text}
</span>
) : <span className="text-foreground-subtle"></span>}
) : <span className="text-foreground-subtle/50"></span>}
</td>
<td className="px-4 py-3 hidden md:table-cell">
<span className="text-body-sm text-foreground-subtle flex items-center gap-1">
<td className="px-5 py-4 hidden md:table-cell">
<span className="text-body-sm text-foreground-subtle flex items-center gap-1.5">
<Clock className="w-3.5 h-3.5" />{formatDate(domain.last_checked)}
</span>
</td>
<td className="px-4 py-3">
<div className="flex items-center justify-end gap-1 opacity-60 group-hover:opacity-100 transition-opacity">
<td className="px-5 py-4">
<div className="flex items-center justify-end gap-0.5 opacity-50 group-hover:opacity-100 transition-opacity">
{isProOrHigher && (
<button onClick={() => loadDomainHistory(domain.id)} className="p-2 text-foreground-subtle hover:text-foreground hover:bg-foreground/5 rounded-lg transition-all" title="History">
<button onClick={() => loadDomainHistory(domain.id)} className="p-2 text-foreground-subtle hover:text-foreground hover:bg-foreground/10 rounded-lg transition-all" title="History">
<History className="w-4 h-4" />
</button>
)}
<button onClick={() => handleGetValuation(domain.name)} className="p-2 text-foreground-subtle hover:text-foreground hover:bg-foreground/5 rounded-lg transition-all" title="Valuation">
<button onClick={() => handleGetValuation(domain.name)} className="p-2 text-foreground-subtle hover:text-foreground hover:bg-foreground/10 rounded-lg transition-all" title="Valuation">
<Sparkles className="w-4 h-4" />
</button>
<button
onClick={() => handleToggleNotify(domain.id, domain.notify_on_available)}
disabled={togglingNotifyId === domain.id}
className={clsx("p-2 rounded-lg transition-all", domain.notify_on_available ? "text-accent hover:bg-accent/10" : "text-foreground-subtle hover:text-foreground hover:bg-foreground/5")}
title={domain.notify_on_available ? "Alerts on" : "Alerts off"}
className={clsx(
"p-2 rounded-lg transition-all",
domain.notify_on_available
? "text-cyan-400 hover:bg-cyan-400/10"
: "text-foreground-subtle hover:text-foreground hover:bg-foreground/10"
)}
title={domain.notify_on_available ? "Monitoring active" : "Enable monitoring"}
>
{togglingNotifyId === domain.id ? <Loader2 className="w-4 h-4 animate-spin" /> : domain.notify_on_available ? <Bell className="w-4 h-4" /> : <BellOff className="w-4 h-4" />}
</button>
<button onClick={() => handleRefresh(domain.id)} disabled={refreshingId === domain.id} className="p-2 text-foreground-subtle hover:text-foreground hover:bg-foreground/5 rounded-lg transition-all" title="Refresh">
<button onClick={() => handleRefresh(domain.id)} disabled={refreshingId === domain.id} className="p-2 text-foreground-subtle hover:text-foreground hover:bg-foreground/10 rounded-lg transition-all" title="Refresh">
<RefreshCw className={clsx("w-4 h-4", refreshingId === domain.id && "animate-spin")} />
</button>
<button onClick={() => handleDelete(domain.id)} className="p-2 text-foreground-subtle hover:text-danger hover:bg-danger/10 rounded-lg transition-all" title="Remove">
<button onClick={() => handleDelete(domain.id)} className="p-2 text-foreground-subtle hover:text-rose-400 hover:bg-rose-400/10 rounded-lg transition-all" title="Remove">
<Trash2 className="w-4 h-4" />
</button>
</div>
@ -573,42 +695,82 @@ export default function DashboardPage() {
{/* Portfolio Stats */}
{portfolioSummary && (
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
<div className="p-4 bg-background-secondary border border-border rounded-xl">
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-1">Total Value</p>
<p className="text-2xl font-display text-foreground">{formatCurrency(portfolioSummary.total_value)}</p>
<div className="p-5 bg-background-secondary/50 border border-border rounded-2xl hover:border-foreground/20 transition-colors">
<div className="flex items-center gap-2 mb-2">
<div className="w-6 h-6 rounded-md bg-foreground/10 flex items-center justify-center">
<DollarSign className="w-3.5 h-3.5 text-foreground-muted" />
</div>
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider">Total Value</p>
</div>
<p className="text-2xl sm:text-3xl font-display text-foreground">{formatCurrency(portfolioSummary.total_value)}</p>
</div>
<div className="p-4 bg-background-secondary border border-border rounded-xl">
<p className="text-ui-xs text-foreground-muted uppercase tracking-wider mb-1">Invested</p>
<p className="text-2xl font-display text-foreground">{formatCurrency(portfolioSummary.total_invested)}</p>
<div className="p-5 bg-violet-500/5 border border-violet-500/20 rounded-2xl hover:border-violet-500/40 transition-colors">
<div className="flex items-center gap-2 mb-2">
<div className="w-6 h-6 rounded-md bg-violet-500/20 flex items-center justify-center">
<Tag className="w-3.5 h-3.5 text-violet-400" />
</div>
<p className="text-ui-xs text-violet-400/80 uppercase tracking-wider">Invested</p>
</div>
<p className="text-2xl sm:text-3xl font-display text-violet-400">{formatCurrency(portfolioSummary.total_invested)}</p>
</div>
<div className={clsx("p-4 border rounded-xl", portfolioSummary.unrealized_profit >= 0 ? "bg-accent/5 border-accent/20" : "bg-danger/5 border-danger/20")}>
<p className={clsx("text-ui-xs uppercase tracking-wider mb-1", portfolioSummary.unrealized_profit >= 0 ? "text-accent/70" : "text-danger/70")}>P/L</p>
<p className={clsx("text-2xl font-display flex items-center gap-1", portfolioSummary.unrealized_profit >= 0 ? "text-accent" : "text-danger")}>
{portfolioSummary.unrealized_profit >= 0 ? <ArrowUpRight className="w-5 h-5" /> : <ArrowDownRight className="w-5 h-5" />}
{formatCurrency(Math.abs(portfolioSummary.unrealized_profit))}
<div className={clsx(
"p-5 border rounded-2xl transition-colors",
portfolioSummary.unrealized_profit >= 0
? "bg-emerald-500/5 border-emerald-500/20 hover:border-emerald-500/40"
: "bg-rose-500/5 border-rose-500/20 hover:border-rose-500/40"
)}>
<div className="flex items-center gap-2 mb-2">
<div className={clsx(
"w-6 h-6 rounded-md flex items-center justify-center",
portfolioSummary.unrealized_profit >= 0 ? "bg-emerald-500/20" : "bg-rose-500/20"
)}>
{portfolioSummary.unrealized_profit >= 0
? <ArrowUpRight className="w-3.5 h-3.5 text-emerald-400" />
: <ArrowDownRight className="w-3.5 h-3.5 text-rose-400" />
}
</div>
<p className={clsx("text-ui-xs uppercase tracking-wider", portfolioSummary.unrealized_profit >= 0 ? "text-emerald-400/80" : "text-rose-400/80")}>P/L</p>
</div>
<p className={clsx("text-2xl sm:text-3xl font-display", portfolioSummary.unrealized_profit >= 0 ? "text-emerald-400" : "text-rose-400")}>
{portfolioSummary.unrealized_profit >= 0 ? '+' : ''}{formatCurrency(portfolioSummary.unrealized_profit)}
</p>
</div>
<div className={clsx("p-4 border rounded-xl", portfolioSummary.overall_roi >= 0 ? "bg-accent/5 border-accent/20" : "bg-danger/5 border-danger/20")}>
<p className={clsx("text-ui-xs uppercase tracking-wider mb-1", portfolioSummary.overall_roi >= 0 ? "text-accent/70" : "text-danger/70")}>ROI</p>
<p className={clsx("text-2xl font-display", portfolioSummary.overall_roi >= 0 ? "text-accent" : "text-danger")}>
<div className={clsx(
"p-5 border rounded-2xl transition-colors",
portfolioSummary.overall_roi >= 0
? "bg-emerald-500/5 border-emerald-500/20 hover:border-emerald-500/40"
: "bg-rose-500/5 border-rose-500/20 hover:border-rose-500/40"
)}>
<div className="flex items-center gap-2 mb-2">
<div className={clsx(
"w-6 h-6 rounded-md flex items-center justify-center",
portfolioSummary.overall_roi >= 0 ? "bg-emerald-500/20" : "bg-rose-500/20"
)}>
<BarChart3 className={clsx("w-3.5 h-3.5", portfolioSummary.overall_roi >= 0 ? "text-emerald-400" : "text-rose-400")} />
</div>
<p className={clsx("text-ui-xs uppercase tracking-wider", portfolioSummary.overall_roi >= 0 ? "text-emerald-400/80" : "text-rose-400/80")}>ROI</p>
</div>
<p className={clsx("text-2xl sm:text-3xl font-display", portfolioSummary.overall_roi >= 0 ? "text-emerald-400" : "text-rose-400")}>
{portfolioSummary.overall_roi >= 0 ? '+' : ''}{portfolioSummary.overall_roi.toFixed(1)}%
</p>
</div>
</div>
)}
<button onClick={() => setShowAddPortfolioModal(true)} className="flex items-center gap-2 px-5 py-3 bg-foreground text-background text-ui-sm font-medium rounded-xl hover:bg-foreground/90 transition-all">
<button onClick={() => setShowAddPortfolioModal(true)} className="flex items-center gap-2.5 px-6 py-3.5 bg-foreground text-background text-ui font-medium rounded-xl hover:bg-foreground/90 transition-all shadow-lg shadow-foreground/10">
<Plus className="w-4 h-4" />
Add Domain
Add Domain to Portfolio
</button>
{loadingPortfolio ? (
<div className="flex justify-center py-16"><Loader2 className="w-6 h-6 animate-spin text-accent" /></div>
<div className="flex justify-center py-20"><Loader2 className="w-7 h-7 animate-spin text-accent" /></div>
) : portfolio.length === 0 ? (
<div className="text-center py-16 border border-dashed border-border rounded-xl">
<Briefcase className="w-10 h-10 text-foreground-subtle mx-auto mb-4" />
<p className="text-body text-foreground-muted">Portfolio is empty</p>
<p className="text-body-sm text-foreground-subtle">Add domains you own to track their value</p>
<div className="text-center py-20 border border-dashed border-border/50 rounded-2xl bg-background-secondary/20">
<div className="w-14 h-14 bg-foreground/5 rounded-2xl flex items-center justify-center mx-auto mb-5">
<Briefcase className="w-7 h-7 text-foreground-subtle" />
</div>
<p className="text-body-lg text-foreground-muted mb-1">Your portfolio is empty</p>
<p className="text-body-sm text-foreground-subtle">Add domains you own to track their value and ROI</p>
</div>
) : (
<div className="space-y-3">
@ -655,18 +817,19 @@ export default function DashboardPage() {
)}
{/* Quick Links */}
<div className="mt-10 p-5 bg-background-secondary/50 border border-border rounded-xl flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
<div className="mt-12 p-6 bg-gradient-to-r from-accent/5 via-cyan-500/5 to-violet-500/5 border border-accent/20 rounded-2xl flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-accent/10 rounded-lg flex items-center justify-center">
<TrendingUp className="w-5 h-5 text-accent" />
<div className="w-12 h-12 bg-accent/10 rounded-xl flex items-center justify-center ring-1 ring-accent/20">
<TrendingUp className="w-6 h-6 text-accent" />
</div>
<div>
<p className="text-body-sm font-medium text-foreground">TLD Price Intelligence</p>
<p className="text-body-xs text-foreground-muted">Track 886+ domain extensions</p>
<p className="text-body font-medium text-foreground">TLD Price Intelligence</p>
<p className="text-body-sm text-foreground-muted">Track 886+ domain extensions in real-time</p>
</div>
</div>
<Link href="/tld-pricing" className="text-ui-sm text-accent hover:text-accent-hover transition-colors flex items-center gap-1">
Explore <ChevronRight className="w-4 h-4" />
<Link href="/tld-pricing" className="text-ui font-medium text-accent hover:text-accent-hover transition-colors flex items-center gap-1.5 group">
Explore Prices
<ChevronRight className="w-4 h-4 group-hover:translate-x-0.5 transition-transform" />
</Link>
</div>
</div>