diff --git a/flake/node-package.nix b/flake/node-package.nix
index 2cf10dc2..d02dcd8d 100644
--- a/flake/node-package.nix
+++ b/flake/node-package.nix
@@ -1912,6 +1912,15 @@ let
sha512 = "7BUT1sEFSNBIcc0wlwKn2l3l3OnYJdjsrlruDbAp6hpOK3HbpgMjLVH4ql6xXwD+qYy+XEHrb2EMkIpo9kWZ+Q==";
};
};
+ "@types/tabulator-tables-5.5.7" = {
+ name = "_at_types_slash_tabulator-tables";
+ packageName = "@types/tabulator-tables";
+ version = "5.5.7";
+ src = fetchurl {
+ url = "https://registry.npmjs.org/@types/tabulator-tables/-/tabulator-tables-5.5.7.tgz";
+ sha512 = "2G6i6QhJ/L+8Xk3KAfFZ91qADS9MEu6ve1uT59iaA7fpA6h6AswbFP/5dl3yg8lUhMsP4Zcst073FhbK7Y0TJA==";
+ };
+ };
"@types/tar-6.1.10" = {
name = "_at_types_slash_tar";
packageName = "@types/tar";
@@ -8610,6 +8619,15 @@ let
sha512 = "C2PqiSdxDA0v+OH9SP8UxyyfTRLzdxtdwgMjeX/5fvPPYbFixaUXp0hQw3aDN2RrLrwE2vmRJK3sAOICk+0wHA==";
};
};
+ "tabulator-tables-5.5.4" = {
+ name = "tabulator-tables";
+ packageName = "tabulator-tables";
+ version = "5.5.4";
+ src = fetchurl {
+ url = "https://registry.npmjs.org/tabulator-tables/-/tabulator-tables-5.5.4.tgz";
+ sha512 = "hVcITAfO2G3gm2ILW9GN2ORgcmNsbVmC+Q+2E3xfthIE9xtFxGKSbhbsNk39h11Uzm9GNUvjGfos1IVKrfeeOA==";
+ };
+ };
"tailwindcss-3.4.0" = {
name = "tailwindcss";
packageName = "tailwindcss";
@@ -9762,6 +9780,7 @@ let
sources."@types/sprintf-js-1.1.4"
sources."@types/svg2ttf-5.0.3"
sources."@types/svgicons2svgfont-10.0.5"
+ sources."@types/tabulator-tables-5.5.7"
sources."@types/tar-6.1.10"
sources."@types/ttf2eot-2.0.2"
sources."@types/ttf2woff-2.0.4"
@@ -10731,6 +10750,7 @@ let
sources."svgo-3.0.3"
sources."svgpath-2.6.0"
sources."svgtofont-4.1.1"
+ sources."tabulator-tables-5.5.4"
(sources."tailwindcss-3.4.0" // {
dependencies = [
(sources."postcss-load-config-4.0.2" // {
diff --git a/package-lock.json b/package-lock.json
index e3423f55..056ac60a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -49,6 +49,7 @@
"svelte-local-storage-store": "^0.6.0",
"svelte-select": "^5.8.0",
"svelte-tiny-virtual-list": "^2.0.5",
+ "tabulator-tables": "^5.5.4",
"textures": "^1.2.3",
"tippy.js": "^6.3.7",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz",
@@ -71,6 +72,7 @@
"@types/lodash": "^4.14.194",
"@types/papaparse": "^5.3.7",
"@types/sprintf-js": "^1.1.2",
+ "@types/tabulator-tables": "^5.5.7",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "^10.4.14",
@@ -2639,6 +2641,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/tabulator-tables": {
+ "version": "5.5.7",
+ "resolved": "https://registry.npmjs.org/@types/tabulator-tables/-/tabulator-tables-5.5.7.tgz",
+ "integrity": "sha512-2G6i6QhJ/L+8Xk3KAfFZ91qADS9MEu6ve1uT59iaA7fpA6h6AswbFP/5dl3yg8lUhMsP4Zcst073FhbK7Y0TJA==",
+ "dev": true
+ },
"node_modules/@types/tar": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@types/tar/-/tar-6.1.10.tgz",
@@ -11795,6 +11803,11 @@
"url": "https://jaywcjlove.github.io/#/sponsor"
}
},
+ "node_modules/tabulator-tables": {
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/tabulator-tables/-/tabulator-tables-5.5.4.tgz",
+ "integrity": "sha512-hVcITAfO2G3gm2ILW9GN2ORgcmNsbVmC+Q+2E3xfthIE9xtFxGKSbhbsNk39h11Uzm9GNUvjGfos1IVKrfeeOA=="
+ },
"node_modules/tailwindcss": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.0.tgz",
@@ -14957,6 +14970,12 @@
"@types/node": "*"
}
},
+ "@types/tabulator-tables": {
+ "version": "5.5.7",
+ "resolved": "https://registry.npmjs.org/@types/tabulator-tables/-/tabulator-tables-5.5.7.tgz",
+ "integrity": "sha512-2G6i6QhJ/L+8Xk3KAfFZ91qADS9MEu6ve1uT59iaA7fpA6h6AswbFP/5dl3yg8lUhMsP4Zcst073FhbK7Y0TJA==",
+ "dev": true
+ },
"@types/tar": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@types/tar/-/tar-6.1.10.tgz",
@@ -21796,6 +21815,11 @@
"yargs": "~17.7.1"
}
},
+ "tabulator-tables": {
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/tabulator-tables/-/tabulator-tables-5.5.4.tgz",
+ "integrity": "sha512-hVcITAfO2G3gm2ILW9GN2ORgcmNsbVmC+Q+2E3xfthIE9xtFxGKSbhbsNk39h11Uzm9GNUvjGfos1IVKrfeeOA=="
+ },
"tailwindcss": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.0.tgz",
diff --git a/package.json b/package.json
index a1d3b69a..e3dd3250 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
"svelte-local-storage-store": "^0.6.0",
"svelte-select": "^5.8.0",
"svelte-tiny-virtual-list": "^2.0.5",
+ "tabulator-tables": "^5.5.4",
"textures": "^1.2.3",
"tippy.js": "^6.3.7",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz",
@@ -78,6 +79,7 @@
"@types/lodash": "^4.14.194",
"@types/papaparse": "^5.3.7",
"@types/sprintf-js": "^1.1.2",
+ "@types/tabulator-tables": "^5.5.7",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "^10.4.14",
diff --git a/src/app.scss b/src/app.scss
index 4b3ae29b..7116a665 100644
--- a/src/app.scss
+++ b/src/app.scss
@@ -31,6 +31,45 @@ $editor-full-height: calc(100vh - 45.5px - 7px - 15.75px - 21px - 57.75px - 10.5
@import "bulma-switch/src/sass/index.sass";
@import "@cityssm/bulma-sticky-table/sticky-table";
+$backgroundColor: $white;
+$borderColor: none;
+$textSize: 1rem;
+$headerBackgroundColor: $white;
+$headerTextColor: $grey-dark;
+$headerBorderColor: rgba($grey-lightest, 1);
+$headerSeparatorColor: rgba($grey-light, 0.5);
+$headerMargin: 0.2857rem;
+$sortArrowActive: $black;
+$sortArrowInactive: $grey-light;
+$rowBackgroundColor: $white;
+$rowAltBackgroundColor: $white;
+$rowBorderColor: rgba($grey-lightest, 0.5);
+$rowTextColor: $grey-dark;
+$rowHoverBackground: $white-bis;
+$rowSelectedBackground: #9abcea;
+$rowSelectedBackgroundHover: #769bcc;
+$editBoxColor: #1d68cd;
+$errorColor: #dd0000;
+$footerBackgroundColor: #fff;
+$footerTextColor: #555;
+$footerBorderColor: #aaa;
+$footerSeparatorColor: #999;
+$footerActiveColor: #d00;
+
+@import "tabulator-tables/src/scss/themes/tabulator_simple.scss";
+
+.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title {
+ white-space: normal;
+}
+
+.tabulator {
+ border-radius: $radius;
+}
+
+.tabulator-col {
+ padding: 0.5rem;
+}
+
// override message style
.message {
diff --git a/src/lib/components/AssetsBalance.svelte b/src/lib/components/AssetsBalance.svelte
index e744ed46..cd7aabf0 100644
--- a/src/lib/components/AssetsBalance.svelte
+++ b/src/lib/components/AssetsBalance.svelte
@@ -1,75 +1,65 @@
-
-
-
+{#if indent}
+
+{:else}
+
+{/if}
diff --git a/src/lib/components/Navbar.svelte b/src/lib/components/Navbar.svelte
index 5af0abbe..96477bab 100644
--- a/src/lib/components/Navbar.svelte
+++ b/src/lib/components/Navbar.svelte
@@ -118,7 +118,7 @@
label: "More",
href: "/more",
children: [
- { label: "Configuration", href: "/config", tag: "alpha", help: "config" },
+ { label: "Configuration", href: "/config", help: "config" },
{ label: "Sheets", href: "/sheets", help: "sheets", disablePreload: true },
{ label: "Goals", href: "/goals", help: "goals" },
{ label: "Doctor", href: "/doctor" },
diff --git a/src/lib/components/Table.svelte b/src/lib/components/Table.svelte
new file mode 100644
index 00000000..37f0533c
--- /dev/null
+++ b/src/lib/components/Table.svelte
@@ -0,0 +1,47 @@
+
+
+
diff --git a/src/lib/table_formatters.ts b/src/lib/table_formatters.ts
new file mode 100644
index 00000000..c64386fa
--- /dev/null
+++ b/src/lib/table_formatters.ts
@@ -0,0 +1,81 @@
+import { type CellComponent } from "tabulator-tables";
+import { formatCurrency, formatFloat, formatPercentage, isZero, lastName } from "./utils";
+import { iconText } from "./icon";
+
+export function indendedAssetAccountName(cell: CellComponent) {
+ const account = cell.getValue();
+ let children = "";
+ const data = cell.getData();
+ if ((data._children?.length || 0) > 0) {
+ children = `(${data._children?.length})`;
+ }
+ return `
+
+ ${iconText(account)}
+ ${lastName(account)}
+ ${children}
+
+`;
+}
+
+export function indendedLiabilityAccountName(cell: CellComponent) {
+ const account = cell.getValue();
+ let children = "";
+ const data = cell.getData();
+ if ((data._children?.length || 0) > 0) {
+ children = `(${data._children?.length})`;
+ }
+ return `
+
+ ${iconText(account)}
+ ${lastName(account)}
+ ${children}
+
+`;
+}
+
+export function accountName(cell: CellComponent) {
+ const account = cell.getValue();
+ return `
+
+ ${iconText(account)}
+ ${account}
+
+`;
+}
+
+function calculateChangeClass(gain: number) {
+ let changeClass = "";
+ if (gain > 0) {
+ changeClass = "has-text-success";
+ } else if (gain < 0) {
+ changeClass = "has-text-danger";
+ }
+ return changeClass;
+}
+
+export function nonZeroCurrency(cell: CellComponent) {
+ const value = cell.getValue();
+ return isZero(value) ? "" : formatCurrency(value);
+}
+
+export function nonZeroFloatChange(cell: CellComponent) {
+ const value = cell.getValue();
+ return isZero(value)
+ ? ""
+ : `${formatFloat(value)}`;
+}
+
+export function nonZeroPercentageChange(cell: CellComponent) {
+ const value = cell.getValue();
+ return isZero(value)
+ ? ""
+ : `${formatPercentage(value, 2)}`;
+}
+
+export function formatCurrencyChange(cell: CellComponent) {
+ const value = cell.getValue();
+ return isZero(value)
+ ? ""
+ : `${formatCurrency(value)}`;
+}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index de971f33..690720c6 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -1276,3 +1276,30 @@ export function dueDateIcon(dueDate: dayjs.Dayjs, clearedDate: dayjs.Dayjs) {
return { icon, color, svgColor, glyph };
}
+
+export function buildTree(items: I[], accountAccessor: (item: I) => string): I[] {
+ const result: I[] = [];
+
+ const sorted = _.sortBy(items, accountAccessor);
+
+ for (const item of sorted) {
+ const account = accountAccessor(item);
+ const parts = account.split(":");
+ let current = result;
+ for (let i = 0; i < parts.length; i++) {
+ const part = parts[i];
+ let found: any = current.find((c) => accountAccessor(c).split(":")[i] === part);
+ if (!found) {
+ found = { ...item };
+ current.push(found);
+ }
+
+ if (i !== parts.length - 1) {
+ found._children = found._children || [];
+ current = found._children;
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/src/routes/(app)/liabilities/balance/+page.svelte b/src/routes/(app)/liabilities/balance/+page.svelte
index 8e06d2ef..0755d34a 100644
--- a/src/routes/(app)/liabilities/balance/+page.svelte
+++ b/src/routes/(app)/liabilities/balance/+page.svelte
@@ -1,29 +1,18 @@
@@ -51,48 +80,7 @@
diff --git a/src/routes/(app)/more/goals/savings/[slug]/+page.svelte b/src/routes/(app)/more/goals/savings/[slug]/+page.svelte
index 083428f5..0528116e 100644
--- a/src/routes/(app)/more/goals/savings/[slug]/+page.svelte
+++ b/src/routes/(app)/more/goals/savings/[slug]/+page.svelte
@@ -177,7 +177,7 @@