Skip to content
4 changes: 2 additions & 2 deletions ui/ts/components/ActionLauncherCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ComponentChildren } from 'preact'
import { ActionLauncherButton } from './ActionLauncherButton.js'
import type { ReadinessAction } from '../types/components.js'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_OPENING } from '../lib/uiStrings.js'

type ActionLauncherCardProps = {
action: ReadinessAction
Expand All @@ -11,7 +11,7 @@ type ActionLauncherCardProps = {
tone?: 'primary' | 'secondary'
}

export function ActionLauncherCard({ action, children, pending = false, pendingLabel = TSX_STRINGS.componentsActionLauncherCard.copy001, tone = 'secondary' }: ActionLauncherCardProps) {
export function ActionLauncherCard({ action, children, pending = false, pendingLabel = UI_STRING_OPENING, tone = 'secondary' }: ActionLauncherCardProps) {
if (action.onAction === undefined && action.blocker === undefined && action.readiness !== 'blocked') return undefined
const disabled = action.readiness === 'blocked' || action.onAction === undefined || action.blocker !== undefined
return (
Expand Down
6 changes: 3 additions & 3 deletions ui/ts/components/AddressInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import type { Address } from '@zoltar/shared/ethereum'
import { AddressValue } from './AddressValue.js'
import { MetricField } from './MetricField.js'
import { getMetricPlaceholderPresentation } from '../lib/userCopy.js'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_UNKNOWN } from '../lib/uiStrings.js'

type AddressInfoProps = {
address: Address | undefined
label: string
unavailableLabel?: string
}

export function AddressInfo({ address, label, unavailableLabel = TSX_STRINGS.componentsAddressInfo.copy001 }: AddressInfoProps) {
const fallbackLabel = unavailableLabel === 'Unknown' ? getMetricPlaceholderPresentation(address)?.placeholder : unavailableLabel
export function AddressInfo({ address, label, unavailableLabel = UI_STRING_UNKNOWN }: AddressInfoProps) {
const fallbackLabel = unavailableLabel === UI_STRING_UNKNOWN ? getMetricPlaceholderPresentation(address)?.placeholder : unavailableLabel
return <MetricField label={label}>{address === undefined ? fallbackLabel : <AddressValue address={address} />}</MetricField>
}
6 changes: 3 additions & 3 deletions ui/ts/components/AddressValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useLayoutEffect, useRef, useState } from 'preact/hooks'
import { useCopyToClipboard } from '../hooks/useCopyToClipboard.js'
import { formatAddress } from '../lib/addresses.js'
import { getMetricPlaceholderPresentation } from '../lib/userCopy.js'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_COPIED, UI_TEMPLATE_COPY_ADDRESS_VALUE } from '../lib/uiStrings.js'

type AddressValueProps = {
address: string | undefined
Expand Down Expand Up @@ -63,8 +63,8 @@ export function AddressValue({ address, className = '' }: AddressValueProps) {
const displayValue = shouldShorten ? formatAddress(address) : address

return (
<button ref={buttonRef} type='button' className={`address-value copyable ${className}`} title={address} aria-label={TSX_STRINGS.componentsAddressValue.copy001(address)} onClick={() => copyText(address)}>
{copied.value ? TSX_STRINGS.componentsAddressValue.copy002 : displayValue}
<button ref={buttonRef} type='button' className={`address-value copyable ${className}`} title={address} aria-label={UI_TEMPLATE_COPY_ADDRESS_VALUE(address)} onClick={() => copyText(address)}>
{copied.value ? UI_STRING_COPIED : displayValue}
<span ref={measureRef} aria-hidden='true' className='address-value-measure'>
{address}
</span>
Expand Down
4 changes: 2 additions & 2 deletions ui/ts/components/AppHeaderShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { TabNavigation } from './TabNavigation.js'
import type { OverviewPanelsProps, TabNavigationProps } from '../types/components.js'
import type { SimulationController } from '../simulation/controller.js'
import type { ComponentChildren } from 'preact'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_SKIP_SIMULATION_CONTROLS } from '../lib/uiStrings.js'

type AppHeaderShellProps = {
overview: OverviewPanelsProps
Expand All @@ -25,7 +25,7 @@ export function AppHeaderShell({ overview, simulationController, subNavigation,
<>
{simulationController === undefined ? undefined : (
<button className='skip-link' type='button' onClick={focusAppContent}>
{TSX_STRINGS.componentsAppHeaderShell.copy001}
{UI_STRING_SKIP_SIMULATION_CONTROLS}
</button>
)}
{simulationController === undefined ? undefined : <SimulationBanner controller={simulationController} onEnvironmentChanged={onEnvironmentChanged} onRefresh={onRefresh} />}
Expand Down
7 changes: 3 additions & 4 deletions ui/ts/components/ApprovedAmountValue.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { CurrencyValue } from './CurrencyValue.js'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_MAX, UI_STRING_UNLIMITED_APPROVAL } from '../lib/uiStrings.js'

export const APPROVAL_MAX_DISPLAY_THRESHOLD = (1n << 200n) - 1n
export const APPROVAL_MAX_LABEL = 'Max'

type ApprovedAmountValueProps = {
className?: string
Expand All @@ -29,8 +28,8 @@ export function ApprovedAmountValue({ className = '', copyable = true, decimals

if (isApprovalAmountMaxDisplay(value))
return (
<span className={['currency-value', 'approval-max', toneClassName === undefined ? '' : `approval-${toneClassName}`, className].filter(Boolean).join(' ')} title={TSX_STRINGS.componentsApprovedAmountValue.copy001}>
{APPROVAL_MAX_LABEL}
<span className={['currency-value', 'approval-max', toneClassName === undefined ? '' : `approval-${toneClassName}`, className].filter(Boolean).join(' ')} title={UI_STRING_UNLIMITED_APPROVAL}>
{UI_STRING_MAX}
</span>
)

Expand Down
10 changes: 5 additions & 5 deletions ui/ts/components/ChildUniverseDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DataGrid } from './DataGrid.js'
import { TimestampValue } from './TimestampValue.js'
import { MetricField } from './MetricField.js'
import type { ZoltarChildUniverseSummary } from '../types/contracts.js'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_FORK_TIME, UI_STRING_OUTCOME, UI_STRING_OUTCOME_INDEX, UI_STRING_REPUTATION_TOKEN } from '../lib/uiStrings.js'

type ChildUniverseDetailsProps = {
child: ZoltarChildUniverseSummary
Expand All @@ -13,15 +13,15 @@ type ChildUniverseDetailsProps = {
export function ChildUniverseDetails({ child, showOutcomeIndex = false }: ChildUniverseDetailsProps) {
return (
<DataGrid className='child-universe-details-grid'>
<MetricField label={TSX_STRINGS.componentsChildUniverseDetails.copy001}>{child.outcomeLabel}</MetricField>
{showOutcomeIndex ? <MetricField label={TSX_STRINGS.componentsChildUniverseDetails.copy002}>{child.outcomeIndex.toString()}</MetricField> : undefined}
<MetricField label={UI_STRING_OUTCOME}>{child.outcomeLabel}</MetricField>
{showOutcomeIndex ? <MetricField label={UI_STRING_OUTCOME_INDEX}>{child.outcomeIndex.toString()}</MetricField> : undefined}
{child.exists ? (
<MetricField label={TSX_STRINGS.componentsChildUniverseDetails.copy003}>
<MetricField label={UI_STRING_REPUTATION_TOKEN}>
<AddressValue address={child.reputationToken} />
</MetricField>
) : undefined}
{child.forkTime !== 0n ? (
<MetricField label={TSX_STRINGS.componentsChildUniverseDetails.copy004}>
<MetricField label={UI_STRING_FORK_TIME}>
<TimestampValue timestamp={child.forkTime} />
</MetricField>
) : undefined}
Expand Down
6 changes: 3 additions & 3 deletions ui/ts/components/CollateralizationCircle.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { CollateralizationCircleProps } from '../types/components.js'
import { formatCollateralizationCompactPercentLabel, getCollateralizationVisualPercent, getToneRatioThreshold, getVisualRatio } from '../lib/visualMetrics.js'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_COLLATERALIZATION_LABEL, UI_TEMPLATE_LABEL_VALUE, UI_TEMPLATE_VALUE_UNAVAILABLE } from '../lib/uiStrings.js'

const MAX_RING_COLLATERALIZATION_PERCENT = 999n * 10n ** 18n
const MAX_RING_COLLATERALIZATION_LABEL = '999%+'

export function CollateralizationCircle({ collateralizationPercent, className = '', label = TSX_STRINGS.componentsCollateralizationCircle.copy001, size = 'medium', successThreshold = 1, targetCollateralizationPercent, tone, warningThreshold = 0.65 }: CollateralizationCircleProps) {
export function CollateralizationCircle({ collateralizationPercent, className = '', label = UI_STRING_COLLATERALIZATION_LABEL, size = 'medium', successThreshold = 1, targetCollateralizationPercent, tone, warningThreshold = 0.65 }: CollateralizationCircleProps) {
const toneRatio = getVisualRatio({ value: collateralizationPercent, maxValue: targetCollateralizationPercent })
const resolvedTone =
tone ??
Expand All @@ -25,7 +25,7 @@ export function CollateralizationCircle({ collateralizationPercent, className =
const strokeDashoffset = circumference - circumference * (clampedCollateralizationVisualPercent / 100)
const displayValueFitsInRing = collateralizationPercent === undefined || collateralizationPercent <= MAX_RING_COLLATERALIZATION_PERCENT
const ringDisplayValue = displayValueFitsInRing ? displayValue : MAX_RING_COLLATERALIZATION_LABEL
const exactValueTitle = collateralizationPercent === undefined ? TSX_STRINGS.componentsCollateralizationCircle.copy002(label) : TSX_STRINGS.componentsCollateralizationCircle.copy003(label, displayValue)
const exactValueTitle = collateralizationPercent === undefined ? UI_TEMPLATE_VALUE_UNAVAILABLE(label) : UI_TEMPLATE_LABEL_VALUE(label, displayValue)

return (
<div className={['collateralization-gauge', `collateralization-gauge-size-${size}`, resolvedTone === undefined ? '' : `tone-${resolvedTone}`, className].filter(Boolean).join(' ').trim()} title={exactValueTitle}>
Expand Down
10 changes: 5 additions & 5 deletions ui/ts/components/CollateralizationMetricField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CurrencyValue } from './CurrencyValue.js'
import { MetricField } from './MetricField.js'
import { getRepPriceSourceCopy, renderRepPriceSourceLabel, type RepPriceSource } from '../lib/repPriceSource.js'
import { getCollateralizationDisplayState, getCollateralizationTone } from '../lib/trading.js'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_AWAITING_REP_ETH_PRICE, UI_STRING_COLLATERALIZATION_LABEL, UI_STRING_NO_ACTIVE_ALLOWANCE, UI_STRING_PERCENT } from '../lib/uiStrings.js'
type CollateralizationMetricFieldProps = {
className?: string | undefined
collateralizationPercent: bigint | undefined
Expand All @@ -18,12 +18,12 @@ function getDefaultLabel(repPerEthSource: RepPriceSource | undefined, repPerEthS
const repPriceSourceCopy = getRepPriceSourceCopy(repPerEthSource)
return (
<span title={repPriceSourceCopy.tooltip}>
{TSX_STRINGS.componentsCollateralizationMetricField.copy001}
{`${UI_STRING_COLLATERALIZATION_LABEL} `}
{renderRepPriceSourceLabel(repPerEthSource, repPerEthSourceUrl)}
</span>
)
}
export function CollateralizationMetricField({ className, collateralizationPercent, label, repPerEthSource, repPerEthSourceUrl, securityBondAllowance, securityMultiplier, unavailableCopy = TSX_STRINGS.componentsCollateralizationMetricField.copy002 }: CollateralizationMetricFieldProps) {
export function CollateralizationMetricField({ className, collateralizationPercent, label, repPerEthSource, repPerEthSourceUrl, securityBondAllowance, securityMultiplier, unavailableCopy = UI_STRING_AWAITING_REP_ETH_PRICE }: CollateralizationMetricFieldProps) {
const displayState = getCollateralizationDisplayState(securityBondAllowance, collateralizationPercent)
const tone = displayState === 'noActiveAllowance' ? undefined : getCollateralizationTone(collateralizationPercent, securityMultiplier)
const valueClassName = (() => {
Expand All @@ -35,10 +35,10 @@ export function CollateralizationMetricField({ className, collateralizationPerce
return (
<MetricField className={className} label={label ?? getDefaultLabel(repPerEthSource, repPerEthSourceUrl)} valueClassName={valueClassName}>
{(() => {
if (displayState === 'noActiveAllowance') return TSX_STRINGS.componentsCollateralizationMetricField.copy003
if (displayState === 'noActiveAllowance') return UI_STRING_NO_ACTIVE_ALLOWANCE
if (displayState === 'unavailable') return unavailableCopy

return <CurrencyValue value={collateralizationPercent} suffix={TSX_STRINGS.componentsCollateralizationMetricField.copy004} copyable={false} />
return <CurrencyValue value={collateralizationPercent} suffix={UI_STRING_PERCENT} copyable={false} />
})()}
</MetricField>
)
Expand Down
8 changes: 4 additions & 4 deletions ui/ts/components/CurrencyValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { LoadingText } from './LoadingText.js'
import { useCopyToClipboard } from '../hooks/useCopyToClipboard.js'
import { formatCompactCurrencyBalance, formatCurrencyBalance, formatRoundedCurrencyBalance } from '../lib/formatters.js'
import { getMetricPlaceholderPresentation } from '../lib/userCopy.js'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_COPIED, UI_STRING_LOADING_WITH_ELLIPSIS, UI_TEMPLATE_COPY_EXACT_CURRENCY_VALUE } from '../lib/uiStrings.js'

type CurrencyValueProps = {
className?: string
Expand Down Expand Up @@ -68,7 +68,7 @@ export function CurrencyValue({ className = '', compactWhenOverflow = false, cop
}
}, [compactWhenOverflow, copiedValue, displayValue, value])

if (loading) return <LoadingText className={`currency-value loading ${className}`}>{TSX_STRINGS.componentsCurrencyValue.copy001}</LoadingText>
if (loading) return <LoadingText className={`currency-value loading ${className}`}>{UI_STRING_LOADING_WITH_ELLIPSIS}</LoadingText>

if (value === undefined || exactValue === undefined || displayValue === undefined || compactDisplayValue === undefined) return <span className={`currency-value unavailable ${className}`}>{getMetricPlaceholderPresentation(value)?.placeholder}</span>

Expand All @@ -89,8 +89,8 @@ export function CurrencyValue({ className = '', compactWhenOverflow = false, cop

return (
<span className='currency-value-wrap'>
<button ref={buttonRef} type='button' className={valueClassName} title={exactTitle} aria-label={TSX_STRINGS.componentsCurrencyValue.copy002(exactValue)} onClick={() => copyText(exactValue)}>
{copiedValue ? TSX_STRINGS.componentsCurrencyValue.copy003 : resolvedDisplayValue}
<button ref={buttonRef} type='button' className={valueClassName} title={exactTitle} aria-label={UI_TEMPLATE_COPY_EXACT_CURRENCY_VALUE(exactValue)} onClick={() => copyText(exactValue)}>
{copiedValue ? UI_STRING_COPIED : resolvedDisplayValue}
</button>
<span ref={measureRef} aria-hidden='true' className={measureClassName} />
</span>
Expand Down
6 changes: 3 additions & 3 deletions ui/ts/components/EnumDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'preact/hooks'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_DROPDOWN_OPTIONS, UI_TEMPLATE_LABEL_VALUE } from '../lib/uiStrings.js'

export type EnumDropdownOption<T extends string> = {
label: string
Expand All @@ -20,7 +20,7 @@ export function EnumDropdown<T extends string>({ ariaLabel, disabled = false, on
const rootRef = useRef<HTMLDivElement | null>(null)
const selectedOption = value === undefined ? undefined : options.find(option => option.value === value)
const triggerLabel = selectedOption?.label ?? value ?? placeholder ?? ''
const accessibleTriggerLabel = ariaLabel === undefined || triggerLabel === '' ? ariaLabel : TSX_STRINGS.componentsEnumDropdown.copy001(ariaLabel, triggerLabel)
const accessibleTriggerLabel = ariaLabel === undefined || triggerLabel === '' ? ariaLabel : UI_TEMPLATE_LABEL_VALUE(ariaLabel, triggerLabel)

const focusMenuOptionAt = (currentTarget: HTMLButtonElement | null, direction: -1 | 1) => {
if (rootRef.current === null || currentTarget === null) return
Expand Down Expand Up @@ -81,7 +81,7 @@ export function EnumDropdown<T extends string>({ ariaLabel, disabled = false, on
<span className='enum-dropdown-chevron' aria-hidden='true' />
</button>
{open ? (
<div className='enum-dropdown-menu' role='listbox' aria-label={TSX_STRINGS.componentsEnumDropdown.copy002}>
<div className='enum-dropdown-menu' role='listbox' aria-label={UI_STRING_DROPDOWN_OPTIONS}>
{options.map(option => (
<button
key={option.value}
Expand Down
4 changes: 2 additions & 2 deletions ui/ts/components/ErrorNotice.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'preact/hooks'
import { isCloseableErrorMessage } from '../lib/errors.js'
import { TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_DISMISS_ERROR } from '../lib/uiStrings.js'

type ErrorNoticeProps = {
message: string | undefined
Expand All @@ -20,7 +20,7 @@ export function ErrorNotice({ message }: ErrorNoticeProps) {
return (
<div className={`notice error${isCloseable ? ' closeable' : ''}`} role='alert' aria-live='assertive' aria-atomic='true'>
{isCloseable ? (
<button type='button' className='notice-dismiss' aria-label={TSX_STRINGS.componentsErrorNotice.copy001} onClick={() => setDismissed(true)}>
<button type='button' className='notice-dismiss' aria-label={UI_STRING_DISMISS_ERROR} onClick={() => setDismissed(true)}>
<span className='notice-dismiss-icon' aria-hidden='true' />
</button>
) : undefined}
Expand Down
10 changes: 5 additions & 5 deletions ui/ts/components/EscalationDepositSelectionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from 'preact/hooks'
import { formatPaginationSummary, getHasNextPaginationPage, getPaginationPageCount, resolvePaginationPageIndex } from '../lib/pagination.js'
import type { EscalationDeposit } from '../types/contracts.js'
import { PaginationControls } from './PaginationControls.js'
import { CURATED_TSX_STRINGS, TSX_STRINGS } from '../lib/uiStrings.js'
import { UI_STRING_DEPOSIT_NUMBER, UI_STRING_NEXT_DEPOSITS, UI_STRING_PREVIOUS_DEPOSITS, UI_TEMPLATE_ESCALATION_DEPOSIT_PAGE_SUMMARY } from '../lib/uiStrings.js'

const ESCALATION_DEPOSIT_SELECTION_PAGE_SIZE = 25

Expand All @@ -29,7 +29,7 @@ export function EscalationDepositSelectionList({ disabled = false, items, onSele
const pageEndIndex = Math.min(items.length, pageStartIndex + ESCALATION_DEPOSIT_SELECTION_PAGE_SIZE)
const visibleItems = useMemo(() => items.slice(pageStartIndex, pageEndIndex), [items, pageEndIndex, pageStartIndex])
const paginationPageSummary = formatPaginationSummary(resolvedPageIndex, pageCount)
const paginationSummary = items.length > ESCALATION_DEPOSIT_SELECTION_PAGE_SIZE && paginationPageSummary !== undefined ? CURATED_TSX_STRINGS.escalationDepositSelectionList.paginationSummary((pageStartIndex + 1).toString(), pageEndIndex.toString(), items.length.toString(), paginationPageSummary) : undefined
const paginationSummary = items.length > ESCALATION_DEPOSIT_SELECTION_PAGE_SIZE && paginationPageSummary !== undefined ? UI_TEMPLATE_ESCALATION_DEPOSIT_PAGE_SUMMARY((pageStartIndex + 1).toString(), pageEndIndex.toString(), items.length.toString(), paginationPageSummary) : undefined

useEffect(() => {
if (resolvedPageIndex !== pageIndex) setPageIndex(resolvedPageIndex)
Expand All @@ -55,7 +55,7 @@ export function EscalationDepositSelectionList({ disabled = false, items, onSele
/>
<span className='withdraw-deposit-copy'>
<strong>
{TSX_STRINGS.componentsEscalationDepositSelectionList.copy001}
{UI_STRING_DEPOSIT_NUMBER}
{deposit.depositIndex.toString()}
</strong>
{details.map((detail, detailIndex) => (
Expand All @@ -70,10 +70,10 @@ export function EscalationDepositSelectionList({ disabled = false, items, onSele
<PaginationControls
hasNextPage={hasNextPage}
hasPreviousPage={hasPreviousPage}
nextLabel={TSX_STRINGS.componentsEscalationDepositSelectionList.copy002}
nextLabel={UI_STRING_NEXT_DEPOSITS}
onNextPage={() => setPageIndex(currentPageIndex => currentPageIndex + 1)}
onPreviousPage={() => setPageIndex(currentPageIndex => Math.max(0, currentPageIndex - 1))}
previousLabel={TSX_STRINGS.componentsEscalationDepositSelectionList.copy003}
previousLabel={UI_STRING_PREVIOUS_DEPOSITS}
summary={paginationSummary}
/>
)}
Expand Down
Loading