Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b7b25a5
remove ionic/normalize and ion-button
bordalix Apr 16, 2026
16c3b74
rebbit fixes
bordalix Apr 16, 2026
67e93cd
feat(wallet): prefix fiat amounts with currency symbols (#535)
sahilc0 Apr 16, 2026
5c5e348
Upgrade ts-sdk 0.4.16 - boltz-swap 0.3.17 (#539)
pietro909 Apr 17, 2026
d6576c3
reverse logs in csv export (#546)
bordalix Apr 20, 2026
2f868e2
Extra tests (#548)
bordalix Apr 21, 2026
e62d84c
Prevent swap after receival (#547)
bordalix Apr 21, 2026
2aa8a22
more removals
bordalix Apr 21, 2026
6a4b1a3
increase viewport size in tests
bordalix Apr 21, 2026
4397770
more removals
bordalix Apr 22, 2026
13586bf
more removals
bordalix Apr 22, 2026
b9080e0
fixes
bordalix Apr 22, 2026
3fe7ebd
fixes
bordalix Apr 22, 2026
a455ca6
fixes
bordalix Apr 22, 2026
96cb933
fix
bordalix Apr 22, 2026
66d6671
remove ion-refresher
bordalix Apr 22, 2026
d6dbe75
Merge branch 'master' into remove_ion-button
bordalix Apr 22, 2026
34ae4d8
fix swap page (#549)
bordalix Apr 21, 2026
dcc4f62
Upgrade ts-sdk 0.4.17 - boltz-swap 0.3.18 (#551)
pietro909 Apr 21, 2026
e90e359
fix(receive): add spacing between button row and share button (#552)
sahilc0 Apr 21, 2026
56e0042
Revert "Upgrade ts-sdk 0.4.17 - boltz-swap 0.3.18 (#551)" (#553)
pietro909 Apr 21, 2026
f2450f7
Upgrade ts-sdk 0.4.17 - boltz-swap 0.3.18 (#551)
pietro909 Apr 21, 2026
55f07ba
Revert "Upgrade ts-sdk 0.4.17 - boltz-swap 0.3.18 (#551)" (#553)
pietro909 Apr 21, 2026
c798415
Upgrade ts-sdk 0.4.18 - boltz-swap 0.3.19 (#554)
pietro909 Apr 22, 2026
7b54f2a
Merge branch 'master' into remove_ion-button
bordalix Apr 23, 2026
a6cd1df
add git commit to chatwoot custom attributes (#563)
bordalix Apr 23, 2026
beb17ba
add lnurl tests (#564)
bordalix Apr 23, 2026
e4ffc92
fix(ui): top-align tx history rows when assets are present (#537)
Kukks Apr 23, 2026
4e86272
final removal
bordalix Apr 23, 2026
b653435
Upgrade ts-sdk 0.4.19 - boltz-swap 0.3.20 (#565)
pietro909 Apr 23, 2026
c8859db
merge master
bordalix Apr 23, 2026
ff38ef8
lint
bordalix Apr 23, 2026
708d25b
fix box-sizing
bordalix Apr 24, 2026
70802f1
.label styles
bordalix Apr 27, 2026
d0f67ef
fix branta lint error (#568)
bordalix Apr 27, 2026
66ebe14
works on refresher
bordalix Apr 27, 2026
6438ce8
fix unit tests
bordalix Apr 27, 2026
a0f9eec
remove ionic/react
bordalix Apr 27, 2026
4b5e685
fix label alignment
bordalix Apr 27, 2026
973232d
DRY: AssetCard
bordalix Apr 27, 2026
9c0f4df
fix inputAmount
bordalix Apr 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"private": true,
"homepage": ".",
"dependencies": {
"@arkade-os/boltz-swap": "0.3.16",
"@arkade-os/sdk": "0.4.15",
"@arkade-os/boltz-swap": "0.3.17",
"@arkade-os/sdk": "0.4.16",
"@branta-ops/branta": "0.0.9",
"@ionic/react": "^8.5.6",
"@lendasat/lendasat-wallet-bridge": "^0.0.90",
Expand Down
2 changes: 1 addition & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default defineConfig({
},
{
name: 'Google Chrome',
use: { ...devices['Desktop Chrome'], channel: 'chrome' },
use: { ...devices['Desktop Chrome'], channel: 'chrome', viewport: { width: 1920, height: 1080 } },
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Inspect Playwright viewport coverage and viewport-dependent tests.
# Expected: Either a desktop project remains at 1280x800, or tests explicitly cover that size.

rg -n -C3 'viewport|setViewportSize|innerWidth|1280|800|1920|1080' playwright.config.ts src/test/e2e

Repository: arkade-os/wallet

Length of output: 2973


🏁 Script executed:

cat -n playwright.config.ts

Repository: arkade-os/wallet

Length of output: 1252


Restore baseline desktop viewport coverage.

Line 32 overrides the global 1280x800 desktop viewport to 1920x1080 for the only desktop project, removing test coverage at the baseline width. Since the PR refactors button styling and navbar typography with regressions already reported, this masks exactly the kind of CSS issues that break at narrower desktop widths. Preserve the baseline project and add a separate large-desktop variant if needed.

Suggested adjustment
   {
     name: 'Google Chrome',
-    use: { ...devices['Desktop Chrome'], channel: 'chrome', viewport: { width: 1920, height: 1080 } },
+    use: { ...devices['Desktop Chrome'], channel: 'chrome' },
+  },
+  {
+    name: 'Google Chrome Large',
+    use: { ...devices['Desktop Chrome'], channel: 'chrome', viewport: { width: 1920, height: 1080 } },
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
use: { ...devices['Desktop Chrome'], channel: 'chrome', viewport: { width: 1920, height: 1080 } },
{
name: 'Google Chrome',
use: { ...devices['Desktop Chrome'], channel: 'chrome' },
},
{
name: 'Google Chrome Large',
use: { ...devices['Desktop Chrome'], channel: 'chrome', viewport: { width: 1920, height: 1080 } },
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playwright.config.ts` at line 32, The current desktop project overrides the
baseline viewport by setting use: { ...devices['Desktop Chrome'], channel:
'chrome', viewport: { width: 1920, height: 1080 } }, which hides regressions at
the intended baseline size; restore that project's viewport to the baseline
1280x800 (keep the same project and its use object referencing devices['Desktop
Chrome']) and add a new separate project (e.g., name it "Desktop Chrome Large")
that copies the same use settings but sets viewport: { width: 1920, height: 1080
} so you preserve baseline coverage while still testing a large-desktop variant.

},
],
})
22 changes: 11 additions & 11 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

158 changes: 9 additions & 149 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@ionic/react/css/core.css'
/* Basic CSS for apps built with Ionic */
import '@ionic/react/css/normalize.css'
// import '@ionic/react/css/normalize.css'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
import '@ionic/react/css/structure.css'
import '@ionic/react/css/typography.css'

Expand All @@ -16,7 +16,7 @@ import '@ionic/react/css/palettes/dark.class.css'

import { AnimatePresence } from 'framer-motion'
import { ConfigContext } from './providers/config'
import { IonApp, IonPage, IonTab, IonTabBar, IonTabButton, IonTabs, setupIonicReact } from '@ionic/react'
import { IonApp, IonPage, setupIonicReact } from '@ionic/react'
import { NavigationContext, pageComponent, Pages, Tabs, type NavigationDirection } from './providers/navigation'
import { useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
import { isInAppBrowser } from './lib/browser'
Expand All @@ -29,14 +29,9 @@ import { AspContext } from './providers/asp'
import { hapticLight } from './lib/haptics'
import { setBootAnimActive as syncBootAnimFlag } from './lib/logoAnchor'
import { PageTransition } from './components/PageTransition'
import SettingsIcon from './icons/Settings'
import BootError from './components/BootError'
import LoadingLogo from './components/LoadingLogo'
import PillNavbarOverlay from './components/PillNavbarOverlay'
import FlexCol from './components/FlexCol'
import WalletIcon from './icons/Wallet'
import AppsIcon from './icons/Apps'
import Focusable from './components/Focusable'
import { useReducedMotion } from './hooks/useReducedMotion'
import { useLoadingStatus } from './hooks/useLoadingStatus'
import { defaultPassword } from './lib/constants'
Expand Down Expand Up @@ -66,29 +61,6 @@ function PageAnimWrapper({
)
}

const animClass = 'tab-anim-pop'

function AnimatedTabIcon({ children, animating }: { children: React.ReactNode; animating: boolean }) {
const ref = useRef<HTMLDivElement>(null)

useEffect(() => {
if (!animating || !ref.current) return
const el = ref.current
el.classList.remove(animClass)
void el.offsetWidth // Force reflow so removing + re-adding the class triggers the animation
el.classList.add(animClass)
const handleEnd = () => el.classList.remove(animClass)
el.addEventListener('animationend', handleEnd)
return () => el.removeEventListener('animationend', handleEnd)
}, [animating])

return (
<div ref={ref} className='tab-icon-animated'>
{children}
</div>
)
}

export default function App() {
const { aspInfo } = useContext(AspContext)
const { configLoaded } = useContext(ConfigContext)
Expand All @@ -101,7 +73,6 @@ export default function App() {
const isIAB = useMemo(() => isInAppBrowser(), [])
const [isCapable, setIsCapable] = useState(false)
const [jsCapabilitiesChecked, setJsCapabilitiesChecked] = useState(false)
const [animatingTab, setAnimatingTab] = useState<string | null>(null)
const [bootAnimActive, setBootAnimActive] = useState(false)
// Syncs the external store before React re-renders, so Wallet reads
// the correct value on the same frame LoadingLogo unmounts.
Expand All @@ -112,10 +83,6 @@ export default function App() {
const [bootAnimDone, setBootAnimDone] = useState(false)
const [bootExitMode, setBootExitMode] = useState<'fly-to-target' | 'fly-up'>('fly-up')

// refs for the tabs to be able to programmatically activate them
const appsRef = useRef<HTMLIonTabElement>(null)
const walletRef = useRef<HTMLIonTabElement>(null)
const settingsRef = useRef<HTMLIonTabElement>(null)
const passwordlessBootAttempted = useRef(false)
const passwordlessReloadTimer = useRef<ReturnType<typeof setTimeout>>()

Expand Down Expand Up @@ -158,52 +125,17 @@ export default function App() {
if (authState === 'locked') return navigate(Pages.Unlock)
}, [walletLoaded, wallet.pubkey, authState, initInfo, aspInfo.unreachable, jsCapabilitiesChecked, isCapable])

// for some reason you need to manually set the active tab
// if you are coming from a page in a different tab
useEffect(() => {
switch (tab) {
case Tabs.Wallet:
walletRef.current?.setActive()
walletRef.current?.classList.remove('tab-hidden')
appsRef.current?.classList.add('tab-hidden')
settingsRef.current?.classList.add('tab-hidden')
break
case Tabs.Apps:
appsRef.current?.setActive()
appsRef.current?.classList.remove('tab-hidden')
walletRef.current?.classList.add('tab-hidden')
settingsRef.current?.classList.add('tab-hidden')
break
case Tabs.Settings:
settingsRef.current?.setActive()
settingsRef.current?.classList.remove('tab-hidden')
walletRef.current?.classList.add('tab-hidden')
appsRef.current?.classList.add('tab-hidden')
break
default:
break
}
}, [tab])

const triggerTabAnim = useCallback((tabName: string) => {
setAnimatingTab(null)
requestAnimationFrame(() => setAnimatingTab(tabName))
}, [])

const handleWallet = () => {
triggerTabAnim('wallet')
hapticLight()
navigate(Pages.Wallet)
}

const handleApps = () => {
triggerTabAnim('apps')
hapticLight()
navigate(Pages.Apps)
}

const handleSettings = () => {
triggerTabAnim('settings')
hapticLight()
setOption(SettingsOptions.Menu)
navigate(Pages.Settings)
Expand Down Expand Up @@ -301,85 +233,13 @@ export default function App() {
return (
<IonApp className={showNavbar ? 'has-pill-navbar' : undefined}>
<IonPage>
{tab === Tabs.None ? (
<div className='page-transition-container'>
<PageAnimWrapper animated={!prefersReduced} direction={effectiveDirection}>
<PageTransition key={String(page)} direction={direction} pageKey={String(page)}>
{comp}
</PageTransition>
</PageAnimWrapper>
</div>
) : (
<>
<IonTabs>
<IonTab ref={walletRef} tab={Tabs.Wallet}>
<div className='page-transition-container'>
<PageAnimWrapper animated={!prefersReduced} direction={effectiveDirection}>
{tab === Tabs.Wallet && (
<PageTransition key={String(page)} direction={direction} pageKey={String(page)}>
{comp}
</PageTransition>
)}
</PageAnimWrapper>
</div>
</IonTab>
<IonTab ref={appsRef} tab={Tabs.Apps}>
<div className='page-transition-container'>
<PageAnimWrapper animated={!prefersReduced} direction={effectiveDirection}>
{tab === Tabs.Apps && (
<PageTransition key={String(page)} direction={direction} pageKey={String(page)}>
{comp}
</PageTransition>
)}
</PageAnimWrapper>
</div>
</IonTab>
<IonTab ref={settingsRef} tab={Tabs.Settings}>
<div className='page-transition-container'>
<PageAnimWrapper animated={!prefersReduced} direction={effectiveDirection}>
{tab === Tabs.Settings && (
<PageTransition key={String(page)} direction={direction} pageKey={String(page)}>
{comp}
</PageTransition>
)}
</PageAnimWrapper>
</div>
</IonTab>
<IonTabBar slot='bottom'>
<IonTabButton tab={Tabs.Wallet} onClick={handleWallet} selected={tab === Tabs.Wallet}>
<Focusable>
<FlexCol centered gap='6px' padding='5px'>
<AnimatedTabIcon animating={animatingTab === 'wallet'}>
<WalletIcon />
</AnimatedTabIcon>
Wallet
</FlexCol>
</Focusable>
</IonTabButton>
<IonTabButton tab={Tabs.Apps} onClick={handleApps} selected={tab === Tabs.Apps}>
<Focusable>
<FlexCol centered gap='6px' padding='5px'>
<AnimatedTabIcon animating={animatingTab === 'apps'}>
<AppsIcon />
</AnimatedTabIcon>
Apps
</FlexCol>
</Focusable>
</IonTabButton>
<IonTabButton tab={Tabs.Settings} onClick={handleSettings} selected={tab === Tabs.Settings}>
<Focusable>
<FlexCol centered gap='6px' padding='5px'>
<AnimatedTabIcon animating={animatingTab === 'settings'}>
<SettingsIcon />
</AnimatedTabIcon>
Settings
</FlexCol>
</Focusable>
</IonTabButton>
</IonTabBar>
</IonTabs>
</>
)}
<div className='page-transition-container' style={{ width: '640px' }}>
<PageAnimWrapper animated={!prefersReduced} direction={effectiveDirection}>
<PageTransition key={String(page)} direction={direction} pageKey={String(page)}>
{comp}
</PageTransition>
</PageAnimWrapper>
</div>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
</IonPage>
{tab !== Tabs.None && !bootAnimActive && (
<PillNavbarOverlay
Expand Down
13 changes: 9 additions & 4 deletions src/components/Balance.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useContext } from 'react'
import { prettyHide, prettyNumber } from '../lib/format'
import { FIAT_SYMBOLS } from '../lib/fiat'
import { CurrencyDisplay, Satoshis } from '../lib/types'
import { FiatContext } from '../providers/fiat'
import Text from './Text'
Expand All @@ -18,17 +19,21 @@ export default function Balance({ amount }: BalanceProps) {

const fiatAmount = toFiat(amount)
const showFiat = config.currencyDisplay === CurrencyDisplay.Fiat
const fiatSymbol = FIAT_SYMBOLS[config.fiat]

const satsBalance = config.showBalance ? prettyNumber(amount) : prettyHide(amount, '')
const fiatBalance = config.showBalance
const fiatBalanceRaw = config.showBalance
? prettyNumber(fiatAmount, fiatDecimals(), true, fiatDecimals())
: prettyHide(fiatAmount, '')
// prettyHide returns '' for a zero balance; skip the symbol prefix to avoid a lone "$".
const fiatBalance = fiatSymbol && fiatBalanceRaw ? `${fiatSymbol}${fiatBalanceRaw}` : fiatBalanceRaw
const fiatUnit = fiatSymbol ? '' : config.fiat

const mainBalance = showFiat ? fiatBalance : satsBalance
const otherBalance = showFiat ? satsBalance : fiatBalance
const satsUnit = amount === 1 ? 'SAT' : 'SATS'
const mainUnit = showFiat ? config.fiat : satsUnit
const otherUnit = showFiat ? satsUnit : config.fiat
const mainUnit = showFiat ? fiatUnit : satsUnit
const otherUnit = showFiat ? satsUnit : fiatUnit

const showBoth = config.currencyDisplay === CurrencyDisplay.Both
const toggleShow = () => updateConfig({ ...config, showBalance: !config.showBalance })
Expand All @@ -40,7 +45,7 @@ export default function Balance({ amount }: BalanceProps) {
{mainBalance}
</Text>
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
<Text heading>{mainUnit}</Text>
{mainUnit ? <Text heading>{mainUnit}</Text> : null}
<button
type='button'
onClick={toggleShow}
Expand Down
9 changes: 5 additions & 4 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { IonButton } from '@ionic/react'
import { ReactElement, ReactNode, useCallback, useState } from 'react'
import FlexRow from './FlexRow'
import ArrowIcon from '../icons/Arrow'
Expand All @@ -20,6 +19,7 @@ interface ButtonProps {
outline?: boolean
red?: boolean
secondary?: boolean
testId?: string
}

export default function Button({
Expand All @@ -35,6 +35,7 @@ export default function Button({
outline,
red,
secondary,
testId,
}: ButtonProps) {
const [pressed, setPressed] = useState(false)

Expand All @@ -59,13 +60,13 @@ export default function Button({
)

return (
<IonButton
<button
className={className}
disabled={disabled}
fill={clear ? 'clear' : outline ? 'outline' : 'solid'}
onClick={handleClick}
onMouseDown={handlePressStart}
onMouseUp={handlePressEnd}
data-testid={testId}
onMouseLeave={handlePressEnd}
onTouchStart={handlePressStart}
onTouchEnd={handlePressEnd}
Expand All @@ -90,7 +91,7 @@ export default function Button({
{children ?? (label ? <Label label={label} /> : null)}
</FlexRow>
)}
</IonButton>
</button>
)
}

Expand Down
Loading