mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2026-02-08 07:44:23 +01:00
Refactor: rewrite button.tsx
This commit is contained in:
@@ -58,7 +58,6 @@
|
||||
"@mutinywallet/waila-wasm": "^0.2.1",
|
||||
"@solid-primitives/upload": "^0.0.111",
|
||||
"@thisbeyond/solid-select": "^0.14.0",
|
||||
"class-variance-authority": "^0.4.0",
|
||||
"i18next": "^22.5.1",
|
||||
"i18next-browser-languagedetector": "^7.1.0",
|
||||
"qr-scanner": "^1.4.2",
|
||||
|
||||
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@@ -49,9 +49,6 @@ importers:
|
||||
'@thisbeyond/solid-select':
|
||||
specifier: ^0.14.0
|
||||
version: 0.14.0(solid-js@1.7.8)
|
||||
class-variance-authority:
|
||||
specifier: ^0.4.0
|
||||
version: 0.4.0(typescript@5.1.6)
|
||||
i18next:
|
||||
specifier: ^22.5.1
|
||||
version: 22.5.1
|
||||
@@ -6200,17 +6197,6 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/class-variance-authority@0.4.0(typescript@5.1.6):
|
||||
resolution: {integrity: sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ==}
|
||||
peerDependencies:
|
||||
typescript: '>= 4.5.5 < 5'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
typescript: 5.1.6
|
||||
dev: false
|
||||
|
||||
/clean-stack@2.2.0:
|
||||
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -12738,6 +12724,7 @@ packages:
|
||||
resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/uglify-js@3.17.4:
|
||||
resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { useNavigate } from "solid-start";
|
||||
import close from "~/assets/icons/close.svg";
|
||||
import currencySwap from "~/assets/icons/currency-swap.svg";
|
||||
import pencil from "~/assets/icons/pencil.svg";
|
||||
import { Button, FeesModal, InfoBox, InlineAmount } from "~/components";
|
||||
import { Button, FeesModal, InfoBox, InlineAmount, VStack } from "~/components";
|
||||
import { useI18n } from "~/i18n/context";
|
||||
import { Network } from "~/logic/mutinyWalletSetup";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
@@ -576,13 +576,13 @@ export const AmountEditable: ParentComponent<{
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
<Button
|
||||
intent="green"
|
||||
class="w-full flex-none"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
{i18n.t("receive.amount_editable.set_amount")}
|
||||
</Button>
|
||||
<VStack>
|
||||
<Button intent="green" onClick={handleSubmit}>
|
||||
{i18n.t(
|
||||
"receive.amount_editable.set_amount"
|
||||
)}
|
||||
</Button>
|
||||
</VStack>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</div>
|
||||
|
||||
@@ -49,9 +49,11 @@ export function ContactForm(props: {
|
||||
</Field> */}
|
||||
</VStack>
|
||||
</div>
|
||||
<Button type="submit" intent="blue" class="w-full flex-none">
|
||||
{props.cta}
|
||||
</Button>
|
||||
<VStack>
|
||||
<Button type="submit" intent="blue">
|
||||
{props.cta}
|
||||
</Button>
|
||||
</VStack>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ function PeerItem(props: { peer: MutinyPeer }) {
|
||||
{JSON.stringify(props.peer, null, 2)}
|
||||
</pre>
|
||||
<Button
|
||||
intent="glowy"
|
||||
intent="red"
|
||||
layout="xs"
|
||||
onClick={handleDisconnectPeer}
|
||||
>
|
||||
@@ -225,21 +225,21 @@ function ChannelItem(props: { channel: MutinyChannel; network?: Network }) {
|
||||
{i18n.t("common.view_transaction")}
|
||||
</ExternalLink>
|
||||
<Button
|
||||
intent="glowy"
|
||||
intent="red"
|
||||
layout="xs"
|
||||
onClick={() => setPendingChannelAction("close")}
|
||||
>
|
||||
{i18n.t("settings.admin.kitchen_sink.close_channel")}
|
||||
</Button>
|
||||
<Button
|
||||
intent="glowy"
|
||||
intent="red"
|
||||
layout="xs"
|
||||
onClick={() => setPendingChannelAction("force_close")}
|
||||
>
|
||||
{i18n.t("settings.admin.kitchen_sink.force_close")}
|
||||
</Button>
|
||||
<Button
|
||||
intent="glowy"
|
||||
intent="red"
|
||||
layout="xs"
|
||||
onClick={() => setPendingChannelAction("abandon")}
|
||||
>
|
||||
|
||||
@@ -25,7 +25,6 @@ export function OnboardWarning() {
|
||||
<ButtonLink
|
||||
intent="blue"
|
||||
layout="xs"
|
||||
class="self-auto"
|
||||
href="/settings/backup"
|
||||
>
|
||||
{i18n.t("settings.backup.title")}
|
||||
|
||||
@@ -1,69 +1,57 @@
|
||||
import { LoadingSpinner } from "@mutinywallet/ui";
|
||||
import { cva, VariantProps } from "class-variance-authority";
|
||||
import { children, JSX, ParentComponent, Show, splitProps } from "solid-js";
|
||||
import { JSX, ParentComponent, Show, splitProps } from "solid-js";
|
||||
import { Dynamic } from "solid-js/web";
|
||||
import { A } from "solid-start";
|
||||
|
||||
const button = cva(
|
||||
"p-3 rounded-xl font-semibold transition disabled:bg-neutral-400/10 disabled:text-white/20 disabled:shadow-inner-button-disabled",
|
||||
{
|
||||
variants: {
|
||||
// TODO: button hover has to work different than buttonlinks (like disabled state)
|
||||
intent: {
|
||||
active: "bg-white text-black border border-white hover:text-[#3B6CCC]",
|
||||
inactive:
|
||||
"bg-transparent text-white border border-white hover:text-[#3B6CCC]",
|
||||
glowy: "bg-black/10 shadow-xl text-white border border-m-blue hover:m-blue-dark hover:text-m-blue",
|
||||
blue: "bg-m-blue text-white shadow-inner-button hover:bg-m-blue-dark text-shadow-button",
|
||||
red: "bg-m-red text-white shadow-inner-button hover:bg-m-red-dark text-shadow-button",
|
||||
green: "bg-m-green text-white shadow-inner-button hover:bg-m-green-dark text-shadow-button",
|
||||
text: ""
|
||||
},
|
||||
layout: {
|
||||
flex: "flex-1 text-xl",
|
||||
pad: "px-8 text-xl",
|
||||
small: "px-4 py-2 w-auto text-lg",
|
||||
xs: "px-4 py-2 w-auto rounded-lg text-base",
|
||||
full: "w-full text-xl"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
intent: "inactive",
|
||||
layout: "flex"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Help from https://github.com/arpadgabor/credee/blob/main/packages/www/src/components/ui/button.tsx
|
||||
|
||||
type StyleProps = VariantProps<typeof button>;
|
||||
export type CommonButtonStyleProps = {
|
||||
intent?: "active" | "inactive" | "blue" | "red" | "green" | "text";
|
||||
layout?: "flex" | "pad" | "small" | "xs" | "full";
|
||||
};
|
||||
|
||||
interface ButtonProps
|
||||
extends JSX.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
StyleProps {
|
||||
CommonButtonStyleProps {
|
||||
loading?: boolean;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const Button: ParentComponent<ButtonProps> = (props) => {
|
||||
const slot = children(() => props.children);
|
||||
const [local, attrs] = splitProps(props, [
|
||||
"children",
|
||||
"intent",
|
||||
"layout",
|
||||
"class"
|
||||
]);
|
||||
interface ButtonLinkProps
|
||||
extends JSX.ButtonHTMLAttributes<HTMLAnchorElement>,
|
||||
CommonButtonStyleProps {
|
||||
href: string;
|
||||
target?: string;
|
||||
rel?: string;
|
||||
}
|
||||
|
||||
export const Button: ParentComponent<ButtonProps> = (props) => {
|
||||
const [local, attrs] = splitProps(props, ["children", "intent", "layout"]);
|
||||
return (
|
||||
<button
|
||||
{...attrs}
|
||||
disabled={props.disabled || props.loading}
|
||||
class={button({
|
||||
class: local.class || "",
|
||||
intent: local.intent,
|
||||
layout: local.layout
|
||||
})}
|
||||
class="rounded-xl p-3 font-semibold transition disabled:bg-neutral-400/10 disabled:text-white/20 disabled:shadow-inner-button-disabled"
|
||||
classList={{
|
||||
"bg-white text-black": local.intent === "active",
|
||||
"bg-transparent text-white":
|
||||
!local.intent || local.intent === "inactive",
|
||||
"border border-white hover:text-[#3B6CCC]":
|
||||
!local.intent || !!local.intent.match(/(active|inactive)/),
|
||||
"bg-m-blue hover:bg-m-blue-dark": local.intent === "blue",
|
||||
"bg-m-red hover:bg-m-red-dark": local.intent === "red",
|
||||
"bg-m-green hover:bg-m-green-dark": local.intent === "green",
|
||||
"text-white shadow-inner-button text-shadow-button":
|
||||
local.intent && !!local.intent.match(/(blue|red|green)/),
|
||||
"": local.intent === "text",
|
||||
"flex-1 text-xl": !local.layout || local.layout === "flex",
|
||||
"px-8 text-xl": local.layout === "pad",
|
||||
"px-4 py-2 w-auto text-lg": local.layout === "small",
|
||||
"px-4 py-2 w-auto rounded-lg text-base": local.layout === "xs",
|
||||
"w-full text-xl": local.layout === "full"
|
||||
}}
|
||||
>
|
||||
<Show when={props.loading} fallback={slot()}>
|
||||
<Show when={props.loading} fallback={local.children}>
|
||||
<div class="flex justify-center">
|
||||
{/* TODO: constrain this to the exact height of the button */}
|
||||
<LoadingSpinner wide />
|
||||
@@ -73,40 +61,43 @@ export const Button: ParentComponent<ButtonProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
interface ButtonLinkProps
|
||||
extends JSX.ButtonHTMLAttributes<HTMLAnchorElement>,
|
||||
StyleProps {
|
||||
href: string;
|
||||
target?: string;
|
||||
rel?: string;
|
||||
}
|
||||
|
||||
export const ButtonLink: ParentComponent<ButtonLinkProps> = (props) => {
|
||||
const slot = children(() => props.children);
|
||||
const [local, attrs] = splitProps(props, [
|
||||
"children",
|
||||
"intent",
|
||||
"layout",
|
||||
"class",
|
||||
"href",
|
||||
"target",
|
||||
"rel"
|
||||
]);
|
||||
|
||||
return (
|
||||
<Dynamic
|
||||
{...attrs}
|
||||
component={local.href?.includes("://") ? "a" : A}
|
||||
href={local.href}
|
||||
target={local.target}
|
||||
rel={local.rel}
|
||||
{...attrs}
|
||||
class={button({
|
||||
class: `flex justify-center no-underline ${local.class || ""}`,
|
||||
intent: local.intent,
|
||||
layout: local.layout
|
||||
})}
|
||||
class="flex justify-center rounded-xl p-3 font-semibold no-underline transition disabled:bg-neutral-400/10 disabled:text-white/20 disabled:shadow-inner-button-disabled"
|
||||
classList={{
|
||||
"bg-white text-black": local.intent === "active",
|
||||
"bg-transparent text-white":
|
||||
!local.intent || local.intent === "inactive",
|
||||
"border border-white hover:text-[#3B6CCC]":
|
||||
!local.intent || !!local.intent.match(/(active|inactive)/),
|
||||
"bg-m-blue hover:bg-m-blue-dark": local.intent === "blue",
|
||||
"bg-m-red hover:bg-m-red-dark": local.intent === "red",
|
||||
"bg-m-green hover:bg-m-green-dark": local.intent === "green",
|
||||
"text-white shadow-inner-button text-shadow-button":
|
||||
local.intent && !!local.intent.match(/(blue|red|green)/),
|
||||
"": local.intent === "text",
|
||||
"flex-1 text-xl": !local.layout || local.layout === "flex",
|
||||
"px-8 text-xl": local.layout === "pad",
|
||||
"px-4 py-2 w-auto text-lg": local.layout === "small",
|
||||
"px-4 py-2 w-auto rounded-lg text-base": local.layout === "xs",
|
||||
"w-full text-xl": local.layout === "full"
|
||||
}}
|
||||
>
|
||||
{slot()}
|
||||
{local.children}
|
||||
</Dynamic>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ export const Collapser: ParentComponent<{
|
||||
activityLight?: "on" | "off";
|
||||
}> = (props) => {
|
||||
return (
|
||||
<Collapsible.Root class="collapsible">
|
||||
<Collapsible.Root defaultOpen={props.defaultOpen} class="collapsible">
|
||||
<Collapsible.Trigger class="flex w-full justify-between px-4 py-2 hover:bg-m-grey-750 active:bg-m-grey-900">
|
||||
<div class="flex items-center gap-2">
|
||||
<Switch>
|
||||
|
||||
@@ -40,7 +40,8 @@ import {
|
||||
SimpleDialog,
|
||||
StyledRadioGroup,
|
||||
SuccessModal,
|
||||
TagEditor
|
||||
TagEditor,
|
||||
VStack
|
||||
} from "~/components";
|
||||
import { useI18n } from "~/i18n/context";
|
||||
import { matchError } from "~/logic/errorDispatch";
|
||||
@@ -390,15 +391,16 @@ export default function Receive() {
|
||||
</Card>
|
||||
|
||||
<div class="flex-1" />
|
||||
<Button
|
||||
class="w-full flex-grow-0"
|
||||
disabled={!amount()}
|
||||
intent="green"
|
||||
onClick={onSubmit}
|
||||
loading={loading()}
|
||||
>
|
||||
{i18n.t("common.continue")}
|
||||
</Button>
|
||||
<VStack>
|
||||
<Button
|
||||
disabled={!amount()}
|
||||
intent="green"
|
||||
onClick={onSubmit}
|
||||
loading={loading()}
|
||||
>
|
||||
{i18n.t("common.continue")}
|
||||
</Button>
|
||||
</VStack>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={unified() && receiveState() === "show"}>
|
||||
|
||||
@@ -715,17 +715,18 @@ export default function Send() {
|
||||
</Match>
|
||||
</Switch>
|
||||
<Show when={destination()}>
|
||||
<Button
|
||||
class="w-full flex-grow-0"
|
||||
disabled={sendButtonDisabled()}
|
||||
intent="blue"
|
||||
onClick={handleSend}
|
||||
loading={sending()}
|
||||
>
|
||||
{sending()
|
||||
? i18n.t("send.sending")
|
||||
: i18n.t("send.confirm_send")}
|
||||
</Button>
|
||||
<VStack>
|
||||
<Button
|
||||
disabled={sendButtonDisabled()}
|
||||
intent="blue"
|
||||
onClick={handleSend}
|
||||
loading={sending()}
|
||||
>
|
||||
{sending()
|
||||
? i18n.t("send.sending")
|
||||
: i18n.t("send.confirm_send")}
|
||||
</Button>
|
||||
</VStack>
|
||||
</Show>
|
||||
<FeedbackLink />
|
||||
</VStack>
|
||||
|
||||
@@ -443,15 +443,16 @@ export default function Swap() {
|
||||
</Show>
|
||||
</VStack>
|
||||
<div class="flex-1" />
|
||||
<Button
|
||||
class="w-full flex-grow-0"
|
||||
disabled={!canSwap()}
|
||||
intent="blue"
|
||||
onClick={handleSwap}
|
||||
loading={loading()}
|
||||
>
|
||||
{i18n.t("swap.confirm_swap")}
|
||||
</Button>
|
||||
<VStack>
|
||||
<Button
|
||||
disabled={!canSwap()}
|
||||
intent="blue"
|
||||
onClick={handleSwap}
|
||||
loading={loading()}
|
||||
>
|
||||
{i18n.t("swap.confirm_swap")}
|
||||
</Button>
|
||||
</VStack>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="none" />
|
||||
</SafeArea>
|
||||
|
||||
@@ -56,7 +56,6 @@ export default defineConfig({
|
||||
// Don't want vite to bundle these late during dev causing reload
|
||||
include: [
|
||||
"qr-scanner",
|
||||
"class-variance-authority",
|
||||
"@kobalte/core",
|
||||
"@solid-primitives/upload",
|
||||
"i18next",
|
||||
|
||||
Reference in New Issue
Block a user