feat: Ausgaben-Anteile wahlweise als Kreisdiagramm
Neue Karten-Option „Darstellung": Liste (Standard) oder Kreis. Dieselben Zahlen, zwei Lesarten – die Liste nennt jeden Anteil genau, der Kreis zeigt die Verteilung auf einen Blick. Nutzt den vorhandenen Donut, dessen Legende Betrag und Anteil ohnehin schon ausweist. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -155,6 +155,16 @@ function ExpenseShare({ props }) {
|
|||||||
const data = useData(() => api.cardExpenseShare(groupBy));
|
const data = useData(() => api.cardExpenseShare(groupBy));
|
||||||
if (!data) return <Loading />;
|
if (!data) return <Loading />;
|
||||||
if (!data.rows?.length) return <div className="dash-empty muted">{t("cards.noExpenses")}</div>;
|
if (!data.rows?.length) return <div className="dash-empty muted">{t("cards.noExpenses")}</div>;
|
||||||
|
// Kreis: der Donut beschriftet seine Legende selbst mit Betrag und Anteil.
|
||||||
|
if ((props?.darstellung || "liste") === "kreis") {
|
||||||
|
return (
|
||||||
|
<Donut
|
||||||
|
segmente={data.rows.map((r) => ({ name: r.name, value: r.amount, color: r.color }))}
|
||||||
|
gesamtLabel={t("cards.spent")}
|
||||||
|
fmt={(v) => formatMoney(v, data.currency)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="dash-list">
|
<div className="dash-list">
|
||||||
{data.rows.map((r) => {
|
{data.rows.map((r) => {
|
||||||
@@ -192,6 +202,16 @@ const AUFSCHLUESSELUNG = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Liste oder Kreis – dieselben Zahlen, zwei Lesarten: die Liste nennt jeden
|
||||||
|
// Anteil genau, der Kreis zeigt die Verteilung auf einen Blick.
|
||||||
|
const DARSTELLUNG = {
|
||||||
|
key: "darstellung", labelKey: "cards.display", def: "liste",
|
||||||
|
choices: [
|
||||||
|
{ v: "liste", labelKey: "cards.asList" },
|
||||||
|
{ v: "kreis", labelKey: "cards.asPie" },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
// Registry: Kartentyp -> { Titel-Schlüssel, Komponente, Standardgröße/Mindestgröße,
|
// Registry: Kartentyp -> { Titel-Schlüssel, Komponente, Standardgröße/Mindestgröße,
|
||||||
// optional `options` (im Anordnen-Modus einstellbare Karten-Optionen) }.
|
// optional `options` (im Anordnen-Modus einstellbare Karten-Optionen) }.
|
||||||
export const KARTEN = {
|
export const KARTEN = {
|
||||||
@@ -200,7 +220,7 @@ export const KARTEN = {
|
|||||||
"net-worth": { titleKey: "cards.netWorth", Comp: NetWorth, w: 8, h: 4, minW: 4, minH: 3 },
|
"net-worth": { titleKey: "cards.netWorth", Comp: NetWorth, w: 8, h: 4, minW: 4, minH: 3 },
|
||||||
"budget-progress": { titleKey: "cards.budgetProgress", Comp: BudgetProgress, w: 4, h: 3, minW: 3, minH: 2, options: [AUFSCHLUESSELUNG] },
|
"budget-progress": { titleKey: "cards.budgetProgress", Comp: BudgetProgress, w: 4, h: 3, minW: 3, minH: 2, options: [AUFSCHLUESSELUNG] },
|
||||||
"expense-share": { titleKey: "cards.expenseShare", Comp: ExpenseShare, w: 4, h: 5, minW: 3, minH: 3,
|
"expense-share": { titleKey: "cards.expenseShare", Comp: ExpenseShare, w: 4, h: 5, minW: 3, minH: 3,
|
||||||
options: [{ ...AUFSCHLUESSELUNG, def: "category" }] },
|
options: [{ ...AUFSCHLUESSELUNG, def: "category" }, DARSTELLUNG] },
|
||||||
"income-expense": { titleKey: "cards.incomeExpense", Comp: IncomeExpense, w: 4, h: 2, minW: 2, minH: 2 },
|
"income-expense": { titleKey: "cards.incomeExpense", Comp: IncomeExpense, w: 4, h: 2, minW: 2, minH: 2 },
|
||||||
"recent-transactions": { titleKey: "cards.recent", Comp: RecentTransactions, w: 4, h: 4, minW: 3, minH: 3 },
|
"recent-transactions": { titleKey: "cards.recent", Comp: RecentTransactions, w: 4, h: 4, minW: 3, minH: 3 },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -134,7 +134,10 @@
|
|||||||
"byGroup": "Gruppen",
|
"byGroup": "Gruppen",
|
||||||
"byCategory": "Kategorien",
|
"byCategory": "Kategorien",
|
||||||
"expenseShare": "Ausgaben-Anteile",
|
"expenseShare": "Ausgaben-Anteile",
|
||||||
"noExpenses": "Noch keine Ausgaben in diesem Monat."
|
"noExpenses": "Noch keine Ausgaben in diesem Monat.",
|
||||||
|
"display": "Darstellung",
|
||||||
|
"asList": "Liste",
|
||||||
|
"asPie": "Kreis"
|
||||||
},
|
},
|
||||||
"server": {
|
"server": {
|
||||||
"unreachable": "Server nicht erreichbar.",
|
"unreachable": "Server nicht erreichbar.",
|
||||||
|
|||||||
@@ -134,7 +134,10 @@
|
|||||||
"byGroup": "Groups",
|
"byGroup": "Groups",
|
||||||
"byCategory": "Categories",
|
"byCategory": "Categories",
|
||||||
"expenseShare": "Expense share",
|
"expenseShare": "Expense share",
|
||||||
"noExpenses": "No expenses this month yet."
|
"noExpenses": "No expenses this month yet.",
|
||||||
|
"display": "Display",
|
||||||
|
"asList": "List",
|
||||||
|
"asPie": "Pie"
|
||||||
},
|
},
|
||||||
"server": {
|
"server": {
|
||||||
"unreachable": "Server unreachable.",
|
"unreachable": "Server unreachable.",
|
||||||
|
|||||||
Reference in New Issue
Block a user