fix: Smart 'Best' label + tooltips for TLD detail pages
BEST VALUE LOGIC:
- 'Best' badge only shown when:
1. Cheapest registration price AND
2. No renewal trap (renewal <= 1.5x registration)
- New 'Cheap Start' badge for cheapest with renewal trap
Shows warning: 'Cheapest registration but high renewal costs'
TOOLTIPS ADDED:
Stats Cards:
- Buy (1y): 'Lowest first-year registration price...'
- Renew (1y): 'Annual renewal price after first year'
or 'Warning: Renewal is Xx the registration price'
- 1y Change: 'Price change over the last 12 months'
- 3y Change: 'Price change over the last 3 years'
Registrar Table Headers:
- Register: 'First year registration price'
- Renew: 'Annual renewal price'
- Transfer: 'Transfer from another registrar'
Registrar Table Cells:
- Registration price: 'First year: $X.XX'
- Renewal price: 'Annual renewal: $X.XX' or trap warning
- Transfer price: 'Transfer from another registrar: $X.XX'
- AlertTriangle icon: 'Renewal trap: Xx registration price'
- Best badge: 'Best overall value: lowest registration...'
- Cheap Start badge: 'Cheapest registration but high renewal...'
- Visit link: 'Register at {registrar}'
Applied to both:
- /command/pricing/[tld] (Command Center)
- /tld-pricing/[tld] (Public)
This commit is contained in:
@ -406,28 +406,38 @@ export default function CommandTldDetailPage() {
|
|||||||
|
|
||||||
{/* Stats Grid - All info from table */}
|
{/* Stats Grid - All info from table */}
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
||||||
<StatCard
|
<div title="Lowest first-year registration price across all tracked registrars">
|
||||||
title="Buy Price (1y)"
|
<StatCard
|
||||||
value={`$${details.pricing.min.toFixed(2)}`}
|
title="Buy Price (1y)"
|
||||||
subtitle={`at ${details.cheapest_registrar}`}
|
value={`$${details.pricing.min.toFixed(2)}`}
|
||||||
icon={DollarSign}
|
subtitle={`at ${details.cheapest_registrar}`}
|
||||||
/>
|
icon={DollarSign}
|
||||||
<StatCard
|
/>
|
||||||
title="Renewal (1y)"
|
</div>
|
||||||
value={details.min_renewal_price ? `$${details.min_renewal_price.toFixed(2)}` : '—'}
|
<div title={renewalInfo?.isTrap
|
||||||
subtitle={renewalInfo?.isTrap ? `${renewalInfo.ratio.toFixed(1)}x registration` : 'per year'}
|
? `Warning: Renewal is ${renewalInfo.ratio.toFixed(1)}x the registration price`
|
||||||
icon={RefreshCw}
|
: 'Annual renewal price after first year'}>
|
||||||
/>
|
<StatCard
|
||||||
<StatCard
|
title="Renewal (1y)"
|
||||||
title="1y Change"
|
value={details.min_renewal_price ? `$${details.min_renewal_price.toFixed(2)}` : '—'}
|
||||||
value={`${details.price_change_1y > 0 ? '+' : ''}${details.price_change_1y.toFixed(0)}%`}
|
subtitle={renewalInfo?.isTrap ? `${renewalInfo.ratio.toFixed(1)}x registration` : 'per year'}
|
||||||
icon={details.price_change_1y > 0 ? TrendingUp : details.price_change_1y < 0 ? TrendingDown : Minus}
|
icon={RefreshCw}
|
||||||
/>
|
/>
|
||||||
<StatCard
|
</div>
|
||||||
title="3y Change"
|
<div title="Price change over the last 12 months">
|
||||||
value={`${details.price_change_3y > 0 ? '+' : ''}${details.price_change_3y.toFixed(0)}%`}
|
<StatCard
|
||||||
icon={BarChart3}
|
title="1y Change"
|
||||||
/>
|
value={`${details.price_change_1y > 0 ? '+' : ''}${details.price_change_1y.toFixed(0)}%`}
|
||||||
|
icon={details.price_change_1y > 0 ? TrendingUp : details.price_change_1y < 0 ? TrendingDown : Minus}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div title="Price change over the last 3 years">
|
||||||
|
<StatCard
|
||||||
|
title="3y Change"
|
||||||
|
value={`${details.price_change_3y > 0 ? '+' : ''}${details.price_change_3y.toFixed(0)}%`}
|
||||||
|
icon={BarChart3}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Risk Level */}
|
{/* Risk Level */}
|
||||||
@ -506,55 +516,95 @@ export default function CommandTldDetailPage() {
|
|||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-border/30">
|
<tr className="border-b border-border/30">
|
||||||
<th className="text-left pb-3 text-sm font-medium text-foreground-muted">Registrar</th>
|
<th className="text-left pb-3 text-sm font-medium text-foreground-muted">Registrar</th>
|
||||||
<th className="text-right pb-3 text-sm font-medium text-foreground-muted">Register</th>
|
<th className="text-right pb-3 text-sm font-medium text-foreground-muted" title="First year registration price">Register</th>
|
||||||
<th className="text-right pb-3 text-sm font-medium text-foreground-muted">Renew</th>
|
<th className="text-right pb-3 text-sm font-medium text-foreground-muted" title="Annual renewal price">Renew</th>
|
||||||
<th className="text-right pb-3 text-sm font-medium text-foreground-muted">Transfer</th>
|
<th className="text-right pb-3 text-sm font-medium text-foreground-muted" title="Transfer from another registrar">Transfer</th>
|
||||||
<th className="text-right pb-3"></th>
|
<th className="text-right pb-3"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-border/20">
|
<tbody className="divide-y divide-border/20">
|
||||||
{details.registrars.map((registrar, idx) => (
|
{details.registrars.map((registrar, idx) => {
|
||||||
<tr key={registrar.name} className={clsx(idx === 0 && "bg-accent/5")}>
|
const hasRenewalTrap = registrar.renewal_price / registrar.registration_price > 1.5
|
||||||
<td className="py-4">
|
const isBestValue = idx === 0 && !hasRenewalTrap
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span className="font-medium text-foreground">{registrar.name}</span>
|
return (
|
||||||
{idx === 0 && (
|
<tr key={registrar.name} className={clsx(isBestValue && "bg-accent/5")}>
|
||||||
<span className="px-2 py-0.5 text-xs bg-accent/10 text-accent rounded-full">Cheapest</span>
|
<td className="py-4">
|
||||||
)}
|
<div className="flex items-center gap-2">
|
||||||
</div>
|
<span className="font-medium text-foreground">{registrar.name}</span>
|
||||||
</td>
|
{isBestValue && (
|
||||||
<td className="py-4 text-right">
|
<span
|
||||||
<span className={clsx(
|
className="px-2 py-0.5 text-xs bg-accent/10 text-accent rounded-full cursor-help"
|
||||||
"font-medium tabular-nums",
|
title="Best overall value: lowest registration price without renewal trap"
|
||||||
idx === 0 ? "text-accent" : "text-foreground"
|
>
|
||||||
)}>
|
Best
|
||||||
${registrar.registration_price.toFixed(2)}
|
</span>
|
||||||
</span>
|
)}
|
||||||
</td>
|
{idx === 0 && hasRenewalTrap && (
|
||||||
<td className="py-4 text-right">
|
<span
|
||||||
<div className="flex items-center gap-1 justify-end">
|
className="px-2 py-0.5 text-xs bg-amber-500/10 text-amber-400 rounded-full cursor-help"
|
||||||
<span className="text-foreground-muted tabular-nums">${registrar.renewal_price.toFixed(2)}</span>
|
title="Cheapest registration but high renewal costs"
|
||||||
{registrar.renewal_price / registrar.registration_price > 2 && (
|
>
|
||||||
<AlertTriangle className="w-3.5 h-3.5 text-amber-400" />
|
Cheap Start
|
||||||
)}
|
</span>
|
||||||
</div>
|
)}
|
||||||
</td>
|
</div>
|
||||||
<td className="py-4 text-right">
|
</td>
|
||||||
<span className="text-foreground-muted tabular-nums">${registrar.transfer_price.toFixed(2)}</span>
|
<td className="py-4 text-right">
|
||||||
</td>
|
<span
|
||||||
<td className="py-4 text-right">
|
className={clsx(
|
||||||
<a
|
"font-medium tabular-nums cursor-help",
|
||||||
href={getRegistrarUrl(registrar.name)}
|
isBestValue ? "text-accent" : "text-foreground"
|
||||||
target="_blank"
|
)}
|
||||||
rel="noopener noreferrer"
|
title={`First year: $${registrar.registration_price.toFixed(2)}`}
|
||||||
className="inline-flex items-center gap-1 text-sm text-accent hover:text-accent/80 transition-colors"
|
>
|
||||||
>
|
${registrar.registration_price.toFixed(2)}
|
||||||
Visit
|
</span>
|
||||||
<ExternalLink className="w-3.5 h-3.5" />
|
</td>
|
||||||
</a>
|
<td className="py-4 text-right">
|
||||||
</td>
|
<div className="flex items-center gap-1 justify-end">
|
||||||
</tr>
|
<span
|
||||||
))}
|
className={clsx(
|
||||||
|
"tabular-nums cursor-help",
|
||||||
|
hasRenewalTrap ? "text-amber-400" : "text-foreground-muted"
|
||||||
|
)}
|
||||||
|
title={hasRenewalTrap
|
||||||
|
? `Renewal is ${(registrar.renewal_price / registrar.registration_price).toFixed(1)}x the registration price`
|
||||||
|
: `Annual renewal: $${registrar.renewal_price.toFixed(2)}`}
|
||||||
|
>
|
||||||
|
${registrar.renewal_price.toFixed(2)}
|
||||||
|
</span>
|
||||||
|
{hasRenewalTrap && (
|
||||||
|
<AlertTriangle
|
||||||
|
className="w-3.5 h-3.5 text-amber-400 cursor-help"
|
||||||
|
title={`Renewal trap: ${(registrar.renewal_price / registrar.registration_price).toFixed(1)}x registration price`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="py-4 text-right">
|
||||||
|
<span
|
||||||
|
className="text-foreground-muted tabular-nums cursor-help"
|
||||||
|
title={`Transfer from another registrar: $${registrar.transfer_price.toFixed(2)}`}
|
||||||
|
>
|
||||||
|
${registrar.transfer_price.toFixed(2)}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td className="py-4 text-right">
|
||||||
|
<a
|
||||||
|
href={getRegistrarUrl(registrar.name)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline-flex items-center gap-1 text-sm text-accent hover:text-accent/80 transition-colors"
|
||||||
|
title={`Register at ${registrar.name}`}
|
||||||
|
>
|
||||||
|
Visit
|
||||||
|
<ExternalLink className="w-3.5 h-3.5" />
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -690,7 +690,10 @@ export default function TldDetailPage() {
|
|||||||
|
|
||||||
{/* Quick Stats - All data from table */}
|
{/* Quick Stats - All data from table */}
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mt-8">
|
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mt-8">
|
||||||
<div className="p-4 bg-background-secondary/50 border border-border/50 rounded-xl">
|
<div
|
||||||
|
className="p-4 bg-background-secondary/50 border border-border/50 rounded-xl cursor-help"
|
||||||
|
title="Lowest first-year registration price across all tracked registrars"
|
||||||
|
>
|
||||||
<p className="text-ui-xs text-foreground-subtle uppercase tracking-wider mb-1">Buy (1y)</p>
|
<p className="text-ui-xs text-foreground-subtle uppercase tracking-wider mb-1">Buy (1y)</p>
|
||||||
{isAuthenticated ? (
|
{isAuthenticated ? (
|
||||||
<p className="text-body-lg font-medium text-foreground tabular-nums">${details.pricing.min.toFixed(2)}</p>
|
<p className="text-body-lg font-medium text-foreground tabular-nums">${details.pricing.min.toFixed(2)}</p>
|
||||||
@ -698,7 +701,12 @@ export default function TldDetailPage() {
|
|||||||
<Shimmer className="h-6 w-16 mt-1" />
|
<Shimmer className="h-6 w-16 mt-1" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 bg-background-secondary/50 border border-border/50 rounded-xl">
|
<div
|
||||||
|
className="p-4 bg-background-secondary/50 border border-border/50 rounded-xl cursor-help"
|
||||||
|
title={renewalInfo?.isTrap
|
||||||
|
? `Warning: Renewal is ${renewalInfo.ratio.toFixed(1)}x the registration price`
|
||||||
|
: 'Annual renewal price after first year'}
|
||||||
|
>
|
||||||
<p className="text-ui-xs text-foreground-subtle uppercase tracking-wider mb-1">Renew (1y)</p>
|
<p className="text-ui-xs text-foreground-subtle uppercase tracking-wider mb-1">Renew (1y)</p>
|
||||||
{isAuthenticated ? (
|
{isAuthenticated ? (
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
@ -706,14 +714,17 @@ export default function TldDetailPage() {
|
|||||||
${details.min_renewal_price.toFixed(2)}
|
${details.min_renewal_price.toFixed(2)}
|
||||||
</p>
|
</p>
|
||||||
{renewalInfo?.isTrap && (
|
{renewalInfo?.isTrap && (
|
||||||
<AlertTriangle className="w-4 h-4 text-amber-400" />
|
<AlertTriangle className="w-4 h-4 text-amber-400" title={`Renewal trap: ${renewalInfo.ratio.toFixed(1)}x registration`} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Shimmer className="h-6 w-20 mt-1" />
|
<Shimmer className="h-6 w-20 mt-1" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 bg-background-secondary/50 border border-border/50 rounded-xl">
|
<div
|
||||||
|
className="p-4 bg-background-secondary/50 border border-border/50 rounded-xl cursor-help"
|
||||||
|
title="Price change over the last 12 months"
|
||||||
|
>
|
||||||
<p className="text-ui-xs text-foreground-subtle uppercase tracking-wider mb-1">1y Change</p>
|
<p className="text-ui-xs text-foreground-subtle uppercase tracking-wider mb-1">1y Change</p>
|
||||||
{isAuthenticated ? (
|
{isAuthenticated ? (
|
||||||
<p className={clsx(
|
<p className={clsx(
|
||||||
@ -728,7 +739,10 @@ export default function TldDetailPage() {
|
|||||||
<Shimmer className="h-6 w-14 mt-1" />
|
<Shimmer className="h-6 w-14 mt-1" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 bg-background-secondary/50 border border-border/50 rounded-xl">
|
<div
|
||||||
|
className="p-4 bg-background-secondary/50 border border-border/50 rounded-xl cursor-help"
|
||||||
|
title="Price change over the last 3 years"
|
||||||
|
>
|
||||||
<p className="text-ui-xs text-foreground-subtle uppercase tracking-wider mb-1">3y Change</p>
|
<p className="text-ui-xs text-foreground-subtle uppercase tracking-wider mb-1">3y Change</p>
|
||||||
{isAuthenticated ? (
|
{isAuthenticated ? (
|
||||||
<p className={clsx(
|
<p className={clsx(
|
||||||
@ -969,68 +983,102 @@ export default function TldDetailPage() {
|
|||||||
<th className="text-left text-ui-xs text-foreground-subtle font-medium uppercase tracking-wider px-5 py-4">
|
<th className="text-left text-ui-xs text-foreground-subtle font-medium uppercase tracking-wider px-5 py-4">
|
||||||
Registrar
|
Registrar
|
||||||
</th>
|
</th>
|
||||||
<th className="text-right text-ui-xs text-foreground-subtle font-medium uppercase tracking-wider px-5 py-4">
|
<th className="text-right text-ui-xs text-foreground-subtle font-medium uppercase tracking-wider px-5 py-4 cursor-help" title="First year registration price">
|
||||||
Register
|
Register
|
||||||
</th>
|
</th>
|
||||||
<th className="text-right text-ui-xs text-foreground-subtle font-medium uppercase tracking-wider px-5 py-4 hidden sm:table-cell">
|
<th className="text-right text-ui-xs text-foreground-subtle font-medium uppercase tracking-wider px-5 py-4 hidden sm:table-cell cursor-help" title="Annual renewal price">
|
||||||
Renew
|
Renew
|
||||||
</th>
|
</th>
|
||||||
<th className="text-right text-ui-xs text-foreground-subtle font-medium uppercase tracking-wider px-5 py-4 hidden sm:table-cell">
|
<th className="text-right text-ui-xs text-foreground-subtle font-medium uppercase tracking-wider px-5 py-4 hidden sm:table-cell cursor-help" title="Transfer from another registrar">
|
||||||
Transfer
|
Transfer
|
||||||
</th>
|
</th>
|
||||||
<th className="px-5 py-4 w-24"></th>
|
<th className="px-5 py-4 w-24"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-border/30">
|
<tbody className="divide-y divide-border/30">
|
||||||
{details.registrars.map((registrar, i) => (
|
{details.registrars.map((registrar, i) => {
|
||||||
<tr key={registrar.name} className={clsx(
|
const hasRenewalTrap = registrar.renewal_price / registrar.registration_price > 1.5
|
||||||
"transition-colors group",
|
const isBestValue = i === 0 && !hasRenewalTrap
|
||||||
i === 0 && "bg-accent/[0.03]"
|
|
||||||
)}>
|
return (
|
||||||
<td className="px-5 py-4">
|
<tr key={registrar.name} className={clsx(
|
||||||
<div className="flex items-center gap-2.5">
|
"transition-colors group",
|
||||||
<span className="text-body-sm font-medium text-foreground">{registrar.name}</span>
|
isBestValue && "bg-accent/[0.03]"
|
||||||
{i === 0 && (
|
)}>
|
||||||
<span className="text-ui-xs text-accent bg-accent/10 px-2 py-0.5 rounded-full font-medium">
|
<td className="px-5 py-4">
|
||||||
Best
|
<div className="flex items-center gap-2.5">
|
||||||
</span>
|
<span className="text-body-sm font-medium text-foreground">{registrar.name}</span>
|
||||||
|
{isBestValue && (
|
||||||
|
<span
|
||||||
|
className="text-ui-xs text-accent bg-accent/10 px-2 py-0.5 rounded-full font-medium cursor-help"
|
||||||
|
title="Best overall value: lowest registration price without renewal trap"
|
||||||
|
>
|
||||||
|
Best
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{i === 0 && hasRenewalTrap && (
|
||||||
|
<span
|
||||||
|
className="text-ui-xs text-amber-400 bg-amber-500/10 px-2 py-0.5 rounded-full font-medium cursor-help"
|
||||||
|
title="Cheapest registration but high renewal costs"
|
||||||
|
>
|
||||||
|
Cheap Start
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="px-5 py-4 text-right">
|
||||||
|
<span
|
||||||
|
className={clsx(
|
||||||
|
"text-body-sm font-medium tabular-nums cursor-help",
|
||||||
|
isBestValue ? "text-accent" : "text-foreground"
|
||||||
|
)}
|
||||||
|
title={`First year: $${registrar.registration_price.toFixed(2)}`}
|
||||||
|
>
|
||||||
|
${registrar.registration_price.toFixed(2)}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td className="px-5 py-4 text-right hidden sm:table-cell">
|
||||||
|
<span
|
||||||
|
className={clsx(
|
||||||
|
"text-body-sm tabular-nums cursor-help",
|
||||||
|
hasRenewalTrap ? "text-amber-400" : "text-foreground-muted"
|
||||||
|
)}
|
||||||
|
title={hasRenewalTrap
|
||||||
|
? `Renewal is ${(registrar.renewal_price / registrar.registration_price).toFixed(1)}x the registration price`
|
||||||
|
: `Annual renewal: $${registrar.renewal_price.toFixed(2)}`}
|
||||||
|
>
|
||||||
|
${registrar.renewal_price.toFixed(2)}
|
||||||
|
</span>
|
||||||
|
{hasRenewalTrap && (
|
||||||
|
<AlertTriangle
|
||||||
|
className="inline-block ml-1.5 w-3.5 h-3.5 text-amber-400 cursor-help"
|
||||||
|
title={`Renewal trap: ${(registrar.renewal_price / registrar.registration_price).toFixed(1)}x registration price`}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</td>
|
||||||
</td>
|
<td className="px-5 py-4 text-right hidden sm:table-cell">
|
||||||
<td className="px-5 py-4 text-right">
|
<span
|
||||||
<span className={clsx(
|
className="text-body-sm text-foreground-muted tabular-nums cursor-help"
|
||||||
"text-body-sm font-medium tabular-nums",
|
title={`Transfer from another registrar: $${registrar.transfer_price.toFixed(2)}`}
|
||||||
i === 0 ? "text-accent" : "text-foreground"
|
>
|
||||||
)}>
|
${registrar.transfer_price.toFixed(2)}
|
||||||
${registrar.registration_price.toFixed(2)}
|
</span>
|
||||||
</span>
|
</td>
|
||||||
</td>
|
<td className="px-5 py-4">
|
||||||
<td className="px-5 py-4 text-right hidden sm:table-cell">
|
<a
|
||||||
<span className="text-body-sm text-foreground-muted tabular-nums">
|
href={getRegistrarUrl(registrar.name, `example.${tld}`)}
|
||||||
${registrar.renewal_price.toFixed(2)}
|
target="_blank"
|
||||||
</span>
|
rel="noopener noreferrer"
|
||||||
{registrar.renewal_price > registrar.registration_price * 1.5 && (
|
className="flex items-center gap-1.5 text-ui-sm text-foreground-muted hover:text-accent transition-colors opacity-0 group-hover:opacity-100"
|
||||||
<AlertTriangle className="inline-block ml-1.5 w-3.5 h-3.5 text-amber-400" />
|
title={`Register at ${registrar.name}`}
|
||||||
)}
|
>
|
||||||
</td>
|
Visit
|
||||||
<td className="px-5 py-4 text-right hidden sm:table-cell">
|
<ExternalLink className="w-3.5 h-3.5" />
|
||||||
<span className="text-body-sm text-foreground-muted tabular-nums">
|
</a>
|
||||||
${registrar.transfer_price.toFixed(2)}
|
</td>
|
||||||
</span>
|
</tr>
|
||||||
</td>
|
)
|
||||||
<td className="px-5 py-4">
|
})}
|
||||||
<a
|
|
||||||
href={getRegistrarUrl(registrar.name, `example.${tld}`)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="flex items-center gap-1.5 text-ui-sm text-foreground-muted hover:text-accent transition-colors opacity-0 group-hover:opacity-100"
|
|
||||||
>
|
|
||||||
Visit
|
|
||||||
<ExternalLink className="w-3.5 h-3.5" />
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user