From 15ce9db8a79c836e3c4e7dafee0831e66a54e27b Mon Sep 17 00:00:00 2001 From: Paul Miller Date: Tue, 23 May 2023 09:12:31 -0500 Subject: [PATCH] swap to ln --- src/assets/icons/info.svg | 3 + src/assets/icons/shuffle.svg | 3 + src/components/AmountCard.tsx | 203 +++++---- src/components/BalanceBox.tsx | 12 +- src/components/InfoBox.tsx | 19 + src/components/KitchenSink.tsx | 2 +- src/components/SimpleSelect.tsx | 0 src/components/layout/Radio.tsx | 2 +- src/root.css | 12 + src/routes/Send.tsx | 778 ++++++++++++++++++-------------- src/routes/Storybook.tsx | 105 ++++- src/routes/Swap.tsx | 299 ++++++++++++ 12 files changed, 1006 insertions(+), 432 deletions(-) create mode 100644 src/assets/icons/info.svg create mode 100644 src/assets/icons/shuffle.svg create mode 100644 src/components/InfoBox.tsx create mode 100644 src/components/SimpleSelect.tsx create mode 100644 src/routes/Swap.tsx diff --git a/src/assets/icons/info.svg b/src/assets/icons/info.svg new file mode 100644 index 0000000..b7dcae9 --- /dev/null +++ b/src/assets/icons/info.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/shuffle.svg b/src/assets/icons/shuffle.svg new file mode 100644 index 0000000..4a315d4 --- /dev/null +++ b/src/assets/icons/shuffle.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/components/AmountCard.tsx b/src/components/AmountCard.tsx index 350b3fa..6574aed 100644 --- a/src/components/AmountCard.tsx +++ b/src/components/AmountCard.tsx @@ -5,87 +5,136 @@ import { satsToUsd } from "~/utils/conversions"; import { AmountEditable } from "./AmountEditable"; const noop = () => { - // do nothing -} + // do nothing +}; -const KeyValue: ParentComponent<{ key: string, gray?: boolean }> = (props) => { - return ( -
-
{props.key}
-
{props.children}
+const KeyValue: ParentComponent<{ key: string; gray?: boolean }> = (props) => { + return ( +
+
{props.key}
+
{props.children}
+
+ ); +}; + +export const InlineAmount: ParentComponent<{ amount: string; sign?: string; fiat?: boolean }> = ( + props +) => { + const prettyPrint = createMemo(() => { + const parsed = Number(props.amount); + if (isNaN(parsed)) { + return props.amount; + } else { + return parsed.toLocaleString(); + } + }); + + return ( +
+ {props.sign ? `${props.sign} ` : ""} + {props.fiat ? "$" : ""} + {prettyPrint()} {props.fiat ? "USD" : "SATS"} +
+ ); +}; + +function USDShower(props: { amountSats: string; fee?: string }) { + const [state, _] = useMegaStore(); + const amountInUsd = () => satsToUsd(state.price, add(props.amountSats, props.fee), true); + + return ( + + +
+ ≈ {amountInUsd()} USD
- ) -} - -export const InlineAmount: ParentComponent<{ amount: string, sign?: string, fiat?: boolean }> = (props) => { - const prettyPrint = createMemo(() => { - const parsed = Number(props.amount); - if (isNaN(parsed)) { - return props.amount; - } else { - return parsed.toLocaleString(); - } - }) - - return (
{props.sign ? `${props.sign} ` : ""}{props.fiat ? "$" : ""}{prettyPrint()} {props.fiat ? "USD" : "SATS"}
) -} - -function USDShower(props: { amountSats: string, fee?: string }) { - const [state, _] = useMegaStore() - const amountInUsd = () => satsToUsd(state.price, add(props.amountSats, props.fee), true) - - return ( - - -
≈ {amountInUsd()} USD
-
-
- ) - +
+
+ ); } function add(a: string, b?: string) { - return Number(a || 0) + Number(b || 0) + return Number(a || 0) + Number(b || 0); } -export function AmountCard(props: { amountSats: string, fee?: string, initialOpen?: boolean, isAmountEditable?: boolean, setAmountSats?: (amount: bigint) => void }) { - return ( - - - - -
- - - }> - - - - - - -
-
-
- - - - -
-
- -
- - - }> - - - - -
-
-
-
-
- ) -} \ No newline at end of file +function subtract(a: string, b?: string) { + return Number(a || 0) - Number(b || 0); +} + +export function AmountCard(props: { + amountSats: string; + fee?: string; + reserve?: string; + initialOpen?: boolean; + isAmountEditable?: boolean; + setAmountSats?: (amount: bigint) => void; +}) { + return ( + + + + +
+ + } + > + + + + + + +
+
+
+ + + + +
+
+ +
+ + + + + + +
+
+
+ + + + +
+
+ +
+ + } + > + + + + +
+
+
+
+
+ ); +} diff --git a/src/components/BalanceBox.tsx b/src/components/BalanceBox.tsx index f0f6c15..d95ab6e 100644 --- a/src/components/BalanceBox.tsx +++ b/src/components/BalanceBox.tsx @@ -2,7 +2,8 @@ import { Show, Suspense } from "solid-js"; import { Button, ButtonLink, FancyCard, Indicator } from "~/components/layout"; import { useMegaStore } from "~/state/megaStore"; import { Amount } from "./Amount"; -import { useNavigate } from "solid-start"; +import { A, useNavigate } from "solid-start"; +import shuffle from "~/assets/icons/shuffle.svg" function prettyPrintAmount(n?: number | bigint): string { if (!n || n.valueOf() === 0) { @@ -22,6 +23,8 @@ export function LoadingShimmer() {
) } +const STYLE = "px-2 py-1 rounded-xl border border-neutral-400 text-sm flex gap-2 items-center font-semibold" + export default function BalanceBox(props: { loading?: boolean }) { const [state, actions] = useMegaStore(); @@ -39,8 +42,13 @@ export default function BalanceBox(props: { loading?: boolean }) { Syncing}> }> -
+
+
+ + swap + +
diff --git a/src/components/InfoBox.tsx b/src/components/InfoBox.tsx new file mode 100644 index 0000000..6475c29 --- /dev/null +++ b/src/components/InfoBox.tsx @@ -0,0 +1,19 @@ +import { ParentComponent } from "solid-js"; +import { ButtonLink, SmallHeader } from "~/components/layout" +import info from "~/assets/icons/info.svg" + +export const InfoBox: ParentComponent<{ accent: "red" | "blue" | "green" | "white" }> = (props) => { + return ( +
+
+ info +
+
+

+ {props.children} +

+
+
+ ) +} diff --git a/src/components/KitchenSink.tsx b/src/components/KitchenSink.tsx index a1e115c..f461587 100644 --- a/src/components/KitchenSink.tsx +++ b/src/components/KitchenSink.tsx @@ -112,7 +112,7 @@ function ConnectPeer(props: { refetchPeers: RefetchPeersType }) { Connect Peer diff --git a/src/components/SimpleSelect.tsx b/src/components/SimpleSelect.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/layout/Radio.tsx b/src/components/layout/Radio.tsx index 8dd785d..7f32ce7 100644 --- a/src/components/layout/Radio.tsx +++ b/src/components/layout/Radio.tsx @@ -15,7 +15,7 @@ export function StyledRadioGroup(props: { value: string, choices: Choices, onVal {choice =>
diff --git a/src/root.css b/src/root.css index 72da87c..a69d595 100644 --- a/src/root.css +++ b/src/root.css @@ -39,3 +39,15 @@ a { #video-container .scan-region-highlight-svg { display: none; } + +select { + @apply appearance-none; + @apply block; + @apply border-[2px] focus:outline-none focus:ring-2 focus:ring-offset-2 ring-offset-black; + @apply font-light text-lg; + @apply py-4 pl-4 pr-8; + background-image: url("data:image/svg+xml,%3Csvg aria-hidden='true' class='w-4 h-4 ml-1' fill='white' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' d='M5.293 7.293a1 1 0 0 1 1.414 0L10 10.586l3.293-3.293a1 1 0 1 1 1.414 1.414l-4 4a1 1 0 0 1-1.414 0l-4-4a1 1 0 0 1 0-1.414z' clip-rule='evenodd'/%3E%3C/svg%3E"); + background-position: right 0.75rem center; + background-size: 20px 20px; + background-repeat: no-repeat; +} diff --git a/src/routes/Send.tsx b/src/routes/Send.tsx index 349505a..470b5fe 100644 --- a/src/routes/Send.tsx +++ b/src/routes/Send.tsx @@ -1,7 +1,18 @@ import { Match, Show, Switch, createEffect, createMemo, createSignal, onMount } from "solid-js"; import { Amount } from "~/components/Amount"; import NavBar from "~/components/NavBar"; -import { Button, ButtonLink, Card, DefaultMain, HStack, LargeHeader, MutinyWalletGuard, SafeArea, SmallHeader, VStack } from "~/components/layout"; +import { + Button, + ButtonLink, + Card, + DefaultMain, + HStack, + LargeHeader, + MutinyWalletGuard, + SafeArea, + SmallHeader, + VStack +} from "~/components/layout"; import { Paste } from "~/assets/svg/Paste"; import { Scan } from "~/assets/svg/Scan"; import { useMegaStore } from "~/state/megaStore"; @@ -11,7 +22,7 @@ import { ParsedParams, toParsedParams } from "./Scanner"; import { showToast } from "~/components/Toaster"; import eify from "~/utils/eify"; import { FullscreenModal } from "~/components/layout/FullscreenModal"; -import megacheck from "~/assets/icons/megacheck.png" +import megacheck from "~/assets/icons/megacheck.png"; import megaex from "~/assets/icons/megaex.png"; import mempoolTxUrl from "~/utils/mempoolTxUrl"; import { BackLink } from "~/components/layout/BackLink"; @@ -22,379 +33,480 @@ import { AmountCard } from "~/components/AmountCard"; import { MutinyTagItem } from "~/utils/tags"; import { BackButton } from "~/components/layout/BackButton"; -type SendSource = "lightning" | "onchain"; +export type SendSource = "lightning" | "onchain"; // const TEST_DEST = "bitcoin:tb1pdh43en28jmhnsrhxkusja46aufdlae5qnfrhucw5jvefw9flce3sdxfcwe?amount=0.00001&label=heyo&lightning=lntbs10u1pjrwrdedq8dpjhjmcnp4qd60w268ve0jencwzhz048ruprkxefhj0va2uspgj4q42azdg89uupp5gngy2pqte5q5uvnwcxwl2t8fsdlla5s6xl8aar4xcsvxeus2w2pqsp5n5jp3pz3vpu92p3uswttxmw79a5lc566herwh3f2amwz2sp6f9tq9qyysgqcqpcxqrpwugv5m534ww5ukcf6sdw2m75f2ntjfh3gzeqay649256yvtecgnhjyugf74zakaf56sdh66ec9fqep2kvu6xv09gcwkv36rrkm38ylqsgpw3yfjl" // const TEST_DEST_ADDRESS = "tb1pdh43en28jmhnsrhxkusja46aufdlae5qnfrhucw5jvefw9flce3sdxfcwe" // TODO: better success / fail type -type SentDetails = { amount?: bigint, destination?: string, txid?: string, failure_reason?: string } +type SentDetails = { + amount?: bigint; + destination?: string; + txid?: string; + failure_reason?: string; +}; -function MethodChooser(props: { source: SendSource, setSource: (source: string) => void, both?: boolean }) { - const [store, _actions] = useMegaStore(); +export function MethodChooser(props: { + source: SendSource; + setSource: (source: string) => void; + both?: boolean; +}) { + const [store, _actions] = useMegaStore(); - const methods = createMemo(() => { - return [ - { value: "lightning", label: "Lightning Balance", caption: store.balance?.lightning ? `${store.balance?.lightning.toLocaleString()} SATS` : "No balance" }, - { value: "onchain", label: "On-chain Balance", caption: store.balance?.confirmed ? `${store.balance?.confirmed.toLocaleString()} SATS` : "No balance" } - ] - - }) - return ( - - - - - - - - - - - - ) + const methods = createMemo(() => { + return [ + { + value: "lightning", + label: "Lightning Balance", + caption: store.balance?.lightning + ? `${store.balance?.lightning.toLocaleString()} SATS` + : "No balance" + }, + { + value: "onchain", + label: "On-chain Balance", + caption: store.balance?.confirmed + ? `${store.balance?.confirmed.toLocaleString()} SATS` + : "No balance" + } + ]; + }); + return ( + + + + + + + + + + + + ); } function DestinationInput(props: { - fieldDestination: string, - setFieldDestination: (destination: string) => void, - handleDecode: () => void, - handlePaste: () => void, + fieldDestination: string; + setFieldDestination: (destination: string) => void; + handleDecode: () => void; + handlePaste: () => void; }) { - return ( - - Destination -