mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-12 12:53:04 +00:00
toolbar main hooked up
This commit is contained in:
1 parent
63f13d1e99
commit
d1f803783b
15 files changed
+247
-59
No files matched your search
@@ -46,6 +46,10 @@ export class Engine {
|
||||
uiEvents.imageToolbar.MOVE.onClick(() => {
|
||||
console.log("move");
|
||||
});
|
||||
|
||||
uiEvents.toolbarMain.SELECT_ONE.onClick(() => {
|
||||
console.log("select one is clicked");
|
||||
});
|
||||
}
|
||||
|
||||
sleep(ms: number): Promise<void> {
|
||||
@@ -101,12 +105,10 @@ export class Engine {
|
||||
// Testing render engine
|
||||
this.renderEngine.addNodes(videoNode);
|
||||
|
||||
|
||||
// await this.renderEngine.startProcessing();
|
||||
|
||||
|
||||
// Call this when test video nodes
|
||||
// await this.renderEngine.startProcessing();
|
||||
// await this.renderEngine.startProcessing();
|
||||
|
||||
//videoNode.simulatedLoading();
|
||||
// TODO support Text nodes
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { forwardRef, HTMLAttributes } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { useRenderCounter } from "~/hooks/useRenderCounter";
|
||||
|
||||
import { ContextualToolbarImage } from "./ContextualToolbarImage";
|
||||
import { ContextualLoadingBar } from "./ContextualLoadingBar";
|
||||
import { ToolbarMain, ErrorDialog } from "~/components/features";
|
||||
|
||||
export const KonvaContainer = forwardRef<
|
||||
HTMLDivElement,
|
||||
HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
useRenderCounter("KonvaContainer");
|
||||
|
||||
const classes = twMerge("pegboard -z-10", className);
|
||||
return (
|
||||
<>
|
||||
<div ref={ref} className={classes} {...props} />
|
||||
<ToolbarMain />
|
||||
<ContextualToolbarImage />
|
||||
<ContextualLoadingBar />
|
||||
<ErrorDialog />
|
||||
</>
|
||||
);
|
||||
});
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,14 @@
|
||||
import { forwardRef, HTMLAttributes } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { useRenderCounter } from "~/hooks/useRenderCounter";
|
||||
|
||||
export const KonvaCanvasContainer = forwardRef<
|
||||
HTMLDivElement,
|
||||
HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
useRenderCounter("KonvaCanvasContainer");
|
||||
|
||||
const classes = twMerge("pegboard -z-10", className);
|
||||
return <div ref={ref} className={classes} {...props} />;
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
import { useCallback } from "react";
|
||||
import { useRenderCounter } from "~/hooks/useRenderCounter";
|
||||
|
||||
import { KonvaCanvasContainer } from "./KonvaCanvasContainer";
|
||||
import { ContextualToolbarImage } from "./ContextualToolbarImage";
|
||||
import { ContextualLoadingBar } from "./ContextualLoadingBar";
|
||||
import { SignaledToolbarMain } from "./SignaledToolbarMain";
|
||||
import { ErrorDialog } from "~/components/features";
|
||||
|
||||
// The KonvaApp is the root of the Konva stage
|
||||
// and only entry point for anything in Konva JS
|
||||
import { KonvaApp } from "~/KonvaApp";
|
||||
|
||||
export const KonvaRootComponent = ({ className }: { className: string }) => {
|
||||
// This is a hook that will log the number of times the component has rerendered
|
||||
// Let's make sure we only log once
|
||||
useRenderCounter("KonvaRootComponent");
|
||||
|
||||
const konvaContainerCallbackRef = useCallback((node: HTMLDivElement) => {
|
||||
if (node !== null) {
|
||||
KonvaApp(node);
|
||||
}
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<KonvaCanvasContainer
|
||||
ref={konvaContainerCallbackRef}
|
||||
className={className}
|
||||
// retreive the classNames from the parent for sizing/styling
|
||||
/>
|
||||
<SignaledToolbarMain />
|
||||
<ContextualToolbarImage />
|
||||
<ContextualLoadingBar />
|
||||
<ErrorDialog />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
import { MouseEventHandler } from "react";
|
||||
|
||||
import { ToolbarMain } from "~/components/features";
|
||||
import { toolbarMain } from "~/signals/uiAccess/toolbarMain";
|
||||
import { dispatchers } from "~/signals/uiEvents/toolbarMain";
|
||||
import { ToolbarMainButtonNames } from "~/components/features/ToolbarMain/enum";
|
||||
|
||||
export const SignaledToolbarMain = () => {
|
||||
const buttonProps = Object.values(ToolbarMainButtonNames).reduce(
|
||||
(acc, buttonName) => {
|
||||
acc[buttonName] = {
|
||||
disabled: toolbarMain.signal.value.buttonStates[buttonName].disabled,
|
||||
active: toolbarMain.signal.value.buttonStates[buttonName].active,
|
||||
onClick: dispatchers[buttonName],
|
||||
};
|
||||
return acc;
|
||||
},
|
||||
{} as {
|
||||
[key in ToolbarMainButtonNames]: {
|
||||
disabled: boolean;
|
||||
active: boolean;
|
||||
onClick: MouseEventHandler<HTMLButtonElement>;
|
||||
};
|
||||
},
|
||||
);
|
||||
return (
|
||||
<ToolbarMain
|
||||
disabled={toolbarMain.signal.value.disabled}
|
||||
buttonProps={buttonProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { KonvaRootComponent } from "./KonvaRootComponent";
|
||||
@@ -0,0 +1,11 @@
|
||||
export enum ToolbarMainButtonNames {
|
||||
MENU = "MENU",
|
||||
SELECT_ONE = "SELECT_ONE",
|
||||
SELECT_AREA = "SELECT_AREA",
|
||||
CHANGE_CAMERA_ORIENTATION = "CHANGE_CAMERA_ORIENTATION",
|
||||
AI_STYLIZE = "AI_STYLIZE",
|
||||
UNDO = "UNDO",
|
||||
REDO = "REDO",
|
||||
SAVE = "SAVE",
|
||||
DOWNLOAD = "DOWNLOAD",
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MouseEventHandler, useCallback, useState } from "react";
|
||||
import { useSignalEffect } from "@preact/signals-react/runtime";
|
||||
import { useCallback, useState } from "react";
|
||||
import {
|
||||
faArrowRotateLeft,
|
||||
faArrowRotateRight,
|
||||
@@ -27,13 +27,27 @@ import { paperWrapperStyles } from "~/components/styles";
|
||||
// for testing
|
||||
import { layout } from "~/signals";
|
||||
|
||||
import { ToolbarMainButtonNames } from "./enum";
|
||||
|
||||
const initialState = {
|
||||
isUploadSubmenuOpen: false,
|
||||
isUploadVideoOpen: false,
|
||||
isUploadImageOpen: false,
|
||||
};
|
||||
|
||||
export const ToolbarMain = () => {
|
||||
export const ToolbarMain = ({
|
||||
disabled = false,
|
||||
buttonProps,
|
||||
}: {
|
||||
disabled?: boolean;
|
||||
buttonProps: {
|
||||
[key in ToolbarMainButtonNames]: {
|
||||
disabled?: boolean;
|
||||
active?: boolean;
|
||||
onClick?: MouseEventHandler<HTMLButtonElement>;
|
||||
};
|
||||
};
|
||||
}) => {
|
||||
//// for testing
|
||||
const {
|
||||
signals: { isMobile },
|
||||
@@ -65,15 +79,21 @@ export const ToolbarMain = () => {
|
||||
className={twMerge(
|
||||
"m-auto flex w-fit items-center divide-x divide-ui-border",
|
||||
paperWrapperStyles,
|
||||
disabled &&
|
||||
"pointer-events-none cursor-default bg-ui-border shadow-md",
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2 px-2">
|
||||
<ToolbarButton icon={faBars} />
|
||||
<ToolbarButton icon={faBars} buttonProps={buttonProps.MENU} />
|
||||
<ToolbarButton
|
||||
icon={faLocationArrow}
|
||||
iconProps={{ className: "fa-flip-horizontal" }}
|
||||
buttonProps={buttonProps.SELECT_ONE}
|
||||
/>
|
||||
<ToolbarButton
|
||||
icon={faSquareDashed}
|
||||
buttonProps={buttonProps.SELECT_AREA}
|
||||
/>
|
||||
<ToolbarButton icon={faSquareDashed} />
|
||||
<div className="relative">
|
||||
<ToolbarButton
|
||||
icon={faFilePlus}
|
||||
@@ -111,14 +131,26 @@ export const ToolbarMain = () => {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ToolbarButton icon={faCameraRotate} />
|
||||
<ToolbarButton icon={faHatWizard} />
|
||||
<ToolbarButton
|
||||
icon={faCameraRotate}
|
||||
buttonProps={buttonProps.CHANGE_CAMERA_ORIENTATION}
|
||||
/>
|
||||
<ToolbarButton
|
||||
icon={faHatWizard}
|
||||
buttonProps={buttonProps.AI_STYLIZE}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-2">
|
||||
<ToolbarButton icon={faArrowRotateLeft} />
|
||||
<ToolbarButton icon={faArrowRotateRight} />
|
||||
<ToolbarButton icon={faFloppyDisk} />
|
||||
<ToolbarButton icon={faDownload} />
|
||||
<ToolbarButton
|
||||
icon={faArrowRotateLeft}
|
||||
buttonProps={buttonProps.UNDO}
|
||||
/>
|
||||
<ToolbarButton
|
||||
icon={faArrowRotateRight}
|
||||
buttonProps={buttonProps.REDO}
|
||||
/>
|
||||
<ToolbarButton icon={faFloppyDisk} buttonProps={buttonProps.SAVE} />
|
||||
<ToolbarButton icon={faDownload} buttonProps={buttonProps.DOWNLOAD} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,34 +1,21 @@
|
||||
import { useCallback } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { withProtectionRoute } from "~/components/hoc";
|
||||
import { useRenderCounter } from "~/hooks/useRenderCounter";
|
||||
|
||||
// Components of the page
|
||||
import { ToolbarUserProfile, ErrorDialog } from "~/components/features";
|
||||
import { ToolbarUserProfile } from "~/components/features";
|
||||
|
||||
// Components of the Konva App are all in the KonvaContainer
|
||||
import { KonvaContainer } from "~/KonvaContainer";
|
||||
|
||||
// The KonvaApp is the root of the Konva stage
|
||||
// and only entry point for anything in Konva JS
|
||||
import { KonvaApp } from "~/KonvaApp";
|
||||
//Components of the Konva App are all in the KonvaComponent
|
||||
import { KonvaRootComponent } from "~/KonvaRootComponent";
|
||||
|
||||
export const Main = withProtectionRoute(() => {
|
||||
// This is a hook that will log the number of times the component has rerendered
|
||||
// Let's make sure we only log once
|
||||
useRenderCounter("Pages/Main");
|
||||
const konvaContainerCallbackRef = useCallback((node: HTMLDivElement) => {
|
||||
if (node !== null) {
|
||||
KonvaApp(node);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="fixed grid h-full w-full grid-cols-12 grid-rows-12">
|
||||
<KonvaContainer
|
||||
ref={konvaContainerCallbackRef}
|
||||
className="col-span-12 col-start-1 row-span-12 row-start-1"
|
||||
/>
|
||||
<KonvaRootComponent className="col-span-12 col-start-1 row-span-12 row-start-1" />
|
||||
<div
|
||||
className={twMerge(
|
||||
"col-span-8 col-start-5 row-span-1 row-start-1 flex justify-end",
|
||||
@@ -37,7 +24,6 @@ export const Main = withProtectionRoute(() => {
|
||||
)}
|
||||
>
|
||||
<ToolbarUserProfile />
|
||||
<ErrorDialog />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ContextualToolbarImage } from "~/KonvaContainer/ContextualToolbarImage";
|
||||
import { ContextualLoadingBar } from "~/KonvaContainer/ContextualLoadingBar";
|
||||
import { ContextualToolbarImage } from "~/KonvaRootComponent/ContextualToolbarImage";
|
||||
import { ContextualLoadingBar } from "~/KonvaRootComponent/ContextualLoadingBar";
|
||||
|
||||
import { ErrorDialog } from "~/components/features";
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { signal } from "@preact/signals-core";
|
||||
import { ToolbarMainButtonNames } from "~/components/features/ToolbarMain/enum";
|
||||
interface ToolbarMainSignalInterface {
|
||||
disabled: boolean;
|
||||
buttonStates: {
|
||||
[key in ToolbarMainButtonNames]: { disabled: boolean; active: boolean };
|
||||
};
|
||||
}
|
||||
const toolbarMainSignal = signal<ToolbarMainSignalInterface>({
|
||||
disabled: false,
|
||||
buttonStates: initButtonStates(),
|
||||
});
|
||||
|
||||
export const toolbarMain = {
|
||||
signal: toolbarMainSignal,
|
||||
|
||||
changeButtonState(
|
||||
buttonName: ToolbarMainButtonNames,
|
||||
{ disabled, active }: { disabled?: boolean; active?: boolean },
|
||||
) {
|
||||
toolbarMainSignal.value = {
|
||||
...toolbarMainSignal.value,
|
||||
buttonStates: {
|
||||
...toolbarMainSignal.value.buttonStates,
|
||||
[buttonName]: {
|
||||
disabled: active ? false : (disabled ?? false),
|
||||
active: active ?? false,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
function initButtonStates() {
|
||||
const ret: { [key: string]: { disabled: boolean; active: boolean } } = {};
|
||||
Object.values(ToolbarMainButtonNames).forEach((buttonName) => {
|
||||
ret[buttonName] = {
|
||||
disabled: false,
|
||||
active: false,
|
||||
};
|
||||
});
|
||||
return ret as ToolbarMainSignalInterface["buttonStates"];
|
||||
}
|
||||
@@ -6,12 +6,18 @@ import {
|
||||
dispatchers as imageToolbarDispatchers,
|
||||
eventsHandlers as imageToolbarEvents,
|
||||
} from "./imageToolbar";
|
||||
import {
|
||||
dispatchers as toolbarMainDispatchers,
|
||||
eventsHandlers as toolbarMainEvents,
|
||||
} from "./toolbarMain";
|
||||
|
||||
export const uiEvents = {
|
||||
...addMediaEvents,
|
||||
imageToolbar: imageToolbarEvents,
|
||||
toolbarMain: toolbarMainEvents,
|
||||
};
|
||||
export const dispatchUiEvents = {
|
||||
...addMediaDispatchers,
|
||||
imageToolbar: imageToolbarDispatchers,
|
||||
toolbarMain: toolbarMainDispatchers,
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
import { MouseEventHandler } from "react";
|
||||
import { signal, effect, Signal } from "@preact/signals-core";
|
||||
|
||||
import { ToolbarMainButtonNames } from "~/components/features/ToolbarMain/enum";
|
||||
|
||||
const events = Object.values(ToolbarMainButtonNames).reduce(
|
||||
(acc, buttonName) => {
|
||||
acc[buttonName] = signal<
|
||||
React.MouseEvent<HTMLButtonElement, MouseEvent> | undefined
|
||||
>();
|
||||
return acc;
|
||||
},
|
||||
{} as {
|
||||
[key in ToolbarMainButtonNames]: Signal<
|
||||
(React.MouseEvent<HTMLButtonElement, MouseEvent> | undefined) | undefined
|
||||
>;
|
||||
},
|
||||
);
|
||||
|
||||
export const eventsHandlers = Object.values(ToolbarMainButtonNames).reduce(
|
||||
(acc, buttonName) => {
|
||||
acc[buttonName] = {
|
||||
onClick: (callback: MouseEventHandler<HTMLButtonElement>) => {
|
||||
effect(() => {
|
||||
if (events[buttonName].value) {
|
||||
callback(events[buttonName].value);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
return acc;
|
||||
},
|
||||
{} as {
|
||||
[key in ToolbarMainButtonNames]: {
|
||||
onClick: (callback: MouseEventHandler<HTMLButtonElement>) => void;
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const dispatchers = Object.values(ToolbarMainButtonNames).reduce(
|
||||
(acc, buttonName) => {
|
||||
acc[buttonName] = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
events[buttonName].value = e;
|
||||
};
|
||||
return acc;
|
||||
},
|
||||
{} as {
|
||||
[key in ToolbarMainButtonNames]: MouseEventHandler<HTMLButtonElement>;
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user