chore(ui): add jar button variants

This commit is contained in:
theborakompanioni 2026-07-09 00:26:27 +02:00 committed by Thebora Kompanioni
parent 5041ce6af5
commit 492ae14dc1
9 changed files with 49 additions and 25 deletions

View file

@ -13,7 +13,7 @@ import { Trans } from 'react-i18next'
import { toast } from 'sonner'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
import { Badge } from '@/components/ui/badge'
import { getJarBadgeVariant } from '@/components/ui/badge-variants'
import { jarBadgeVariant } from '@/components/ui/badge-variants'
import { Button } from '@/components/ui/button'
import { buttonVariants } from '@/components/ui/button-variants'
import { Card, CardContent } from '@/components/ui/card'
@ -418,7 +418,7 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial
</div>
<div className="bg-muted/50 rounded-lg p-4">
<p className="text-muted-foreground mb-1 text-xs">{t('earn.fidelity_bond.review_inputs.label_jar')}</p>
<Badge variant={getJarBadgeVariant(selectedJarIndex)}>
<Badge variant={jarBadgeVariant(selectedJarIndex)}>
{selectedJar ? (
<>
{selectedJar.name} <span>#{selectedJar.jarIndex}</span>

View file

@ -40,7 +40,7 @@ import type { FidelityBondUtxo, Utxo } from '@/hooks/useQueryUtxos'
import { getErrorReason } from '@/lib/errorReason'
import { cn, formatSats, type WalletFileName } from '@/lib/utils'
import type { JarIndex } from '@/types/global'
import { getJarBadgeVariant } from '../ui/badge-variants'
import { jarBadgeVariant } from '../ui/badge-variants'
import { Address } from '../ui/jam/Address'
type Step = 'select_jar' | 'confirm' | 'sending' | 'success'
@ -282,7 +282,7 @@ export function MoveToJarDialog({ open, onOpenChange, walletFileName, utxo }: Mo
<p className="text-muted-foreground mb-1 text-xs">
{t('earn.fidelity_bond.review_inputs.label_jar')}
</p>
<Badge variant={getJarBadgeVariant(utxo.mixdepth)}>
<Badge variant={jarBadgeVariant(utxo.mixdepth)}>
{sourceJar?.name ? (
<>
{sourceJar.name} <span>#{utxo.mixdepth}</span>
@ -294,7 +294,7 @@ export function MoveToJarDialog({ open, onOpenChange, walletFileName, utxo }: Mo
</div>
<div className="bg-muted/50 rounded-lg p-4">
<p className="text-muted-foreground mb-1 text-xs">{t('earn.fidelity_bond.move.label_destination')}</p>
<Badge variant={getJarBadgeVariant(selectedJarIndex)}>
<Badge variant={jarBadgeVariant(selectedJarIndex)}>
{destinationJar?.name ? (
<>
{destinationJar.name} <span>#{selectedJarIndex}</span>

View file

@ -41,7 +41,7 @@ import { getErrorReason } from '@/lib/errorReason'
import * as fb from '@/lib/fidelityBondUtils'
import { cn, formatSats, type WalletFileName } from '@/lib/utils'
import { useDeveloperMode } from '@/store/jamSettingsStore'
import { getJarBadgeVariant } from '../ui/badge-variants'
import { jarBadgeVariant } from '../ui/badge-variants'
import { Address } from '../ui/jam/Address'
import { generateLockdateOptions, getYearOptions, getMonthOptions } from './CreateFidelityBondDialog/types'
@ -332,7 +332,7 @@ export function RenewBondDialog({ open, onOpenChange, walletFileName, utxo }: Re
</div>
<div className="bg-muted/50 rounded-lg p-3">
<p className="text-muted-foreground text-xs">{t('earn.fidelity_bond.review_inputs.label_jar')}</p>
<Badge variant={getJarBadgeVariant(utxo.mixdepth)}>
<Badge variant={jarBadgeVariant(utxo.mixdepth)}>
{sourceJar?.name ? (
<>
{sourceJar.name} <span>#{utxo.mixdepth}</span>

View file

@ -18,7 +18,7 @@ import { cn, type WalletFileName } from '@/lib/utils'
import { useDeveloperMode } from '@/store/jamSettingsStore'
import type { AmountSats, BitcoinAddress } from '@/types/global'
import { Badge } from '../ui/badge'
import { getJarBadgeVariant } from '../ui/badge-variants'
import { jarBadgeVariant } from '../ui/badge-variants'
import { buttonVariants } from '../ui/button-variants'
import { Address } from '../ui/jam/Address'
import { BitcoinAddressQrCode } from '../ui/jam/BitcoinQrCode'
@ -175,7 +175,7 @@ export const ReceivePage = ({ walletFileName }: ReceivePageProps) => {
)}
<Badge
className="min-h-6 text-sm"
variant={sourceJar ? getJarBadgeVariant(sourceJar.jarIndex) : 'secondary'}
variant={sourceJar ? jarBadgeVariant(sourceJar.jarIndex) : 'secondary'}
>
{sourceJar ? (
<>

View file

@ -3,7 +3,7 @@ import { DialogTitle } from '@radix-ui/react-dialog'
import { InfoIcon } from 'lucide-react'
import { Trans, useTranslation } from 'react-i18next'
import { Badge } from '@/components/ui/badge'
import { getJarBadgeVariant } from '@/components/ui/badge-variants'
import { jarBadgeVariant } from '@/components/ui/badge-variants'
import type { Jar } from '@/context/JamWalletInfoContext'
import type { Utxo } from '@/hooks/useQueryUtxos'
import type { JamFeeConfigValues } from '@/lib/feeConfig'
@ -111,7 +111,7 @@ export default function PaymentConfirmDialog({
<div className="grid grid-cols-1 gap-x-4 gap-y-1 md:grid-cols-5">
<div className="col-span-1 font-semibold md:text-right">{t('send.confirm_send_modal.label_source_jar')}</div>
<div className="col-span-4">
<Badge variant={getJarBadgeVariant(meta.sourceJar.jarIndex)}>
<Badge variant={jarBadgeVariant(meta.sourceJar.jarIndex)}>
{meta.sourceJar.name} <span>#{meta.sourceJar.jarIndex}</span>
</Badge>
</div>
@ -121,7 +121,7 @@ export default function PaymentConfirmDialog({
{meta.destinationJar !== undefined ? (
<>
<div>
<Badge variant={getJarBadgeVariant(meta.destinationJar.jarIndex)}>
<Badge variant={jarBadgeVariant(meta.destinationJar.jarIndex)}>
{meta.destinationJar.name} <span>#{meta.destinationJar.jarIndex}</span>
</Badge>
</div>

View file

@ -23,7 +23,7 @@ import { DevBadge } from '../dev/DevBadge'
import { buildSweepPreconditionSummary } from '../sweep/preconditions'
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '../ui/accordion'
import { Badge } from '../ui/badge'
import { getJarBadgeVariant } from '../ui/badge-variants'
import { jarBadgeVariant } from '../ui/badge-variants'
import { Button } from '../ui/button'
import { ButtonGroup } from '../ui/button-group'
import { Card, CardContent, CardHeader } from '../ui/card'
@ -411,7 +411,7 @@ export function SendForm({
)}
>
<Address value={values.destination.address} copyable={true} className="text-xs sm:text-sm" />
<Badge className="shrink-0 text-sm" variant={getJarBadgeVariant(destinationJar.jarIndex)}>
<Badge className="shrink-0 text-sm" variant={jarBadgeVariant(destinationJar.jarIndex)}>
{destinationJar.name} <span className="text-xs">#{destinationJar.jarIndex}</span>
</Badge>
</div>
@ -512,7 +512,7 @@ export function SendForm({
<Balance valueString={values.amount.sweepAmount.toFixed(0)} />
)}
<Badge className="shrink-0 text-sm" variant={getJarBadgeVariant(sourceJar?.jarIndex)}>
<Badge className="shrink-0 text-sm" variant={jarBadgeVariant(sourceJar?.jarIndex)}>
{sourceJar?.name} <span className="text-xs">#{sourceJar?.jarIndex}</span>
</Badge>
</div>

View file

@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest'
import { getJarBadgeVariant } from './badge-variants'
import { jarBadgeVariant } from './badge-variants'
describe('getJarBadgeVariant', () => {
describe('jarBadgeVariant', () => {
it.each([
[0, 'jar0'],
[1, 'jar1'],
@ -9,14 +9,14 @@ describe('getJarBadgeVariant', () => {
[3, 'jar3'],
[4, 'jar4'],
])('returns the jar badge variant for jar index %i', (jarIndex, variant) => {
expect(getJarBadgeVariant(jarIndex)).toBe(variant)
expect(jarBadgeVariant(jarIndex)).toBe(variant)
})
it('returns undefined when no jar is available', () => {
expect(getJarBadgeVariant()).toBeUndefined()
expect(jarBadgeVariant()).toBeUndefined()
})
it('returns the unknown jar badge variant for non-standard jar indexes', () => {
expect(getJarBadgeVariant(5)).toBe('jarUnknown')
expect(jarBadgeVariant(5)).toBe('jarUnknown')
})
})

View file

@ -1,4 +1,5 @@
import { cva, type VariantProps } from 'class-variance-authority'
import type { JarIndex } from '@/types/global'
const badgeVariants = cva(
'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
@ -27,7 +28,7 @@ const badgeVariants = cva(
type BadgeVariant = NonNullable<VariantProps<typeof badgeVariants>['variant']>
const JAR_BADGE_VARIANTS: Record<number, BadgeVariant> = {
const JAR_BADGE_VARIANTS: Record<JarIndex, BadgeVariant> = {
0: 'jar0',
1: 'jar1',
2: 'jar2',
@ -35,7 +36,7 @@ const JAR_BADGE_VARIANTS: Record<number, BadgeVariant> = {
4: 'jar4',
}
const getJarBadgeVariant = (jarIndex?: number): BadgeVariant | undefined =>
const jarBadgeVariant = (jarIndex?: JarIndex): BadgeVariant | undefined =>
jarIndex === undefined ? undefined : (JAR_BADGE_VARIANTS[jarIndex] ?? 'jarUnknown')
export { badgeVariants, getJarBadgeVariant }
export { badgeVariants, jarBadgeVariant }

View file

@ -1,7 +1,8 @@
import { cva } from 'class-variance-authority'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
import type { JarIndex } from '@/types/global'
export const buttonVariants = cva(
const buttonVariants = cva(
cn(
"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-lg border border-transparent text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
'cursor-pointer disabled:cursor-not-allowed',
@ -20,6 +21,13 @@ export const buttonVariants = cva(
destructive:
'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
link: 'text-primary underline-offset-4 hover:underline',
jar0: 'border-transparent bg-jar0 text-primary-foreground [a&]:hover:bg-jar0/90',
jar1: 'border-transparent bg-jar1 text-primary-foreground [a&]:hover:bg-jar1/90',
jar2: 'border-transparent bg-jar2 text-primary-foreground [a&]:hover:bg-jar2/90',
jar3: 'border-transparent bg-jar3 text-primary-foreground [a&]:hover:bg-jar3/90',
jar4: 'border-transparent bg-jar4 text-primary-foreground [a&]:hover:bg-jar4/90',
jarUnknown: 'border-transparent bg-jar-unknown text-primary-foreground [a&]:hover:bg-jar-unknown/90',
},
size: {
default: 'h-10 gap-1.5 px-3.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3',
@ -40,3 +48,18 @@ export const buttonVariants = cva(
},
},
)
type ButtonVariant = NonNullable<VariantProps<typeof buttonVariants>['variant']>
const JAR_BUTTON_VARIANTS: Record<JarIndex, ButtonVariant> = {
0: 'jar0',
1: 'jar1',
2: 'jar2',
3: 'jar3',
4: 'jar4',
}
const jarButtonVariant = (jarIndex?: JarIndex): ButtonVariant | undefined =>
jarIndex === undefined ? undefined : (JAR_BUTTON_VARIANTS[jarIndex] ?? 'jarUnknown')
export { buttonVariants, jarButtonVariant }