- This project is completely free and open-source.
-
- If you have enjoyed it, please consider supporting ThunderHub with
- some sats
-
-
-
- amountSet(Number(value))}
- />
-
-
-
- {renderButton(() => setWithPoints(true), 'Yes', withPoints)}
- {renderButton(() => setWithPoints(false), 'No', !withPoints)}
-
-
- {withPoints && (
- <>
-
- This means your node will appear in the ThunderHub donation
- leaderboard. If you want to remain anonymous, do not enable this
- option. Your node alias and public key will be stored if you
- enable it.
-
-
- Due to the increasing price of Bitcoin, to incentivize development
- and to give everyone an opportunity to be in the top of the
- leaderboard, points have a half life of 6 months. This means that
- every 6 months they are halved.
-
- >
- )}
-
- getInvoice({ variables: { amount } })}
- loading={loading}
- disabled={amount <= 0 || loading}
- fullWidth={true}
- withMargin={'8px 0 0 0'}
- >
- Send
-
-
+
+ This project is completely free and open-source.
+
+ If you have enjoyed it, please consider supporting ThunderHub with
+ some sats
+
+
+
+ amountSet(Number(value))}
+ />
+
+
+
+ {renderButton(() => setWithPoints(true), 'Yes', withPoints)}
+ {renderButton(() => setWithPoints(false), 'No', !withPoints)}
+
+
+ {withPoints && (
+ <>
+
+ This means your node will appear in the ThunderHub donation
+ leaderboard. If you want to remain anonymous, do not enable this
+ option. Your node alias and public key will be stored if you enable
+ it.
+
+
+ Due to the increasing price of Bitcoin, to incentivize development
+ and to give everyone an opportunity to be in the top of the
+ leaderboard, points have a half life of 6 months. This means that
+ every 6 months they are halved.
+
+ >
+ )}
+
+ getInvoice({ variables: { amount } })}
+ loading={loading}
+ disabled={amount <= 0 || loading}
+ fullWidth={true}
+ withMargin={'8px 0 0 0'}
+ >
+ Send
+
diff --git a/src/views/settings/DashPanel.tsx b/src/views/settings/DashPanel.tsx
new file mode 100644
index 00000000..3aa40f70
--- /dev/null
+++ b/src/views/settings/DashPanel.tsx
@@ -0,0 +1,101 @@
+import { groupBy } from 'lodash';
+import { Fragment } from 'react';
+import { Layouts } from 'react-grid-layout';
+import { ColorButton } from 'src/components/buttons/colorButton/ColorButton';
+import { Card, SubTitle } from 'src/components/generic/Styled';
+import { Link } from 'src/components/link/Link';
+import { useLocalStorage } from 'src/hooks/UseLocalStorage';
+import styled from 'styled-components';
+import { StoredWidget } from '../dashboard';
+import { widgetList } from '../dashboard/widgets/widgetList';
+import { WidgetRow } from './WidgetRow';
+
+const S = {
+ subTitle: styled(SubTitle)`
+ margin: 32px 0 8px;
+ `,
+};
+
+export type NormalizedWidgets = {
+ id: number;
+ name: string;
+ group: string;
+ active: boolean;
+};
+
+const DashPanel = () => {
+ const [, setLayouts] = useLocalStorage('layouts', {});
+ const [availableWidgets, setAvailableWidgets] = useLocalStorage<
+ StoredWidget[]
+ >('dashboardWidgets', []);
+
+ const normalizedList: NormalizedWidgets[] = widgetList.reduce((p, w) => {
+ if (w.hidden) return p;
+
+ const active =
+ availableWidgets.findIndex((a: StoredWidget) => {
+ return a.id === w.id;
+ }) >= 0;
+
+ return [...p, { ...w, active }];
+ }, [] as NormalizedWidgets[]);
+
+ const handleAdd = (id: number) => {
+ const filtered = availableWidgets.filter(a => a.id !== id);
+ setAvailableWidgets([...filtered, { id }]);
+ };
+
+ const handleDelete = (id: number) => {
+ const filtered = availableWidgets.filter(a => a.id !== id);
+ setAvailableWidgets(filtered);
+ };
+
+ const grouped = groupBy(normalizedList, 'group');
+ const keys = Object.keys(grouped);
+
+ return (
+
+ {keys.map((key, index) => {
+ const widgets = grouped[key];
+ const subGrouped = groupBy(widgets, 'subgroup');
+ const subKeys = Object.keys(subGrouped);
+
+ return subKeys.map((subKey, subIndex) => {
+ const subWidgets = subGrouped[subKey];
+
+ return (
+
+ {subKey ? `${key} - ${subKey}` : key}
+ {subWidgets.map(w => (
+
+
+
+ ))}
+
+ );
+ });
+ })}
+
+
+ To Dashboard
+
+
+ {
+ setLayouts({});
+ setAvailableWidgets([]);
+ }}
+ >
+ Reset Widgets
+
+
+ );
+};
+
+export default DashPanel;
diff --git a/src/views/settings/Dashboard.tsx b/src/views/settings/Dashboard.tsx
new file mode 100644
index 00000000..0c73594d
--- /dev/null
+++ b/src/views/settings/Dashboard.tsx
@@ -0,0 +1,27 @@
+import { useRouter } from 'next/router';
+import { SettingsLine } from 'pages/settings';
+import { ColorButton } from 'src/components/buttons/colorButton/ColorButton';
+import {
+ Card,
+ CardWithTitle,
+ Sub4Title,
+ SubTitle,
+} from 'src/components/generic/Styled';
+
+export const DashboardSettings = () => {
+ const { push } = useRouter();
+
+ return (
+
+ Dashboard
+
+
+ Widgets
+ push('/settings/dashboard')}>
+ Change
+
+
+
+
+ );
+};
diff --git a/src/views/settings/WidgetRow.tsx b/src/views/settings/WidgetRow.tsx
new file mode 100644
index 00000000..ce0e5a65
--- /dev/null
+++ b/src/views/settings/WidgetRow.tsx
@@ -0,0 +1,47 @@
+import { FC } from 'react';
+import {
+ MultiButton,
+ SingleButton,
+} from 'src/components/buttons/multiButton/MultiButton';
+import { DarkSubTitle } from 'src/components/generic/Styled';
+import styled from 'styled-components';
+import { NormalizedWidgets } from './DashPanel';
+
+const S = {
+ line: styled.div`
+ margin-bottom: 8px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ `,
+};
+
+type WidgetRowParams = {
+ widget: NormalizedWidgets;
+ handleAdd: (id: number) => void;
+ handleDelete: (id: number) => void;
+};
+
+export const WidgetRow: FC = ({
+ widget,
+ handleAdd,
+ handleDelete,
+}) => (
+
+ {widget.name}
+
+ handleAdd(widget.id)}
+ >
+ Show
+
+ handleDelete(widget.id)}
+ >
+ Hide
+
+
+
+);
diff --git a/src/views/tools/messages/Messages.tsx b/src/views/tools/messages/Messages.tsx
index 33498776..35eb73d2 100644
--- a/src/views/tools/messages/Messages.tsx
+++ b/src/views/tools/messages/Messages.tsx
@@ -5,7 +5,7 @@ import {
SubTitle,
Card,
} from '../../../components/generic/Styled';
-import { SignMessage } from './SignMessage';
+import { SignMessageCard } from './SignMessage';
import { VerifyMessage } from './VerifyMessage';
export const NoWrap = styled.div`
@@ -19,7 +19,7 @@ export const MessagesView = () => {
Messages
-
+
);
diff --git a/src/views/tools/messages/SignMessage.tsx b/src/views/tools/messages/SignMessage.tsx
index 22f6b9ba..6c34c2ce 100644
--- a/src/views/tools/messages/SignMessage.tsx
+++ b/src/views/tools/messages/SignMessage.tsx
@@ -16,7 +16,6 @@ import { NoWrap } from './Messages';
export const SignMessage = () => {
const [message, setMessage] = useState('');
- const [isPasting, setIsPasting] = useState(false);
const [signed, setSigned] = useState('');
const [signMessage, { data, loading }] = useSignMessageLazyQuery({
@@ -49,40 +48,51 @@ export const SignMessage = () => {
>
Sign
-
>
);
const renderMessage = () => (
-
- {signed}
- toast.success('Signature Copied')}
- >
-
-
- Copy
-
-
-
+ <>
+
+
+ {signed}
+ toast.success('Signature Copied')}
+ >
+
+
+ Copy
+
+
+
+ >
);
+ return (
+ <>
+ {renderInput()}
+ {signed !== '' && renderMessage()}
+ >
+ );
+};
+
+export const SignMessageCard = () => {
+ const [isPasting, setIsPasting] = useState(false);
+
return (
<>
Sign Message setIsPasting(prev => !prev)}
>
{isPasting ? : 'Sign'}
- {isPasting && renderInput()}
- {signed !== '' && isPasting && renderMessage()}
+ {isPasting && }
>
);
};