Skip to content

Commit 89afbe8

Browse files
committed
Abstracted accordion out of token balance elements
1 parent a0f6625 commit 89afbe8

2 files changed

Lines changed: 166 additions & 138 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<script lang="ts">
2+
import { cn } from '$lib/utils/style';
3+
import { ChevronRight } from 'lucide-svelte';
4+
import { type Snippet } from 'svelte';
5+
6+
interface AccordionProps {
7+
class?: string;
8+
open?: boolean;
9+
header: () => ReturnType<Snippet>;
10+
children: Snippet;
11+
}
12+
13+
let {
14+
class: className = 'break-after-avoid',
15+
open = $bindable(false),
16+
header,
17+
children
18+
}: AccordionProps = $props();
19+
20+
let detailsElement = $state<HTMLDetailsElement>();
21+
22+
const syncOpen = () => {
23+
if (!detailsElement) return;
24+
if (detailsElement.open) {
25+
open = true;
26+
} else {
27+
open = false;
28+
}
29+
};
30+
</script>
31+
32+
<details
33+
bind:this={detailsElement}
34+
class={cn('group bg-surface-container rounded-xl', className)}
35+
{open}
36+
>
37+
<summary
38+
class="focus-visible:outline-solar-500 @container flex cursor-pointer justify-between gap-4 rounded-xl p-5 select-none focus-visible:outline"
39+
onclick={syncOpen}
40+
>
41+
<div class="text-muted flex flex-1 flex-wrap justify-between gap-y-4 text-nowrap">
42+
{@render header()}
43+
</div>
44+
45+
<ChevronRight class="text-muted transition-transform duration-100 group-open:rotate-90" />
46+
</summary>
47+
48+
<div class="bg-surface-container-low grid grid-cols-[auto_1fr_auto] rounded-b-xl p-5 pt-3">
49+
{@render children()}
50+
</div>
51+
</details>
Lines changed: 115 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<script lang="ts">
2-
import AssetText from '$lib/components/elements/asset.svelte';
32
import { Asset } from '@wharfkit/antelope';
3+
import { getContext } from 'svelte';
4+
import { Info } from 'lucide-svelte';
5+
6+
import AssetText from '$lib/components/elements/asset.svelte';
47
import TradingPair from '$lib/components/elements/tradingpair.svelte';
5-
import { cn } from '$lib/utils/style';
68
import type { NetworkState } from '$lib/state/network.svelte';
79
import {
810
TokenBalance,
@@ -11,13 +13,12 @@
1113
ZeroUnits,
1214
type TokenPair
1315
} from '$lib/types/token';
14-
import { ChevronRight, Info } from 'lucide-svelte';
1516
import * as m from '$lib/paraglide/messages';
16-
import Button from '../button/button.svelte';
17-
import { getContext } from 'svelte';
17+
import Button from '$lib/components/button/button.svelte';
1818
import type { UnicoveContext } from '$lib/state/client.svelte';
19-
import Code from '../code.svelte';
20-
import Link from '../elements/link.svelte';
19+
import Code from '$lib/components/code.svelte';
20+
import Link from '$lib/components/elements/link.svelte';
21+
import Accordion from '$lib/components/accordion.svelte';
2122
2223
const context = getContext<UnicoveContext>('state');
2324
@@ -67,17 +68,6 @@
6768
const balanceDelegated = $derived(_balance.child('delegated'));
6869
const balanceUsed = $derived(_balance.child('used'));
6970
const balanceWRAM = $derived(_balance.child('wram'));
70-
71-
let detailsElement = $state<HTMLDetailsElement>();
72-
73-
const syncOpen = () => {
74-
if (!detailsElement) return;
75-
if (detailsElement.open) {
76-
open = true;
77-
} else {
78-
open = false;
79-
}
80-
};
8171
</script>
8272

