feat: color-code rank badges in backlinks tables (#73)

* feat: color-code rank badges in backlinks tables

Add colored score badges to rank/authority columns across all backlinks
tables (Backlinks, Referring Domains, Top Pages). Uses the same tier
system as keyword difficulty but reversed (higherIsBetter) so high
authority shows green and low authority shows red.

* style: fix prettier formatting in BacklinksPageTables

* style: fix prettier formatting in subscribe page
This commit is contained in:
Ben Senescu 2026-04-04 17:26:22 -04:00 committed by Ben Senescu
parent 8a4e5f429d
commit fdb2d453e4
2 changed files with 40 additions and 20 deletions

View File

@ -10,6 +10,7 @@ import {
BacklinksSourceLink,
} from "./BacklinksPageLinks";
import type { BacklinksOverviewData } from "./backlinksPageTypes";
import { scoreTierClass } from "../keywords/utils";
import {
DEFAULT_BACKLINKS_SORT,
DEFAULT_REFERRING_DOMAINS_SORT,
@ -78,7 +79,9 @@ export function ReferringDomainsTable({
<td className="font-medium break-all">{row.domain ?? "-"}</td>
<td>{formatNumber(row.backlinks)}</td>
<td>{formatNumber(row.referringPages)}</td>
<td>{formatNumber(row.rank)}</td>
<td>
<RankBadge value={row.rank} />
</td>
<td>{formatDecimal(row.spamScore)}</td>
<td>{formatCompactDate(row.firstSeen)}</td>
<td>
@ -129,7 +132,9 @@ export function TopPagesTable({
</td>
<td>{formatNumber(row.backlinks)}</td>
<td>{formatNumber(row.referringDomains)}</td>
<td>{formatNumber(row.rank)}</td>
<td>
<RankBadge value={row.rank} />
</td>
<td>{formatNumber(row.brokenBacklinks)}</td>
</tr>
))}
@ -178,19 +183,18 @@ function BacklinksTableRow({
</div>
</td>
<td>{hasNotableFlags ? <BacklinkFlags row={row} /> : null}</td>
<td className="text-right tabular-nums text-sm">
<span
<td
className="text-center"
title={
row.spamScore != null
? `Spam score: ${formatDecimal(row.spamScore)}`
: undefined
}
>
{formatNumber(row.rank)}
</span>
<RankBadge value={row.rank} />
</td>
<td className="text-right tabular-nums text-sm">
{formatNumber(row.domainFromRank)}
<td className="text-center">
<RankBadge value={row.domainFromRank} />
</td>
<td className="whitespace-nowrap text-sm">
<div>{formatCompactDate(row.firstSeen)}</div>
@ -204,6 +208,18 @@ function BacklinksTableRow({
);
}
function RankBadge({ value }: { value: number | null }) {
if (value == null) return <span>-</span>;
const tierClass = scoreTierClass(value, /* higherIsBetter */ true);
return (
<span
className={`score-badge ${tierClass} inline-flex items-center justify-center rounded-full size-6 text-[10px] font-semibold`}
>
{value}
</span>
);
}
function BacklinkFlags({
row,
}: {

View File

@ -1,12 +1,16 @@
export { LOCATIONS, getLanguageCode } from "./locations";
export function scoreTierClass(value: number | null): string {
export function scoreTierClass(
value: number | null,
higherIsBetter?: boolean,
): string {
if (value == null) return "score-tier-na";
if (value <= 20) return "score-tier-1";
if (value <= 35) return "score-tier-2";
if (value <= 50) return "score-tier-3";
if (value <= 65) return "score-tier-4";
if (value <= 80) return "score-tier-5";
const v = higherIsBetter ? 100 - value : value;
if (v <= 20) return "score-tier-1";
if (v <= 35) return "score-tier-2";
if (v <= 50) return "score-tier-3";
if (v <= 65) return "score-tier-4";
if (v <= 80) return "score-tier-5";
return "score-tier-6";
}