movie-web/src/components/Button.tsx
mrjvs 061c944034 finish register and login flow + suspense fallback fix
Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
2023-11-18 15:12:31 +01:00

130 lines
3.5 KiB
TypeScript

import classNames from "classnames";
import { ReactNode, useCallback } from "react";
import { useHistory } from "react-router-dom";
import { Icon, Icons } from "@/components/Icon";
import { Spinner } from "@/components/layout/Spinner";
interface Props {
icon?: Icons;
onClick?: () => void;
children?: ReactNode;
theme?: "white" | "purple" | "secondary" | "danger";
padding?: string;
className?: string;
href?: string;
disabled?: boolean;
download?: string;
loading?: boolean;
}
export function Button(props: Props) {
const history = useHistory();
const { onClick, href, loading } = props;
const cb = useCallback(() => {
if (loading) return;
if (href) history.push(href);
else onClick?.();
}, [onClick, href, history, loading]);
let colorClasses = "bg-white hover:bg-gray-200 text-black";
if (props.theme === "purple")
colorClasses = "bg-buttons-purple hover:bg-buttons-purpleHover text-white";
if (props.theme === "secondary")
colorClasses =
"bg-buttons-cancel hover:bg-buttons-cancelHover transition-colors duration-100 text-white";
if (props.theme === "danger")
colorClasses = "bg-buttons-danger hover:bg-buttons-dangerHover text-white";
let 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",
props.padding ?? "px-4 py-3",
props.className,
colorClasses,
props.disabled ? "cursor-not-allowed bg-opacity-60 text-opacity-60" : null
);
if (props.disabled)
classes = classes
.split(" ")
.filter(
(className) =>
!className.startsWith("hover:") && !className.startsWith("active:")
)
.join(" ");
const content = (
<>
{props.icon && !props.loading ? (
<span className="mr-3 hidden md:inline-block">
<Icon icon={props.icon} />
</span>
) : null}
{props.loading ? (
<span className="mr-3 inline-flex justify-center">
<Spinner className="text-lg" />
</span>
) : null}
{props.children}
</>
);
if (
props.href &&
(props.href.startsWith("https://") || props.href?.startsWith("data:"))
)
return (
<a
className={classes}
href={props.href}
target="_blank"
rel="noreferrer"
download={props.download}
>
{content}
</a>
);
if (props.href)
return (
<a className={classes} onClick={cb}>
{content}
</a>
);
return (
<button type="button" onClick={cb} className={classes}>
{content}
</button>
);
}
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")
colorClasses = "bg-buttons-purple hover:bg-buttons-purpleHover text-white";
if (props.theme === "secondary")
colorClasses =
"bg-buttons-cancel hover:bg-buttons-cancelHover transition-colors duration-100 text-white";
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>
);
}