mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2026-01-04 14:54:24 +01:00
settings reorg
This commit is contained in:
5
src/assets/icons/forward.svg
Normal file
5
src/assets/icons/forward.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="icons">
|
||||
<path id="Vector" d="M10 17L15 12L10 7" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 244 B |
@@ -1,5 +1,5 @@
|
||||
import { Show } from "solid-js";
|
||||
import { Button, FancyCard, Hr, Indicator } from "~/components/layout";
|
||||
import { Button, FancyCard, Indicator } from "~/components/layout";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { Amount } from "./Amount";
|
||||
import { A, useNavigate } from "solid-start";
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { Hr, Button, InnerCard, VStack } from "~/components/layout";
|
||||
import NostrWalletConnectModal from "~/components/NostrWalletConnectModal";
|
||||
import {
|
||||
For,
|
||||
Match,
|
||||
@@ -16,10 +15,8 @@ import mempoolTxUrl from "~/utils/mempoolTxUrl";
|
||||
import eify from "~/utils/eify";
|
||||
import { ConfirmDialog } from "~/components/Dialog";
|
||||
import { showToast } from "~/components/Toaster";
|
||||
import { ImportExport } from "~/components/ImportExport";
|
||||
import { Network } from "~/logic/mutinyWalletSetup";
|
||||
import { ExternalLink } from "./layout/ExternalLink";
|
||||
import { Logs } from "./Logs";
|
||||
import { Restart } from "./Restart";
|
||||
import { ResyncOnchain } from "./ResyncOnchain";
|
||||
import { MiniStringShower } from "./DetailsModal";
|
||||
@@ -399,53 +396,6 @@ function OpenChannel(props: { refetchChannels: RefetchChannelsListType }) {
|
||||
);
|
||||
}
|
||||
|
||||
function LnUrlAuth() {
|
||||
const [state, _] = useMegaStore();
|
||||
|
||||
const [value, setValue] = createSignal("");
|
||||
|
||||
const onSubmit = async (e: SubmitEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
const lnurl = value().trim();
|
||||
await state.mutiny_wallet?.lnurl_auth(0, lnurl);
|
||||
|
||||
setValue("");
|
||||
};
|
||||
|
||||
return (
|
||||
<InnerCard>
|
||||
<form class="flex flex-col gap-4" onSubmit={onSubmit}>
|
||||
<TextField.Root
|
||||
value={value()}
|
||||
onChange={setValue}
|
||||
validationState={
|
||||
value() == "" ||
|
||||
value().toLowerCase().startsWith("lnurl")
|
||||
? "valid"
|
||||
: "invalid"
|
||||
}
|
||||
class="flex flex-col gap-4"
|
||||
>
|
||||
<TextField.Label class="text-sm font-semibold uppercase">
|
||||
LNURL Auth
|
||||
</TextField.Label>
|
||||
<TextField.Input
|
||||
class="w-full p-2 rounded-lg text-black"
|
||||
placeholder="LNURL..."
|
||||
/>
|
||||
<TextField.ErrorMessage class="text-red-500">
|
||||
Expecting something like LNURL...
|
||||
</TextField.ErrorMessage>
|
||||
</TextField.Root>
|
||||
<Button layout="small" type="submit">
|
||||
Auth
|
||||
</Button>
|
||||
</form>
|
||||
</InnerCard>
|
||||
);
|
||||
}
|
||||
|
||||
function ListNodes() {
|
||||
const [state, _] = useMegaStore();
|
||||
|
||||
@@ -470,24 +420,16 @@ function ListNodes() {
|
||||
export default function KitchenSink() {
|
||||
return (
|
||||
<>
|
||||
<Logs />
|
||||
<Hr />
|
||||
<ListNodes />
|
||||
<Hr />
|
||||
<NostrWalletConnectModal />
|
||||
<Hr />
|
||||
<PeersList />
|
||||
<Hr />
|
||||
<ChannelsList />
|
||||
<Hr />
|
||||
<LnUrlAuth />
|
||||
<Hr />
|
||||
<ResyncOnchain />
|
||||
<Hr />
|
||||
<Restart />
|
||||
<Hr />
|
||||
<ImportExport />
|
||||
<Hr />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
import { Show, createResource } from "solid-js";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { Card, NiceP, SmallHeader, TinyText, VStack } from "./layout";
|
||||
import { AmountSmall } from "./Amount";
|
||||
|
||||
function BalanceBar(props: { inbound: number; outbound: number }) {
|
||||
return (
|
||||
<VStack smallgap>
|
||||
<div class="flex justify-between">
|
||||
<SmallHeader>Outbound</SmallHeader>
|
||||
<SmallHeader>Inbound</SmallHeader>
|
||||
</div>
|
||||
<div class="flex gap-1 w-full">
|
||||
<div
|
||||
class="bg-m-green p-2 rounded-l-xl min-w-fit"
|
||||
style={{
|
||||
"flex-grow": props.outbound || 1
|
||||
}}
|
||||
>
|
||||
<AmountSmall amountSats={props.outbound} />
|
||||
</div>
|
||||
<div
|
||||
class="bg-m-blue p-2 rounded-r-xl min-w-fit"
|
||||
style={{
|
||||
"flex-grow": props.inbound || 1
|
||||
}}
|
||||
>
|
||||
<AmountSmall amountSats={props.inbound} />
|
||||
</div>
|
||||
</div>
|
||||
</VStack>
|
||||
);
|
||||
}
|
||||
|
||||
export function LiquidityMonitor() {
|
||||
const [state, _actions] = useMegaStore();
|
||||
|
||||
const [channelInfo] = createResource(async () => {
|
||||
try {
|
||||
const channels = await state.mutiny_wallet?.list_channels();
|
||||
let inbound = 0n;
|
||||
|
||||
for (const channel of channels) {
|
||||
inbound =
|
||||
inbound +
|
||||
BigInt(channel.size) -
|
||||
BigInt(channel.balance + channel.reserve);
|
||||
}
|
||||
|
||||
return { inbound, channelCount: channels?.length };
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return { inbound: 0, channelCount: 0 };
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Show when={channelInfo()?.channelCount}>
|
||||
<Card>
|
||||
<NiceP>
|
||||
You have {channelInfo()?.channelCount} lightning{" "}
|
||||
{channelInfo()?.channelCount === 1 ? "channel" : "channels"}
|
||||
.
|
||||
</NiceP>{" "}
|
||||
<BalanceBar
|
||||
inbound={Number(channelInfo()?.inbound) || 0}
|
||||
outbound={Number(state.balance?.lightning) || 0}
|
||||
/>
|
||||
<TinyText>
|
||||
Outbound is the amount of money you can spend on lightning.
|
||||
Inbound is the amount you can receive without incurring a
|
||||
lightning service fee.
|
||||
</TinyText>
|
||||
</Card>
|
||||
</Show>
|
||||
);
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
import { QRCodeSVG } from "solid-qr-code";
|
||||
import { As, Dialog } from "@kobalte/core";
|
||||
import { Button, Card, InnerCard, NiceP } from "~/components/layout";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { createResource, Show } from "solid-js";
|
||||
|
||||
const OVERLAY = "fixed inset-0 z-50 bg-black/50 backdrop-blur-sm";
|
||||
const DIALOG_POSITIONER = "fixed inset-0 z-50 flex items-center justify-center";
|
||||
const DIALOG_CONTENT =
|
||||
"w-[80vw] max-w-[400px] max-h-[100dvh] overflow-y-auto disable-scrollbars p-4 bg-gray/50 backdrop-blur-md shadow-xl rounded-xl border border-white/10";
|
||||
const SMALL_HEADER = "text-sm font-semibold uppercase";
|
||||
|
||||
export default function NostrWalletConnectModal() {
|
||||
const [state, actions] = useMegaStore();
|
||||
|
||||
const getConnectionURI = () => {
|
||||
if (state.mutiny_wallet) {
|
||||
return state.mutiny_wallet.get_nwc_uri();
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const [connectionURI] = createResource(getConnectionURI);
|
||||
|
||||
const toggleNwc = async () => {
|
||||
if (state.nwc_enabled) {
|
||||
actions.setNwc(false);
|
||||
window.location.reload();
|
||||
} else {
|
||||
actions.setNwc(true);
|
||||
const nodes = await state.mutiny_wallet?.list_nodes();
|
||||
const firstNode = (nodes[0] as string) || "";
|
||||
await state.mutiny_wallet?.start_nostr_wallet_connect(firstNode);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: a lot of this markup is probably reusable as a "Modal" component
|
||||
return (
|
||||
<InnerCard title="Nostr Wallet Connect">
|
||||
<NiceP>Test out some nostr stuff.</NiceP>
|
||||
<div />
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger asChild>
|
||||
<As component={Button}>Show Nostr Wallet Connect URI</As>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay class={OVERLAY} />
|
||||
<div class={DIALOG_POSITIONER}>
|
||||
<Dialog.Content class={DIALOG_CONTENT}>
|
||||
<div class="flex justify-between mb-2">
|
||||
<Dialog.Title class={SMALL_HEADER}>
|
||||
Nostr Wallet Connect
|
||||
</Dialog.Title>
|
||||
<Dialog.CloseButton class="dialog__close-button">
|
||||
<code>X</code>
|
||||
</Dialog.CloseButton>
|
||||
</div>
|
||||
<Dialog.Description class="flex flex-col gap-4">
|
||||
<Show when={connectionURI()}>
|
||||
<div class="w-full bg-white rounded-xl">
|
||||
<QRCodeSVG
|
||||
value={connectionURI() || ""}
|
||||
class="w-full h-full p-8 max-h-[400px]"
|
||||
/>
|
||||
</div>
|
||||
<Card>
|
||||
<code class="break-all">
|
||||
{connectionURI() || ""}
|
||||
</code>
|
||||
</Card>
|
||||
</Show>
|
||||
<Button onClick={toggleNwc}>
|
||||
{state.nwc_enabled ? "Disable" : "Enable"}
|
||||
</Button>
|
||||
</Dialog.Description>
|
||||
</Dialog.Content>
|
||||
</div>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
||||
</InnerCard>
|
||||
);
|
||||
}
|
||||
@@ -83,7 +83,7 @@ export function OnboardWarning() {
|
||||
intent="blue"
|
||||
layout="xs"
|
||||
class="self-auto"
|
||||
href="/backup"
|
||||
href="/settings/backup"
|
||||
>
|
||||
Backup
|
||||
</ButtonLink>
|
||||
|
||||
@@ -60,6 +60,22 @@ export const FancyCard: ParentComponent<{
|
||||
);
|
||||
};
|
||||
|
||||
export const SettingsCard: ParentComponent<{
|
||||
title?: string;
|
||||
}> = (props) => {
|
||||
return (
|
||||
<VStack smallgap>
|
||||
<div class="mt-2 pl-4">
|
||||
<SmallHeader>{props.title}</SmallHeader>
|
||||
</div>
|
||||
<div class="rounded-xl py-4 flex flex-col gap-2 bg-m-grey-800 w-full">
|
||||
{props.children}
|
||||
</div>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export const SafeArea: ParentComponent = (props) => {
|
||||
return (
|
||||
<div class="h-[100dvh] safe-left safe-right">
|
||||
|
||||
@@ -12,8 +12,6 @@ import {
|
||||
} from "~/components/layout";
|
||||
import { BackLink } from "~/components/layout/BackLink";
|
||||
import { CombinedActivity } from "~/components/Activity";
|
||||
import { A } from "solid-start";
|
||||
import settings from "~/assets/icons/settings.svg";
|
||||
import { Tabs } from "@kobalte/core";
|
||||
import { gradientsPerContact } from "~/utils/gradientHash";
|
||||
import { ContactEditor } from "~/components/ContactEditor";
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
import {
|
||||
ButtonLink,
|
||||
Card,
|
||||
DefaultMain,
|
||||
LargeHeader,
|
||||
MutinyWalletGuard,
|
||||
NiceP,
|
||||
SafeArea,
|
||||
VStack
|
||||
} from "~/components/layout";
|
||||
import { BackLink } from "~/components/layout/BackLink";
|
||||
import NavBar from "~/components/NavBar";
|
||||
import { SeedWords } from "~/components/SeedWords";
|
||||
import { SettingsStringsEditor } from "~/components/SettingsStringsEditor";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { LiquidityMonitor } from "~/components/LiquidityMonitor";
|
||||
import { A } from "solid-start";
|
||||
import { Suspense } from "solid-js";
|
||||
|
||||
export default function Settings() {
|
||||
const [store, _actions] = useMegaStore();
|
||||
|
||||
return (
|
||||
<MutinyWalletGuard>
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<BackLink />
|
||||
<LargeHeader>Settings</LargeHeader>
|
||||
<VStack biggap>
|
||||
<LiquidityMonitor />
|
||||
<Card title="Backup your seed words">
|
||||
<VStack>
|
||||
<NiceP>
|
||||
These 12 words allow you to recover your
|
||||
on-chain funds in case you lose your device
|
||||
or clear your browser storage.
|
||||
</NiceP>
|
||||
<SeedWords
|
||||
words={
|
||||
store.mutiny_wallet?.show_seed() || ""
|
||||
}
|
||||
/>
|
||||
</VStack>
|
||||
</Card>
|
||||
<SettingsStringsEditor />
|
||||
<Card title="Emergency Kit">
|
||||
<NiceP>
|
||||
Having some serious problems with your wallet?
|
||||
Check out the{" "}
|
||||
<A href="/emergencykit">emergency kit.</A>
|
||||
</NiceP>
|
||||
</Card>
|
||||
<Card title="If you know what you're doing">
|
||||
<VStack>
|
||||
<NiceP>
|
||||
We have some not-very-pretty debug tools we
|
||||
use to test the wallet. Use wisely!
|
||||
</NiceP>
|
||||
<div class="flex justify-center">
|
||||
<ButtonLink href="/admin" layout="xs">
|
||||
Secret Debug Tools
|
||||
</ButtonLink>
|
||||
</div>
|
||||
</VStack>
|
||||
</Card>
|
||||
</VStack>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
</MutinyWalletGuard>
|
||||
);
|
||||
}
|
||||
@@ -35,7 +35,7 @@ export default function Admin() {
|
||||
</div>
|
||||
</VStack>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="none" />
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
</MutinyWalletGuard>
|
||||
);
|
||||
@@ -49,7 +49,7 @@ function Quiz(props: { setHasCheckedAll: (hasChecked: boolean) => void }) {
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
export default function Backup() {
|
||||
const [store, actions] = useMegaStore();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -65,7 +65,7 @@ export default function App() {
|
||||
<MutinyWalletGuard>
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<BackLink />
|
||||
<BackLink href="/settings" title="Settings" />
|
||||
<LargeHeader>Backup</LargeHeader>
|
||||
|
||||
<VStack>
|
||||
@@ -98,7 +98,7 @@ export default function App() {
|
||||
</Button>
|
||||
</VStack>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="none" />
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
</MutinyWalletGuard>
|
||||
);
|
||||
115
src/routes/settings/Channels.tsx
Normal file
115
src/routes/settings/Channels.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
import { Match, Switch, createResource } from "solid-js";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import {
|
||||
Card,
|
||||
DefaultMain,
|
||||
LargeHeader,
|
||||
MutinyWalletGuard,
|
||||
NiceP,
|
||||
SafeArea,
|
||||
SmallHeader,
|
||||
TinyText,
|
||||
VStack
|
||||
} from "~/components/layout";
|
||||
import { AmountSmall } from "~/components/Amount";
|
||||
import { BackLink } from "~/components/layout/BackLink";
|
||||
import NavBar from "~/components/NavBar";
|
||||
|
||||
function BalanceBar(props: { inbound: number; outbound: number }) {
|
||||
return (
|
||||
<VStack smallgap>
|
||||
<div class="flex justify-between">
|
||||
<SmallHeader>Outbound</SmallHeader>
|
||||
<SmallHeader>Inbound</SmallHeader>
|
||||
</div>
|
||||
<div class="flex gap-1 w-full">
|
||||
<div
|
||||
class="bg-m-green p-2 rounded-l-xl min-w-fit"
|
||||
style={{
|
||||
"flex-grow": props.outbound || 1
|
||||
}}
|
||||
>
|
||||
<AmountSmall amountSats={props.outbound} />
|
||||
</div>
|
||||
<div
|
||||
class="bg-m-blue p-2 rounded-r-xl min-w-fit"
|
||||
style={{
|
||||
"flex-grow": props.inbound || 1
|
||||
}}
|
||||
>
|
||||
<AmountSmall amountSats={props.inbound} />
|
||||
</div>
|
||||
</div>
|
||||
</VStack>
|
||||
);
|
||||
}
|
||||
|
||||
export function LiquidityMonitor() {
|
||||
const [state, _actions] = useMegaStore();
|
||||
|
||||
const [channelInfo] = createResource(async () => {
|
||||
try {
|
||||
const channels = await state.mutiny_wallet?.list_channels();
|
||||
let inbound = 0n;
|
||||
|
||||
for (const channel of channels) {
|
||||
inbound =
|
||||
inbound +
|
||||
BigInt(channel.size) -
|
||||
BigInt(channel.balance + channel.reserve);
|
||||
}
|
||||
|
||||
return { inbound, channelCount: channels?.length };
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return { inbound: 0, channelCount: 0 };
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Match when={channelInfo()?.channelCount}>
|
||||
<Card>
|
||||
<NiceP>
|
||||
You have {channelInfo()?.channelCount} lightning{" "}
|
||||
{channelInfo()?.channelCount === 1
|
||||
? "channel"
|
||||
: "channels"}
|
||||
.
|
||||
</NiceP>{" "}
|
||||
<BalanceBar
|
||||
inbound={Number(channelInfo()?.inbound) || 0}
|
||||
outbound={Number(state.balance?.lightning) || 0}
|
||||
/>
|
||||
<TinyText>
|
||||
Outbound is the amount of money you can spend on
|
||||
lightning. Inbound is the amount you can receive without
|
||||
incurring a lightning service fee.
|
||||
</TinyText>
|
||||
</Card>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<NiceP>
|
||||
It looks like you don't have any channels yet. To get
|
||||
started, receive some sats over lightning, or swap some
|
||||
on-chain funds into a channel. Get your hands dirty!
|
||||
</NiceP>
|
||||
</Match>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Channels() {
|
||||
return (
|
||||
<MutinyWalletGuard>
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<BackLink href="/settings" title="Settings" />
|
||||
<LargeHeader>Lightning Channels</LargeHeader>
|
||||
<LiquidityMonitor />
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
</MutinyWalletGuard>
|
||||
);
|
||||
}
|
||||
68
src/routes/settings/Connections.tsx
Normal file
68
src/routes/settings/Connections.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import { Show, createMemo } from "solid-js";
|
||||
import { QRCodeSVG } from "solid-qr-code";
|
||||
import NavBar from "~/components/NavBar";
|
||||
import { ShareCard } from "~/components/ShareCard";
|
||||
import {
|
||||
Button,
|
||||
DefaultMain,
|
||||
LargeHeader,
|
||||
MutinyWalletGuard,
|
||||
NiceP,
|
||||
SafeArea
|
||||
} from "~/components/layout";
|
||||
import { BackLink } from "~/components/layout/BackLink";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
|
||||
export default function Connections() {
|
||||
const [state, actions] = useMegaStore();
|
||||
|
||||
const connectionURI = createMemo(() => {
|
||||
if (state.nwc_enabled) {
|
||||
return state.mutiny_wallet?.get_nwc_uri();
|
||||
}
|
||||
});
|
||||
|
||||
const toggleNwc = async () => {
|
||||
if (state.nwc_enabled) {
|
||||
actions.setNwc(false);
|
||||
window.location.reload();
|
||||
} else {
|
||||
actions.setNwc(true);
|
||||
const nodes = await state.mutiny_wallet?.list_nodes();
|
||||
const firstNode = (nodes[0] as string) || "";
|
||||
await state.mutiny_wallet?.start_nostr_wallet_connect(firstNode);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<MutinyWalletGuard>
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<BackLink href="/settings" title="Settings" />
|
||||
<LargeHeader>Wallet Connections</LargeHeader>
|
||||
<NiceP>
|
||||
Authorize Mutiny Wallet with external services like
|
||||
Nostr clients.
|
||||
</NiceP>
|
||||
|
||||
<Button onClick={toggleNwc}>
|
||||
{state.nwc_enabled
|
||||
? "Disable Nostr Wallet Connect"
|
||||
: "Enable Nostr Wallet Connect"}
|
||||
</Button>
|
||||
<Show when={connectionURI() && state.nwc_enabled}>
|
||||
<div class="w-full bg-white rounded-xl">
|
||||
<QRCodeSVG
|
||||
value={connectionURI() || ""}
|
||||
class="w-full h-full p-8 max-h-[400px]"
|
||||
/>
|
||||
</div>
|
||||
<ShareCard text={connectionURI() || ""} />
|
||||
</Show>
|
||||
<div class="h-full" />
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
</MutinyWalletGuard>
|
||||
);
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export default function EmergencyKit() {
|
||||
return (
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<BackLink />
|
||||
<BackLink href="/settings" title="Settings" />
|
||||
<LargeHeader>Emergency Kit</LargeHeader>
|
||||
<VStack>
|
||||
<NiceP>
|
||||
@@ -39,7 +39,7 @@ export default function EmergencyKit() {
|
||||
</div>
|
||||
</VStack>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="none" />
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
);
|
||||
}
|
||||
69
src/routes/settings/LnUrlAuth.tsx
Normal file
69
src/routes/settings/LnUrlAuth.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { TextField } from "@kobalte/core";
|
||||
import { createSignal } from "solid-js";
|
||||
import NavBar from "~/components/NavBar";
|
||||
import {
|
||||
Button,
|
||||
DefaultMain,
|
||||
InnerCard,
|
||||
LargeHeader,
|
||||
MutinyWalletGuard,
|
||||
SafeArea
|
||||
} from "~/components/layout";
|
||||
import { BackLink } from "~/components/layout/BackLink";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
|
||||
export default function LnUrlAuth() {
|
||||
const [state, _] = useMegaStore();
|
||||
|
||||
const [value, setValue] = createSignal("");
|
||||
|
||||
const onSubmit = async (e: SubmitEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
const lnurl = value().trim();
|
||||
await state.mutiny_wallet?.lnurl_auth(0, lnurl);
|
||||
|
||||
setValue("");
|
||||
};
|
||||
|
||||
return (
|
||||
<MutinyWalletGuard>
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<BackLink href="/settings" title="Settings" />
|
||||
<LargeHeader>LNURL Auth</LargeHeader>
|
||||
<InnerCard>
|
||||
<form class="flex flex-col gap-4" onSubmit={onSubmit}>
|
||||
<TextField.Root
|
||||
value={value()}
|
||||
onChange={setValue}
|
||||
validationState={
|
||||
value() == "" ||
|
||||
value().toLowerCase().startsWith("lnurl")
|
||||
? "valid"
|
||||
: "invalid"
|
||||
}
|
||||
class="flex flex-col gap-4"
|
||||
>
|
||||
<TextField.Label class="text-sm font-semibold uppercase">
|
||||
LNURL Auth
|
||||
</TextField.Label>
|
||||
<TextField.Input
|
||||
class="w-full p-2 rounded-lg text-black"
|
||||
placeholder="LNURL..."
|
||||
/>
|
||||
<TextField.ErrorMessage class="text-red-500">
|
||||
Expecting something like LNURL...
|
||||
</TextField.ErrorMessage>
|
||||
</TextField.Root>
|
||||
<Button layout="small" type="submit">
|
||||
Auth
|
||||
</Button>
|
||||
</form>
|
||||
</InnerCard>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
</MutinyWalletGuard>
|
||||
);
|
||||
}
|
||||
@@ -5,10 +5,20 @@ import {
|
||||
getExistingSettings,
|
||||
setAndGetMutinySettings
|
||||
} from "~/logic/mutinyWalletSetup";
|
||||
import { Button, Card, NiceP } from "~/components/layout";
|
||||
import { showToast } from "./Toaster";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
DefaultMain,
|
||||
LargeHeader,
|
||||
MutinyWalletGuard,
|
||||
NiceP,
|
||||
SafeArea
|
||||
} from "~/components/layout";
|
||||
import { showToast } from "~/components/Toaster";
|
||||
import eify from "~/utils/eify";
|
||||
import { ExternalLink } from "./layout/ExternalLink";
|
||||
import { ExternalLink } from "~/components/layout/ExternalLink";
|
||||
import { BackLink } from "~/components/layout/BackLink";
|
||||
import NavBar from "~/components/NavBar";
|
||||
|
||||
export function SettingsStringsEditor() {
|
||||
const existingSettings = getExistingSettings();
|
||||
@@ -107,3 +117,18 @@ export function SettingsStringsEditor() {
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Servers() {
|
||||
return (
|
||||
<MutinyWalletGuard>
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<BackLink href="/settings" title="Settings" />
|
||||
<LargeHeader>Backup</LargeHeader>
|
||||
<SettingsStringsEditor />
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
</MutinyWalletGuard>
|
||||
);
|
||||
}
|
||||
118
src/routes/settings/index.tsx
Normal file
118
src/routes/settings/index.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import {
|
||||
DefaultMain,
|
||||
LargeHeader,
|
||||
MutinyWalletGuard,
|
||||
SafeArea,
|
||||
SettingsCard,
|
||||
VStack
|
||||
} from "~/components/layout";
|
||||
import { BackLink } from "~/components/layout/BackLink";
|
||||
import NavBar from "~/components/NavBar";
|
||||
import { A } from "solid-start";
|
||||
import { For, Show } from "solid-js";
|
||||
import forward from "~/assets/icons/forward.svg";
|
||||
|
||||
function SettingsLinkList(props: {
|
||||
header: string;
|
||||
links: {
|
||||
href: string;
|
||||
text: string;
|
||||
caption?: string;
|
||||
accent?: "red" | "green";
|
||||
}[];
|
||||
}) {
|
||||
return (
|
||||
<SettingsCard title={props.header}>
|
||||
<For each={props.links}>
|
||||
{(link) => (
|
||||
<A
|
||||
href={link.href}
|
||||
class="no-underline flex w-full flex-col gap-1 py-2 hover:bg-m-grey-750 active:bg-m-grey-900 px-4 "
|
||||
>
|
||||
<div class="flex justify-between">
|
||||
<span
|
||||
classList={{
|
||||
"text-m-red": link.accent === "red",
|
||||
"text-m-green": link.accent === "green"
|
||||
}}
|
||||
>
|
||||
{link.text}
|
||||
</span>
|
||||
<img src={forward} alt="go" />
|
||||
</div>
|
||||
<Show when={link.caption}>
|
||||
<div class="text-sm text-m-grey-400">
|
||||
{link.caption}
|
||||
</div>
|
||||
</Show>
|
||||
</A>
|
||||
)}
|
||||
</For>
|
||||
</SettingsCard>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Settings() {
|
||||
return (
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<BackLink />
|
||||
<LargeHeader>Settings</LargeHeader>
|
||||
<VStack biggap>
|
||||
<SettingsLinkList
|
||||
header="General"
|
||||
links={[
|
||||
{
|
||||
href: "/settings/channels",
|
||||
text: "Lightning Channels"
|
||||
},
|
||||
{
|
||||
href: "/settings/backup",
|
||||
text: "Backup",
|
||||
accent: "green"
|
||||
},
|
||||
{
|
||||
href: "/settings/servers",
|
||||
text: "Servers",
|
||||
caption:
|
||||
"Don't trust us! Use your own servers to back Mutiny."
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<SettingsLinkList
|
||||
header="Beta Features"
|
||||
links={[
|
||||
{
|
||||
href: "/settings/connections",
|
||||
text: "Wallet Connections"
|
||||
},
|
||||
{
|
||||
href: "/settings/lnurlauth",
|
||||
text: "LNURL Auth"
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<SettingsLinkList
|
||||
header="Debug Tools"
|
||||
links={[
|
||||
{
|
||||
href: "/settings/emergencykit",
|
||||
text: "Emergency Kit",
|
||||
caption:
|
||||
"Diagnose and solve problems with your wallet."
|
||||
},
|
||||
{
|
||||
href: "/settings/admin",
|
||||
text: "Admin Page",
|
||||
caption:
|
||||
"Our internal debug tools. Use wisely!",
|
||||
accent: "red"
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</VStack>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user