feat: show every amount in one currency, chosen in the header, $ toggles it

A selector in the header and the palette's Currency group pick the
currency, the primary one by default; the choice persists between pages
and $ switches it on and off. Rates come from Firefly's exchange rates,
then from the owner's own transactions with a foreign amount, walking
through other currencies when there is no direct pair. Amount converts
with a ≈ and keeps the original in its title; Money sums several
currencies into one converted amount.
This commit is contained in:
hh committed 2026-10-16 18:15:53 +00:00
1 parent 3c1d8a4867
commit 2231c08eee
6 files changed
+315 -44

No files matched your search

+27 -3
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { formatMoney, type Money, toNumber } from "#lib/format.js";
import { display } from "#lib/money/display.svelte.js";
export type Tone = "income" | "expense" | "transfer" | "neutral" | "auto";
@@ -10,10 +11,31 @@
decimals,
tone = "auto",
signed = false,
approx = false,
exact = false,
class: className = "",
}: Money & { tone?: Tone; signed?: boolean; class?: string } = $props();
}: Money & {
tone?: Tone;
signed?: boolean;
approx?: boolean;
exact?: boolean;
class?: string;
} = $props();
const value = $derived(toNumber(amount));
const converted = $derived(
exact || !code || code === display.code
? null
: display.convert(value, code)
);
const original = $derived(
formatMoney({ amount, code, decimals, symbol }, signed)
);
const shown = $derived(
converted === null
? original
: formatMoney({ ...display.target, amount: converted }, signed)
);
const resolved = $derived.by(() => {
if (tone !== "auto") {
return tone;
@@ -33,6 +55,8 @@
);
</script>
<span class="num font-medium {color} {className}"
>{formatMoney({ amount, code, decimals, symbol }, signed)}</span
<span
class="num font-medium {color} {className}"
title={converted === null ? undefined : original}
>{approx || converted !== null ? "≈" : ""}{shown}</span
>