refactor: shared CustomFormatBadge and Score components to be used in library/testing views

This commit is contained in:
Sam Chau
2026-01-16 20:47:47 +10:30
parent 643ba8ce00
commit 1f97a96e34
4 changed files with 68 additions and 22 deletions

View File

@@ -0,0 +1,20 @@
<script lang="ts">
export let name: string;
export let score: number;
$: scoreClass =
score > 0
? 'text-emerald-600 dark:text-emerald-400'
: score < 0
? 'text-red-600 dark:text-red-400'
: 'text-neutral-500';
$: displayScore = score > 0 ? `+${score.toLocaleString()}` : score.toLocaleString();
</script>
<span
class="inline-flex items-center gap-1.5 rounded-md border border-neutral-200 bg-white px-2 py-1 text-xs dark:border-neutral-700 dark:bg-neutral-800"
>
<span class="text-neutral-500 dark:text-neutral-400">{name}</span>
<span class="font-mono font-medium {scoreClass}">{displayScore}</span>
</span>

View File

@@ -0,0 +1,40 @@
<script lang="ts">
/**
* Displays a numeric score with optional color coding.
* - Positive: green with + prefix (when colored=true)
* - Negative: red (when colored=true)
* - Zero/neutral: neutral gray
*/
export let score: number | null = null;
export let showSign: boolean = true;
export let size: 'sm' | 'md' = 'md';
export let colored: boolean = true;
$: colorClass =
score === null
? 'text-neutral-400'
: !colored
? 'text-neutral-900 dark:text-neutral-100'
: score > 0
? 'text-emerald-600 dark:text-emerald-400'
: score < 0
? 'text-red-600 dark:text-red-400'
: 'text-neutral-500';
$: sizeClass = size === 'sm' ? 'text-xs' : 'text-sm';
$: displayValue =
score === null
? null
: showSign && score > 0
? `+${score.toLocaleString()}`
: score.toLocaleString();
</script>
{#if score !== null}
<span class="font-mono font-medium {colorClass} {sizeClass}">
{displayValue}
</span>
{:else}
<span class="text-neutral-400 {sizeClass}"></span>
{/if}

View File

@@ -1,5 +1,7 @@
<script lang="ts">
import { Check, ExternalLink, CircleAlert } from 'lucide-svelte';
import Score from '$ui/arr/Score.svelte';
import CustomFormatBadge from '$ui/arr/CustomFormatBadge.svelte';
import type { RadarrLibraryItem } from '$utils/arr/types.ts';
import type { Column } from '$ui/table/types';
@@ -52,9 +54,7 @@
</code>
{:else if column.key === 'customFormatScore'}
<div class="text-right">
<span class="font-mono font-medium {row.cutoffMet ? 'text-green-600 dark:text-green-400' : 'text-neutral-900 dark:text-neutral-100'}">
{row.customFormatScore.toLocaleString()}
</span>
<Score score={row.customFormatScore} showSign={false} colored={false} />
<span class="text-xs text-neutral-500 dark:text-neutral-400">
/ {row.cutoffScore.toLocaleString()}
</span>
@@ -111,14 +111,8 @@
{#if row.scoreBreakdown.length > 0}
<div class="flex flex-wrap items-center gap-2">
{#each [...row.scoreBreakdown].sort((a, b) => b.score - a.score) as item}
<div class="inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs {item.score > 0 ? 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400' : item.score < 0 ? 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400' : 'bg-neutral-100 text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400'}">
<span class="font-medium">{item.name}</span>
<span class="font-mono">{item.score >= 0 ? '+' : ''}{item.score.toLocaleString()}</span>
</div>
<CustomFormatBadge name={item.name} score={item.score} />
{/each}
<span class="text-xs text-neutral-500 dark:text-neutral-400">
= <span class="font-mono font-medium">{row.customFormatScore.toLocaleString()}</span>
</span>
</div>
{:else}
<div class="text-xs text-neutral-500 dark:text-neutral-400">No custom formats matched</div>

View File

@@ -5,6 +5,8 @@
import ExpandableTable from '$ui/table/ExpandableTable.svelte';
import TableActionButton from '$ui/table/TableActionButton.svelte';
import Badge from '$ui/badge/Badge.svelte';
import Score from '$ui/arr/Score.svelte';
import CustomFormatBadge from '$ui/arr/CustomFormatBadge.svelte';
import { alertStore } from '$lib/client/alerts/store';
import type { Column } from '$ui/table/types';
import type { TestRelease, ProfileCfScores, CustomFormatInfo } from './types';
@@ -151,14 +153,7 @@
<span class="text-neutral-400"></span>
{/if}
{:else if column.key === 'score'}
{@const score = calculateScore(release.id, entityType)}
{#if score !== null}
<span class="font-mono text-sm font-medium {score > 0 ? 'text-emerald-600 dark:text-emerald-400' : score < 0 ? 'text-red-600 dark:text-red-400' : 'text-neutral-500'}">
{score > 0 ? '+' : ''}{score.toLocaleString()}
</span>
{:else}
<span class="text-neutral-400"></span>
{/if}
<Score score={calculateScore(release.id, entityType)} />
{/if}
</svelte:fragment>
@@ -266,10 +261,7 @@
{:else}
<div class="flex flex-wrap gap-2">
{#each matchingFormats as cf}
<span class="inline-flex items-center gap-1.5 rounded-md border border-neutral-200 bg-white px-2 py-1 dark:border-neutral-700 dark:bg-neutral-800">
<span class="text-neutral-500 dark:text-neutral-400">{cf.name}</span>
<span class="font-mono font-medium {cf.score > 0 ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}">{cf.score > 0 ? '+' : ''}{cf.score.toLocaleString()}</span>
</span>
<CustomFormatBadge name={cf.name} score={cf.score} />
{/each}
</div>
{/if}