8373
{#snippet SubBalance(label: string, value: Asset, action?: { text: string; href: string })}
@@ -98,140 +88,127 @@
9888
</div>
9989
{/snippet}
10090

101-
<details
102-
bind:this={detailsElement}
103-
class={cn('group token-balance-card bg-surface-container rounded-xl', className)}
104-
open={open && _balance instanceof TokenBalance}
105-
>
106-
<summary
107-
class="focus-visible:outline-solar-500 @container flex cursor-pointer justify-between gap-4 rounded-xl p-5 select-none focus-visible:outline"
108-
onclick={syncOpen}
109-
>
110-
<div class="text-muted flex flex-1 flex-wrap justify-between gap-y-4 text-nowrap">
111-
<!-- Left -->
112-
<div class="left flex flex-col justify-center gap-2">
113-
<h4
114-
class="text-on-surface inline-flex items-center gap-2 text-xl leading-none font-bold capitalize"
91+
{#snippet AccordionHeader()}
92+
<!-- Left -->
93+
<div class="left flex flex-col justify-center gap-2">
94+
<h4
95+
class="text-on-surface inline-flex items-center gap-2 text-xl leading-none font-bold capitalize"
96+
>
97+
<img
98+
class="size-6 object-contain"
99+
alt="{_balance.token.name} Logo"
100+
src={_balance.token.media?.logo?.light}
101+
/>
102+
{#if isRamToken}
103+
<Link class="text-on-surface" href="/{network}/ram">
104+
{balance.token.name} (RAM)
105+
</Link>
106+
{:else}
107+
<Link
108+
class="text-on-surface"
109+
href="/{network}/token/{balance.token.contract}/{balance.token.name}"
115110
>
116-
<img
117-
class="size-6 object-contain"
118-
alt="{_balance.token.name} Logo"
119-
src={_balance.token.media?.logo?.light}
120-
/>
121-
{#if isRamToken}
122-
<Link class="text-on-surface" href="/{network}/ram">
123-
{balance.token.name} (RAM)
124-
</Link>
125-
{:else}
126-
<Link
127-
class="text-on-surface"
128-
href="/{network}/token/{balance.token.contract}/{balance.token.name}"
129-
>
130-
{balance.token.name}
131-
<Info class="text-muted size-5" />
132-
</Link>
133-
{/if}
134-
</h4>
135-
136-
{#if pair && hasValue}
137-
{#if pair.price.units.gt(ZeroUnits)}
138-
<TradingPair class="leading-none" {historic} {historicTimeframe} value={pair} />
139-
{:else}
140-
<div class="bg-surface-container-high h-4 w-32 animate-pulse rounded">&nbsp;</div>
141-
{/if}
142-
{/if}
143-
</div>
144-
145-
<!-- Right -->
146-
<div class="right text-muted flex flex-col justify-between gap-2">
147-
<div class="h-6 w-full content-center">
148-
<h4 class="text-on-surface text-right text-xl leading-none font-bold capitalize">
149-
<AssetText value={balance.balance} />
150-
</h4>
151-
</div>
152-
153-
{#if pair && hasValue}
154-
{#if value.units.gt(ZeroUnits)}
155-
<AssetText class="leading-none" variant="full" {value} />
156-
{:else}
157-
<div class="bg-surface-container-high max-w-48 animate-pulse rounded-md">&nbsp;</div>
158-
{/if}
159-
{/if}
160-
</div>
161-
</div>
162-
163-
<ChevronRight class="text-muted transition-transform duration-100 group-open:rotate-90" />
164-
</summary>
165-
166-
<div class="bg-surface-container-low grid grid-cols-[auto_1fr_auto] rounded-b-xl p-5 pt-3">
167-
{@render SubBalance(
168-
m.common_available(),
169-
_balance.balance,
170-
!_balance.locked
171-
? {
172-
text: m.common_send(),
173-
href: `/${network}/send/${balance.token.id.url}`
174-
}
175-
: undefined
176-
)}
177-
178-
{#if tokenEquals(balance.token.id, network.token.id)}
179-
{#if network.supports('staking') && balanceStaked}
180-
{@render SubBalance(m.common_staked(), balanceStaked.balance, {
181-
text: m.common_staking(),
182-
href: `/${network}/staking`
183-
})}
111+
{balance.token.name}
112+
<Info class="text-muted size-5" />
113+
</Link>
184114
{/if}
115+
</h4>
185116

186-
{#if balanceUnstaked && balanceUnstaked.balance.value > 0}
187-
{@render SubBalance(m.common_unstaked(), balanceUnstaked.balance, {
188-
text: m.common_withdraw(),
189-
href: `/${network}/staking/withdraw`
190-
})}
117+
{#if pair && hasValue}
118+
{#if pair.price.units.gt(ZeroUnits)}
119+
<TradingPair class="leading-none" {historic} {historicTimeframe} value={pair} />
120+
{:else}
121+
<div class="bg-surface-container-high h-4 w-32 animate-pulse rounded">&nbsp;</div>
191122
{/if}
123+
{/if}
124+
</div>
192125

193-
{#if balanceDelegated && balanceDelegated.balance.value > 0}
194-
{@render SubBalance(m.common_delegated(), balanceDelegated.balance, {
195-
text: m.common_reclaim(),
196-
href: `/${network}/undelegate`
197-
})}
198-
{/if}
126+
<!-- Right -->
127+
<div class="right text-muted flex flex-col justify-between gap-2">
128+
<div class="h-6 w-full content-center">
129+
<h4 class="text-on-surface text-right text-xl leading-none font-bold capitalize">
130+
<AssetText value={balance.balance} />
131+
</h4>
132+
</div>
199133

200-
{#if balanceRefunding && balanceRefunding.balance.value > 0}
201-
{@render SubBalance(m.common_refunding(), balanceRefunding.balance, {
202-
text: m.common_claim(),
203-
href: `/${network}/refund`
204-
})}
134+
{#if pair && hasValue}
135+
{#if value.units.gt(ZeroUnits)}
136+
<AssetText class="leading-none" variant="full" {value} />
137+
{:else}
138+
<div class="bg-surface-container-high max-w-48 animate-pulse rounded-md">&nbsp;</div>
205139
{/if}
206140
{/if}
141+
</div>
142+
{/snippet}
207143

208-
{#if balanceUsed && balanceUsed.balance.value > 0}
209-
{@render SubBalance(m.common_used(), balanceUsed.balance)}
144+
<Accordion class={className} header={AccordionHeader} {open}>
145+
{@render SubBalance(
146+
m.common_available(),
147+
_balance.balance,
148+
!_balance.locked
149+
? {
150+
text: m.common_send(),
151+
href: `/${network}/send/${balance.token.id.url}`
152+
}
153+
: undefined
154+
)}
155+
156+
{#if tokenEquals(balance.token.id, network.token.id)}
157+
{#if network.supports('staking') && balanceStaked}
158+
{@render SubBalance(m.common_staked(), balanceStaked.balance, {
159+
text: m.common_staking(),
160+
href: `/${network}/staking`
161+
})}
210162
{/if}
211163

212-
{#if isRamToken && balanceWRAM}
213-
{@render SubBalance('WRAM', balanceWRAM.balance, {
214-
text: m.common_swap(),
215-
href: `/${network}/swap/${balanceWRAM.token.id.url}/${network.getRamToken().id.url}`
164+
{#if balanceUnstaked && balanceUnstaked.balance.value > 0}
165+
{@render SubBalance(m.common_unstaked(), balanceUnstaked.balance, {
166+
text: m.common_withdraw(),
167+
href: `/${network}/staking/withdraw`
216168
})}
217169
{/if}
218170

219-
{#if cta && cta.length}
220-
<div class="col-span-full flex gap-6">
221-
{#each cta as action}
222-
<Button
223-
class="mt-4 {action.visible ? '' : 'hidden'}"
224-
variant={action.variant || 'secondary'}
225-
href={action.href}
226-
>
227-
{action.text}
228-
</Button>
229-
{/each}
230-
</div>
171+
{#if balanceDelegated && balanceDelegated.balance.value > 0}
172+
{@render SubBalance(m.common_delegated(), balanceDelegated.balance, {
173+
text: m.common_reclaim(),
174+
href: `/${network}/undelegate`
175+
})}
231176
{/if}
232-
</div>
233177

234-
{#if debug}
235-
<Code json={_balance} />
178+
{#if balanceRefunding && balanceRefunding.balance.value > 0}
179+
{@render SubBalance(m.common_refunding(), balanceRefunding.balance, {
180+
text: m.common_claim(),
181+
href: `/${network}/refund`
182+
})}
183+
{/if}
184+
{/if}
185+
186+
{#if balanceUsed && balanceUsed.balance.value > 0}
187+
{@render SubBalance(m.common_used(), balanceUsed.balance)}
188+
{/if}
189+
190+
{#if isRamToken && balanceWRAM}
191+
{@render SubBalance('WRAM', balanceWRAM.balance, {
192+
text: m.common_swap(),
193+
href: `/${network}/swap/${balanceWRAM.token.id.url}/${network.getRamToken().id.url}`
194+
})}
236195
{/if}
237-
</details>
196+
197+
{#if cta && cta.length}
198+
<div class="col-span-full flex gap-6">
199+
{#each cta as action}
200+
<Button
201+
class="mt-4 {action.visible ? '' : 'hidden'}"
202+
variant={action.variant || 'secondary'}
203+
href={action.href}
204+
>
205+
{action.text}
206+
</Button>
207+
{/each}
208+
</div>
209+
{/if}
210+
</Accordion>
211+
212+
{#if debug}
213+
<Code json={_balance} />
214+
{/if}

0 commit comments

Comments
 (0)