uievent more structurized, uieventdispathcers now has structure, imagetoolbar events

This commit is contained in:
wil committed 2024-09-07 20:08:28 -04:00
1 parent 6b7506c5f1
commit c3f1837b6d
9 files changed
+168 -98

No files matched your search

+26 -4
View File
@@ -1,23 +1,45 @@
import { MouseEventHandler } from "react";
import { useSignals } from "@preact/signals-react/runtime";
import { Transition } from "@headlessui/react";
import { twMerge } from "tailwind-merge";
import { ToolbarImage } from "~/components/features/ToolbarImage";
import { uiAccess } from "~/signals/uiAccess";
import { dispatchUiEvents } from "~/signals/uiEvents";
import { ToolbarImageButtonNames } from "~/components/features/ToolbarImage/enums";
import { transitionTimingStyles } from "~/components/styles";
export const ContextualToolbarImage = () => {
useSignals();
const { isShowing, ...rest } = uiAccess.imageToolbar.signal.value;
const { isShowing, position, ...rest } = uiAccess.imageToolbar.signal.value;
const buttonsProps = Object.values(ToolbarImageButtonNames).reduce(
(acc, buttonName) => {
acc[buttonName] = {
onClick: dispatchUiEvents.imageToolbar[buttonName],
};
return acc;
},
{} as {
[key in ToolbarImageButtonNames]: {
onClick: MouseEventHandler<HTMLButtonElement>;
};
},
);
return (
<Transition show={isShowing}>
<div
className={twMerge(transitionTimingStyles, "data-[closed]:opacity-0")}
className={twMerge(
transitionTimingStyles,
"fixed data-[closed]:opacity-0",
)}
style={{
top: position.y,
left: position.x,
}}
>
<ToolbarImage {...rest} />
<ToolbarImage {...rest} buttonsProps={buttonsProps} />
</div>
</Transition>
);
@@ -6,33 +6,41 @@ import {
} from "@fortawesome/react-fontawesome";
import { IconDefinition } from "@fortawesome/pro-solid-svg-icons";
export const ToolbarButtons = ({
export interface ToolbarButtonProps
extends ButtonHTMLAttributes<HTMLButtonElement> {
active?: boolean;
}
export const ToolbarButton = ({
icon,
onClick,
buttonProps = { className: "" },
buttonProps = {},
iconProps,
}: {
icon: IconDefinition;
onClick?: MouseEventHandler<HTMLButtonElement>;
buttonProps?: ButtonHTMLAttributes<HTMLButtonElement>;
buttonProps?: ToolbarButtonProps;
iconProps?: Omit<FontAwesomeIconProps, "icon">;
}) => {
const {
className: customButtonClassNames,
disabled,
active,
onClick: customOnClick,
...restButtonProps
} = buttonProps;
const mergedButtonClasses = twMerge(
"size-10 rounded-2xl p-2 hover:bg-secondary-500 hover:text-white",
disabled && "pointer-events-none text-secondary-300",
active && "pointer-events-none text-primary ",
customButtonClassNames,
);
return (
<button
className={mergedButtonClasses}
onClick={onClick}
disabled={disabled}
{...restButtonProps}
onClick={onClick ? onClick : customOnClick}
>
<FontAwesomeIcon icon={icon} {...iconProps} />
</button>
+13 -37
View File
@@ -1,66 +1,42 @@
import { MouseEventHandler } from "react";
import { twMerge } from "tailwind-merge";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faImage } from "@fortawesome/pro-solid-svg-icons";
import { ToolbarButtons } from "~/components/features/ToolbarButtons";
import {
ToolbarButton,
ToolbarButtonProps,
} from "~/components/features/ToolbarButton";
import { paperWrapperStyles } from "~/components/styles";
import { ToolbarImageButtonNames } from "./enums";
import { ToolbarImageButtonData } from "./data";
export const ToolbarImage = ({
position,
disabled,
buttonStates,
buttonCallbacks,
}: {
position: {
x: number;
y: number;
};
export interface ToolbarImageProps {
disabled?: boolean;
buttonStates?: {
[key in ToolbarImageButtonNames]: {
disabled: boolean;
};
buttonsProps?: {
[key in ToolbarImageButtonNames]: ToolbarButtonProps;
};
buttonCallbacks?: {
[key in ToolbarImageButtonNames]:
| MouseEventHandler<HTMLButtonElement>
| undefined;
};
}) => {
}
export const ToolbarImage = ({ disabled, buttonsProps }: ToolbarImageProps) => {
return (
<div
className={twMerge(
paperWrapperStyles,
disabled && "pointer-events-none cursor-default bg-ui-border shadow-md",
"fixed flex gap-2 transition",
"flex gap-2 transition",
)}
style={{
top: position.y,
left: position.x,
}}
>
<div className="flex size-10 items-center justify-center rounded-3xl bg-ui-border p-2">
<FontAwesomeIcon icon={faImage} />
</div>
{ToolbarImageButtonData.map((buttonDatum, idx) => {
const buttonProps =
buttonStates && buttonStates[buttonDatum.name]
? { disabled: buttonStates[buttonDatum.name].disabled }
: undefined;
const buttonCallback =
buttonCallbacks && buttonCallbacks[buttonDatum.name]
? buttonCallbacks[buttonDatum.name]
: undefined;
const buttonProps = buttonsProps?.[buttonDatum.name];
return (
<ToolbarButtons
<ToolbarButton
icon={buttonDatum.icon}
key={idx}
buttonProps={buttonProps}
onClick={buttonCallback}
/>
);
})}
+13 -17
View File
@@ -9,17 +9,13 @@ import {
faFilePlus,
faFilm,
faFloppyDisk,
// faHand,
faHatWizard,
faImage,
faLocationArrow,
// faPlus,
// faMinus,
faSquareDashed,
} from "@fortawesome/pro-solid-svg-icons";
import { ToolbarButtons } from "../ToolbarButtons";
import { ToolbarButton } from "../ToolbarButton";
import { twMerge } from "tailwind-merge";
import { UploadImage } from "../UploadImage";
@@ -76,14 +72,14 @@ export const ToolbarMain = () => {
)}
>
<div className="flex items-center gap-2 px-2">
<ToolbarButtons icon={faBars} />
<ToolbarButtons
<ToolbarButton icon={faBars} />
<ToolbarButton
icon={faLocationArrow}
iconProps={{ className: "fa-flip-horizontal" }}
/>
<ToolbarButtons icon={faSquareDashed} />
<ToolbarButton icon={faSquareDashed} />
<div className="relative">
<ToolbarButtons
<ToolbarButton
icon={faFilePlus}
onClick={() => {
setState({ ...state, isUploadSubmenuOpen: true });
@@ -96,7 +92,7 @@ export const ToolbarMain = () => {
paperWrapperStyles,
)}
>
<ToolbarButtons
<ToolbarButton
icon={faImage}
onClick={() =>
setState({
@@ -106,7 +102,7 @@ export const ToolbarMain = () => {
})
}
/>
<ToolbarButtons
<ToolbarButton
icon={faFilm}
onClick={() =>
setState({
@@ -119,14 +115,14 @@ export const ToolbarMain = () => {
</div>
)}
</div>
<ToolbarButtons icon={faCameraRotate} />
<ToolbarButtons icon={faHatWizard} />
<ToolbarButton icon={faCameraRotate} />
<ToolbarButton icon={faHatWizard} />
</div>
<div className="flex items-center gap-2 px-2">
<ToolbarButtons icon={faArrowRotateLeft} />
<ToolbarButtons icon={faArrowRotateRight} />
<ToolbarButtons icon={faFloppyDisk} />
<ToolbarButtons icon={faDownload} />
<ToolbarButton icon={faArrowRotateLeft} />
<ToolbarButton icon={faArrowRotateRight} />
<ToolbarButton icon={faFloppyDisk} />
<ToolbarButton icon={faDownload} />
</div>
</div>
@@ -6,7 +6,7 @@ import { FileUploader, IMAGE_FILE_TYPE } from "../FileUploader";
import { Button } from "~/components/ui";
import { paperWrapperStyles } from "~/components/styles";
import { addImageToEngine } from "~/signals/uiEvents";
import { dispatchUiEvents } from "~/signals/uiEvents/";
export const UploadImage = ({
isOpen,
@@ -24,7 +24,7 @@ export const UploadImage = ({
function handleEnter() {
if (assetFile) {
addImageToEngine(assetFile);
dispatchUiEvents.addImageToEngine(assetFile);
}
handleClose();
}
@@ -6,7 +6,7 @@ import { FileUploader, VIDEO_FILE_TYPE } from "../FileUploader";
import { Button } from "~/components/ui";
import { paperWrapperStyles } from "~/components/styles";
import { addVideoToEngine } from "~/signals/uiEvents";
import { dispatchUiEvents } from "~/signals/uiEvents";
export const UploadVideo = ({
isOpen,
@@ -24,7 +24,7 @@ export const UploadVideo = ({
function handleEnter() {
if (assetFile) {
addVideoToEngine(assetFile);
dispatchUiEvents.addVideoToEngine(assetFile);
}
handleClose();
}
+40
View File
@@ -0,0 +1,40 @@
import { signal } from "@preact/signals-core";
import { effect } from "@preact/signals-react";
const stagedImage = signal<File | null>(null);
const addImageToEngine = (image: File) => {
stagedImage.value = image;
};
const onGetStagedImage = (callback: (file: File) => void) => {
effect(() => {
if (stagedImage.value) {
callback(stagedImage.value);
}
});
};
const stagedVideo = signal<File | null>(null);
const addVideoToEngine = (video: File) => {
stagedVideo.value = video;
};
const onGetStagedVideo = (callback: (file: File) => void) => {
effect(() => {
if (stagedVideo.value) {
callback(stagedVideo.value);
}
});
};
export const dispatchers = {
addImageToEngine,
addVideoToEngine,
};
export const events = {
onGetStagedImage,
onGetStagedVideo,
};
+46
View File
@@ -0,0 +1,46 @@
import { MouseEventHandler } from "react";
import { signal, effect } from "@preact/signals-core";
import { ToolbarImageButtonNames } from "~/components/features/ToolbarImage/enums";
const events = signal<{
[key in ToolbarImageButtonNames]?: React.MouseEvent<
HTMLButtonElement,
MouseEvent
>;
}>();
export const eventsHandlers = Object.values(ToolbarImageButtonNames).reduce(
(acc, buttonName) => {
acc[buttonName] = {
onClick: (callback: MouseEventHandler<HTMLButtonElement>) => {
effect(() => {
if (events.value?.[buttonName]) {
callback(events.value?.[buttonName]);
}
});
},
};
return acc;
},
{} as {
[key in ToolbarImageButtonNames]: {
onClick: (callback: MouseEventHandler<HTMLButtonElement>) => void;
};
},
);
export const dispatchers = Object.values(ToolbarImageButtonNames).reduce(
(acc, buttonName) => {
acc[buttonName] = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
events.value = {
...events.value,
[buttonName]: e,
};
};
return acc;
},
{} as {
[key in ToolbarImageButtonNames]: MouseEventHandler<HTMLButtonElement>;
},
);
+14 -32
View File
@@ -1,35 +1,17 @@
import { signal } from "@preact/signals-core";
import { effect } from "@preact/signals-react";
const stagedImage = signal<File | null>(null);
export const addImageToEngine = (image: File) => {
stagedImage.value = image;
};
const onGetStagedImage = (callback: (file: File) => void) => {
effect(() => {
if (stagedImage.value) {
callback(stagedImage.value);
}
});
};
const stagedVideo = signal<File | null>(null);
export const addVideoToEngine = (video: File) => {
stagedVideo.value = video;
};
const onGetStagedVideo = (callback: (file: File) => void) => {
effect(() => {
if (stagedVideo.value) {
callback(stagedVideo.value);
}
});
};
import {
dispatchers as addMediaDispatchers,
events as addMediaEvents,
} from "./addMedia";
import {
dispatchers as imageToolbarDispatchers,
eventsHandlers as imageToolbarEvents,
} from "./imageToolbar";
export const uiEvents = {
onGetStagedImage,
onGetStagedVideo,
...addMediaEvents,
imageToolbar: imageToolbarEvents,
};
export const dispatchUiEvents = {
...addMediaDispatchers,
imageToolbar: imageToolbarDispatchers,
};