From 3913889a2224d0ac9221c497961a51bd1b74c9cc Mon Sep 17 00:00:00 2001 From: TZGyn Date: Tue, 4 Aug 2026 22:19:13 +0800 Subject: [PATCH] add portfolio allocation donut chart on dashboard --- apps/desktop/src/routes/index.svelte | 91 ++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/apps/desktop/src/routes/index.svelte b/apps/desktop/src/routes/index.svelte index 90aba9c..b24aae2 100644 --- a/apps/desktop/src/routes/index.svelte +++ b/apps/desktop/src/routes/index.svelte @@ -15,6 +15,9 @@ import WalletIcon from '@lucide/svelte/icons/wallet' import Loader from '$lib/components/loader.svelte' import { frontendLog, frontendLogError } from '$lib/electrobun.js' + import { arc } from 'd3-shape' + import { tweened } from 'svelte/motion' + import { cubicOut } from 'svelte/easing' let feError = $state(null) @@ -43,6 +46,33 @@ const portfolioUsd = $derived(xrpTotalUsd + xmrTotalUsd) + const xrpShare = $derived(portfolioUsd > 0 ? xrpTotalUsd / portfolioUsd : 0) + const xmrShare = $derived( + portfolioUsd > 0 ? xmrTotalUsd / portfolioUsd : 0, + ) + + const tweenedUsd = tweened(0, { duration: 600, easing: cubicOut }) + const tweenedXrpShare = tweened(0, { duration: 600, easing: cubicOut }) + + $effect(() => { + tweenedUsd.set(portfolioUsd) + tweenedXrpShare.set(xrpShare) + }) + + const donut = $derived.by(() => { + if (portfolioUsd <= 0) return { xrp: '', xmr: '' } + const a = arc<{ startAngle: number; endAngle: number }>() + .innerRadius(62) + .outerRadius(80) + .padAngle(0.02) + const start = -Math.PI / 2 + const endXrp = start + $tweenedXrpShare * 2 * Math.PI + return { + xrp: a({ startAngle: start, endAngle: endXrp }) ?? '', + xmr: a({ startAngle: endXrp, endAngle: start + 2 * Math.PI }) ?? '', + } + }) + const hasXrp = $derived(xrpWallet.wallets.length > 0) const hasXmr = $derived(moneroWallet.wallets.length > 0) const noWallets = $derived(!hasXrp && !hasXmr) @@ -69,6 +99,8 @@ maximumFractionDigits: dp, }) + const fmtPct = (v: number) => `${Math.round(v * 100)}%` + onMount(() => { frontendLog('dashboard mounted') }) @@ -143,18 +175,55 @@ {:else} -
-

Total Portfolio Value

- {#if moneroWallet.opening || (moneroWallet.wallets.length > 0 && !moneroWallet.walletOpen) || (xrpWallet.wallets.length > 0 && !xrpWallet.price) || (moneroWallet.walletOpen && !moneroWallet.price)} -
- {:else} -

- ${fmtUsd(portfolioUsd)} -

- {/if} -
+
+

Total Portfolio Value

+ {#if moneroWallet.opening || (moneroWallet.wallets.length > 0 && !moneroWallet.walletOpen) || (xrpWallet.wallets.length > 0 && !xrpWallet.price) || (moneroWallet.walletOpen && !moneroWallet.price)} +
+ {:else} +

+ ${fmtUsd(portfolioUsd)} +

+ {/if} +
-
+ + + Portfolio Allocation + + Share of your balance by asset + + + +
+ + + + +
+

$ + {fmtUsd($tweenedUsd)} +

+

+ Portfolio +

+
+
+
+ + + XRP · {fmtPct($tweenedXrpShare)} + + + + XMR · {fmtPct(1 - $tweenedXrpShare)} + +
+
+
+ +