mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2025-12-27 02:44:26 +01:00
lint extravaganza
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
import { LoadingSpinner, NiceP, SmallAmount, SmallHeader } from "./layout"
|
||||
import { LoadingSpinner, NiceP } from "./layout"
|
||||
import {
|
||||
For,
|
||||
Match,
|
||||
Show,
|
||||
Switch,
|
||||
createEffect,
|
||||
createMemo,
|
||||
@@ -11,9 +10,6 @@ import {
|
||||
} from "solid-js"
|
||||
import { useMegaStore } from "~/state/megaStore"
|
||||
import { MutinyInvoice } from "@mutinywallet/mutiny-wasm"
|
||||
import { JsonModal } from "~/components/JsonModal"
|
||||
import utxoIcon from "~/assets/icons/coin.svg"
|
||||
import { getRedshifted } from "~/utils/fakeLabels"
|
||||
import { ActivityItem } from "./ActivityItem"
|
||||
import { MutinyTagItem } from "~/utils/tags"
|
||||
import { Network } from "~/logic/mutinyWalletSetup"
|
||||
@@ -76,7 +72,7 @@ function OnChainItem(props: {
|
||||
}
|
||||
date={props.item.confirmation_time?.Confirmed?.time}
|
||||
positive={isReceive()}
|
||||
onClick={() => setOpen(!open())}
|
||||
onClick={() => setOpen(o => !o)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
@@ -96,52 +92,12 @@ function InvoiceItem(props: { item: MutinyInvoice; labels: MutinyTagItem[] }) {
|
||||
amount={props.item.amount_sats || 0n}
|
||||
date={props.item.last_updated}
|
||||
positive={!isSend()}
|
||||
onClick={() => setOpen(!open())}
|
||||
onClick={() => setOpen(o => !o)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function Utxo(props: { item: UtxoItem }) {
|
||||
const spent = createMemo(() => props.item.is_spent)
|
||||
|
||||
const [open, setOpen] = createSignal(false)
|
||||
|
||||
const redshifted = createMemo(() => getRedshifted(props.item.outpoint))
|
||||
|
||||
return (
|
||||
<>
|
||||
<JsonModal
|
||||
open={open()}
|
||||
data={props.item}
|
||||
title="Unspent Transaction Output"
|
||||
setOpen={setOpen}
|
||||
/>
|
||||
<div class={THREE_COLUMNS} onClick={() => setOpen(!open())}>
|
||||
<div class="flex items-center">
|
||||
<img src={utxoIcon} alt="coin" />
|
||||
</div>
|
||||
<div class={CENTER_COLUMN}>
|
||||
<div class="flex gap-2">
|
||||
<Show
|
||||
when={redshifted()}
|
||||
fallback={<h2 class={MISSING_LABEL}>Unknown</h2>}
|
||||
>
|
||||
<h2 class={REDSHIFT_LABEL}>Redshift</h2>
|
||||
</Show>
|
||||
</div>
|
||||
<SmallAmount amount={props.item.txout.value} />
|
||||
</div>
|
||||
<div class={RIGHT_COLUMN}>
|
||||
<SmallHeader class={spent() ? "text-m-red" : "text-m-green"}>
|
||||
{/* {spent() ? "SPENT" : "UNSPENT"} */}
|
||||
</SmallHeader>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
type ActivityItem = {
|
||||
type: "onchain" | "lightning"
|
||||
item: OnChainTx | MutinyInvoice
|
||||
|
||||
@@ -41,8 +41,8 @@ export const ActivityAmount: ParentComponent<{ amount: string, price: number, po
|
||||
function LabelCircle(props: { name?: string, contact: boolean }) {
|
||||
|
||||
// TODO: don't need to run this if it's not a contact
|
||||
const [gradient] = createResource(props.name, async (name: string) => {
|
||||
return generateGradient(name || "?")
|
||||
const [gradient] = createResource(async () => {
|
||||
return generateGradient(props.name || "?")
|
||||
})
|
||||
|
||||
const text = () => (props.contact && props.name && props.name.length) ? props.name[0] : (props.name && props.name.length) ? "≡" : "?"
|
||||
|
||||
@@ -57,10 +57,6 @@ function add(a: string, b?: string) {
|
||||
return Number(a || 0) + Number(b || 0);
|
||||
}
|
||||
|
||||
function subtract(a: string, b?: string) {
|
||||
return Number(a || 0) - Number(b || 0);
|
||||
}
|
||||
|
||||
export function AmountCard(props: {
|
||||
amountSats: string;
|
||||
fee?: string;
|
||||
|
||||
@@ -18,7 +18,7 @@ function SingleDigitButton(props: { character: string, onClick: (c: string) => v
|
||||
<Show when={props.fiat || !(props.character === ".")} fallback={<div />}>
|
||||
<button
|
||||
disabled={props.character === "."}
|
||||
class="disabled:opacity-50 p-2 rounded-lg hover:bg-white/10 active:bg-m-blue text-white text-4xl font-semi font-mono"
|
||||
class="disabled:opacity-50 p-2 rounded-lg md:hover:bg-white/10 active:bg-m-blue text-white text-4xl font-semi font-mono"
|
||||
onClick={() => props.onClick(props.character)}
|
||||
>
|
||||
{props.character}
|
||||
@@ -148,7 +148,7 @@ export const AmountEditable: ParentComponent<{ initialAmountSats: string, initia
|
||||
<Dialog.Content class={DIALOG_CONTENT} onEscapeKeyDown={() => setIsOpen(false)}>
|
||||
{/* TODO: figure out how to submit on enter */}
|
||||
<div class="w-full flex justify-end">
|
||||
<button tabindex="-1" onClick={() => setIsOpen(false)} class="hover:bg-white/10 rounded-lg active:bg-m-blue">
|
||||
<button onClick={() => setIsOpen(false)} class="hover:bg-white/10 rounded-lg active:bg-m-blue w-8 h-8">
|
||||
<img src={close} alt="Close" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import logo from '~/assets/icons/mutiny-logo.svg';
|
||||
import { DefaultMain, SafeArea, VStack, Card, LoadingSpinner } from "~/components/layout";
|
||||
import { DefaultMain, SafeArea, VStack, Card } from "~/components/layout";
|
||||
import BalanceBox, { LoadingShimmer } from "~/components/BalanceBox";
|
||||
import NavBar from "~/components/NavBar";
|
||||
import ReloadPrompt from "~/components/Reload";
|
||||
@@ -18,7 +18,7 @@ export default function App() {
|
||||
<DefaultMain>
|
||||
<header class="w-full flex justify-between items-center mt-4 mb-2">
|
||||
<img src={logo} class="h-10" alt="logo" />
|
||||
<A class="md:hidden p-2 hover:bg-white/5 rounded-lg active:bg-m-blue" href="/activity"><img src={userClock} alt="Activity" /></A>
|
||||
<A class="md:hidden p-2 hover:bg-white/5 rounded-lg active:bg-m-blue" href="/activity"><img src={userClock} alt="Activity" class="h-8 w-8" /></A>
|
||||
</header>
|
||||
<Show when={!state.wallet_loading}>
|
||||
<OnboardWarning />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Show, Suspense } from "solid-js";
|
||||
import { Button, ButtonLink, FancyCard, 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";
|
||||
@@ -15,10 +15,10 @@ function prettyPrintAmount(n?: number | bigint): string {
|
||||
export function LoadingShimmer() {
|
||||
return (<div class="flex flex-col gap-2 animate-pulse">
|
||||
<h1 class="text-4xl font-light">
|
||||
<div class="w-[12rem] rounded bg-neutral-700 h-[2.5rem]"></div>
|
||||
<div class="w-[12rem] rounded bg-neutral-700 h-[2.5rem]" />
|
||||
</h1>
|
||||
<h2 class="text-xl font-light text-white/70" >
|
||||
<div class="w-[8rem] rounded bg-neutral-700 h-[1.75rem]"></div>
|
||||
<div class="w-[8rem] rounded bg-neutral-700 h-[1.75rem]" />
|
||||
</h2>
|
||||
</div>)
|
||||
}
|
||||
@@ -26,7 +26,7 @@ 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();
|
||||
const [state, _actions] = useMegaStore();
|
||||
|
||||
const emptyBalance = () => (state.balance?.confirmed || 0n) === 0n && (state.balance?.lightning || 0n) === 0n
|
||||
|
||||
@@ -46,7 +46,7 @@ export default function BalanceBox(props: { loading?: boolean }) {
|
||||
<Amount amountSats={state.balance?.confirmed} showFiat />
|
||||
<div class="self-end justify-self-end">
|
||||
<A href="/swap" class={STYLE}>
|
||||
<img src={shuffle} alt="swap" />
|
||||
<img src={shuffle} alt="swap" class="h-8 w-8" />
|
||||
</A>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,11 +8,10 @@ import {
|
||||
Switch,
|
||||
createMemo,
|
||||
} from "solid-js"
|
||||
import { Hr, TinyButton, VStack } from "~/components/layout"
|
||||
import { Hr, ModalCloseButton, TinyButton, VStack } from "~/components/layout"
|
||||
import { MutinyInvoice } from "@mutinywallet/mutiny-wasm"
|
||||
import { OnChainTx } from "./Activity"
|
||||
|
||||
import close from "~/assets/icons/close.svg"
|
||||
import bolt from "~/assets/icons/bolt-black.svg"
|
||||
import chain from "~/assets/icons/chain-black.svg"
|
||||
import copyIcon from "~/assets/icons/copy.svg"
|
||||
@@ -27,9 +26,9 @@ import mempoolTxUrl from "~/utils/mempoolTxUrl"
|
||||
import { Network } from "~/logic/mutinyWalletSetup"
|
||||
import { AmountSmall } from "./Amount"
|
||||
|
||||
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 =
|
||||
export const OVERLAY = "fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"
|
||||
export const DIALOG_POSITIONER = "fixed inset-0 z-50 flex items-center justify-center"
|
||||
export const DIALOG_CONTENT =
|
||||
"max-w-[500px] w-[90vw] max-h-[100dvh] overflow-y-scroll disable-scrollbars mx-4 p-4 bg-neutral-800/80 backdrop-blur-md shadow-xl rounded-xl border border-white/10"
|
||||
|
||||
function LightningHeader(props: { info: MutinyInvoice }) {
|
||||
@@ -37,7 +36,7 @@ function LightningHeader(props: { info: MutinyInvoice }) {
|
||||
|
||||
const tags = createMemo(() => {
|
||||
if (props.info.labels.length) {
|
||||
let contact = state.mutiny_wallet?.get_contact(props.info.labels[0])
|
||||
const contact = state.mutiny_wallet?.get_contact(props.info.labels[0])
|
||||
if (contact) {
|
||||
return [tagToMutinyTag(contact)]
|
||||
} else {
|
||||
@@ -64,7 +63,9 @@ function LightningHeader(props: { info: MutinyInvoice }) {
|
||||
/>
|
||||
<For each={tags()}>
|
||||
{(tag) => (
|
||||
<TinyButton tag={tag} onClick={() => {}}>
|
||||
<TinyButton tag={tag} onClick={() => {
|
||||
// noop
|
||||
}}>
|
||||
{tag.name}
|
||||
</TinyButton>
|
||||
)}
|
||||
@@ -78,7 +79,7 @@ function OnchainHeader(props: { info: OnChainTx }) {
|
||||
|
||||
const tags = createMemo(() => {
|
||||
if (props.info.labels.length) {
|
||||
let contact = state.mutiny_wallet?.get_contact(props.info.labels[0])
|
||||
const contact = state.mutiny_wallet?.get_contact(props.info.labels[0])
|
||||
if (contact) {
|
||||
return [tagToMutinyTag(contact)]
|
||||
} else {
|
||||
@@ -117,7 +118,9 @@ function OnchainHeader(props: { info: OnChainTx }) {
|
||||
/>
|
||||
<For each={tags()}>
|
||||
{(tag) => (
|
||||
<TinyButton tag={tag} onClick={() => {}}>
|
||||
<TinyButton tag={tag} onClick={() => {
|
||||
// noop
|
||||
}}>
|
||||
{tag.name}
|
||||
</TinyButton>
|
||||
)}
|
||||
@@ -250,7 +253,7 @@ export function DetailsModal(props: {
|
||||
return (
|
||||
<Dialog.Root
|
||||
open={props.open}
|
||||
onOpenChange={(isOpen) => props.setOpen(isOpen)}
|
||||
onOpenChange={props.setOpen}
|
||||
>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay class={OVERLAY} />
|
||||
@@ -259,12 +262,7 @@ export function DetailsModal(props: {
|
||||
<div class="flex justify-between mb-2">
|
||||
<div />
|
||||
<Dialog.CloseButton>
|
||||
<button
|
||||
tabindex="-1"
|
||||
class="self-center hover:bg-white/10 rounded-lg active:bg-m-blue "
|
||||
>
|
||||
<img src={close} alt="Close" class="w-8 h-8" />
|
||||
</button>
|
||||
<ModalCloseButton />
|
||||
</Dialog.CloseButton>
|
||||
</div>
|
||||
<Dialog.Title>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Title } from "solid-start";
|
||||
import { Button, ButtonLink, DefaultMain, LargeHeader, SafeArea, SmallHeader } from "~/components/layout";
|
||||
import { Button, DefaultMain, LargeHeader, SafeArea, SmallHeader } from "~/components/layout";
|
||||
|
||||
export default function ErrorDisplay(props: { error: Error }) {
|
||||
return (
|
||||
|
||||
@@ -34,14 +34,16 @@ export function ImportExport() {
|
||||
reject(new Error("No text found in file"));
|
||||
}
|
||||
};
|
||||
fileReader.onerror = e => reject(new Error("File read error"));
|
||||
fileReader.onerror = _e => reject(new Error("File read error"));
|
||||
fileReader.readAsText(file, "UTF-8");
|
||||
});
|
||||
|
||||
// This should throw if there's a parse error, so we won't end up clearing
|
||||
JSON.parse(text);
|
||||
if (text) {
|
||||
JSON.parse(text);
|
||||
MutinyWallet.import_json(text);
|
||||
}
|
||||
|
||||
MutinyWallet.import_json(text);
|
||||
if (state.mutiny_wallet) {
|
||||
await state.mutiny_wallet.stop();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
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) => {
|
||||
|
||||
@@ -1,42 +1,36 @@
|
||||
import { Dialog } from "@kobalte/core";
|
||||
import { JSX, createMemo } from "solid-js";
|
||||
import { Button, SmallHeader } from "~/components/layout";
|
||||
import { useCopy } from "~/utils/useCopy";
|
||||
import { ModalCloseButton, SmallHeader } from "~/components/layout";
|
||||
import { DIALOG_CONTENT, DIALOG_POSITIONER, OVERLAY } from "~/components/DetailsModal";
|
||||
import { CopyButton } from "./ShareCard";
|
||||
|
||||
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 = "max-w-[600px] max-h-full mx-4 p-4 bg-neutral-900/50 backdrop-blur-md shadow-xl rounded-xl border border-white/10"
|
||||
|
||||
export function JsonModal(props: { title: string, open: boolean, data?: unknown, setOpen: (open: boolean) => void, children?: JSX.Element }) {
|
||||
const json = createMemo(() => JSON.stringify(props.data, null, 2));
|
||||
|
||||
const [copy, copied] = useCopy({ copiedTimeout: 1000 });
|
||||
export function JsonModal(props: { title: string, open: boolean, plaintext?: string, data?: unknown, setOpen: (open: boolean) => void, children?: JSX.Element }) {
|
||||
const json = createMemo(() => props.plaintext ? props.plaintext : JSON.stringify(props.data, null, 2));
|
||||
|
||||
return (
|
||||
<Dialog.Root open={props.open} onOpenChange={(isOpen) => props.setOpen(isOpen)}>
|
||||
<Dialog.Root open={props.open} onOpenChange={props.setOpen}>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay class={OVERLAY} />
|
||||
<div class={DIALOG_POSITIONER}>
|
||||
<Dialog.Content class={DIALOG_CONTENT}>
|
||||
<div class="flex justify-between mb-2">
|
||||
<div class="flex justify-between mb-2 items-center">
|
||||
<Dialog.Title>
|
||||
<SmallHeader>
|
||||
{props.title}
|
||||
</SmallHeader>
|
||||
</Dialog.Title>
|
||||
<Dialog.CloseButton>
|
||||
<code>X</code>
|
||||
<ModalCloseButton />
|
||||
</Dialog.CloseButton>
|
||||
</div>
|
||||
<Dialog.Description class="flex flex-col gap-4">
|
||||
<div class="bg-white/10 rounded-xl max-h-[50vh] overflow-y-scroll disable-scrollbars p-4">
|
||||
<Dialog.Description class="flex flex-col gap-4 items-center">
|
||||
<div class="bg-white/5 rounded-xl max-h-[50vh] overflow-y-scroll disable-scrollbars p-4">
|
||||
<pre class="whitespace-pre-wrap break-all">
|
||||
{json()}
|
||||
</pre>
|
||||
</div>
|
||||
{props.children}
|
||||
<Button onClick={(_) => copy(json() ?? "")}>{copied() ? "Copied" : "Copy"}</Button>
|
||||
<Button onClick={(_) => props.setOpen(false)}>Close</Button>
|
||||
<CopyButton title="Copy" text={json()} />
|
||||
</Dialog.Description>
|
||||
</Dialog.Content>
|
||||
</div>
|
||||
|
||||
@@ -7,13 +7,15 @@ export default function Scanner(props: { onResult: (result: string) => void }) {
|
||||
// TODO: not sure it's appropriate to use a signal for this but it works!
|
||||
const [scanner, setScanner] = createSignal<QrScanner | null>(null);
|
||||
|
||||
const handleResult = (result: { data: string }) => {
|
||||
props.onResult(result.data);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (container) {
|
||||
const newScanner = new QrScanner(
|
||||
container,
|
||||
(result: { data: string }) => {
|
||||
props.onResult(result.data);
|
||||
},
|
||||
handleResult,
|
||||
{
|
||||
returnDetailedScanResult: true,
|
||||
}
|
||||
|
||||
@@ -2,26 +2,26 @@ import type { Component } from 'solid-js'
|
||||
import { Show } from 'solid-js'
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { useRegisterSW } from 'virtual:pwa-register/solid'
|
||||
import { Button, Card } from '~/components/layout'
|
||||
|
||||
const ReloadPrompt: Component = () => {
|
||||
const {
|
||||
offlineReady: [offlineReady, setOfflineReady],
|
||||
needRefresh: [needRefresh, setNeedRefresh],
|
||||
updateServiceWorker,
|
||||
offlineReady: [offlineReady, _setOfflineReady],
|
||||
needRefresh: [needRefresh, _setNeedRefresh],
|
||||
updateServiceWorker: _update,
|
||||
} = useRegisterSW({
|
||||
onRegistered(r: ServiceWorkerRegistration) {
|
||||
console.log('SW Registered: ' + r.scope)
|
||||
immediate: true,
|
||||
onRegisteredSW(swUrl, r) {
|
||||
console.log('SW Registered: ' + r?.scope)
|
||||
},
|
||||
onRegisterError(error: Error) {
|
||||
console.log('SW registration error', error)
|
||||
},
|
||||
})
|
||||
|
||||
const close = () => {
|
||||
setOfflineReady(false)
|
||||
setNeedRefresh(false)
|
||||
}
|
||||
// const close = () => {
|
||||
// setOfflineReady(false)
|
||||
// setNeedRefresh(false)
|
||||
// }
|
||||
|
||||
return (
|
||||
<Show when={offlineReady() || needRefresh()}>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Button, Card, NiceP, VStack } from "~/components/layout";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { downloadTextFile } from "~/utils/download";
|
||||
|
||||
export function Restart() {
|
||||
const [state, _] = useMegaStore()
|
||||
|
||||
async function handleStop() {
|
||||
const result = await state.mutiny_wallet?.stop()
|
||||
await state.mutiny_wallet?.stop()
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -6,7 +6,7 @@ import eyeIcon from "~/assets/icons/eye.svg"
|
||||
import { Show, createSignal } from "solid-js";
|
||||
import { JsonModal } from "./JsonModal";
|
||||
|
||||
const STYLE = "px-4 py-2 rounded-xl border-2 border-white flex gap-2 items-center font-semibold"
|
||||
const STYLE = "px-4 py-2 rounded-xl border-2 border-white flex gap-2 items-center font-semibold hover:text-m-blue transition-colors"
|
||||
|
||||
export function ShareButton(props: { receiveString: string }) {
|
||||
async function share(receiveString: string) {
|
||||
@@ -34,7 +34,7 @@ export function StringShower(props: { text: string }) {
|
||||
const [open, setOpen] = createSignal(false);
|
||||
return (
|
||||
<>
|
||||
<JsonModal open={open()} data={props.text} title="Details" setOpen={setOpen} />
|
||||
<JsonModal open={open()} plaintext={props.text} title="Details" setOpen={setOpen} />
|
||||
<div class="w-full grid grid-cols-[minmax(0,_1fr)_auto]">
|
||||
<pre class="truncate text-neutral-400">{props.text}</pre>
|
||||
<button class="w-[2rem]" onClick={() => setOpen(true)}>
|
||||
|
||||
@@ -44,6 +44,11 @@ export function TagEditor(props: {
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME: eslint is mad about reactivity
|
||||
const onTagTap = (tag: MutinyTagItem) => {
|
||||
props.setSelectedValues([...props.selectedValues!, tag]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="flex flex-col gap-2 flex-shrink flex-1" >
|
||||
<Select
|
||||
@@ -57,7 +62,8 @@ export function TagEditor(props: {
|
||||
<Show when={availableTags() && availableTags()!.length > 0}>
|
||||
<For each={availableTags()!.slice(0, 3)}>
|
||||
{(tag) => (
|
||||
<TinyButton tag={tag} onClick={() => props.setSelectedValues([...props.selectedValues!, tag])}>
|
||||
// eslint-disable-next-line solid/reactivity
|
||||
<TinyButton tag={tag} onClick={() => onTagTap(tag)}>
|
||||
{tag.name}
|
||||
</TinyButton>
|
||||
)}
|
||||
|
||||
@@ -15,8 +15,13 @@ type FullscreenModalProps = {
|
||||
}
|
||||
|
||||
export function FullscreenModal(props: FullscreenModalProps) {
|
||||
|
||||
const onNice = () => {
|
||||
props.onConfirm ? props.onConfirm() : props.setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog.Root open={props.open} onOpenChange={(isOpen) => props.setOpen(isOpen)}>
|
||||
<Dialog.Root open={props.open} onOpenChange={props.setOpen}>
|
||||
<Dialog.Portal>
|
||||
<div class={DIALOG_POSITIONER}>
|
||||
<Dialog.Content class={DIALOG_CONTENT}>
|
||||
@@ -34,7 +39,7 @@ export function FullscreenModal(props: FullscreenModalProps) {
|
||||
{props.children}
|
||||
</Dialog.Description>
|
||||
<div class="w-full flex">
|
||||
<Button onClick={(_) => props.onConfirm ? props.onConfirm() : props.setOpen(false)}>{props.confirmText ?? "Nice"}</Button>
|
||||
<Button onClick={onNice}>{props.confirmText ?? "Nice"}</Button>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,7 @@ export default function Linkify(props: LinkifyProps): JSX.Element {
|
||||
links.push(beforeLink);
|
||||
}
|
||||
|
||||
links.push(<a href={href} target="_blank" rel="noopener noreferrer">{link}</a>);
|
||||
links.push(<a href={href} class="break-all" target="_blank" rel="noopener noreferrer">{link}</a>);
|
||||
}
|
||||
|
||||
const remainingText = text.slice(lastIndex);
|
||||
|
||||
@@ -7,7 +7,7 @@ type Choices = { value: string, label: string, caption: string }[]
|
||||
export function StyledRadioGroup(props: { value: string, choices: Choices, onValueChange: (value: string) => void, small?: boolean, accent?: "red" | "white" }) {
|
||||
return (
|
||||
// TODO: rewrite this with CVA, props are bad for tailwind
|
||||
<RadioGroup.Root value={props.value} onChange={(e) => props.onValueChange(e)}
|
||||
<RadioGroup.Root value={props.value} onChange={props.onValueChange}
|
||||
class={"grid w-full gap-4"}
|
||||
classList={{ "grid-cols-2": props.choices.length === 2, "grid-cols-3": props.choices.length === 3, "gap-2": props.small }}
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { JSX, ParentComponent, Show, Suspense, createResource, createSignal } from "solid-js"
|
||||
import { JSX, ParentComponent, Show, Suspense, createResource } from "solid-js"
|
||||
import Linkify from "./Linkify"
|
||||
import { Button, ButtonLink } from "./Button"
|
||||
import { Checkbox as KCheckbox, Separator } from "@kobalte/core"
|
||||
@@ -6,6 +6,7 @@ import { useMegaStore } from "~/state/megaStore"
|
||||
import check from "~/assets/icons/check.svg"
|
||||
import { MutinyTagItem } from "~/utils/tags"
|
||||
import { generateGradient } from "~/utils/gradientHash"
|
||||
import close from "~/assets/icons/close.svg"
|
||||
|
||||
export {
|
||||
Button,
|
||||
@@ -128,8 +129,8 @@ export const NiceP: ParentComponent = (props) => {
|
||||
|
||||
export const TinyButton: ParentComponent<{ onClick: () => void, tag?: MutinyTagItem }> = (props) => {
|
||||
// TODO: don't need to run this if it's not a contact
|
||||
const [gradient] = createResource(props.tag?.name, async (name: string) => {
|
||||
return generateGradient(name || "?")
|
||||
const [gradient] = createResource(async () => {
|
||||
return generateGradient(props.tag?.name || "?")
|
||||
})
|
||||
|
||||
const bg = () => (props.tag?.name && props.tag?.kind === "Contact") ? gradient() : "rgb(255 255 255 / 0.1)"
|
||||
@@ -161,4 +162,12 @@ export function Checkbox(props: { label: string, checked: boolean, onChange: (ch
|
||||
<KCheckbox.Label class="flex-1 text-xl font-light">{props.label}</KCheckbox.Label>
|
||||
</KCheckbox.Root>
|
||||
)
|
||||
}
|
||||
|
||||
export function ModalCloseButton() {
|
||||
return (<button
|
||||
class="self-center justify-self-center hover:bg-white/10 rounded-lg active:bg-m-blue"
|
||||
>
|
||||
<img src={close} alt="Close" class="w-8 h-8" />
|
||||
</button>)
|
||||
}
|
||||
@@ -35,12 +35,12 @@ export function WaitlistAlreadyIn() {
|
||||
const [posts] = createResource("", postsFetcher);
|
||||
|
||||
return (
|
||||
<main class='flex flex-col gap-2 sm:gap-4 py-8 px-4 max-w-xl mx-auto items-start drop-shadow-blue-glow'>
|
||||
<main class='flex flex-col gap-4 sm:gap-4 py-8 px-4 max-w-xl mx-auto items-start drop-shadow-blue-glow'>
|
||||
<a href="https://mutinywallet.com">
|
||||
<img src={logo} class="h-10" alt="logo" />
|
||||
</a>
|
||||
<h1 class="text-4xl font-bold">You're on a list!</h1>
|
||||
<h2 class="text-xl">
|
||||
<h2 class="text-xl pr-4">
|
||||
We'll message you when Mutiny Wallet is ready.
|
||||
</h2>
|
||||
<div class="px-4 sm:px-8 py-8 rounded-xl bg-half-black w-full">
|
||||
|
||||
Reference in New Issue
Block a user