mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 09:48:44 +00:00
- login now flows automatically smoothly to the next step after login - settings modal: misc/audio panes styling and toggle switch - account settings disconnect sora account button remaining TODO: - link logout sora endpoint
156 lines
4.2 KiB
TypeScript
156 lines
4.2 KiB
TypeScript
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
import { twMerge } from "tailwind-merge";
|
|
import { ButtonHTMLAttributes, AnchorHTMLAttributes } from "react";
|
|
import { faSpinnerThird } from "@fortawesome/pro-solid-svg-icons";
|
|
|
|
type AnchorProps = Omit<
|
|
AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
keyof ButtonHTMLAttributes<HTMLButtonElement>
|
|
>;
|
|
|
|
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
icon?: IconDefinition;
|
|
iconClassName?: string;
|
|
iconFlip?: boolean;
|
|
htmlFor?: string;
|
|
variant?: "primary" | "secondary" | "action" | "destructive";
|
|
loading?: boolean;
|
|
as?: "button" | "link";
|
|
href?: string;
|
|
target?: string;
|
|
}
|
|
|
|
export const Button = ({
|
|
icon,
|
|
iconClassName,
|
|
children,
|
|
className: propsClassName,
|
|
htmlFor,
|
|
variant: propsVariant = "primary",
|
|
disabled,
|
|
iconFlip = false,
|
|
loading,
|
|
as = "button",
|
|
href,
|
|
target,
|
|
...rest
|
|
}: ButtonProps) => {
|
|
function getVariantClassNames(variant: string) {
|
|
switch (variant) {
|
|
case "secondary": {
|
|
return "bg-secondary hover:bg-secondary-700 text-white focus-visible:outline-secondary";
|
|
}
|
|
case "action": {
|
|
return "bg-action hover:bg-action-900 text-white focus-visible:outline-action";
|
|
}
|
|
case "destructive": {
|
|
return "bg-red/70 hover:bg-red/50 text-white focus-visible:outline-red";
|
|
}
|
|
case "primary":
|
|
default: {
|
|
return "bg-primary hover:bg-primary-400 text-white focus-visible:outline-primary-600";
|
|
}
|
|
}
|
|
}
|
|
|
|
const disabledClass = twMerge(
|
|
disabled || loading ? "opacity-50 pointer-events-none" : ""
|
|
);
|
|
|
|
const className = twMerge(
|
|
"w-fit text-sm font-medium rounded-lg px-3 py-2 border border-transparent shadow-sm focus-visible:outline focus-visible:outline-0 focus-visible:outline-offset-0 transition-all duration-150 flex gap-2 items-center justify-center",
|
|
getVariantClassNames(propsVariant),
|
|
propsClassName,
|
|
disabledClass
|
|
);
|
|
|
|
if (htmlFor) {
|
|
return (
|
|
<label className={className} htmlFor={htmlFor} style={rest.style}>
|
|
{loading && !iconFlip ? (
|
|
<FontAwesomeIcon icon={faSpinnerThird} className="animate-spin" />
|
|
) : (
|
|
<>
|
|
{icon && !iconFlip ? (
|
|
<FontAwesomeIcon icon={icon} className={iconClassName} />
|
|
) : null}
|
|
</>
|
|
)}
|
|
{children}
|
|
{loading && iconFlip ? (
|
|
<FontAwesomeIcon icon={faSpinnerThird} className="animate-spin" />
|
|
) : (
|
|
<>
|
|
{icon && iconFlip ? (
|
|
<FontAwesomeIcon icon={icon} className={iconClassName} />
|
|
) : null}
|
|
</>
|
|
)}
|
|
</label>
|
|
);
|
|
}
|
|
|
|
if (as === "link" && href) {
|
|
return (
|
|
<a
|
|
href={href}
|
|
className={className}
|
|
style={rest.style}
|
|
{...(rest as unknown as AnchorProps)}
|
|
target={target}
|
|
>
|
|
{loading && !iconFlip ? (
|
|
<FontAwesomeIcon icon={faSpinnerThird} className="animate-spin" />
|
|
) : (
|
|
<>
|
|
{icon && !iconFlip ? (
|
|
<FontAwesomeIcon icon={icon} className={iconClassName} />
|
|
) : null}
|
|
</>
|
|
)}
|
|
{children}
|
|
{loading && iconFlip ? (
|
|
<FontAwesomeIcon icon={faSpinnerThird} className="animate-spin" />
|
|
) : (
|
|
<>
|
|
{icon && iconFlip ? (
|
|
<FontAwesomeIcon icon={icon} className={iconClassName} />
|
|
) : null}
|
|
</>
|
|
)}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<button
|
|
className={className}
|
|
disabled={disabled || loading}
|
|
{...{ ...rest, htmlFor }}
|
|
>
|
|
{loading && !iconFlip ? (
|
|
<FontAwesomeIcon icon={faSpinnerThird} className="animate-spin" />
|
|
) : (
|
|
<>
|
|
{icon && !iconFlip ? (
|
|
<FontAwesomeIcon icon={icon} className={iconClassName} />
|
|
) : null}
|
|
</>
|
|
)}
|
|
{children}
|
|
{loading && iconFlip ? (
|
|
<FontAwesomeIcon icon={faSpinnerThird} className="animate-spin" />
|
|
) : (
|
|
<>
|
|
{icon && iconFlip ? (
|
|
<FontAwesomeIcon icon={icon} className={iconClassName} />
|
|
) : null}
|
|
</>
|
|
)}
|
|
</button>
|
|
);
|
|
};
|
|
|
|
export default Button;
|