refactor: import lucide icons with -Icon postfix name

This commit is contained in:
theborakompanioni 2026-01-06 21:50:08 +01:00
parent 505c02dc00
commit 9b03971b92
No known key found for this signature in database
GPG key ID: E8070AF0053AAC0D
19 changed files with 86 additions and 60 deletions

View file

@ -1,5 +1,5 @@
import type { SVGAttributes } from 'react'
import { EyeOff } from 'lucide-react'
import { EyeOffIcon } from 'lucide-react'
import { cn } from '@/lib/utils'
import type { Currency } from '@/types/global'
@ -11,7 +11,9 @@ type CurrencySymbolProps = {
export function CurrencySymbol({ currency, isPrivate, size = 'lg' }: CurrencySymbolProps) {
if (isPrivate) {
return <EyeOff size={size === 'sm' ? 14 : 24} className="text-muted-foreground mx-1 inline-block align-middle" />
return (
<EyeOffIcon size={size === 'sm' ? 14 : 24} className="text-muted-foreground mx-1 inline-block align-middle" />
)
}
if (currency === 'btc') {

View file

@ -102,8 +102,17 @@ export default function JamLanding({ walletFileName }: JamLandingProps) {
onClick={() => refetchWalletData()}
className="flex items-center gap-2 text-gray-500"
>
<RefreshCwIcon className="h-4 w-4" />
{t('global.refresh')}
{isLoading ? (
<>
<RefreshCwIcon className="animate-spin motion-reduce:hidden" />
{t('global.refresh')}
</>
) : (
<>
<RefreshCwIcon className="motion-reduce:hidden" />
{t('global.refresh')}
</>
)}
</Button>
</div>
</div>

View file

@ -1,7 +1,7 @@
import React, { useMemo, useState } from 'react'
import { listwalletsOptions, unlockwalletMutation } from '@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query'
import { useMutation, useQuery } from '@tanstack/react-query'
import { AlertCircle, Eye, EyeOff, Loader2Icon, Lock, RefreshCwIcon, Wallet } from 'lucide-react'
import { AlertCircleIcon, EyeIcon, EyeOffIcon, Loader2Icon, LockIcon, RefreshCwIcon, WalletIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import { toast } from 'sonner'
@ -100,7 +100,7 @@ const LoginForm = ({ wallets, isSubmitting, onSubmit }: LoginFormProps) => {
<div className="space-y-2">
<Label htmlFor="password">Password</Label>
<div className="relative">
<Lock className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform" />
<LockIcon className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform" />
<Input
id="password"
type={showPassword ? 'text' : 'password'}
@ -117,7 +117,7 @@ const LoginForm = ({ wallets, isSubmitting, onSubmit }: LoginFormProps) => {
className="absolute top-1/2 right-1 -translate-y-1/2 transform"
onClick={() => setShowPassword((val) => !val)}
>
{showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
{showPassword ? <EyeOffIcon className="h-4 w-4" /> : <EyeIcon className="h-4 w-4" />}
</Button>
</div>
</div>
@ -214,7 +214,7 @@ const LoginPage = () => {
{isLoadingWallets ? (
<Loader2Icon className="h-6 w-6 animate-spin" />
) : (
<Wallet className="text-primary h-6 w-6" onClick={async () => await listwalletsQuery.refetch()} />
<WalletIcon className="text-primary h-6 w-6" onClick={async () => await listwalletsQuery.refetch()} />
)}
</div>
<CardTitle className="text-2xl font-bold">Welcome to Jam</CardTitle>
@ -232,7 +232,7 @@ const LoginPage = () => {
{listwalletsError ? (
<CardContent className="space-y-6">
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertCircleIcon className="h-4 w-4" />
<AlertTitle>{listwalletsError.message}</AlertTitle>
<AlertDescription>{listwalletsError.error_description}</AlertDescription>
</Alert>

View file

@ -1,5 +1,5 @@
import type { PropsWithChildren } from 'react'
import { Loader2Icon, LogOutIcon, MoonIcon, Settings, SunIcon, WalletIcon } from 'lucide-react'
import { Loader2Icon, LogOutIcon, MoonIcon, SettingsIcon, SunIcon, WalletIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Link, useNavigate } from 'react-router-dom'
import { useStore } from 'zustand'
@ -143,7 +143,7 @@ export function Navbar({
variant="ghost"
size="icon"
>
<Settings />
<SettingsIcon />
</Button>
</Link>
<Button

View file

@ -11,7 +11,7 @@ import {
type ColumnDef,
useReactTable,
} from '@tanstack/react-table'
import { ChevronDownIcon, ChevronUpIcon, RefreshCw, ArrowUpDown, Plus, AlertCircleIcon } from 'lucide-react'
import { ChevronDownIcon, ChevronUpIcon, RefreshCwIcon, ArrowUpDownIcon, PlusIcon, AlertCircleIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { useStore } from 'zustand'
import { Balance } from '@/components/ui/Balance'
@ -463,7 +463,7 @@ export const Orderbook = ({ isModal = false }: OrderbookProps) => {
const getSortIcon = (columnKey: SortKey) => {
const col = table.getColumn(columnKey)
const dir = col?.getIsSorted()
if (!dir) return <ArrowUpDown className="ml-2 h-4 w-4" />
if (!dir) return <ArrowUpDownIcon className="ml-2 h-4 w-4" />
return dir === 'desc' ? <ChevronDownIcon className="ml-2 h-4 w-4" /> : <ChevronUpIcon className="ml-2 h-4 w-4" />
}
@ -480,7 +480,7 @@ export const Orderbook = ({ isModal = false }: OrderbookProps) => {
</Alert>
<Button onClick={() => refetch()} disabled={isLoadingData}>
<RefreshCw className={cn('ml-2 h-4 w-4', isLoadingData ? 'animate-spin' : '')} />
<RefreshCwIcon className={cn('ml-2 h-4 w-4', { 'animate-spin': isLoadingData })} />
{t('global.retry')}
</Button>
</div>
@ -519,7 +519,7 @@ export const Orderbook = ({ isModal = false }: OrderbookProps) => {
className="relative"
>
Generate Demo Entry
<Plus className="ml-2 h-4 w-4" />
<PlusIcon className="ml-2 h-4 w-4" />
<DevBadge />
</Button>
)}
@ -534,7 +534,7 @@ export const Orderbook = ({ isModal = false }: OrderbookProps) => {
disabled={isLoadingData}
>
{t('orderbook.button_reload_title')}
<RefreshCw className={cn('ml-2 h-4 w-4', isLoadingData && 'animate-spin')} />
<RefreshCwIcon className={cn('ml-2 h-4 w-4', { 'animate-spin': isLoadingData })} />
</Button>
<div className="relative">
<Button
@ -603,7 +603,7 @@ export const Orderbook = ({ isModal = false }: OrderbookProps) => {
className="relative"
>
Generate Demo Entry
<Plus className="ml-2 h-4 w-4" />
<PlusIcon className="ml-2 h-4 w-4" />
<DevBadge />
</Button>
)}
@ -618,7 +618,11 @@ export const Orderbook = ({ isModal = false }: OrderbookProps) => {
disabled={isLoadingData}
>
{t('orderbook.button_reload_title')}
<RefreshCw className={cn('ml-2 h-4 w-4', isLoadingData && 'animate-spin')} />
<RefreshCwIcon
className={cn('ml-2 h-4 w-4', {
'animate-spin': isLoadingData,
})}
/>
</Button>
<div className="relative">
<Button

View file

@ -1,4 +1,4 @@
import { X } from 'lucide-react'
import { XIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { Orderbook } from './Orderbook'
@ -19,7 +19,7 @@ export function OrderbookDialog({ open, onOpenChange }: OrderbookDialogProps) {
<div className="flex items-center justify-between border-b px-6 py-4">
<h1 className="text-lg font-semibold">{t('orderbook.title')}</h1>
<Button variant="ghost" size="lg" onClick={() => onOpenChange(false)} className="h-8 w-8 p-0">
<X className="h-10 w-10" />
<XIcon className="h-10 w-10" />
<span className="sr-only">Close</span>
</Button>
</div>

View file

@ -16,11 +16,9 @@ export const jarTemplates: Array<{
{ name: 'Elderberry', color: '#7c3fa6' },
]
export interface Jar {
name: string
color: JarColor
export type Jar = Pick<(typeof jarTemplates)[number], 'name' | 'color'> & {
balance: AmountSats
account?: string
account: string
}
export interface DisplayModeContextType {

View file

@ -1,4 +1,4 @@
import { ArrowUpDown } from 'lucide-react'
import { ArrowUpDownIcon } from 'lucide-react'
import type { Currency } from '@/types/global'
import { CurrencySymbol } from '../CurrencySymbol'
import { Button } from '../ui/button'
@ -51,7 +51,7 @@ export const BitcoinAmountInput = ({
</div>
<Button variant="outline" size="sm" className="py-4 whitespace-nowrap" onClick={toggleCurrencyUnit}>
{currency === 'sats' ? 'BTC' : 'Sats'}
<ArrowUpDown />
<ArrowUpDownIcon />
</Button>
</div>
</>

View file

@ -1,7 +1,7 @@
import { useState, useEffect, useCallback } from 'react'
import { getaddressOptions } from '@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query'
import { useQuery } from '@tanstack/react-query'
import { Copy, CopyCheck, RefreshCw, Share } from 'lucide-react'
import { CopyCheckIcon, CopyIcon, RefreshCwIcon, ShareIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { useApiClient } from '@/hooks/useApiClient'
@ -171,12 +171,12 @@ export const Receive = ({ walletFileName }: ReceiveProps) => {
<Button variant="outline" size="sm" onClick={getNewAddress} disabled={getAddressQuery.isFetching}>
{getAddressQuery.isFetching ? (
<>
<RefreshCw className="animate-spin motion-reduce:hidden" />
<RefreshCwIcon className="animate-spin motion-reduce:hidden" />
{t('receive.text_getting_address')}
</>
) : (
<>
<RefreshCw />
<RefreshCwIcon className="motion-reduce:hidden" />
{t('receive.button_new_address')}
</>
)}
@ -188,7 +188,7 @@ export const Receive = ({ walletFileName }: ReceiveProps) => {
onClick={copyToClipboard}
disabled={getAddressQuery.isFetching || !bitcoinAddress}
>
{copied ? <CopyCheck /> : <Copy />}
{copied ? <CopyCheckIcon /> : <CopyIcon />}
{copied ? t('global.button_copy_text_confirmed') : t('global.button_copy_text')}
</Button>
@ -199,7 +199,7 @@ export const Receive = ({ walletFileName }: ReceiveProps) => {
onClick={shareAddress}
disabled={getAddressQuery.isFetching || !bitcoinAddress}
>
<Share />
<ShareIcon />
{t('receive.button_share_address')}
</Button>
)}

View file

@ -1,5 +1,5 @@
import { useState, useEffect, forwardRef, useImperativeHandle, useCallback } from 'react'
import { Info } from 'lucide-react'
import { InfoIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
@ -103,7 +103,7 @@ export const CollaboratorFeesForm = forwardRef<CollaboratorFeesFormRef, Collabor
<p className="text-muted-foreground mb-6 text-sm">{t('settings.fees.description_max_cj_fee_settings')}</p>
<Alert variant="default" className="mb-6">
<Info className="text-muted-foreground size-4 shrink-0" />
<InfoIcon className="text-muted-foreground size-4 shrink-0" />
<AlertDescription>{t('settings.fees.subtitle_max_cj_fee')}</AlertDescription>
</Alert>

View file

@ -1,4 +1,4 @@
import { Globe } from 'lucide-react'
import { GlobeIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import languages from '@/i18n/languages'
@ -19,7 +19,7 @@ export const LanguageSelector = () => {
<div className="flex items-center justify-between py-2">
<div className="flex items-center gap-2">
<div className="bg-muted/50 flex h-7 w-7 items-center justify-center rounded-lg border">
<Globe className="text-muted-foreground h-3 w-3" />
<GlobeIcon className="text-muted-foreground h-3 w-3" />
</div>
<div>
<p className="text-sm font-medium">{t('settings.label_select_language')}</p>

View file

@ -1,7 +1,7 @@
import { yupResolver } from '@hookform/resolvers/yup'
import { rescanblockchain } from '@joinmarket-webui/joinmarket-api-ts/jm'
import { useMutation } from '@tanstack/react-query'
import { ArrowLeft, RefreshCw } from 'lucide-react'
import { ArrowLeftIcon, RefreshCwIcon } from 'lucide-react'
import { useForm } from 'react-hook-form'
import type { SubmitHandler } from 'react-hook-form'
import { useTranslation } from 'react-i18next'
@ -62,7 +62,7 @@ function RescanChainForm({ rescanInfo, onSubmit, disabled }: RescanChainFormProp
<p className="text-muted-foreground text-xs">{t('rescan_chain.description_blockheight')}</p>
<div className="relative">
<div className="absolute top-1/2 left-3 -translate-y-1/2">
<RefreshCw className="text-muted-foreground h-4 w-4" />
<RefreshCwIcon className="text-muted-foreground h-4 w-4" />
</div>
<Input
@ -163,7 +163,7 @@ export const RescanChain = ({ walletFileName }: RescanChainProps) => {
onClick={() => navigate(routes.settings)}
className="hover:bg-muted/50 h-8 w-8 p-0"
>
<ArrowLeft className="h-4 w-4" />
<ArrowLeftIcon className="h-4 w-4" />
</Button>
<h1 className="text-2xl font-semibold tracking-tight">{t('rescan_chain.title')}</h1>
</div>
@ -180,7 +180,7 @@ export const RescanChain = ({ walletFileName }: RescanChainProps) => {
{rescanInfo.rescanning && (
<div className="bg-muted/50 mt-4 animate-pulse rounded-lg p-3 duration-100">
<div className="flex items-center gap-2">
<RefreshCw className="h-4 w-4 animate-spin motion-reduce:hidden" />
<RefreshCwIcon className="h-4 w-4 animate-spin motion-reduce:hidden" />
<span className="text-sm">
{rescanInfo?.progress === undefined
? t('app.alert_rescan_in_progress')

View file

@ -1,4 +1,4 @@
import { Settings } from 'lucide-react'
import { SettingsIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { Button } from '@/components/ui/button'
@ -16,7 +16,7 @@ export const FeeConfigErrorAlert = ({ onOpenFeeConfig, className }: FeeConfigErr
<AlertDescription className="flex items-center justify-between">
<span>{t('send.taker_error_message_max_fees_config_missing')}</span>
<Button variant="outline" size="sm" onClick={onOpenFeeConfig} className="ml-4 shrink-0">
<Settings className="mr-2 h-4 w-4" />
<SettingsIcon className="mr-2 h-4 w-4" />
{t('settings.show_fee_config')}
</Button>
</AlertDescription>

View file

@ -1,4 +1,4 @@
import { ChevronLeft, ChevronRight, ChevronsLeftIcon, ChevronsRightIcon } from 'lucide-react'
import { ChevronLeftIcon, ChevronRightIcon, ChevronsLeftIcon, ChevronsRightIcon } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
@ -75,7 +75,7 @@ const Pagination = ({
onClick={() => handlePageChange(currentPage - 1)}
disabled={currentPage === 1}
>
<ChevronLeft />
<ChevronLeftIcon />
</Button>
<div className="flex items-center justify-center text-sm font-medium">{currentPage}</div>
@ -86,7 +86,7 @@ const Pagination = ({
onClick={() => handlePageChange(currentPage + 1)}
disabled={currentPage === totalPages}
>
<ChevronRight />
<ChevronRightIcon />
</Button>
<Button

View file

@ -1,6 +1,8 @@
import { useCallback } from 'react'
import { useStore } from 'zustand'
import { satsToBtc } from '@/lib/utils'
import { jamSettingsStore } from '@/store/jamSettingsStore'
import type { AmountSats } from '@/types/global'
export function useDisplaySettings() {
const {
@ -33,13 +35,13 @@ export function useDisplaySettings() {
}, [privateMode, currencyUnit, update])
const formatAmount = useCallback(
(amount: number): string => {
(amount: AmountSats): string => {
if (privateMode) {
return '■■■■'
}
if (currencyUnit === 'btc') {
return (amount / 100_000_000).toLocaleString(undefined, {
return satsToBtc(String(amount)).toLocaleString(undefined, {
minimumFractionDigits: 8,
maximumFractionDigits: 8,
})

View file

@ -10,10 +10,11 @@ import { withQueryDelay } from '@/lib/queryClient'
import { walletDisplayName } from '@/lib/utils'
import { authStore } from '@/store/authStore'
import { jmSessionStore } from '@/store/jmSessionStore'
import type { AmountSats } from '@/types/global'
export interface UseWalletDisplayResult {
jars: Jar[]
totalBalance: number
totalBalance: AmountSats
walletName: string | null
isLoading: boolean
error: Error | ErrorMessage | null
@ -21,7 +22,7 @@ export interface UseWalletDisplayResult {
}
interface AccountBalance {
balance: number
balance: AmountSats
account: string
}
@ -78,7 +79,7 @@ export function useWalletDisplay(): UseWalletDisplayResult {
}
})
// Sort accounts by mixdepth number
accountBalances.sort((a, b) => parseInt(a.account) - parseInt(b.account))
accountBalances.sort((a, b) => parseInt(a.account, 10) - parseInt(b.account, 10))
// Create the jars array by starting with all jar templates (with zero balance)
// and then updating the ones that have UTXOs
@ -90,7 +91,7 @@ export function useWalletDisplay(): UseWalletDisplayResult {
// Update jars with actual balances from UTXOs
accountBalances.forEach((account) => {
const mixdepthNum = parseInt(account.account)
const mixdepthNum = parseInt(account.account, 10)
// Only process accounts that map to our predefined jars
if (mixdepthNum < jarTemplates.length) {

View file

@ -66,9 +66,9 @@ export const setIntervalDebounced = (
})()
}
export const satsToBtc = (value: string) => parseInt(value, 10) / 100000000
export const satsToBtc = (value: string) => parseInt(value, 10) / 100_000_000
export const btcToSats = (value: string) => Math.round(parseFloat(value) * 100000000)
export const btcToSats = (value: string) => Math.round(parseFloat(value) * 100_000_000)
export const SEGWIT_ACTIVATION_BLOCK = 481_824 // https://github.com/bitcoin/bitcoin/blob/v25.0/src/kernel/chainparams.cpp#L86

View file

@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react-vite'
import { AlertCircle, CheckCircle2 } from 'lucide-react'
import { AlertCircleIcon, CheckCircle2Icon } from 'lucide-react'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
const meta: Meta<typeof Alert> = {
@ -21,7 +21,7 @@ type Story = StoryObj<typeof Alert>
export const Default: Story = {
render: () => (
<Alert>
<AlertCircle />
<AlertCircleIcon />
<AlertTitle>Alert Title</AlertTitle>
<AlertDescription>This is a default alert message.</AlertDescription>
</Alert>
@ -31,7 +31,7 @@ export const Default: Story = {
export const Destructive: Story = {
render: () => (
<Alert variant="destructive">
<AlertCircle />
<AlertCircleIcon />
<AlertTitle>Error</AlertTitle>
<AlertDescription>Something went wrong. Please try again later.</AlertDescription>
</Alert>
@ -49,18 +49,28 @@ export const WithoutIcon: Story = {
export const Success: Story = {
render: () => (
<Alert>
<CheckCircle2 />
<Alert variant="success">
<CheckCircle2Icon />
<AlertTitle>Success</AlertTitle>
<AlertDescription>Your action was completed successfully!</AlertDescription>
</Alert>
),
}
export const Warning: Story = {
render: () => (
<Alert variant="warning">
<AlertCircleIcon />
<AlertTitle>Warning</AlertTitle>
<AlertDescription>Your action was not successfully completed!</AlertDescription>
</Alert>
),
}
export const LongContent: Story = {
render: () => (
<Alert>
<AlertCircle />
<AlertCircleIcon />
<AlertTitle>Important Notice</AlertTitle>
<AlertDescription>
This is a longer alert message that demonstrates how the component handles multiple lines of text. The content

View file

@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react-vite'
import { Bitcoin } from 'lucide-react'
import { BitcoinIcon } from 'lucide-react'
import { MemoryRouter } from 'react-router-dom'
import { Navbar } from '@/components/Navbar'
@ -20,7 +20,7 @@ export default meta
type Story = StoryObj<typeof Navbar>
const mockFormatAmount = (amount: number) => `${amount} sats`
const mockCurrencySymbol = (size: 'sm' | 'lg') => <Bitcoin size={size === 'sm' ? 18 : 32} />
const mockCurrencySymbol = (size: 'sm' | 'lg') => <BitcoinIcon size={size === 'sm' ? 18 : 32} />
export const Default: Story = {
args: {