mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2025-12-19 15:24:25 +01:00
peer connect modal with Dismiss
This commit is contained in:
4
.env
4
.env
@@ -1,3 +1,3 @@
|
|||||||
VITE_NETWORK="regtest"
|
VITE_NETWORK="signet"
|
||||||
VITE_PROXY="wss://p.mutinywallet.com"
|
VITE_PROXY="wss://p.mutinywallet.com"
|
||||||
VITE_ESPLORA="http://localhost:3003"
|
VITE_ESPLORA="https://mutinynet.com/api"
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
"class-variance-authority": "^0.4.0",
|
"class-variance-authority": "^0.4.0",
|
||||||
"nostr-tools": "^1.8.2",
|
"nostr-tools": "^1.8.2",
|
||||||
"qr-scanner": "^1.4.2",
|
"qr-scanner": "^1.4.2",
|
||||||
|
"solid-dismiss": "^1.7.11",
|
||||||
"solid-js": "^1.7.2",
|
"solid-js": "^1.7.2",
|
||||||
"solid-qr-code": "^0.0.8",
|
"solid-qr-code": "^0.0.8",
|
||||||
"solid-start": "^0.2.26",
|
"solid-start": "^0.2.26",
|
||||||
|
|||||||
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
@@ -25,6 +25,9 @@ dependencies:
|
|||||||
qr-scanner:
|
qr-scanner:
|
||||||
specifier: ^1.4.2
|
specifier: ^1.4.2
|
||||||
version: 1.4.2
|
version: 1.4.2
|
||||||
|
solid-dismiss:
|
||||||
|
specifier: ^1.7.11
|
||||||
|
version: 1.7.11(solid-js@1.7.2)
|
||||||
solid-js:
|
solid-js:
|
||||||
specifier: ^1.7.2
|
specifier: ^1.7.2
|
||||||
version: 1.7.2
|
version: 1.7.2
|
||||||
@@ -4387,6 +4390,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
/solid-dismiss@1.7.11(solid-js@1.7.2):
|
||||||
|
resolution: {integrity: sha512-JO05u/6Y/s+Is33Hyw4pzTRaTiUG7z3UGqpLY36JaHu9CmUSr7+8IJj6Rp/n8YpIPhjvzmCnMa6HTAZYLbfowA==}
|
||||||
|
peerDependencies:
|
||||||
|
solid-js: '1'
|
||||||
|
dependencies:
|
||||||
|
solid-js: 1.7.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/solid-js@1.7.2:
|
/solid-js@1.7.2:
|
||||||
resolution: {integrity: sha512-01f8GIc+HTTlfDXtK+TFku3AllHyJ3hNsIpxM2qpObRP4VbEGVIP6VbULnThPlpse+J1y/I/1N9QeQ9MNkE8Ow==}
|
resolution: {integrity: sha512-01f8GIc+HTTlfDXtK+TFku3AllHyJ3hNsIpxM2qpObRP4VbEGVIP6VbULnThPlpse+J1y/I/1N9QeQ9MNkE8Ow==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@@ -3,9 +3,13 @@ import { Motion, Presence } from "@motionone/solid";
|
|||||||
|
|
||||||
import logo from '~/assets/icons/mutiny-logo.svg';
|
import logo from '~/assets/icons/mutiny-logo.svg';
|
||||||
import send from '~/assets/icons/send.svg';
|
import send from '~/assets/icons/send.svg';
|
||||||
import BalanceBox from "./BalanceBox";
|
import BalanceBox from "~/components/BalanceBox";
|
||||||
import SafeArea from "./SafeArea";
|
import SafeArea from "~/components/SafeArea";
|
||||||
import NavBar from "./NavBar";
|
import NavBar from "~/components/NavBar";
|
||||||
|
import Card from "~/components/Card";
|
||||||
|
import { Button, ButtonLink } from "~/components/Button";
|
||||||
|
import Modal from "./Modal";
|
||||||
|
import PeerConnectModal from "./PeerConnectModal";
|
||||||
|
|
||||||
// TODO: use this reload prompt for real
|
// TODO: use this reload prompt for real
|
||||||
// import ReloadPrompt from "./Reload";
|
// import ReloadPrompt from "./Reload";
|
||||||
@@ -33,30 +37,11 @@ export default function App() {
|
|||||||
</header>
|
</header>
|
||||||
{/* <ReloadPrompt /> */}
|
{/* <ReloadPrompt /> */}
|
||||||
<BalanceBox />
|
<BalanceBox />
|
||||||
<div class='rounded-xl p-4 flex flex-col gap-2 bg-[rgba(0,0,0,0.5)]'>
|
<Card title="Kitchen Sink">
|
||||||
<header class='text-sm font-semibold uppercase'>
|
<PeerConnectModal />
|
||||||
Activity
|
<ButtonLink target="_blank" rel="noopener noreferrer" href="https://faucet.mutinynet.com/?address=abc123">Tap the Faucet</ButtonLink>
|
||||||
</header>
|
</Card>
|
||||||
<For each={[1, 2, 3, 4]}>
|
|
||||||
{() =>
|
|
||||||
<Presence>
|
|
||||||
<Motion
|
|
||||||
initial={{ opacity: 0, scaleY: 0 }}
|
|
||||||
animate={{ opacity: 1, scaleY: 1 }}
|
|
||||||
exit={{ opacity: 0, scaleY: 0 }}
|
|
||||||
transition={{ duration: 0.3 }}
|
|
||||||
>
|
|
||||||
<ActivityItem />
|
|
||||||
</Motion>
|
|
||||||
</Presence>
|
|
||||||
}
|
|
||||||
</For>
|
|
||||||
<div class='flex justify-end py-4'>
|
|
||||||
<a href="#" class='underline text-sm'>
|
|
||||||
MORE
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* safety div */}
|
{/* safety div */}
|
||||||
<div class="h-32" />
|
<div class="h-32" />
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ function prettyPrintAmount(n?: number | bigint): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function prettyPrintBalance(b: MutinyBalance): string {
|
function prettyPrintBalance(b: MutinyBalance): string {
|
||||||
return prettyPrintAmount(b.confirmed.valueOf() + b.lightning.valueOf())
|
return prettyPrintAmount(b.confirmed.valueOf() + b.lightning.valueOf() + b.unconfirmed.valueOf())
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BalanceBox() {
|
export default function BalanceBox() {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { cva, VariantProps } from "class-variance-authority";
|
import { cva, VariantProps } from "class-variance-authority";
|
||||||
import { children, JSX, ParentComponent, splitProps } from "solid-js";
|
import { children, JSX, ParentComponent, splitProps } from "solid-js";
|
||||||
|
import { Dynamic } from "solid-js/web";
|
||||||
import { A } from "solid-start";
|
import { A } from "solid-start";
|
||||||
|
|
||||||
const button = cva(["p-4", "rounded-xl", "text-xl", "font-semibold"], {
|
const button = cva(["p-4", "rounded-xl", "text-xl", "font-semibold"], {
|
||||||
@@ -23,7 +24,6 @@ const button = cva(["p-4", "rounded-xl", "text-xl", "font-semibold"], {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Help from https://github.com/arpadgabor/credee/blob/main/packages/www/src/components/ui/button.tsx
|
// Help from https://github.com/arpadgabor/credee/blob/main/packages/www/src/components/ui/button.tsx
|
||||||
|
|
||||||
type StyleProps = VariantProps<typeof button>
|
type StyleProps = VariantProps<typeof button>
|
||||||
@@ -49,15 +49,20 @@ export const Button: ParentComponent<ButtonProps> = props => {
|
|||||||
|
|
||||||
interface ButtonLinkProps extends JSX.ButtonHTMLAttributes<HTMLAnchorElement>, StyleProps {
|
interface ButtonLinkProps extends JSX.ButtonHTMLAttributes<HTMLAnchorElement>, StyleProps {
|
||||||
href: string
|
href: string
|
||||||
|
target?: string
|
||||||
|
rel?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ButtonLink: ParentComponent<ButtonLinkProps> = props => {
|
export const ButtonLink: ParentComponent<ButtonLinkProps> = props => {
|
||||||
const slot = children(() => props.children)
|
const slot = children(() => props.children)
|
||||||
const [local, attrs] = splitProps(props, ['children', 'intent', 'layout', 'class', 'href'])
|
const [local, attrs] = splitProps(props, ['children', 'intent', 'layout', 'class', 'href', 'target', 'rel'])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<A
|
<Dynamic
|
||||||
|
component={local.href?.includes('://') ? 'a' : A}
|
||||||
href={local.href}
|
href={local.href}
|
||||||
|
target={local.target}
|
||||||
|
rel={local.rel}
|
||||||
{...attrs}
|
{...attrs}
|
||||||
class={button({
|
class={button({
|
||||||
class: `flex justify-center no-underline ${local.class || ""}`,
|
class: `flex justify-center no-underline ${local.class || ""}`,
|
||||||
@@ -66,6 +71,6 @@ export const ButtonLink: ParentComponent<ButtonLinkProps> = props => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{slot()}
|
{slot()}
|
||||||
</A>
|
</Dynamic>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
13
src/components/Card.tsx
Normal file
13
src/components/Card.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { ParentComponent } from "solid-js"
|
||||||
|
|
||||||
|
const Card: ParentComponent<{ title?: string }> = (props) => {
|
||||||
|
return (
|
||||||
|
<div class='rounded-xl p-4 flex flex-col gap-2 bg-[rgba(0,0,0,0.5)]'>
|
||||||
|
{props.title && <header class='text-sm font-semibold uppercase'>{props.title}</header>}
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Card
|
||||||
59
src/components/Modal.tsx
Normal file
59
src/components/Modal.tsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { ParentComponent, createSignal } from "solid-js";
|
||||||
|
import Dismiss from "solid-dismiss";
|
||||||
|
import { Motion, Presence } from "@motionone/solid";
|
||||||
|
import { Button } from "./Button";
|
||||||
|
|
||||||
|
const ModalToggleScrollbar: ParentComponent = (props) => {
|
||||||
|
const [open, setOpen] = createSignal(false);
|
||||||
|
let btnEl!: HTMLButtonElement;
|
||||||
|
let btnSaveEl!: HTMLButtonElement;
|
||||||
|
|
||||||
|
const onClickClose = () => {
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClickOverlay = (e: Event) => {
|
||||||
|
if (e.target !== e.currentTarget) return;
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: scrollbar toggle is a think if we're experiencing visual jank
|
||||||
|
// https://github.com/aquaductape/solid-dismiss/blob/main/demo/src/components/Examples/ModalToggleScrollbar.tsx
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button ref={btnEl}>
|
||||||
|
Show Peer Connect Info
|
||||||
|
</Button>
|
||||||
|
<Dismiss
|
||||||
|
menuButton={btnEl}
|
||||||
|
open={open}
|
||||||
|
setOpen={setOpen}
|
||||||
|
modal
|
||||||
|
focusElementOnOpen={() => btnSaveEl}
|
||||||
|
>
|
||||||
|
<Presence>
|
||||||
|
<Motion
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
transition={{ duration: 0.2 }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class={"fixed top-0 left-0 w-full h-full flex justify-center items-center z-50 bg-black/50"}
|
||||||
|
onClick={onClickOverlay}
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
|
<div class={"relative w-[80vw] max-w-[800px] p-4 bg-gray shadow-xl rounded-xl border border-white"} role="dialog" aria-modal="true" tabindex="-1">
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Motion>
|
||||||
|
</Presence>
|
||||||
|
</Dismiss >
|
||||||
|
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModalToggleScrollbar;
|
||||||
19
src/components/PeerConnectModal.tsx
Normal file
19
src/components/PeerConnectModal.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { QRCodeSVG } from "solid-qr-code";
|
||||||
|
import Modal from "./Modal";
|
||||||
|
import Card from "./Card";
|
||||||
|
|
||||||
|
export default function PeerConnectModal() {
|
||||||
|
const connectString = "mutiny:02a91f8d620f5635a65a5f0cf51279ad9f73fd30f1bfdb4739342deddfba32fb7d@p.mutinywallet.com"
|
||||||
|
return (
|
||||||
|
<Modal>
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="w-full bg-white rounded-xl">
|
||||||
|
<QRCodeSVG value={connectString} class="w-full h-full p-8 max-h-[400px]" />
|
||||||
|
</div>
|
||||||
|
<Card>
|
||||||
|
<code class="break-all">{connectString}</code>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user