diff --git a/public/locales/en.json b/public/locales/en.json
index 17be5ff..a8cee1e 100644
--- a/public/locales/en.json
+++ b/public/locales/en.json
@@ -187,6 +187,24 @@
"errorWalletLimitDescription": "You currently cannot add any more wallets."
},
+ "dashboard": {
+ "siteTitle": "Dashboard",
+
+ "walletOverviewCardTitle": "Wallets",
+ "walletOverviewTotalBalance": "Total balance",
+ "walletOverviewNames": "Names",
+ "walletOverviewNamesCount": "{{count}} name",
+ "walletOverviewNamesCount_plural": "{{count}} names",
+ "walletOverviewSeeMore": "See all {{count}}...",
+ "walletOverviewAddWallets": "Add wallets...",
+
+ "transactionsCardTitle": "Transactions",
+
+ "blockValueCardTitle": "Block Value",
+
+ "blockDifficultyCardTitle": "Block Difficulty"
+ },
+
"credits": {
"title": "Credits",
"madeBy": "Made by <1>{{authorName}}1>",
diff --git a/src/layout/AppLayout.less b/src/layout/AppLayout.less
index 5e60b05..485ae1d 100644
--- a/src/layout/AppLayout.less
+++ b/src/layout/AppLayout.less
@@ -56,6 +56,7 @@
.ant-tag {
margin-left: 0.5em;
+ margin-right: 0;
}
}
diff --git a/src/layout/AppRouter.tsx b/src/layout/AppRouter.tsx
index 742bc96..84701c5 100644
--- a/src/layout/AppRouter.tsx
+++ b/src/layout/AppRouter.tsx
@@ -1,7 +1,7 @@
import React from "react";
import { Switch, Route } from "react-router-dom";
-import { DashboardPage } from "../pages/DashboardPage";
+import { DashboardPage } from "../pages/dashboard/DashboardPage";
import { WalletsPage } from "../pages/wallets/WalletsPage";
import { SettingsPage } from "../pages/settings/SettingsPage";
diff --git a/src/pages/DashboardPage.tsx b/src/pages/DashboardPage.tsx
deleted file mode 100644
index c6dfa7e..0000000
--- a/src/pages/DashboardPage.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from "react";
-import { Button, message } from "antd";
-
-import { useDispatch, useSelector, shallowEqual } from "react-redux";
-import { RootState } from "../store";
-
-import { syncWallets } from "../krist/wallets/Wallet";
-
-import { PageLayout } from "../layout/PageLayout";
-import { AuthorisedAction } from "../components/auth/AuthorisedAction";
-
-export function DashboardPage(): JSX.Element {
- const { isAuthed, hasMasterPassword }
- = useSelector((s: RootState) => s.walletManager, shallowEqual);
- const { wallets } = useSelector((s: RootState) => s.wallets, shallowEqual);
- const dispatch = useDispatch();
-
- return {/* TODO */}
- Is authed: {isAuthed ? "yes" : "no"}
- Has master password: {hasMasterPassword ? "yes" : "no"}
-
-
-
-
-
-
-
-
-
- message.success("Something authed happened!")}>
-
-
- ;
-}
diff --git a/src/pages/dashboard/BlockDifficultyCard.tsx b/src/pages/dashboard/BlockDifficultyCard.tsx
new file mode 100644
index 0000000..552ac73
--- /dev/null
+++ b/src/pages/dashboard/BlockDifficultyCard.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+import { Card } from "antd";
+
+import { useTranslation } from "react-i18next";
+
+export function BlockDifficultyCard(): JSX.Element {
+ const { t } = useTranslation();
+
+ return
+
+ ;
+}
diff --git a/src/pages/dashboard/BlockValueCard.tsx b/src/pages/dashboard/BlockValueCard.tsx
new file mode 100644
index 0000000..1556906
--- /dev/null
+++ b/src/pages/dashboard/BlockValueCard.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+import { Card } from "antd";
+
+import { useTranslation } from "react-i18next";
+
+export function BlockValueCard(): JSX.Element {
+ const { t } = useTranslation();
+
+ return
+
+ ;
+}
diff --git a/src/pages/dashboard/DashboardPage.less b/src/pages/dashboard/DashboardPage.less
new file mode 100644
index 0000000..d88e5dd
--- /dev/null
+++ b/src/pages/dashboard/DashboardPage.less
@@ -0,0 +1,119 @@
+@import (reference) "../../App.less";
+
+.dashboard-page {
+ .dashboard-main-row {
+ margin-bottom: @margin-md;
+ align-items: stretch;
+
+ & > .ant-col > .ant-card {
+ height: 100%;
+
+ border: none;
+ border-radius: @kw-big-card-border-radius;
+
+ .ant-card-head {
+ border-bottom: 0;
+ margin-bottom: 0;
+
+ border-radius: @kw-big-card-border-radius @kw-big-card-border-radius 0 0;
+
+ .ant-card-head-title {
+ padding-bottom: 0;
+ }
+ }
+
+ .ant-card-body {
+ padding-top: @padding-sm;
+ }
+ }
+ }
+
+ .dashboard-statistic {
+ &-title {
+ color: @kw-text-secondary;
+ display: block;
+ }
+
+ &-value {
+ font-size: @heading-3-size;
+ }
+ }
+
+ .dashboard-card-wallets {
+ .dashboard-wallets-top-row {
+ margin-bottom: @margin-sm;
+ }
+
+ .dashboard-wallets-balance {
+ .krist-value {
+ color: @kw-green;
+
+ .anticon svg, .krist-currency-long {
+ color: fade(@kw-green, 75%);
+ }
+
+ &.empty {
+ color: @text-color;
+
+ .anticon svg, .krist-currency-long {
+ color: fade(@text-color, 75%);
+ }
+ }
+ }
+ }
+
+ .dashboard-wallet-preview {
+ padding: @padding-sm @padding-md;
+ margin-bottom: @margin-xs;
+
+ background: @kw-dark;
+ border-radius: @kw-big-card-border-radius;
+
+ height: 60px;
+ justify-content: center;
+
+ line-height: 1.5;
+
+ .wallet-left {
+ flex: 1;
+ height: 100%;
+
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+
+ .wallet-label {
+ font-weight: bold;
+ }
+ }
+
+ .wallet-right {
+ flex: 0;
+ font-size: @font-size-lg;
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+ }
+
+ .dashboard-more a {
+ display: block;
+ width: 100%;
+
+ margin-bottom: -@padding-sm;
+
+ color: @text-color-secondary;
+ font-size: 90%;
+ text-align: center;
+
+ &:hover {
+ color: lighten(@text-color-secondary, 10%);
+ }
+ }
+}
diff --git a/src/pages/dashboard/DashboardPage.tsx b/src/pages/dashboard/DashboardPage.tsx
new file mode 100644
index 0000000..6a3f9e9
--- /dev/null
+++ b/src/pages/dashboard/DashboardPage.tsx
@@ -0,0 +1,25 @@
+import React from "react";
+import { Row, Col } from "antd";
+
+import { PageLayout } from "../../layout/PageLayout";
+
+import { WalletOverviewCard } from "./WalletOverviewCard";
+import { TransactionsCard } from "./TransactionsCard";
+import { BlockValueCard } from "./BlockValueCard";
+import { BlockDifficultyCard } from "./BlockDifficultyCard";
+
+import "./DashboardPage.less";
+
+export function DashboardPage(): JSX.Element {
+ return
+
+
+
+
+
+
+
+
+
+ ;
+}
diff --git a/src/pages/dashboard/Statistic.tsx b/src/pages/dashboard/Statistic.tsx
new file mode 100644
index 0000000..5a89ee3
--- /dev/null
+++ b/src/pages/dashboard/Statistic.tsx
@@ -0,0 +1,18 @@
+import React from "react";
+
+import { useTranslation } from "react-i18next";
+
+interface Props {
+ title?: string;
+ titleKey?: string;
+ value?: React.ReactNode;
+}
+
+export function Statistic({ title, titleKey, value }: Props): JSX.Element {
+ const { t } = useTranslation();
+
+ return
+ {titleKey ? t(titleKey) : title}
+ {value}
+
;
+}
diff --git a/src/pages/dashboard/TransactionsCard.tsx b/src/pages/dashboard/TransactionsCard.tsx
new file mode 100644
index 0000000..879a9ef
--- /dev/null
+++ b/src/pages/dashboard/TransactionsCard.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+import { Card } from "antd";
+
+import { useTranslation } from "react-i18next";
+
+export function TransactionsCard(): JSX.Element {
+ const { t } = useTranslation();
+
+ return
+
+ ;
+}
diff --git a/src/pages/dashboard/WalletOverviewCard.tsx b/src/pages/dashboard/WalletOverviewCard.tsx
new file mode 100644
index 0000000..2a9b173
--- /dev/null
+++ b/src/pages/dashboard/WalletOverviewCard.tsx
@@ -0,0 +1,73 @@
+import React from "react";
+import { Card, Row, Col, Typography } from "antd";
+
+import { useSelector, shallowEqual } from "react-redux";
+import { RootState } from "../../store";
+import { useTranslation } from "react-i18next";
+import { Link } from "react-router-dom";
+
+import { Wallet } from "../../krist/wallets/Wallet";
+
+import { KristValue } from "../../components/KristValue";
+import { Statistic } from "./Statistic";
+
+import { keyedNullSort } from "../../utils";
+
+export function WalletPreview({ wallet }: { wallet: Wallet }): JSX.Element {
+ return
+
+ {wallet.label && {wallet.label}}
+ {wallet.address}
+
+
+
+
+
+
;
+}
+
+export function WalletOverviewCard(): JSX.Element {
+ const { wallets } = useSelector((s: RootState) => s.wallets, shallowEqual);
+ const { t } = useTranslation();
+
+ const clonedWallets = [...Object.values(wallets)];
+
+ const balance = clonedWallets.filter(w => w.balance !== undefined)
+ .reduce((acc, w) => acc + w.balance!, 0);
+ const names = clonedWallets.filter(w => w.names !== undefined)
+ .reduce((acc, w) => acc + w.names!, 0);
+
+ const topWallets = [...clonedWallets];
+ const sort = keyedNullSort("balance", undefined);
+ topWallets.sort((a: Wallet, b: Wallet) => sort(a, b, "descend"));
+ topWallets.reverse();
+ const top4Wallets = topWallets.slice(0, 4);
+
+ return
+
+
+ 0 ? "" : "empty"} />}
+ />
+
+
+
+
+
+
+
+ {top4Wallets.map(w => )}
+
+
+
+ {clonedWallets.length > 0
+ ? t("dashboard.walletOverviewSeeMore", { count: clonedWallets.length })
+ : t("dashboard.walletOverviewAddWallets")}
+
+
+ ;
+}
diff --git a/src/style/theme.less b/src/style/theme.less
index 559961c..b24677b 100644
--- a/src/style/theme.less
+++ b/src/style/theme.less
@@ -94,6 +94,9 @@
}
@table-header-icon-color: @text-color-secondary;
+@card-background: mix(@kw-dark, @kw-slighter, 75%);
+@kw-big-card-border-radius: 4px;
+
// general theme
// ---
@kw-sidebar-bg: @kw-darker;