2023-10-23 23:06:24 +02:00
|
|
|
import classNames from "classnames";
|
2023-11-18 15:12:31 +01:00
|
|
|
import { ReactNode, useCallback } from "react";
|
2023-10-23 23:06:24 +02:00
|
|
|
import { useHistory } from "react-router-dom";
|
2023-02-19 18:36:53 +01:00
|
|
|
|
2023-04-24 17:41:54 +02:00
|
|
|
import { Icon, Icons } from "@/components/Icon";
|
2023-11-18 15:12:31 +01:00
|
|
|
import { Spinner } from "@/components/layout/Spinner";
|
2023-04-24 17:41:54 +02:00
|
|
|
|
2023-02-19 18:36:53 +01:00
|
|
|
interface Props {
|
|
|
|
icon?: Icons;
|
|
|
|
onClick?: () => void;
|
|
|
|
children?: ReactNode;
|
2023-10-27 21:51:14 +02:00
|
|
|
theme?: "white" | "purple" | "secondary" | "danger";
|
2023-10-23 23:06:24 +02:00
|
|
|
padding?: string;
|
|
|
|
className?: string;
|
|
|
|
href?: string;
|
2023-10-25 16:41:52 +02:00
|
|
|
disabled?: boolean;
|
2023-10-25 19:14:41 +02:00
|
|
|
download?: string;
|
2023-11-18 15:12:31 +01:00
|
|
|
loading?: boolean;
|
2023-02-19 18:36:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export function Button(props: Props) {
|
2023-10-23 23:06:24 +02:00
|
|
|
const history = useHistory();
|
2023-11-18 15:12:31 +01:00
|
|
|
const { onClick, href, loading } = props;
|
|
|
|
const cb = useCallback(() => {
|
|
|
|
if (loading) return;
|
|
|
|
if (href) history.push(href);
|
|
|
|
else onClick?.();
|
|
|
|
}, [onClick, href, history, loading]);
|
2023-10-23 23:06:24 +02:00
|
|
|
|
|
|
|
let colorClasses = "bg-white hover:bg-gray-200 text-black";
|
|
|
|
if (props.theme === "purple")
|
2023-11-18 15:12:31 +01:00
|
|
|
colorClasses = "bg-buttons-purple hover:bg-buttons-purpleHover text-white";
|
2023-10-23 23:06:24 +02:00
|
|
|
if (props.theme === "secondary")
|
|
|
|
colorClasses =
|
2023-11-18 15:12:31 +01:00
|
|
|
"bg-buttons-cancel hover:bg-buttons-cancelHover transition-colors duration-100 text-white";
|
2023-10-27 21:51:14 +02:00
|
|
|
if (props.theme === "danger")
|
|
|
|
colorClasses = "bg-buttons-danger hover:bg-buttons-dangerHover text-white";
|
2023-10-23 23:06:24 +02:00
|
|
|
|
2023-10-25 16:41:52 +02:00
|
|
|
let classes = classNames(
|
2023-10-23 23:06:24 +02:00
|
|
|
"cursor-pointer inline-flex items-center justify-center rounded-lg font-medium transition-[transform,background-color] duration-100 active:scale-105 md:px-8",
|
|
|
|
props.padding ?? "px-4 py-3",
|
|
|
|
props.className,
|
2023-10-25 16:41:52 +02:00
|
|
|
colorClasses,
|
|
|
|
props.disabled ? "cursor-not-allowed bg-opacity-60 text-opacity-60" : null
|
2023-10-23 23:06:24 +02:00
|
|
|
);
|
|
|
|
|
2023-10-25 16:41:52 +02:00
|
|
|
if (props.disabled)
|
|
|
|
classes = classes
|
|
|
|
.split(" ")
|
|
|
|
.filter(
|
|
|
|
(className) =>
|
|
|
|
!className.startsWith("hover:") && !className.startsWith("active:")
|
|
|
|
)
|
|
|
|
.join(" ");
|
|
|
|
|
2023-10-23 23:06:24 +02:00
|
|
|
const content = (
|
|
|
|
<>
|
2023-11-18 15:12:31 +01:00
|
|
|
{props.icon && !props.loading ? (
|
2023-02-19 19:54:34 +01:00
|
|
|
<span className="mr-3 hidden md:inline-block">
|
2023-02-19 18:36:53 +01:00
|
|
|
<Icon icon={props.icon} />
|
|
|
|
</span>
|
|
|
|
) : null}
|
2023-11-18 15:12:31 +01:00
|
|
|
{props.loading ? (
|
|
|
|
<span className="mr-3 inline-flex justify-center">
|
|
|
|
<Spinner className="text-lg" />
|
|
|
|
</span>
|
|
|
|
) : null}
|
2023-02-19 18:36:53 +01:00
|
|
|
{props.children}
|
2023-10-23 23:06:24 +02:00
|
|
|
</>
|
|
|
|
);
|
|
|
|
|
2023-10-25 16:41:52 +02:00
|
|
|
if (
|
|
|
|
props.href &&
|
|
|
|
(props.href.startsWith("https://") || props.href?.startsWith("data:"))
|
|
|
|
)
|
2023-10-24 13:27:10 +02:00
|
|
|
return (
|
2023-10-25 16:41:52 +02:00
|
|
|
<a
|
|
|
|
className={classes}
|
|
|
|
href={props.href}
|
|
|
|
target="_blank"
|
|
|
|
rel="noreferrer"
|
|
|
|
download={props.download}
|
|
|
|
>
|
2023-10-24 13:27:10 +02:00
|
|
|
{content}
|
|
|
|
</a>
|
|
|
|
);
|
|
|
|
|
2023-10-23 23:06:24 +02:00
|
|
|
if (props.href)
|
|
|
|
return (
|
2023-11-18 15:12:31 +01:00
|
|
|
<a className={classes} onClick={cb}>
|
2023-10-23 23:06:24 +02:00
|
|
|
{content}
|
|
|
|
</a>
|
|
|
|
);
|
|
|
|
|
|
|
|
return (
|
2023-11-18 15:12:31 +01:00
|
|
|
<button type="button" onClick={cb} className={classes}>
|
2023-10-23 23:06:24 +02:00
|
|
|
{content}
|
2023-02-19 18:36:53 +01:00
|
|
|
</button>
|
|
|
|
);
|
|
|
|
}
|
2023-10-24 20:34:54 +02:00
|
|
|
|
|
|
|
interface ButtonPlainProps {
|
|
|
|
onClick?: () => void;
|
|
|
|
children?: ReactNode;
|
|
|
|
theme?: "white" | "purple" | "secondary";
|
|
|
|
className?: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function ButtonPlain(props: ButtonPlainProps) {
|
|
|
|
let colorClasses = "bg-white hover:bg-gray-200 text-black";
|
|
|
|
if (props.theme === "purple")
|
2023-11-18 15:12:31 +01:00
|
|
|
colorClasses = "bg-buttons-purple hover:bg-buttons-purpleHover text-white";
|
2023-10-24 20:34:54 +02:00
|
|
|
if (props.theme === "secondary")
|
|
|
|
colorClasses =
|
2023-11-18 15:12:31 +01:00
|
|
|
"bg-buttons-cancel hover:bg-buttons-cancelHover transition-colors duration-100 text-white";
|
2023-10-24 20:34:54 +02:00
|
|
|
|
|
|
|
const classes = classNames(
|
|
|
|
"cursor-pointer inline-flex items-center justify-center rounded-lg font-medium transition-[transform,background-color] duration-100 active:scale-105 md:px-8",
|
|
|
|
"px-4 py-3",
|
|
|
|
props.className,
|
|
|
|
colorClasses
|
|
|
|
);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<button type="button" onClick={props.onClick} className={classes}>
|
|
|
|
{props.children}
|
|
|
|
</button>
|
|
|
|
);
|
|
|
|
}
|