Merge branch 'test' into feature/audio-sidepanel-v2

This commit is contained in:
Michael Chung committed 2024-04-24 12:51:03 -04:00
commit 45f8a13ba2
5 files changed
+277 -49

No files matched your search

+6 -3
View File
@@ -5,6 +5,7 @@ import { twMerge } from "tailwind-merge";
export interface ButtonPropsI
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
icon?: IconDefinition;
iconFlip?: boolean;
variant?: "primary" | "secondary" | "action";
}
@@ -14,12 +15,13 @@ export const Button = ({
className: propsClassName,
variant: propsVariant = "primary",
disabled,
iconFlip = false,
...rest
}: ButtonPropsI) => {
function getVariantClassNames(variant: string) {
switch (variant) {
case "secondary": {
return " bg-brand-secondary hover:bg-brand-secondary-900 text-white focus-visible:outline-brand-secondary";
return "bg-brand-secondary hover:bg-brand-secondary-900 text-white focus-visible:outline-brand-secondary";
}
case "action": {
return " bg-action hover:bg-action-500 text-white focus-visible:outline-action";
@@ -44,8 +46,9 @@ export const Button = ({
return (
<button className={className} disabled={disabled} {...rest}>
{icon && <FontAwesomeIcon icon={icon} size="sm" />}
{children}
{icon && !iconFlip ? <FontAwesomeIcon icon={icon} /> : null}
<div>{children}</div>
{icon && iconFlip ? <FontAwesomeIcon icon={icon} /> : null}
</button>
);
};
+139
View File
@@ -0,0 +1,139 @@
import { Fragment, useState } from "react";
import { Menu, Transition } from "@headlessui/react";
import {
IconDefinition,
faChevronDown,
} from "@fortawesome/pro-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Button, ButtonPropsI } from "./Button";
import { TransitionDialogue } from "~/components/TransitionDialogue";
type UnionedButtonProps = { label?: string } & ButtonPropsI;
type ModalPropsType = ButtonDropdownProps["options"][number]["dialogProps"];
interface ButtonDropdownProps {
label: string;
icon?: IconDefinition;
options: Array<{
label: string;
description?: string;
onClick?: () => void;
disabled?: boolean;
divider?: boolean;
dialogProps?: {
title: string;
content: React.ReactNode;
className?: string;
confirmButtonProps?: UnionedButtonProps;
closeButtonProps?: UnionedButtonProps;
showClose?: boolean;
};
}>;
}
export const ButtonDropdown = ({
label,
options,
icon,
}: ButtonDropdownProps) => {
const [isOpen, setIsOpen] = useState(false);
const [modalProps, setModalProps] = useState<ModalPropsType | null>(null);
const closeModal = () => setIsOpen(false);
const handleOptionClick = (option) => {
if (option.onClick) {
option.onClick();
}
if (option.dialogProps) {
setModalProps(option.dialogProps);
setIsOpen(true);
}
};
return (
<div className="relative">
<Menu as="div" className="inline-block text-left">
<Menu.Button as="div">
<Button icon={faChevronDown} iconFlip={true} variant="secondary">
{icon ? <FontAwesomeIcon icon={icon} className="mr-2" /> : null}
{label}
</Button>
</Menu.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95">
<Menu.Items
static
className="absolute left-0 mt-1 w-max divide-y divide-gray-100 overflow-hidden rounded-lg bg-brand-secondary py-1.5 focus:outline-none">
<div>
{options.map((option, index) => (
<Fragment key={index}>
{option.divider && (
<div className="my-1.5 border-t border-ui-divider" />
)}
<Menu.Item>
{({ active }) => (
<button
disabled={option.disabled}
className={`duration-50 bg-brand-secondary font-medium text-white transition-all ${
active ? "bg-ui-controls-button/60" : ""
} ${option.disabled ? "pointer-events-none opacity-40" : ""} group flex w-full items-center py-1.5 pl-7 pr-4 text-sm`.trim()}
onClick={() => handleOptionClick(option)}>
<div className="flex w-full">
<div className="grow text-start">{option.label}</div>
<div className="ml-10 font-normal text-white/75">
{option.description && option.description}
</div>
</div>
</button>
)}
</Menu.Item>
</Fragment>
))}
</div>
</Menu.Items>
</Transition>
</Menu>
{modalProps && (
<TransitionDialogue
title={modalProps.title}
isOpen={isOpen}
onClose={closeModal}
className={modalProps.className}>
{modalProps.content}
<div className="mt-6 flex justify-end gap-2">
{modalProps.showClose !== false && modalProps.closeButtonProps && (
<Button
variant="secondary"
{...modalProps.closeButtonProps}
onClick={closeModal}>
{modalProps.closeButtonProps.label}
</Button>
)}
{modalProps.confirmButtonProps && (
<Button
{...modalProps.confirmButtonProps}
onClick={(e) => {
if (modalProps.confirmButtonProps?.onClick) {
modalProps.confirmButtonProps?.onClick(e);
}
closeModal();
}}>
{modalProps.confirmButtonProps.label || "Confirm"}
</Button>
)}
</div>
</TransitionDialogue>
)}
</div>
);
};
+6 -3
View File
@@ -4,8 +4,11 @@ import { IconDefinition } from "@fortawesome/pro-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Label } from "./Typography";
import { kebabCase } from "~/utilities";
import { disableHotkeyInput,enableHotkeyInput,DomLevels } from "~/pages/PageEnigma/store";
import {
disableHotkeyInput,
enableHotkeyInput,
DomLevels,
} from "~/pages/PageEnigma/store";
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
@@ -18,7 +21,7 @@ export const Input = React.forwardRef(({
ref: React.ForwardedRef<HTMLInputElement>
) => {
return (
<div className={twMerge("flex flex-col gap-2", className)}>
<div className={twMerge("flex flex-col", className)}>
{label && <Label htmlFor={id ? id : kebabCase(label)}>{label}</Label>}
<div className="relative w-full">
+19 -5
View File
@@ -1,26 +1,40 @@
import { Button } from "./Button";
import { ButtonDropdown } from "./ButtonDropdown";
import { ButtonIcon } from "./ButtonIcon";
import { ButtonLink } from "./ButtonLink";
import { ButtonIconSelect } from "./ButtonIconSelect";
import { Input } from "./Input";
import { InputVector } from "./InputVector";
import { H1, H2, H3, H4, H5, H6, P, Label, Link} from "./Typography";
import { H1, H2, H3, H4, H5, H6, P, Label, Link } from "./Typography";
import { ItemPicker } from "./ItemPicker";
import { Textarea } from "./Textarea";
import { TransitionDialogue } from "./TransitionDialogue";
import { ListDropdown } from "./ListDropdown"
import { ListSearchDropdown } from "./ListSearchDropdown"
import { ListDropdown } from "./ListDropdown";
import { ListSearchDropdown } from "./ListSearchDropdown";
import { LoadingBar } from "./LoadingBar";
import { LoadingDots, LoadingDotsBricks, LoadingDotsTyping } from "./LoadingDots";
import {
LoadingDots,
LoadingDotsBricks,
LoadingDotsTyping,
} from "./LoadingDots";
import { Pill } from "./Pill";
import { WaveformPlayer } from "./WaveformPlayer";
export {
Button,
ButtonDropdown,
ButtonIcon,
ButtonLink,
ButtonIconSelect,
H1,H2,H3,H4,H5,H6,P,Label,Link,
H1,
H2,
H3,
H4,
H5,
H6,
P,
Label,
Link,
ItemPicker,
Textarea,
TransitionDialogue,
@@ -1,5 +1,5 @@
import { useContext, useState } from "react";
import { Input } from "~/components";
import { ButtonDropdown, Input } from "~/components";
import { ButtonDialogue } from "~/modules/ButtonDialogue";
import { EngineContext } from "../../../../contexts/EngineContext";
import { ToasterContext } from "~/contexts/ToasterContext";
@@ -7,6 +7,7 @@ import { ToasterContext } from "~/contexts/ToasterContext";
import { TestFeaturesButtons } from "./TestFeaturesButtons";
import { Help } from "./Help";
import { faFile } from "@fortawesome/pro-solid-svg-icons";
export const ControlsTopButtons = () => {
const editorEngine = useContext(EngineContext);
@@ -39,44 +40,112 @@ export const ControlsTopButtons = () => {
return (
<div className="flex flex-col gap-2 pl-3 pt-3">
<div className="flex gap-2">
<ButtonDialogue
buttonProps={{
variant: "secondary",
label: "Load Scene",
}}
title="Load Scene"
confirmButtonProps={{
label: "Load",
disabled: sceneToken === "",
onClick: handleButtonLoadScene,
}}>
<Input
label="Please provide the Token of the scene you wished to load:"
onChange={(e) => {
setSceneToken(e.target.value);
}}
/>
</ButtonDialogue>
<div className="flex gap-1.5">
<ButtonDropdown
label="File"
icon={faFile}
options={[
{
label: "New scene",
description: "Ctrl+N",
dialogProps: {
title: "Create a New Scene",
content: (
<Input
label="Please enter a name for your new scene"
onChange={(e) => {
setSceneToken(e.target.value);
}}
/>
),
confirmButtonProps: {
label: "Create",
disabled: sceneName === "",
onClick: () => console.log("NEW SCENE"),
},
closeButtonProps: {
label: "Cancel",
},
showClose: true,
},
},
{
label: "Load existing scene",
description: "Ctrl+O",
dialogProps: {
title: "Load a Scene",
content: (
<Input
label="Please provide the token of the scene you want to load"
onChange={(e) => {
setSceneToken(e.target.value);
}}
/>
),
confirmButtonProps: {
label: "Load",
disabled: sceneToken === "",
onClick: handleButtonLoadScene,
},
closeButtonProps: {
label: "Cancel",
},
showClose: true,
},
},
<ButtonDialogue
buttonProps={{
variant: "secondary",
label: "Save Scene",
}}
title="Save Scene"
confirmButtonProps={{
label: "Save",
disabled: sceneName === "",
onClick: handleButtonSave,
}}>
<Input
label="Please Enter a name for your scene"
onChange={(e) => {
setSceneName(e.target.value);
}}
/>
</ButtonDialogue>
{
label: "Save scene",
description: "Ctrl+S",
dialogProps: {
title: "Save Scene",
content: (
<Input
label="Please enter a name for your scene"
onChange={(e) => {
setSceneName(e.target.value);
}}
/>
),
confirmButtonProps: {
label: "Save",
disabled: sceneName === "",
onClick: handleButtonSave,
},
closeButtonProps: {
label: "Cancel",
},
showClose: true,
},
divider: true,
},
{
label: "Save scene as copy",
description: "Ctrl+Shift+S",
dialogProps: {
title: "Save Scene as Copy",
content: (
<Input
label="Please enter a name for your scene"
onChange={(e) => {
setSceneName(e.target.value);
}}
/>
),
confirmButtonProps: {
label: "Save",
disabled: sceneName === "",
onClick: handleButtonSave,
},
closeButtonProps: {
label: "Cancel",
},
showClose: true,
},
},
]}
/>
<ButtonDialogue
buttonProps={{