Refactor: rewrite button.tsx

This commit is contained in:
benalleng
2023-08-16 16:55:23 -04:00
committed by Paul Miller
parent 6fa32d1949
commit 9f9a239492
12 changed files with 110 additions and 129 deletions

View File

@@ -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
View File

@@ -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==}

View File

@@ -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>

View File

@@ -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>
);
}

View File

@@ -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")}
>

View File

@@ -25,7 +25,6 @@ export function OnboardWarning() {
<ButtonLink
intent="blue"
layout="xs"
class="self-auto"
href="/settings/backup"
>
{i18n.t("settings.backup.title")}

View File

@@ -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>
);
};

View File

@@ -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>

View File

@@ -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"}>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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",