mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2025-12-18 06:44:27 +01:00
qr redesign
This commit is contained in:
3
src/assets/icons/copy-black.svg
Normal file
3
src/assets/icons/copy-black.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 21H8V7h11m0-2H8c-.53043 0-1.03914.21071-1.41421.58579C6.21071 5.96086 6 6.46957 6 7v14c0 .5304.21071 1.0391.58579 1.4142C6.96086 22.7893 7.46957 23 8 23h11c.5304 0 1.0391-.2107 1.4142-.5858S21 21.5304 21 21V7c0-.53043-.2107-1.03914-.5858-1.41421C20.0391 5.21071 19.5304 5 19 5Zm-3-4H4c-.53043 0-1.03914.21071-1.41421.58579C2.21071 1.96086 2 2.46957 2 3v14h2V3h12V1Z" fill="#000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 478 B |
3
src/assets/icons/share-black.svg
Normal file
3
src/assets/icons/share-black.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 23c-.55 0-1.021-.196-1.413-.588C4.195 22.02 3.99934 21.5493 4 21V10c0-.55.196-1.021.588-1.413C4.98 8.195 5.45067 7.99933 6 8h3v2H6v11h12V10h-3V8h3c.55 0 1.021.196 1.413.588.392.392.5877.86267.587 1.412v11c0 .55-.196 1.021-.588 1.413-.392.392-.8627.5877-1.412.587H6Zm5-7V4.825l-1.6 1.6L8 5l4-4 4 4-1.4 1.425-1.6-1.6V16h-2Z" fill="#000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 433 B |
5
src/assets/icons/side-to-side.svg
Normal file
5
src/assets/icons/side-to-side.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="icons">
|
||||
<path id="Vector" d="M12.4105 1.91098C12.5668 1.75475 12.7787 1.66699 12.9997 1.66699C13.2206 1.66699 13.4326 1.75475 13.5888 1.91098L16.9222 5.24431C17.0784 5.40059 17.1662 5.61251 17.1662 5.83348C17.1662 6.05445 17.0784 6.26637 16.9222 6.42265L13.5888 9.75598C13.4317 9.90778 13.2212 9.99177 13.0027 9.98987C12.7842 9.98798 12.5752 9.90034 12.4207 9.74583C12.2662 9.59132 12.1785 9.38231 12.1766 9.16381C12.1747 8.94532 12.2587 8.73482 12.4105 8.57765L14.3213 6.66681H4.66634C4.44533 6.66681 4.23337 6.57902 4.07709 6.42274C3.92081 6.26646 3.83301 6.05449 3.83301 5.83348C3.83301 5.61247 3.92081 5.40051 4.07709 5.24423C4.23337 5.08794 4.44533 5.00015 4.66634 5.00015H14.3213L12.4105 3.08931C12.2543 2.93304 12.1665 2.72112 12.1665 2.50015C12.1665 2.27918 12.2543 2.06725 12.4105 1.91098ZM8.58884 10.2443C8.74507 10.4006 8.83283 10.6125 8.83283 10.8335C8.83283 11.0545 8.74507 11.2664 8.58884 11.4226L6.67801 13.3335H16.333C16.554 13.3335 16.766 13.4213 16.9223 13.5776C17.0785 13.7338 17.1663 13.9458 17.1663 14.1668C17.1663 14.3878 17.0785 14.5998 16.9223 14.7561C16.766 14.9123 16.554 15.0001 16.333 15.0001H6.67801L8.58884 16.911C8.74064 17.0681 8.82463 17.2786 8.82274 17.4971C8.82084 17.7156 8.7332 17.9247 8.57869 18.0792C8.42418 18.2337 8.21517 18.3213 7.99668 18.3232C7.77818 18.3251 7.56768 18.2411 7.41051 18.0893L4.07717 14.756C3.92095 14.5997 3.83319 14.3878 3.83319 14.1668C3.83319 13.9458 3.92095 13.7339 4.07717 13.5776L7.41051 10.2443C7.56678 10.0881 7.7787 10.0003 7.99967 10.0003C8.22064 10.0003 8.43257 10.0881 8.58884 10.2443Z" fill="#A3A3A3"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -17,6 +17,7 @@ export function Amount(props: {
|
||||
loading?: boolean;
|
||||
centered?: boolean;
|
||||
icon?: "lightning" | "chain";
|
||||
whiteBg?: boolean;
|
||||
}) {
|
||||
const [state, _] = useMegaStore();
|
||||
|
||||
@@ -26,7 +27,9 @@ export function Amount(props: {
|
||||
return (
|
||||
<div
|
||||
class="flex flex-col gap-1"
|
||||
classList={{ "items-center": props.centered }}
|
||||
classList={{
|
||||
"items-center": props.centered
|
||||
}}
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<Show when={props.icon === "lightning"}>
|
||||
@@ -35,7 +38,12 @@ export function Amount(props: {
|
||||
<Show when={props.icon === "chain"}>
|
||||
<img src={chain} alt="chain" class="h-[18px]" />
|
||||
</Show>
|
||||
<h1 class="text-2xl font-light">
|
||||
<h1
|
||||
class="text-2xl font-light"
|
||||
classList={{
|
||||
"text-black": props.whiteBg
|
||||
}}
|
||||
>
|
||||
{props.loading
|
||||
? "..."
|
||||
: prettyPrintAmount(props.amountSats)}
|
||||
@@ -44,7 +52,13 @@ export function Amount(props: {
|
||||
</h1>
|
||||
</div>
|
||||
<Show when={props.showFiat}>
|
||||
<h2 class="text-sm font-light text-white/70">
|
||||
<h2
|
||||
class="text-sm font-light"
|
||||
classList={{
|
||||
"text-black": props.whiteBg,
|
||||
"text-white/70": !props.whiteBg
|
||||
}}
|
||||
>
|
||||
≈ {props.loading ? "..." : amountInUsd()}
|
||||
<span class="text-sm">USD</span>
|
||||
</h2>
|
||||
|
||||
111
src/components/IntegratedQR.tsx
Normal file
111
src/components/IntegratedQR.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import { Match, Show, Switch } from "solid-js";
|
||||
import { QRCodeSVG } from "solid-qr-code";
|
||||
import { ReceiveFlavor } from "~/routes/Receive";
|
||||
import { useCopy } from "~/utils/useCopy";
|
||||
import { Amount } from "./Amount";
|
||||
import { TruncateMiddle } from "./ShareCard";
|
||||
import copyBlack from "~/assets/icons/copy-black.svg";
|
||||
import shareBlack from "~/assets/icons/share-black.svg";
|
||||
import chainBlack from "~/assets/icons/chain-black.svg";
|
||||
import boltBlack from "~/assets/icons/bolt-black.svg";
|
||||
|
||||
function KindIndicator(props: { kind: ReceiveFlavor }) {
|
||||
return (
|
||||
<div class="text-black flex flex-col items-end">
|
||||
<Switch>
|
||||
<Match when={props.kind === "onchain"}>
|
||||
<h3 class="font-semibold">On-chain</h3>
|
||||
<img src={chainBlack} alt="chain" />
|
||||
</Match>
|
||||
|
||||
<Match when={props.kind === "lightning"}>
|
||||
<h3 class="font-semibold">Lightning</h3>
|
||||
<img src={boltBlack} alt="bolt" />
|
||||
</Match>
|
||||
|
||||
<Match when={props.kind === "unified"}>
|
||||
<h3 class="font-semibold">Unified</h3>
|
||||
<div class="flex gap-1">
|
||||
<img src={chainBlack} alt="chain" />
|
||||
<img src={boltBlack} alt="bolt" />
|
||||
</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
async function share(receiveString: string) {
|
||||
// If the browser doesn't support share we can just copy the address
|
||||
if (!navigator.share) {
|
||||
console.error("Share not supported");
|
||||
}
|
||||
const shareData: ShareData = {
|
||||
title: "Mutiny Wallet",
|
||||
text: receiveString
|
||||
};
|
||||
try {
|
||||
await navigator.share(shareData);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export function IntegratedQr(props: {
|
||||
value: string;
|
||||
amountSats: string;
|
||||
kind: ReceiveFlavor;
|
||||
}) {
|
||||
const [copy, copied] = useCopy({ copiedTimeout: 1000 });
|
||||
return (
|
||||
<div
|
||||
id="qr"
|
||||
class="w-full bg-white rounded-xl relative flex flex-col items-center px-4"
|
||||
onClick={() => copy(props.value)}
|
||||
>
|
||||
<Show when={copied()}>
|
||||
<div class="absolute w-full h-full bg-neutral-900/60 z-50 rounded-xl flex flex-col items-center justify-center transition-all">
|
||||
<p class="text-xl font-bold">Copied</p>
|
||||
</div>
|
||||
</Show>
|
||||
<div class="w-full flex justify-between items-center py-4 max-w-[256px]">
|
||||
<Amount
|
||||
amountSats={Number(props.amountSats)}
|
||||
showFiat
|
||||
whiteBg
|
||||
/>
|
||||
<KindIndicator kind={props.kind} />
|
||||
</div>
|
||||
|
||||
<QRCodeSVG
|
||||
value={props.value}
|
||||
class="w-full h-full max-h-[256px]"
|
||||
/>
|
||||
<div
|
||||
class="w-full grid gap-1 py-4 max-w-[256px] "
|
||||
classList={{
|
||||
"grid-cols-[2rem_minmax(0,1fr)_2rem]": !!navigator.share,
|
||||
"grid-cols-[minmax(0,1fr)_2rem]": !navigator.share
|
||||
}}
|
||||
>
|
||||
<Show when={!!navigator.share}>
|
||||
<button
|
||||
class="justify-self-start"
|
||||
onClick={(_) => share(props.value)}
|
||||
>
|
||||
<img src={shareBlack} alt="share" />
|
||||
</button>
|
||||
</Show>
|
||||
<div class="">
|
||||
<TruncateMiddle text={props.value} whiteBg />
|
||||
</div>
|
||||
<button
|
||||
class=" justify-self-end"
|
||||
onClick={() => copy(props.value)}
|
||||
>
|
||||
<img src={copyBlack} alt="copy" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Card, VStack } from "~/components/layout";
|
||||
import { useCopy } from "~/utils/useCopy";
|
||||
import copyIcon from "~/assets/icons/copy.svg";
|
||||
import copyBlack from "~/assets/icons/copy-black.svg";
|
||||
import shareIcon from "~/assets/icons/share.svg";
|
||||
import shareBlack from "~/assets/icons/share-black.svg";
|
||||
import eyeIcon from "~/assets/icons/eye.svg";
|
||||
import { Show, createSignal } from "solid-js";
|
||||
import { JsonModal } from "./JsonModal";
|
||||
@@ -9,7 +11,10 @@ import { JsonModal } from "./JsonModal";
|
||||
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 }) {
|
||||
export function ShareButton(props: {
|
||||
receiveString: string;
|
||||
whiteBg?: boolean;
|
||||
}) {
|
||||
async function share(receiveString: string) {
|
||||
// If the browser doesn't support share we can just copy the address
|
||||
if (!navigator.share) {
|
||||
@@ -29,14 +34,20 @@ export function ShareButton(props: { receiveString: string }) {
|
||||
return (
|
||||
<button class={STYLE} onClick={(_) => share(props.receiveString)}>
|
||||
<span>Share</span>
|
||||
<img src={shareIcon} alt="share" />
|
||||
<img src={props.whiteBg ? shareBlack : shareIcon} alt="share" />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export function TruncateMiddle(props: { text: string }) {
|
||||
export function TruncateMiddle(props: { text: string; whiteBg?: boolean }) {
|
||||
return (
|
||||
<div class="flex text-neutral-300 font-mono">
|
||||
<div
|
||||
class="flex font-mono"
|
||||
classList={{
|
||||
"text-black": props.whiteBg,
|
||||
"text-neutral-300": !props.whiteBg
|
||||
}}
|
||||
>
|
||||
<span class="truncate">{props.text}</span>
|
||||
<span class="pr-2">
|
||||
{props.text.length > 8 ? props.text.slice(-8) : ""}
|
||||
@@ -65,7 +76,11 @@ export function StringShower(props: { text: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function CopyButton(props: { text?: string; title?: string }) {
|
||||
export function CopyButton(props: {
|
||||
text?: string;
|
||||
title?: string;
|
||||
whiteBg?: boolean;
|
||||
}) {
|
||||
const [copy, copied] = useCopy({ copiedTimeout: 1000 });
|
||||
|
||||
function handleCopy() {
|
||||
@@ -75,7 +90,7 @@ export function CopyButton(props: { text?: string; title?: string }) {
|
||||
return (
|
||||
<button class={STYLE} onClick={handleCopy}>
|
||||
{copied() ? "Copied" : props.title ?? "Copy"}
|
||||
<img src={copyIcon} alt="copy" />
|
||||
<img src={props.whiteBg ? copyBlack : copyIcon} alt="copy" />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,16 +15,20 @@ export function StyledRadioGroup(props: {
|
||||
onValueChange: (value: string) => void;
|
||||
small?: boolean;
|
||||
accent?: "red" | "white";
|
||||
vertical?: boolean;
|
||||
}) {
|
||||
return (
|
||||
// TODO: rewrite this with CVA, props are bad for tailwind
|
||||
<RadioGroup.Root
|
||||
value={props.value}
|
||||
onChange={props.onValueChange}
|
||||
class={"grid w-full gap-4"}
|
||||
class={"w-full gap-4"}
|
||||
classList={{
|
||||
"grid-cols-2": props.choices.length === 2,
|
||||
"grid-cols-3": props.choices.length === 3,
|
||||
"flex flex-col": props.vertical,
|
||||
"grid grid-cols-2":
|
||||
props.choices.length === 2 && !props.vertical,
|
||||
"grid grid-cols-3":
|
||||
props.choices.length === 3 && !props.vertical,
|
||||
"gap-2": props.small
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from "solid-js";
|
||||
import Linkify from "./Linkify";
|
||||
import { Button, ButtonLink } from "./Button";
|
||||
import { Checkbox as KCheckbox, Separator } from "@kobalte/core";
|
||||
import { Dialog, Checkbox as KCheckbox, Separator } from "@kobalte/core";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import check from "~/assets/icons/check.svg";
|
||||
import { MutinyTagItem } from "~/utils/tags";
|
||||
@@ -75,7 +75,6 @@ export const SettingsCard: ParentComponent<{
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export const SafeArea: ParentComponent = (props) => {
|
||||
return (
|
||||
<div class="h-[100dvh] safe-left safe-right">
|
||||
@@ -166,7 +165,7 @@ export const LargeHeader: ParentComponent<{ action?: JSX.Element }> = (
|
||||
) => {
|
||||
return (
|
||||
<header class="w-full flex justify-between items-center mt-4 mb-2">
|
||||
<h1 class="text-3xl font-semibold">{props.children}</h1>
|
||||
<h1 class="text-2xl font-semibold">{props.children}</h1>
|
||||
<Show when={props.action}>{props.action}</Show>
|
||||
</header>
|
||||
);
|
||||
@@ -282,3 +281,38 @@ export function ModalCloseButton() {
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export const SIMPLE_OVERLAY = "fixed inset-0 z-50 bg-black/70 backdrop-blur-md";
|
||||
export const SIMPLE_DIALOG_POSITIONER =
|
||||
"fixed inset-0 z-50 flex items-center justify-center";
|
||||
export const SIMPLE_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";
|
||||
|
||||
export const SimpleDialog: ParentComponent<{
|
||||
title: string;
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
}> = (props) => {
|
||||
return (
|
||||
<Dialog.Root open={props.open} onOpenChange={props.setOpen}>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay class={SIMPLE_OVERLAY} />
|
||||
<div class={SIMPLE_DIALOG_POSITIONER}>
|
||||
<Dialog.Content class={SIMPLE_DIALOG_CONTENT}>
|
||||
<div class="flex justify-between mb-2 items-center">
|
||||
<Dialog.Title>
|
||||
<SmallHeader>{props.title}</SmallHeader>
|
||||
</Dialog.Title>
|
||||
<Dialog.CloseButton>
|
||||
<ModalCloseButton />
|
||||
</Dialog.CloseButton>
|
||||
</div>
|
||||
<Dialog.Description class="flex flex-col gap-4">
|
||||
{props.children}
|
||||
</Dialog.Description>
|
||||
</Dialog.Content>
|
||||
</div>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -20,7 +20,8 @@ import {
|
||||
Indicator,
|
||||
LargeHeader,
|
||||
MutinyWalletGuard,
|
||||
SafeArea
|
||||
SafeArea,
|
||||
SimpleDialog
|
||||
} from "~/components/layout";
|
||||
import NavBar from "~/components/NavBar";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
@@ -33,16 +34,16 @@ import { StyledRadioGroup } from "~/components/layout/Radio";
|
||||
import { showToast } from "~/components/Toaster";
|
||||
import { useNavigate } from "solid-start";
|
||||
import { AmountCard } from "~/components/AmountCard";
|
||||
import { ShareCard } from "~/components/ShareCard";
|
||||
import { BackButton } from "~/components/layout/BackButton";
|
||||
import { MutinyTagItem } from "~/utils/tags";
|
||||
import { Network } from "~/logic/mutinyWalletSetup";
|
||||
import { SuccessModal } from "~/components/successfail/SuccessModal";
|
||||
import { MegaCheck } from "~/components/successfail/MegaCheck";
|
||||
import { ExternalLink } from "~/components/layout/ExternalLink";
|
||||
import { CopyableQR } from "~/components/CopyableQR";
|
||||
import { InfoBox } from "~/components/InfoBox";
|
||||
import { FeesModal } from "~/components/MoreInfoModal";
|
||||
import { IntegratedQr } from "~/components/IntegratedQR";
|
||||
import side2side from "~/assets/icons/side-to-side.svg";
|
||||
|
||||
type OnChainTx = {
|
||||
transaction: {
|
||||
@@ -69,12 +70,27 @@ type OnChainTx = {
|
||||
};
|
||||
|
||||
const RECEIVE_FLAVORS = [
|
||||
{ value: "unified", label: "Unified", caption: "Sender decides" },
|
||||
{ value: "lightning", label: "Lightning", caption: "Fast and cool" },
|
||||
{ value: "onchain", label: "On-chain", caption: "Just like Satoshi did it" }
|
||||
{
|
||||
value: "unified",
|
||||
label: "Unified",
|
||||
caption:
|
||||
"Combines a bitcoin address and a lightning invoice. Sender chooses payment method."
|
||||
},
|
||||
{
|
||||
value: "lightning",
|
||||
label: "Lightning invoice",
|
||||
caption:
|
||||
"Ideal for small transactions. Usually lower fees than on-chain."
|
||||
},
|
||||
{
|
||||
value: "onchain",
|
||||
label: "Bitcoin address",
|
||||
caption:
|
||||
"On-chain, just like Satoshi did it. Ideal for very large transactions."
|
||||
}
|
||||
];
|
||||
|
||||
type ReceiveFlavor = "unified" | "lightning" | "onchain";
|
||||
export type ReceiveFlavor = "unified" | "lightning" | "onchain";
|
||||
type ReceiveState = "edit" | "show" | "paid";
|
||||
type PaidState = "lightning_paid" | "onchain_paid";
|
||||
|
||||
@@ -292,6 +308,8 @@ export default function Receive() {
|
||||
});
|
||||
});
|
||||
|
||||
const [methodChooserOpen, setMethodChooserOpen] = createSignal(false);
|
||||
|
||||
return (
|
||||
<MutinyWalletGuard>
|
||||
<SafeArea>
|
||||
@@ -347,31 +365,34 @@ export default function Receive() {
|
||||
</Match>
|
||||
<Match when={unified() && receiveState() === "show"}>
|
||||
<FeeWarning fee={lspFee()} flavor={flavor()} />
|
||||
<CopyableQR value={receiveString() ?? ""} />
|
||||
<IntegratedQr
|
||||
value={receiveString() ?? ""}
|
||||
amountSats={amount() || "0"}
|
||||
kind={flavor()}
|
||||
/>
|
||||
<p class="text-neutral-400 text-center">
|
||||
<Switch>
|
||||
<Match when={flavor() === "lightning"}>
|
||||
Show or share this invoice with the
|
||||
sender.
|
||||
</Match>
|
||||
<Match when={flavor() === "onchain"}>
|
||||
Show or share this address with the
|
||||
sender.
|
||||
</Match>
|
||||
<Match when={flavor() === "unified"}>
|
||||
Show or share this code with the sender.
|
||||
Sender decides method of payment.
|
||||
</Match>
|
||||
</Switch>
|
||||
Keep Mutiny open to receive the payment.
|
||||
</p>
|
||||
<StyledRadioGroup
|
||||
small
|
||||
value={flavor()}
|
||||
onValueChange={setFlavor}
|
||||
choices={RECEIVE_FLAVORS}
|
||||
accent="white"
|
||||
/>{" "}
|
||||
<ShareCard text={receiveString() ?? ""} />
|
||||
<button
|
||||
class="font-bold text-m-grey-400 flex gap-2 p-2 items-center mx-auto"
|
||||
onClick={() => setMethodChooserOpen(true)}
|
||||
>
|
||||
<span>Choose format</span>
|
||||
<img class="w-4 h-4" src={side2side} />
|
||||
</button>
|
||||
<SimpleDialog
|
||||
title="Choose payment format"
|
||||
open={methodChooserOpen()}
|
||||
setOpen={(open) => setMethodChooserOpen(open)}
|
||||
>
|
||||
<StyledRadioGroup
|
||||
value={flavor()}
|
||||
onValueChange={setFlavor}
|
||||
choices={RECEIVE_FLAVORS}
|
||||
accent="white"
|
||||
vertical
|
||||
/>
|
||||
</SimpleDialog>
|
||||
</Match>
|
||||
<Match
|
||||
when={
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
DefaultMain,
|
||||
LargeHeader,
|
||||
MutinyWalletGuard,
|
||||
SafeArea,
|
||||
SettingsCard,
|
||||
VStack
|
||||
|
||||
@@ -30,8 +30,9 @@ module.exports = {
|
||||
"m-red-dark": "hsla(343, 92%, 44%, 1)",
|
||||
"sidebar-gray": "hsla(222, 15%, 7%, 1)",
|
||||
"m-grey-400": "hsla(0, 0%, 64%, 1)",
|
||||
"m-grey-800": "hsla(0, 0%, 12%, 1)",
|
||||
"m-grey-700": "hsla(0, 0%, 25%, 1)",
|
||||
"m-grey-750": "hsla(0, 0%, 17%, 1)",
|
||||
"m-grey-800": "hsla(0, 0%, 12%, 1)",
|
||||
"m-grey-900": "hsla(0, 0%, 9%, 1)"
|
||||
},
|
||||
backgroundImage: {
|
||||
|
||||
Reference in New Issue
Block a user