mirror of
https://github.com/joinmarket-webui/jam.git
synced 2026-08-13 12:33:26 +02:00
Improve component sizing for buttons and inputs (#1302)
* style: increase shared control sizing * style: improve form control sizing * style: broaden component sizing pass * style: format component sizing updates * fix: align grouped control sizing
This commit is contained in:
parent
d66f5e9c82
commit
a486002a71
15 changed files with 25 additions and 27 deletions
|
|
@ -94,7 +94,7 @@ export default function MainWalletPage({ walletFileName }: MainWalletPageProps)
|
|||
{t('global.errors.error_loading_wallet_failed', {
|
||||
reason: error.message || t('global.errors.reason_unknown'),
|
||||
})}
|
||||
<Button variant="outline" size="sm" onClick={() => void refetchWalletData()}>
|
||||
<Button variant="outline" onClick={() => void refetchWalletData()}>
|
||||
<RefreshCwIcon className={cn({ 'motion-safe:animate-spin': isFetching })} />
|
||||
{t('global.retry')}
|
||||
</Button>
|
||||
|
|
@ -146,7 +146,7 @@ export default function MainWalletPage({ walletFileName }: MainWalletPageProps)
|
|||
</div>
|
||||
</div>
|
||||
<div className="flex w-full max-w-xl justify-end">
|
||||
<Button variant="ghost" size="xs" onClick={() => void refetchWalletData()}>
|
||||
<Button variant="ghost" onClick={() => void refetchWalletData()}>
|
||||
<RefreshCwIcon className={cn({ 'motion-safe:animate-spin': isFetching })} />
|
||||
{t('global.refresh')}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -237,11 +237,11 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial
|
|||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button variant="outline" size="sm" onClick={selectAllUtxos} className="shadow-sm">
|
||||
<Button variant="outline" onClick={selectAllUtxos} className="shadow-sm">
|
||||
<CheckIcon className="mr-1 h-3.5 w-3.5" />
|
||||
{t('earn.fidelity_bond.select_utxos.button_select_all')}
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" onClick={deselectAllUtxos} className="shadow-sm">
|
||||
<Button variant="outline" onClick={deselectAllUtxos} className="shadow-sm">
|
||||
{t('earn.fidelity_bond.select_utxos.button_deselect_all')}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ export const EarnPage = ({ walletFileName }: EarnPageProps) => {
|
|||
<PageTitle title={t('earn.title')} subtitle={t('earn.subtitle')} />
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button variant="outline" size="sm" onClick={() => setShowEarnReport(true)}>
|
||||
<Button variant="outline" onClick={() => setShowEarnReport(true)}>
|
||||
<FileTextIcon />
|
||||
{t('earn.button_show_report')}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ export const LoginCard = ({
|
|||
{listWalletsError ? (
|
||||
<>
|
||||
<WalletLoadErrorAlert reason={listWalletsError.message} />
|
||||
<Button variant="ghost" size="sm" onClick={() => void onReloadClick()} disabled={listWalletsFetching}>
|
||||
<Button variant="ghost" onClick={() => void onReloadClick()} disabled={listWalletsFetching}>
|
||||
<RefreshCwIcon className={cn({ 'motion-safe:animate-spin': listWalletsFetching })} />
|
||||
{t('global.retry')}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export const BitcoinAmountInput = ({
|
|||
{...inputProps}
|
||||
/>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" className="py-4 whitespace-nowrap" onClick={toggleCurrencyUnit}>
|
||||
<Button variant="outline" size="lg" className="whitespace-nowrap" onClick={toggleCurrencyUnit}>
|
||||
{currency === 'sats' ? 'BTC' : 'Sats'}
|
||||
<ArrowUpDownIcon />
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -364,7 +364,6 @@ export function SendForm({
|
|||
required: destinationJar === undefined,
|
||||
disabled,
|
||||
})}
|
||||
className="h-auto"
|
||||
type="text"
|
||||
placeholder={t('send.placeholder_recipient')}
|
||||
onPaste={handleAddressPaste}
|
||||
|
|
@ -406,7 +405,7 @@ export function SendForm({
|
|||
id="send-destination-address-from-jar"
|
||||
className={cn(
|
||||
inputVariants(),
|
||||
'flex min-h-8 min-w-0 flex-col items-start justify-center gap-1 sm:flex-row sm:items-center sm:justify-between sm:gap-2',
|
||||
'flex min-h-10 min-w-0 flex-col items-start justify-center gap-1 sm:flex-row sm:items-center sm:justify-between sm:gap-2',
|
||||
'bg-input/50 dark:bg-input/80 h-auto',
|
||||
)}
|
||||
>
|
||||
|
|
@ -465,7 +464,7 @@ export function SendForm({
|
|||
min={MIN_SEND_AMOUNT}
|
||||
max={MAX_SEND_AMOUNT}
|
||||
type="number"
|
||||
className="h-auto pl-9"
|
||||
className="pl-9"
|
||||
placeholder={t('send.placeholder_amount_input')}
|
||||
/>
|
||||
<div className="absolute top-1/2 left-0 flex -translate-y-1/2 items-center px-3">
|
||||
|
|
@ -503,7 +502,7 @@ export function SendForm({
|
|||
id="send-amount-sweep-from-jar"
|
||||
className={cn(
|
||||
inputVariants(),
|
||||
'flex min-h-8 min-w-0 flex-col items-start justify-center gap-1 sm:flex-row sm:items-center sm:justify-between sm:gap-2',
|
||||
'flex min-h-10 min-w-0 flex-col items-start justify-center gap-1 sm:flex-row sm:items-center sm:justify-between sm:gap-2',
|
||||
'bg-input/50 dark:bg-input/80 h-auto',
|
||||
)}
|
||||
aria-disabled
|
||||
|
|
|
|||
|
|
@ -461,7 +461,6 @@ export const SendPage = ({ walletFileName }: SendPageProps) => {
|
|||
<div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
clearCurrentPaymentAttempt()
|
||||
}}
|
||||
|
|
@ -480,7 +479,6 @@ export const SendPage = ({ walletFileName }: SendPageProps) => {
|
|||
<div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setFormId((current) => current + 1)
|
||||
clearCurrentPaymentAttempt()
|
||||
|
|
@ -524,7 +522,6 @@ export const SendPage = ({ walletFileName }: SendPageProps) => {
|
|||
<div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setShowAbortCoinjoinDialog(true)}
|
||||
disabled={isWaitingCoinjoinStop}
|
||||
>
|
||||
|
|
@ -603,7 +600,6 @@ export const SendPage = ({ walletFileName }: SendPageProps) => {
|
|||
sourceJarLabelButton={
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
disabled={utxoSelectionDialog.utxoSelectorDisabled}
|
||||
onClick={utxoSelectionDialog.onOpenUtxoSelector}
|
||||
|
|
|
|||
|
|
@ -72,11 +72,11 @@ export const SweepDestinationInputs = ({ form, fields, disabled }: SweepDestinat
|
|||
<FieldLabel htmlFor={`sweep-destination-${index}`}>
|
||||
{t('scheduler.label_destination_input', { destination: index + 1 })}
|
||||
</FieldLabel>
|
||||
<ButtonGroup>
|
||||
<ButtonGroup className="w-full">
|
||||
<Input
|
||||
id={`sweep-destination-${index}`}
|
||||
{...register(`destinations.${index}.address`)}
|
||||
className="h-auto font-mono"
|
||||
className="font-mono"
|
||||
placeholder={t('scheduler.placeholder_destination_input')}
|
||||
disabled={disabled}
|
||||
autoComplete="off"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Separator } from '@/components/ui/separator'
|
|||
import { cn } from '@/lib/utils'
|
||||
|
||||
const buttonGroupVariants = cva(
|
||||
"flex w-fit max-w-full items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:min-w-0 [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
|
||||
"flex w-fit max-w-full items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=input]]:h-auto [&>[data-slot=input]]:self-stretch [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:min-w-0 [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
|
||||
{
|
||||
variants: {
|
||||
orientation: {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { cn } from '@/lib/utils'
|
|||
|
||||
export 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 bg-clip-padding 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",
|
||||
"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',
|
||||
),
|
||||
{
|
||||
|
|
@ -22,12 +22,12 @@ export const buttonVariants = cva(
|
|||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
size: {
|
||||
default: 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
|
||||
default: 'h-10 gap-1.5 px-3.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3',
|
||||
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
||||
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
||||
lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3',
|
||||
lg: 'h-11 gap-1.5 px-4 has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4',
|
||||
xxl: 'h-12 gap-2 px-4 has-data-[icon=inline-end]:pr-5 has-data-[icon=inline-start]:pl-5',
|
||||
icon: 'size-8',
|
||||
icon: 'size-9',
|
||||
'icon-xs':
|
||||
"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
|
||||
'icon-sm': 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',
|
||||
|
|
|
|||
|
|
@ -104,7 +104,10 @@ function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|||
return (
|
||||
<div
|
||||
data-slot="dialog-footer"
|
||||
className={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}
|
||||
className={cn(
|
||||
'flex flex-col-reverse gap-2 sm:flex-row sm:justify-end [&>[data-slot=button]]:min-h-10 [&>[data-slot=button]]:w-full sm:[&>[data-slot=button]]:w-auto sm:[&>[data-slot=button]]:min-w-28',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|||
data-slot="input-group"
|
||||
role="group"
|
||||
className={cn(
|
||||
'border-input dark:bg-input/30 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-disabled:bg-input/50 dark:has-disabled:bg-input/80 group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg border transition-colors outline-none has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot][aria-invalid=true]]:ring-[3px] has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 [[data-slot=combobox-content]_&]:focus-within:border-inherit [[data-slot=combobox-content]_&]:focus-within:ring-0',
|
||||
'border-input dark:bg-input/30 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-disabled:bg-input/50 dark:has-disabled:bg-input/80 group/input-group relative flex h-10 w-full min-w-0 items-center rounded-lg border transition-colors outline-none has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot][aria-invalid=true]]:ring-[3px] has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 [[data-slot=combobox-content]_&]:focus-within:border-inherit [[data-slot=combobox-content]_&]:focus-within:ring-0',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { cva } from 'class-variance-authority'
|
||||
|
||||
const inputVariants = cva(
|
||||
'dark:bg-input/30 border-input 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 disabled:bg-input/50 dark:disabled:bg-input/80 file:text-foreground placeholder:text-muted-foreground h-8 w-full min-w-0 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-[3px] md:text-sm',
|
||||
'dark:bg-input/30 border-input 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 disabled:bg-input/50 dark:disabled:bg-input/80 file:text-foreground placeholder:text-muted-foreground h-10 w-full min-w-0 rounded-lg border bg-transparent px-3 py-2 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-[3px] md:text-sm',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export const FeeConfigErrorAlert = ({ onOpenFeeConfig, className }: FeeConfigErr
|
|||
<AlertDescription className="flex flex-col gap-2">
|
||||
<div>{t('send.taker_error_message_max_fees_config_missing')}</div>
|
||||
<div>
|
||||
<Button variant="outline" size="sm" onClick={onOpenFeeConfig}>
|
||||
<Button variant="outline" onClick={onOpenFeeConfig}>
|
||||
<HandCoinsIcon />
|
||||
{t('settings.show_fee_config')}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ function SelectTrigger({
|
|||
data-slot="select-trigger"
|
||||
data-size={size}
|
||||
className={cn(
|
||||
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground 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:bg-input/30 dark:hover:bg-input/50 flex w-fit max-w-full min-w-0 items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:min-w-0 *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground 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:bg-input/30 dark:hover:bg-input/50 flex w-fit max-w-full min-w-0 items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-10 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:min-w-0 *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue