mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
Removing not needed files and components.
This commit is contained in:
1 parent
0ee9b7c442
commit
fc824a10ae
20 files changed
-1458
No files matched your search
@@ -1,20 +0,0 @@
|
||||
import { Canvas, Meta } from '@storybook/blocks';
|
||||
|
||||
import * as ButtonStories from './Button.stories';
|
||||
|
||||
<Meta of={ButtonStories} />
|
||||
|
||||
# Button
|
||||
|
||||
A button denotes a possible action to be taken on behalf of the user.
|
||||
|
||||
There are three types of Button: primary, secondary, action.
|
||||
|
||||
<Canvas of={ButtonStories.Primary} />
|
||||
<Canvas of={ButtonStories.Secondary} />
|
||||
<Canvas of={ButtonStories.Action} />
|
||||
|
||||
It can be shown with an optional icon. If "iconFlip" is true, the icon shows after the "children", if false it shows before.
|
||||
|
||||
<Canvas of={ButtonStories.WithIconFlip} />
|
||||
<Canvas of={ButtonStories.WithIconNoFlip} />
|
||||
@@ -1,46 +0,0 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { Button } from "./Button";
|
||||
import { withActions } from "@storybook/addon-actions/decorator";
|
||||
import { faAngleLeft } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
const meta: Meta<typeof Button> = {
|
||||
component: Button,
|
||||
parameters: {
|
||||
actions: {
|
||||
handles: ["click"],
|
||||
},
|
||||
},
|
||||
decorators: [withActions],
|
||||
};
|
||||
|
||||
type Story = StoryObj<typeof Button>;
|
||||
|
||||
export const Primary: Story = {
|
||||
render: () => <Button variant="primary">Primary</Button>,
|
||||
};
|
||||
|
||||
export const Secondary: Story = {
|
||||
render: () => <Button variant="secondary">Secondary</Button>,
|
||||
};
|
||||
|
||||
export const Action: Story = {
|
||||
render: () => <Button variant="action">Action</Button>,
|
||||
};
|
||||
|
||||
export const WithIconFlip: Story = {
|
||||
render: () => (
|
||||
<Button variant="secondary" iconFlip icon={faAngleLeft}>
|
||||
Icon Flip
|
||||
</Button>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithIconNoFlip: Story = {
|
||||
render: () => (
|
||||
<Button variant="secondary" icon={faAngleLeft}>
|
||||
Icon
|
||||
</Button>
|
||||
),
|
||||
};
|
||||
|
||||
export default meta;
|
||||
@@ -1,107 +0,0 @@
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { ButtonHTMLAttributes } from "react";
|
||||
import { faSpinnerThird } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
icon?: IconDefinition;
|
||||
iconClassName?: string;
|
||||
iconFlip?: boolean;
|
||||
htmlFor?: string;
|
||||
variant?: "primary" | "secondary" | "action";
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
export const Button = ({
|
||||
icon,
|
||||
iconClassName,
|
||||
children,
|
||||
className: propsClassName,
|
||||
htmlFor,
|
||||
variant: propsVariant = "primary",
|
||||
disabled,
|
||||
iconFlip = false,
|
||||
loading,
|
||||
...rest
|
||||
}: ButtonProps) => {
|
||||
function getVariantClassNames(variant: string) {
|
||||
switch (variant) {
|
||||
case "secondary": {
|
||||
return "bg-brand-secondary hover:bg-brand-secondary-700 text-white focus-visible:outline-brand-secondary";
|
||||
}
|
||||
case "action": {
|
||||
return "bg-action hover:bg-action-900 text-white focus-visible:outline-action";
|
||||
}
|
||||
case "primary":
|
||||
default: {
|
||||
return "bg-brand-primary hover:bg-brand-primary-400 text-white focus-visible:outline-brand-primary-600";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const disabledClass = twMerge(
|
||||
disabled || loading ? "opacity-50 pointer-events-none" : "",
|
||||
);
|
||||
|
||||
const className = twMerge(
|
||||
"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,
|
||||
);
|
||||
|
||||
// const ButtonType = htmlFor ? "label" : "button";
|
||||
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>
|
||||
);
|
||||
}
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./Button";
|
||||
@@ -1,81 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import { TransitionDialogue, Button, ButtonProps } from "~/components";
|
||||
|
||||
type UnionedButtonProps = { label?: string } & ButtonProps;
|
||||
|
||||
interface ButtonDialoguePropsI {
|
||||
buttonProps?: UnionedButtonProps;
|
||||
confirmButtonProps?: UnionedButtonProps;
|
||||
closeButtonProps?: UnionedButtonProps;
|
||||
dialogProps?: {
|
||||
className?: string;
|
||||
};
|
||||
title?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
showClose?: boolean;
|
||||
}
|
||||
|
||||
export const ButtonDialogue = ({
|
||||
dialogProps = {},
|
||||
buttonProps: unionedButtonProps,
|
||||
confirmButtonProps,
|
||||
closeButtonProps: unionedCloseButtonProps,
|
||||
title,
|
||||
children,
|
||||
showClose = true,
|
||||
}: ButtonDialoguePropsI) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const closeModal = () => setIsOpen(false);
|
||||
const openModal = () => setIsOpen(true);
|
||||
|
||||
const { label: buttonLabel, ...buttonProps } = unionedButtonProps || {
|
||||
label: "Open",
|
||||
};
|
||||
const { label: closeButtonLabel, ...closeButtonProps } =
|
||||
unionedCloseButtonProps || { label: "Close" };
|
||||
return (
|
||||
<>
|
||||
<Button type="button" onClick={openModal} {...buttonProps}>
|
||||
{buttonLabel}
|
||||
</Button>
|
||||
|
||||
<TransitionDialogue
|
||||
title={title}
|
||||
isOpen={isOpen}
|
||||
onClose={closeModal}
|
||||
className={dialogProps.className}
|
||||
>
|
||||
<div className="mt-2 h-full">{children}</div>
|
||||
|
||||
<div className="mt-6 flex justify-end gap-2">
|
||||
{showClose && (
|
||||
<Button
|
||||
type="button"
|
||||
onClick={closeModal}
|
||||
{...closeButtonProps}
|
||||
variant="secondary"
|
||||
>
|
||||
{closeButtonLabel}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{confirmButtonProps && (
|
||||
<Button
|
||||
type="button"
|
||||
{...confirmButtonProps}
|
||||
onClick={(e) => {
|
||||
if (confirmButtonProps.onClick) {
|
||||
confirmButtonProps.onClick(e);
|
||||
}
|
||||
closeModal();
|
||||
}}
|
||||
>
|
||||
{confirmButtonProps.label ? confirmButtonProps.label : "Confirm"}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</TransitionDialogue>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export { ButtonDialogue } from './ButtonDialogue';
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from "./Badge";
|
||||
export * from "./Button";
|
||||
export * from "./ButtonDialogue";
|
||||
export * from "./ButtonDropdown";
|
||||
export * from "./ButtonIcon";
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { pageHeight, pageWidth } from "~/signals";
|
||||
import { SidePanelButtons } from "~/stories/SidePanelStories/SidePanelButtons";
|
||||
import {
|
||||
dndSidePanelWidth,
|
||||
sidePanelVisible,
|
||||
sidePanelWidth,
|
||||
} from "~/pages/PageEnigma/signals";
|
||||
import { SidePanelTabs } from "~/pages/PageEnigma/comps/SidePanelTabs";
|
||||
|
||||
export const RenderStoryContent = () => {
|
||||
useSignals();
|
||||
const displayWidth =
|
||||
dndSidePanelWidth.value > -1
|
||||
? dndSidePanelWidth.value
|
||||
: sidePanelWidth.value;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative flex justify-between bg-ui-background"
|
||||
style={{ width: pageWidth.value - 32, height: pageHeight.value - 32 }}
|
||||
>
|
||||
<div>
|
||||
<SidePanelButtons />
|
||||
</div>
|
||||
<div
|
||||
className={[
|
||||
"fixed",
|
||||
"border-l border-l-ui-panel-border bg-ui-panel",
|
||||
"flex",
|
||||
"transition-all duration-300 ease-in-out",
|
||||
].join(" ")}
|
||||
style={{
|
||||
top: 16,
|
||||
right: 24,
|
||||
width: sidePanelVisible.value ? displayWidth : 0,
|
||||
}}
|
||||
>
|
||||
<div className="relative block h-full w-full bg-ui-panel">
|
||||
<SidePanelTabs />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
import { environmentVariables, login, pageHeight, pageWidth } from "~/signals";
|
||||
import {
|
||||
selectedTab,
|
||||
sidePanelVisible,
|
||||
sidePanelWidth,
|
||||
timelineHeight,
|
||||
} from "~/pages/PageEnigma/signals";
|
||||
import { SidePanelTabs } from "~/pages/PageEnigma/comps/SidePanelTabs";
|
||||
import { tabList } from "~/pages/PageEnigma/comps/SidePanel/tabList";
|
||||
import { RenderStoryContent } from "./RenderStoryContent";
|
||||
import EnvironmentVariables from "~/Classes/EnvironmentVariables";
|
||||
|
||||
const meta: Meta<typeof SidePanelTabs> = {
|
||||
component: SidePanelTabs,
|
||||
render: () => {
|
||||
return <RenderStoryContent />;
|
||||
},
|
||||
};
|
||||
|
||||
EnvironmentVariables.initialize({ BASE_API: "", CDN_API: "" });
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof SidePanelTabs>;
|
||||
|
||||
export const SidePanelDocumentation: Story = {
|
||||
loaders: [
|
||||
() => {
|
||||
pageHeight.value = window.innerHeight;
|
||||
pageWidth.value = window.innerWidth;
|
||||
timelineHeight.value = -32;
|
||||
sidePanelWidth.value = 340;
|
||||
sidePanelVisible.value = true;
|
||||
selectedTab.value = tabList[0];
|
||||
environmentVariables.value = { BASE_API: "", CDN_API: "" };
|
||||
},
|
||||
async () => {
|
||||
await login({ password: "SEptember30!", usernameOrEmail: "coliphant" });
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,70 +0,0 @@
|
||||
import { Button } from "~/components";
|
||||
import { selectedTab, sidePanelVisible } from "~/pages/PageEnigma/signals";
|
||||
import { tabList } from "~/pages/PageEnigma/comps/SidePanel/tabList";
|
||||
|
||||
export const SidePanelButtons = () => {
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (!sidePanelVisible.value) {
|
||||
sidePanelVisible.value = true;
|
||||
}
|
||||
selectedTab.value = tabList[0];
|
||||
}}
|
||||
>
|
||||
Character Panel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (!sidePanelVisible.value) {
|
||||
sidePanelVisible.value = true;
|
||||
}
|
||||
selectedTab.value = tabList[1];
|
||||
}}
|
||||
>
|
||||
Animations Panel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (!sidePanelVisible.value) {
|
||||
sidePanelVisible.value = true;
|
||||
}
|
||||
selectedTab.value = tabList[2];
|
||||
}}
|
||||
>
|
||||
Expressions Panel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (!sidePanelVisible.value) {
|
||||
sidePanelVisible.value = true;
|
||||
}
|
||||
selectedTab.value = tabList[3];
|
||||
}}
|
||||
>
|
||||
Objects Panel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (!sidePanelVisible.value) {
|
||||
sidePanelVisible.value = true;
|
||||
}
|
||||
selectedTab.value = tabList[4];
|
||||
}}
|
||||
>
|
||||
Audio Panel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (!sidePanelVisible.value) {
|
||||
sidePanelVisible.value = true;
|
||||
}
|
||||
selectedTab.value = tabList[5];
|
||||
}}
|
||||
>
|
||||
Stylize Panel
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import { parseQueueData } from "./parseQueueData";
|
||||
|
||||
export const CallIn = ({ values }: any) => {
|
||||
return (
|
||||
<div className="text-black">
|
||||
<div>
|
||||
<strong>Call Parameters</strong>
|
||||
</div>
|
||||
<div className="h-[210px] w-[200px] overflow-auto">
|
||||
Params: {parseQueueData(values, 1)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,122 +0,0 @@
|
||||
import { Button } from "~/components";
|
||||
import {
|
||||
addCharacterAnimation,
|
||||
addCharacterExpression,
|
||||
addGlobalAudio,
|
||||
} from "~/pages/PageEnigma/signals";
|
||||
import { AssetType } from "~/enums";
|
||||
import { CallIn } from "~/stories/TimelineStories/CallIn";
|
||||
import { useState } from "react";
|
||||
|
||||
export const DnDActions = ({ setRefresh }: { setRefresh: () => void }) => {
|
||||
const [callValues, setCallValues] = useState<any>(null);
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<div>
|
||||
<strong>DnD Actions</strong>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
setCallValues({
|
||||
dragItem: {
|
||||
version: 1,
|
||||
type: AssetType.ANIMATION,
|
||||
media_type: "type",
|
||||
media_id: "id",
|
||||
name: "walk",
|
||||
length: 85,
|
||||
},
|
||||
characterId: "michael",
|
||||
offset: 27,
|
||||
});
|
||||
addCharacterAnimation({
|
||||
dragItem: {
|
||||
version: 1,
|
||||
type: AssetType.ANIMATION,
|
||||
media_type: "type",
|
||||
media_id: "id",
|
||||
name: "walk",
|
||||
length: 85,
|
||||
},
|
||||
characterId: "michael",
|
||||
offset: 27,
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Drop Animation (on michael)
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
setCallValues({
|
||||
dragItem: {
|
||||
version: 1,
|
||||
type: AssetType.EXPRESSION,
|
||||
media_type: "type",
|
||||
media_id: "id",
|
||||
name: "smile",
|
||||
length: 85,
|
||||
},
|
||||
characterId: "michael",
|
||||
offset: 10,
|
||||
});
|
||||
addCharacterExpression({
|
||||
dragItem: {
|
||||
version: 1,
|
||||
type: AssetType.EXPRESSION,
|
||||
media_type: "type",
|
||||
media_id: "id",
|
||||
name: "smile",
|
||||
length: 85,
|
||||
},
|
||||
characterId: "michael",
|
||||
offset: 10,
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Drop Expression (on michael)
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
setCallValues({
|
||||
dragItem: {
|
||||
version: 1,
|
||||
type: AssetType.AUDIO,
|
||||
media_type: "type",
|
||||
media_id: "id",
|
||||
name: "singing",
|
||||
length: 106,
|
||||
},
|
||||
audioId: "AG-1",
|
||||
offset: 5,
|
||||
});
|
||||
addGlobalAudio({
|
||||
dragItem: {
|
||||
version: 1,
|
||||
type: AssetType.AUDIO,
|
||||
media_type: "type",
|
||||
media_id: "id",
|
||||
name: "singing",
|
||||
length: 106,
|
||||
},
|
||||
audioId: "AG-1",
|
||||
offset: 5,
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Drop Audio (on global)
|
||||
</Button>
|
||||
</div>
|
||||
<CallIn values={callValues} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,272 +0,0 @@
|
||||
import { Button } from "~/components";
|
||||
import Queue, { QueueNames } from "~/pages/PageEnigma/Queue";
|
||||
import { fromEngineActions } from "~/pages/PageEnigma/Queue/fromEngineActions";
|
||||
import { AssetType, ClipGroup } from "~/enums";
|
||||
import { toTimelineActions } from "~/pages/PageEnigma/Queue/toTimelineActions";
|
||||
|
||||
export const EngineActions = ({ setRefresh }: { setRefresh: () => void }) => {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<div>
|
||||
<strong>Engine Actions</strong>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.FROM_ENGINE,
|
||||
action: fromEngineActions.UPDATE_CHARACTER_ID,
|
||||
data: {
|
||||
version: 1,
|
||||
type: AssetType.CHARACTER,
|
||||
media_id: "id",
|
||||
object_uuid: "michael",
|
||||
name: "Michael",
|
||||
},
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Add Character (michael)
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.FROM_ENGINE,
|
||||
action: fromEngineActions.ADD_OBJECT,
|
||||
data: {
|
||||
version: 1,
|
||||
type: AssetType.OBJECT,
|
||||
media_id: "id",
|
||||
object_uuid: "square",
|
||||
name: "Square",
|
||||
},
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Add Object (square)
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.FROM_ENGINE,
|
||||
action: fromEngineActions.DELETE_OBJECT,
|
||||
data: {
|
||||
version: 1,
|
||||
type: AssetType.CHARACTER,
|
||||
media_id: "id",
|
||||
object_uuid: "michael",
|
||||
name: "Michael",
|
||||
},
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Delete Character (michael)
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.FROM_ENGINE,
|
||||
action: fromEngineActions.DESELECT_OBJECT,
|
||||
data: null,
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Deselect Object
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.FROM_ENGINE,
|
||||
action: fromEngineActions.RESET_TIMELINE,
|
||||
data: null,
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Reset Timeline
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.FROM_ENGINE,
|
||||
action: fromEngineActions.SELECT_OBJECT,
|
||||
data: {
|
||||
version: 1,
|
||||
name: "Square",
|
||||
media_id: "id",
|
||||
type: AssetType.OBJECT,
|
||||
object_uuid: "square",
|
||||
},
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Select Object (square)
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<strong>More Engine Actions</strong>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.FROM_ENGINE,
|
||||
action: fromEngineActions.UPDATE_TIME,
|
||||
data: {
|
||||
currentTime: 66,
|
||||
},
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Update Time (66)
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.FROM_ENGINE,
|
||||
action: fromEngineActions.UPDATE_TIME_LINE,
|
||||
data: [
|
||||
{
|
||||
version: 1,
|
||||
group: "character",
|
||||
name: "Default",
|
||||
type: "fake",
|
||||
clip_uuid: "a406ac71-b6e2-4add-a6c6-91df6a669037",
|
||||
object_uuid: "a406ac71-b6e2-4add-a6c6-91df6a669037",
|
||||
object_name: "Female Doll",
|
||||
media_id: "m_r7w1tmkx2jg8nznr3hyzj4k6zhfh7d ",
|
||||
start_offset: 0,
|
||||
ending_offset: 0,
|
||||
keyframe_offset: 0,
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
group: "global_audio",
|
||||
name: "Talk (Demo Sounds)",
|
||||
type: "audio",
|
||||
clip_uuid: "1a6ab5a4-3eeb-49da-9756-eed36be76b44",
|
||||
object_name: "undefined",
|
||||
media_id: "m_403phjvjkbbaxxbz8y7r6qjay07mfd",
|
||||
start_offset: 8,
|
||||
ending_offset: 102.04064000000001,
|
||||
keyframe_offset: 0,
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
group: "global_audio",
|
||||
name: "Charlie Brown",
|
||||
type: "audio",
|
||||
clip_uuid: "edb83efe-6858-4d64-8651-75b137628e58",
|
||||
object_uuid: "m_djc4975qfm9sc86r9j4ap1ryaqmjfr",
|
||||
object_name: "undefined",
|
||||
media_id: "m_djc4975qfm9sc86r9j4ap1ryaqmjfr",
|
||||
start_offset: 121,
|
||||
ending_offset: 299.98,
|
||||
keyframe_offset: 0,
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
group: "object",
|
||||
name: "Default",
|
||||
type: "fake",
|
||||
clip_uuid: "03e390e0-2eb8-4989-af6e-e53ef945d74b",
|
||||
object_uuid: "03e390e0-2eb8-4989-af6e-e53ef945d74b",
|
||||
object_name: "Barbie Dreamland Test",
|
||||
media_id: "m_jn3v94e8ny4dw1cnwf9d5djhpd2q2e",
|
||||
start_offset: 0,
|
||||
ending_offset: 0,
|
||||
keyframe_offset: 0,
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
group: "camera",
|
||||
name: "::CAM::",
|
||||
type: "transform",
|
||||
clip_uuid: "77c12706-f31f-4d4c-8721-9f4036ab40e5",
|
||||
object_uuid: "55b606c1-274b-4158-8531-c65a4e6748a5",
|
||||
object_name: "::CAM::",
|
||||
media_id: "",
|
||||
start_offset: 0,
|
||||
ending_offset: 59,
|
||||
keyframe_offset: 59,
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
group: "camera",
|
||||
name: "::CAM::",
|
||||
type: "transform",
|
||||
clip_uuid: "ece94dde-4597-478f-923e-b46f02e56b2a",
|
||||
object_uuid: "55b606c1-274b-4158-8531-c65a4e6748a5",
|
||||
object_name: "::CAM::",
|
||||
media_id: "",
|
||||
start_offset: 0,
|
||||
ending_offset: 2,
|
||||
keyframe_offset: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Update Timeline
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setRefresh();
|
||||
setTimeout(() => {
|
||||
Queue.publish({
|
||||
queueName: QueueNames.TO_TIMELINE,
|
||||
action: toTimelineActions.ADD_KEYFRAME,
|
||||
data: {
|
||||
version: 1,
|
||||
group: ClipGroup.CAMERA,
|
||||
object_uuid: "camera",
|
||||
object_name: "Camera",
|
||||
position: {
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
},
|
||||
rotation: {
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
},
|
||||
scale: {
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
},
|
||||
},
|
||||
});
|
||||
}, 300);
|
||||
}}
|
||||
>
|
||||
Add Keyframe (camera)
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,48 +0,0 @@
|
||||
import { useQueueHandler } from "~/pages/PageEnigma/hooks/useQueueHandler";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { QueueSubscribeType } from "~/pages/PageEnigma/Queue/Queue";
|
||||
import Queue, { QueueNames } from "~/pages/PageEnigma/Queue";
|
||||
import { parseQueueData } from "~/stories/TimelineStories/parseQueueData";
|
||||
|
||||
export const QueueIn = ({ refresh }: { refresh: number }) => {
|
||||
useQueueHandler();
|
||||
const [queueAction, setQueueAction] = useState("");
|
||||
const [queueData, setQueueData] = useState<any>();
|
||||
|
||||
useEffect(() => {
|
||||
setQueueAction("");
|
||||
setQueueData(null);
|
||||
}, [refresh]);
|
||||
|
||||
const handleFromEngineActions = useCallback(
|
||||
({ action, data }: QueueSubscribeType) => {
|
||||
setQueueAction(action);
|
||||
setQueueData(data);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const handleToTimelineActions = useCallback(
|
||||
({ action, data }: QueueSubscribeType) => {
|
||||
setQueueAction(action);
|
||||
setQueueData(data);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
Queue.subscribe(QueueNames.FROM_ENGINE, "fromE", handleFromEngineActions);
|
||||
Queue.subscribe(QueueNames.TO_TIMELINE, "toTL", handleToTimelineActions);
|
||||
}, [handleFromEngineActions, handleToTimelineActions]);
|
||||
return (
|
||||
<div className="text-black">
|
||||
<div>
|
||||
<strong>Messages from Engine</strong>
|
||||
</div>
|
||||
<div>Action: {queueAction || "None"}</div>
|
||||
<div className="h-[210px] w-[200px] overflow-auto">
|
||||
Data: {parseQueueData(queueData, 1)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
import { useQueueHandler } from "~/pages/PageEnigma/hooks/useQueueHandler";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { QueueSubscribeType } from "~/pages/PageEnigma/Queue/Queue";
|
||||
import Queue, { QueueNames } from "~/pages/PageEnigma/Queue";
|
||||
import { parseQueueData } from "~/stories/TimelineStories/parseQueueData";
|
||||
|
||||
export const QueueOut = ({ refresh }: { refresh: number }) => {
|
||||
useQueueHandler();
|
||||
const [queueAction, setQueueAction] = useState("");
|
||||
const [queueData, setQueueData] = useState<any>();
|
||||
|
||||
useEffect(() => {
|
||||
setQueueAction("");
|
||||
setQueueData(null);
|
||||
}, [refresh]);
|
||||
|
||||
const handleToEngineActions = useCallback(
|
||||
({ action, data }: QueueSubscribeType) => {
|
||||
setQueueAction(action);
|
||||
setQueueData(data);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
Queue.subscribe(QueueNames.TO_ENGINE, "toE", handleToEngineActions);
|
||||
}, [handleToEngineActions]);
|
||||
return (
|
||||
<div className="text-black">
|
||||
<div>
|
||||
<strong>Messages to Engine</strong>
|
||||
</div>
|
||||
<div>Action: {queueAction || "None"}</div>
|
||||
<div className="h-[210px] w-[200px] overflow-auto">
|
||||
Data: {parseQueueData(queueData, 1)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Timeline } from "~/pages/PageEnigma/comps/Timeline";
|
||||
import { QueueIn } from "~/stories/TimelineStories/QueueIn";
|
||||
import { QueueOut } from "~/stories/TimelineStories/QueueOut";
|
||||
import { EngineActions } from "~/stories/TimelineStories/EngineActions";
|
||||
import { DnDActions } from "~/stories/TimelineStories/DnDActions";
|
||||
import { useState } from "react";
|
||||
|
||||
export const RenderStoryContent = () => {
|
||||
const [refresh, setRefresh] = useState(0);
|
||||
|
||||
return (
|
||||
<div className="text-black">
|
||||
<div>All length and offsets are in frames.</div>
|
||||
<div className="flex gap-4">
|
||||
<EngineActions
|
||||
setRefresh={() => setRefresh((count) => (count + 1) % 10000)}
|
||||
/>
|
||||
<QueueIn refresh={refresh} />
|
||||
<QueueOut refresh={refresh} />
|
||||
<DnDActions
|
||||
setRefresh={() => setRefresh((count) => (count + 1) % 10000)}
|
||||
/>
|
||||
<Timeline />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
import { Timeline } from "~/pages/PageEnigma/comps/Timeline";
|
||||
import { pageHeight, pageWidth } from "~/signals";
|
||||
import { timelineHeight } from "~/pages/PageEnigma/signals";
|
||||
import { RenderStoryContent } from "~/stories/TimelineStories/RenderStoryContent";
|
||||
|
||||
const meta: Meta<typeof Timeline> = {
|
||||
component: Timeline,
|
||||
render: () => {
|
||||
return <RenderStoryContent />;
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Timeline>;
|
||||
|
||||
export const TimelineDocumentation: Story = {
|
||||
loaders: [
|
||||
() => {
|
||||
pageHeight.value = 300;
|
||||
pageWidth.value = window.innerWidth - 32;
|
||||
timelineHeight.value = 280;
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
export function parseQueueData(data: any, indent: number) {
|
||||
if (data === undefined || data === null) {
|
||||
return "None";
|
||||
}
|
||||
if (typeof data === "object") {
|
||||
return (
|
||||
<div className="relative">
|
||||
{Object.entries(data).map(([key, value]) => (
|
||||
<div key={key} style={{ paddingLeft: 8 * indent }}>
|
||||
{key}: {parseQueueData(value, indent + 1)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return data.toString();
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
import os
|
||||
import hashlib
|
||||
import filecmp
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import difflib
|
||||
|
||||
|
||||
def get_file_hash(filepath):
|
||||
"""Calculate MD5 hash of a file."""
|
||||
md5_hash = hashlib.md5()
|
||||
try:
|
||||
with open(filepath, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(4096), b""):
|
||||
md5_hash.update(chunk)
|
||||
return md5_hash.hexdigest()
|
||||
except Exception:
|
||||
return "Error calculating hash"
|
||||
|
||||
|
||||
def format_size(size_bytes):
|
||||
"""Format file size nicely."""
|
||||
if size_bytes < 1000:
|
||||
return f"{size_bytes}B"
|
||||
elif size_bytes < 1000000:
|
||||
return f"{size_bytes / 1000:.1f}KB"
|
||||
else:
|
||||
return f"{size_bytes / 1000000:.1f}MB"
|
||||
|
||||
|
||||
def count_lines(filepath):
|
||||
"""Count lines in a file safely."""
|
||||
try:
|
||||
with open(filepath, "rb") as f:
|
||||
return sum(1 for _ in f)
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
|
||||
def calculate_diff_ratio(file1, file2):
|
||||
"""Calculate how different two files are using difflib."""
|
||||
try:
|
||||
with (
|
||||
open(file1, "r", errors="replace") as f1,
|
||||
open(file2, "r", errors="replace") as f2,
|
||||
):
|
||||
text1 = f1.readlines()
|
||||
text2 = f2.readlines()
|
||||
matcher = difflib.SequenceMatcher(None, text1, text2)
|
||||
return 1.0 - matcher.ratio() # Higher value means more different
|
||||
except Exception:
|
||||
return 1.0 # If we can't compare, assume completely different
|
||||
|
||||
|
||||
def get_relative_path(file_path, base_path):
|
||||
"""Get relative path from base directory."""
|
||||
return str(Path(file_path).relative_to(base_path))
|
||||
|
||||
|
||||
def collect_files_recursive(folder_path):
|
||||
"""Recursively collect all files in a folder."""
|
||||
folder_path = Path(folder_path)
|
||||
file_dict = {}
|
||||
|
||||
for path in folder_path.rglob("*"):
|
||||
if path.is_file():
|
||||
rel_path = get_relative_path(path, folder_path)
|
||||
file_dict[rel_path] = path
|
||||
|
||||
return file_dict
|
||||
|
||||
|
||||
def compare_folders_recursive(folder1, folder2, output_file=None):
|
||||
"""Compare two folders recursively and generate a detailed report."""
|
||||
# Automatically generate output filename if not specified
|
||||
if output_file is None:
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
output_file = f"folder_comparison_{timestamp}.md"
|
||||
|
||||
# Get folder paths
|
||||
folder1_path = Path(folder1)
|
||||
folder2_path = Path(folder2)
|
||||
|
||||
# Get shorthand names for display
|
||||
folder1_name = folder1_path.name
|
||||
folder2_name = folder2_path.name
|
||||
|
||||
# Get all files recursively
|
||||
print(f"Collecting files from {folder1_name}...")
|
||||
files1 = collect_files_recursive(folder1_path)
|
||||
print(f"Collecting files from {folder2_name}...")
|
||||
files2 = collect_files_recursive(folder2_path)
|
||||
|
||||
# All unique file paths across both folders
|
||||
all_files = sorted(set(files1.keys()) | set(files2.keys()))
|
||||
|
||||
# Calculate column widths for alignment
|
||||
max_filepath_len = max(len(file) for file in all_files) + 2
|
||||
hash_col_width = 10 # For hash comparison
|
||||
size_col_width = 20 # For size and line count
|
||||
diff_col_width = 30 # For difference description
|
||||
|
||||
# Initialize report
|
||||
report = [
|
||||
f"# Recursive Folder Comparison Report: {folder1_name} vs {folder2_name}\n",
|
||||
f"Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n",
|
||||
"## File Comparison Table\n",
|
||||
f"| {'File Path'.ljust(max_filepath_len)} | {'Status'.ljust(hash_col_width)} | {folder1_name.ljust(size_col_width)} | {folder2_name.ljust(size_col_width)} | {'Difference'.ljust(diff_col_width)} |",
|
||||
f"|{'-' * max_filepath_len}|{'-' * hash_col_width}|{'-' * size_col_width}|{'-' * size_col_width}|{'-' * diff_col_width}|",
|
||||
]
|
||||
|
||||
# Track file categories
|
||||
identical_files = []
|
||||
different_files = []
|
||||
only_in_folder1 = []
|
||||
only_in_folder2 = []
|
||||
|
||||
# Store detailed file comparisons for sorting later
|
||||
file_comparisons = []
|
||||
|
||||
# Compare each file
|
||||
print(f"Comparing {len(all_files)} unique files...")
|
||||
for rel_path in all_files:
|
||||
in_folder1 = rel_path in files1
|
||||
in_folder2 = rel_path in files2
|
||||
|
||||
# Default values
|
||||
status = "—"
|
||||
size1_str = "—"
|
||||
size2_str = "—"
|
||||
diff_str = "—"
|
||||
diff_ratio = 0
|
||||
|
||||
# Get details for folder1
|
||||
if in_folder1:
|
||||
file1 = files1[rel_path]
|
||||
size1 = file1.stat().st_size
|
||||
lines1 = count_lines(file1)
|
||||
hash1 = get_file_hash(file1)
|
||||
size1_str = f"{format_size(size1)} ({lines1} lines)"
|
||||
else:
|
||||
hash1 = "—"
|
||||
size1 = 0
|
||||
lines1 = 0
|
||||
|
||||
# Get details for folder2
|
||||
if in_folder2:
|
||||
file2 = files2[rel_path]
|
||||
size2 = file2.stat().st_size
|
||||
lines2 = count_lines(file2)
|
||||
hash2 = get_file_hash(file2)
|
||||
size2_str = f"{format_size(size2)} ({lines2} lines)"
|
||||
else:
|
||||
hash2 = "—"
|
||||
size2 = 0
|
||||
lines2 = 0
|
||||
|
||||
# Calculate difference and determine status
|
||||
if not in_folder1:
|
||||
status = "MISSING"
|
||||
diff_str = f"Only in {folder2_name}"
|
||||
only_in_folder2.append(rel_path)
|
||||
diff_ratio = 1.0 # Completely different (missing)
|
||||
elif not in_folder2:
|
||||
status = "MISSING"
|
||||
diff_str = f"Only in {folder1_name}"
|
||||
only_in_folder1.append(rel_path)
|
||||
diff_ratio = 1.0 # Completely different (missing)
|
||||
else:
|
||||
# Both files exist, compare them
|
||||
if hash1 == hash2 and hash1 != "Error calculating hash":
|
||||
status = "IDENTICAL"
|
||||
diff_str = "Identical content"
|
||||
identical_files.append(rel_path)
|
||||
diff_ratio = 0.0
|
||||
else:
|
||||
status = "DIFFERENT"
|
||||
size_diff = size2 - size1
|
||||
lines_diff = lines2 - lines1
|
||||
sign = "+" if size_diff > 0 else ""
|
||||
sign_lines = "+" if lines_diff > 0 else ""
|
||||
|
||||
# Calculate how different the files are
|
||||
diff_ratio = calculate_diff_ratio(file1, file2)
|
||||
different_files.append((rel_path, diff_ratio))
|
||||
|
||||
# Format difference description
|
||||
diff_pct = int(diff_ratio * 100)
|
||||
diff_str = f"{sign}{format_size(size_diff)} ({sign_lines}{lines_diff} lines) {diff_pct}% different"
|
||||
|
||||
# Store comparison for sorting later
|
||||
file_comparisons.append(
|
||||
{
|
||||
"rel_path": rel_path,
|
||||
"status": status,
|
||||
"size1_str": size1_str,
|
||||
"size2_str": size2_str,
|
||||
"diff_str": diff_str,
|
||||
"diff_ratio": diff_ratio,
|
||||
"in_folder1": in_folder1,
|
||||
"in_folder2": in_folder2,
|
||||
"hash1": hash1[:8] if len(hash1) > 8 else hash1,
|
||||
"hash2": hash2[:8] if len(hash2) > 8 else hash2,
|
||||
}
|
||||
)
|
||||
|
||||
# Sort files by difference ratio (most different first)
|
||||
file_comparisons.sort(key=lambda x: x["diff_ratio"], reverse=True)
|
||||
|
||||
# Generate the sorted table
|
||||
for comp in file_comparisons:
|
||||
hash_display = (
|
||||
f"{comp['hash1']}:{comp['hash2']}"
|
||||
if comp["status"] == "DIFFERENT"
|
||||
else comp["status"]
|
||||
)
|
||||
report.append(
|
||||
f"| {comp['rel_path'].ljust(max_filepath_len)} | "
|
||||
f"{hash_display.ljust(hash_col_width)} | "
|
||||
f"{comp['size1_str'].ljust(size_col_width)} | "
|
||||
f"{comp['size2_str'].ljust(size_col_width)} | "
|
||||
f"{comp['diff_str'].ljust(diff_col_width)} |"
|
||||
)
|
||||
|
||||
# Sort different files by difference ratio for the detailed section
|
||||
different_files.sort(key=lambda x: x[1], reverse=True)
|
||||
|
||||
# Add Files Missing From Each Folder sections
|
||||
report.append("\n## Files Present in One Folder But Missing in the Other\n")
|
||||
|
||||
if only_in_folder1:
|
||||
report.append(
|
||||
f"\n### Files Only in {folder1_name} ({len(only_in_folder1)} files)"
|
||||
)
|
||||
for rel_path in sorted(only_in_folder1):
|
||||
file1 = files1[rel_path]
|
||||
size1 = file1.stat().st_size
|
||||
lines1 = count_lines(file1)
|
||||
hash1 = get_file_hash(file1)[:8]
|
||||
report.append(
|
||||
f"- `{rel_path}` ({format_size(size1)}, {lines1} lines, hash: {hash1})"
|
||||
)
|
||||
|
||||
if only_in_folder2:
|
||||
report.append(
|
||||
f"\n### Files Only in {folder2_name} ({len(only_in_folder2)} files)"
|
||||
)
|
||||
for rel_path in sorted(only_in_folder2):
|
||||
file2 = files2[rel_path]
|
||||
size2 = file2.stat().st_size
|
||||
lines2 = count_lines(file2)
|
||||
hash2 = get_file_hash(file2)[:8]
|
||||
report.append(
|
||||
f"- `{rel_path}` ({format_size(size2)}, {lines2} lines, hash: {hash2})"
|
||||
)
|
||||
|
||||
# Add detailed section for different files
|
||||
if different_files:
|
||||
report.append(f"\n## Files with Differences (Sorted by Most Different First)\n")
|
||||
for rel_path, diff_ratio in different_files:
|
||||
file1 = files1[rel_path]
|
||||
file2 = files2[rel_path]
|
||||
size1 = file1.stat().st_size
|
||||
size2 = file2.stat().st_size
|
||||
lines1 = count_lines(file1)
|
||||
lines2 = count_lines(file2)
|
||||
hash1 = get_file_hash(file1)[:8]
|
||||
hash2 = get_file_hash(file2)[:8]
|
||||
size_diff = size2 - size1
|
||||
lines_diff = lines2 - lines1
|
||||
diff_pct = int(diff_ratio * 100)
|
||||
|
||||
report.append(f"### `{rel_path}` ({diff_pct}% different)")
|
||||
report.append(
|
||||
f"- {folder1_name}: {format_size(size1)}, {lines1} lines, hash: {hash1}"
|
||||
)
|
||||
report.append(
|
||||
f"- {folder2_name}: {format_size(size2)}, {lines2} lines, hash: {hash2}"
|
||||
)
|
||||
report.append(
|
||||
f"- Difference: {size_diff:+d} bytes, {lines_diff:+d} lines\n"
|
||||
)
|
||||
|
||||
# Add summary section
|
||||
report.extend(
|
||||
[
|
||||
"\n## Summary",
|
||||
f"- **Total Unique Files**: {len(all_files)}",
|
||||
f"- **Files in {folder1_name}**: {len(files1)}",
|
||||
f"- **Files in {folder2_name}**: {len(files2)}",
|
||||
f"- **Identical Files**: {len(identical_files)}",
|
||||
f"- **Different Files**: {len(different_files)}",
|
||||
f"- **Files Only in {folder1_name}**: {len(only_in_folder1)}",
|
||||
f"- **Files Only in {folder2_name}**: {len(only_in_folder2)}",
|
||||
f"\n## Path Information",
|
||||
f"- {folder1_name}: `{folder1}`",
|
||||
f"- {folder2_name}: `{folder2}`",
|
||||
]
|
||||
)
|
||||
|
||||
# Write report to file
|
||||
with open(output_file, "w") as f:
|
||||
f.write("\n".join(report))
|
||||
|
||||
print(f"Recursive comparison report written to {output_file}")
|
||||
return "\n".join(report)
|
||||
|
||||
|
||||
# Execute the comparison
|
||||
if __name__ == "__main__":
|
||||
folder1 = "/Users/michaelchung/storyteller-rust/frontend/apps/editor2d/src/Classes/"
|
||||
folder2 = "/Users/michaelchung/storyteller-rust/frontend/apps/editor3d/app/Classes/"
|
||||
|
||||
report = compare_folders_recursive(folder1, folder2)
|
||||
@@ -1,165 +0,0 @@
|
||||
# Recursive Folder Comparison Report: Classes vs Classes
|
||||
|
||||
Generated on: 2025-04-16 13:33:19
|
||||
|
||||
## File Comparison Table
|
||||
|
||||
| File Path | Status | Classes | Classes | Difference |
|
||||
|------------------------------------|----------|--------------------|--------------------|------------------------------|
|
||||
| ApiHelpers.ts | MISSING | — | 637B (17 lines) | Only in Classes |
|
||||
| ApiManager/SegmentationApi.ts | MISSING | 1.9KB (84 lines) | — | Only in Classes |
|
||||
| ApiManager/StudioGen2Api.ts | MISSING | — | 1.6KB (61 lines) | Only in Classes |
|
||||
| EnvironmentVariables.ts | MISSING | — | 263B (10 lines) | Only in Classes |
|
||||
| GetFrontendEnvironment.ts | MISSING | — | 1.9KB (65 lines) | Only in Classes |
|
||||
| ApiManager/MediaUploadApi.ts | 707d2bf2:06a93d8c | 10.3KB (349 lines) | 10.0KB (339 lines) | -255B (-10 lines) 72% different |
|
||||
| ApiManager/EngineApi.ts | c4850e80:85e20a81 | 1.0KB (39 lines) | 5.5KB (213 lines) | +4.5KB (+174 lines) 69% different |
|
||||
| ApiManager/JobsApi.ts | f7eb8e22:2aa03349 | 2.0KB (77 lines) | 1.9KB (74 lines) | -56B (-3 lines) 28% different |
|
||||
| ApiManager/ApiManager.ts | 44db0b07:67a3a046 | 5.5KB (235 lines) | 5.3KB (211 lines) | -200B (-24 lines) 14% different |
|
||||
| ApiManager/BillingApi.ts | 20051893:f5b7af84 | 1.0KB (33 lines) | 1.0KB (33 lines) | -8B (0 lines) 6% different |
|
||||
| ApiManager/VoiceDesignerApi.ts | e4d874c3:3635ba42 | 2.0KB (77 lines) | 2.1KB (78 lines) | +94B (+1 lines) 5% different |
|
||||
| ApiManager/MediaFilesApi.ts | be67aab2:44342e0f | 10.6KB (364 lines) | 10.6KB (369 lines) | +56B (+5 lines) 5% different |
|
||||
| ApiManager/PromptsApi.ts | d73d329a:c4824d2e | 648B (25 lines) | 657B (25 lines) | +9B (0 lines) 4% different |
|
||||
| ApiManager/MiscApi.ts | 298f5d93:187ad676 | 799B (26 lines) | 799B (26 lines) | 0B (0 lines) 3% different |
|
||||
| ApiManager/TtsApi.ts | 5feb5cad:6228b278 | 1.7KB (64 lines) | 1.7KB (64 lines) | +2B (0 lines) 3% different |
|
||||
| ApiManager/index.ts | 55a9094b:1fe59701 | 564B (18 lines) | 597B (19 lines) | +33B (+1 lines) 2% different |
|
||||
| ApiManager/UserBookmarksApi.ts | e3e4cb19:fd3afc78 | 5.4KB (201 lines) | 5.5KB (202 lines) | +56B (+1 lines) 2% different |
|
||||
| ApiManager/WeightsApi.ts | c12a98df:8a7dbb68 | 7.8KB (295 lines) | 7.9KB (296 lines) | +39B (+1 lines) 2% different |
|
||||
| ApiManager/VideoApi.ts | a9947328:cb947c07 | 1.9KB (70 lines) | 1.9KB (70 lines) | -11B (0 lines) 1% different |
|
||||
| ApiManager/BetaKeysApi.ts | 8d4ec6f1:33f1e4b3 | 4.3KB (167 lines) | 4.3KB (167 lines) | -3B (0 lines) 1% different |
|
||||
| ApiManager/UsersApi.ts | 65121217:72db0eae | 3.9KB (161 lines) | 3.9KB (161 lines) | -6B (0 lines) 0% different |
|
||||
| ApiManager/AnalyticsApi.ts | IDENTICAL | 944B (38 lines) | 944B (38 lines) | Identical content |
|
||||
| ApiManager/CommentsApi.ts | IDENTICAL | 2.3KB (91 lines) | 2.3KB (91 lines) | Identical content |
|
||||
| ApiManager/FeaturedItemsApi.ts | IDENTICAL | 2.3KB (96 lines) | 2.3KB (96 lines) | Identical content |
|
||||
| ApiManager/ModerationApi.ts | IDENTICAL | 960B (42 lines) | 960B (42 lines) | Identical content |
|
||||
| ApiManager/UserRatingsApi.ts | IDENTICAL | 2.4KB (92 lines) | 2.4KB (92 lines) | Identical content |
|
||||
| ApiManager/VoiceConversionApi.ts | IDENTICAL | 1.4KB (53 lines) | 1.4KB (53 lines) | Identical content |
|
||||
|
||||
## Files Present in One Folder But Missing in the Other
|
||||
|
||||
|
||||
### Files Only in Classes (23 files)
|
||||
- `ApiManager/SegmentationApi.ts` (1.9KB, 84 lines, hash: bb14fbf6)
|
||||
- `ApiManager/enums/Api.ts` (254B, 7 lines, hash: ea867d98)
|
||||
- `ApiManager/enums/Billing.ts` (242B, 11 lines, hash: e47c3eaa)
|
||||
- `ApiManager/enums/Job.ts` (433B, 16 lines, hash: d148fd64)
|
||||
- `ApiManager/enums/MediaFileClass.ts` (524B, 26 lines, hash: c90ce542)
|
||||
- `ApiManager/enums/MediaFileType.ts` (1.7KB, 58 lines, hash: a2374fec)
|
||||
- `ApiManager/enums/QueryFilters.ts` (579B, 29 lines, hash: 6d10a292)
|
||||
- `ApiManager/enums/Tts.ts` (205B, 7 lines, hash: f6393d2e)
|
||||
- `ApiManager/enums/UserFeatures.ts` (167B, 6 lines, hash: 05d49e51)
|
||||
- `ApiManager/enums/Visibility.ts` (92B, 5 lines, hash: 297d031b)
|
||||
- `ApiManager/enums/WeightCategory.ts` (180B, 8 lines, hash: f9be3d32)
|
||||
- `ApiManager/enums/WeightType.ts` (208B, 11 lines, hash: 80436726)
|
||||
- `ApiManager/models/BetaKeys.ts` (502B, 26 lines, hash: 7c718ac6)
|
||||
- `ApiManager/models/Billing.tsx` (416B, 17 lines, hash: 8db6eb3b)
|
||||
- `ApiManager/models/Dataset.ts` (588B, 23 lines, hash: 6af860ff)
|
||||
- `ApiManager/models/Job.ts` (1.8KB, 72 lines, hash: 9d7b385a)
|
||||
- `ApiManager/models/MediaFile.ts` (1.8KB, 59 lines, hash: 41778349)
|
||||
- `ApiManager/models/Pagination.ts` (200B, 9 lines, hash: 837b24d3)
|
||||
- `ApiManager/models/Prompts.ts` (424B, 16 lines, hash: 8ef1f366)
|
||||
- `ApiManager/models/StatusAlert.ts` (175B, 9 lines, hash: fcee4684)
|
||||
- `ApiManager/models/UserBookmark.ts` (1.6KB, 75 lines, hash: 8f70d1b1)
|
||||
- `ApiManager/models/Users.ts` (1.3KB, 50 lines, hash: 5ed82bbd)
|
||||
- `ApiManager/models/Weight.ts` (767B, 40 lines, hash: 3f9cccdb)
|
||||
|
||||
### Files Only in Classes (4 files)
|
||||
- `ApiHelpers.ts` (637B, 17 lines, hash: 9b638c6c)
|
||||
- `ApiManager/StudioGen2Api.ts` (1.6KB, 61 lines, hash: b2707195)
|
||||
- `EnvironmentVariables.ts` (263B, 10 lines, hash: 29c93666)
|
||||
- `GetFrontendEnvironment.ts` (1.9KB, 65 lines, hash: 7ee8b738)
|
||||
|
||||
## Files with Differences (Sorted by Most Different First)
|
||||
|
||||
### `ApiManager/MediaUploadApi.ts` (72% different)
|
||||
- Classes: 10.3KB, 349 lines, hash: 707d2bf2
|
||||
- Classes: 10.0KB, 339 lines, hash: 06a93d8c
|
||||
- Difference: -255 bytes, -10 lines
|
||||
|
||||
### `ApiManager/EngineApi.ts` (69% different)
|
||||
- Classes: 1.0KB, 39 lines, hash: c4850e80
|
||||
- Classes: 5.5KB, 213 lines, hash: 85e20a81
|
||||
- Difference: +4469 bytes, +174 lines
|
||||
|
||||
### `ApiManager/JobsApi.ts` (28% different)
|
||||
- Classes: 2.0KB, 77 lines, hash: f7eb8e22
|
||||
- Classes: 1.9KB, 74 lines, hash: 2aa03349
|
||||
- Difference: -56 bytes, -3 lines
|
||||
|
||||
### `ApiManager/ApiManager.ts` (14% different)
|
||||
- Classes: 5.5KB, 235 lines, hash: 44db0b07
|
||||
- Classes: 5.3KB, 211 lines, hash: 67a3a046
|
||||
- Difference: -200 bytes, -24 lines
|
||||
|
||||
### `ApiManager/BillingApi.ts` (6% different)
|
||||
- Classes: 1.0KB, 33 lines, hash: 20051893
|
||||
- Classes: 1.0KB, 33 lines, hash: f5b7af84
|
||||
- Difference: -8 bytes, +0 lines
|
||||
|
||||
### `ApiManager/VoiceDesignerApi.ts` (5% different)
|
||||
- Classes: 2.0KB, 77 lines, hash: e4d874c3
|
||||
- Classes: 2.1KB, 78 lines, hash: 3635ba42
|
||||
- Difference: +94 bytes, +1 lines
|
||||
|
||||
### `ApiManager/MediaFilesApi.ts` (5% different)
|
||||
- Classes: 10.6KB, 364 lines, hash: be67aab2
|
||||
- Classes: 10.6KB, 369 lines, hash: 44342e0f
|
||||
- Difference: +56 bytes, +5 lines
|
||||
|
||||
### `ApiManager/PromptsApi.ts` (4% different)
|
||||
- Classes: 648B, 25 lines, hash: d73d329a
|
||||
- Classes: 657B, 25 lines, hash: c4824d2e
|
||||
- Difference: +9 bytes, +0 lines
|
||||
|
||||
### `ApiManager/MiscApi.ts` (3% different)
|
||||
- Classes: 799B, 26 lines, hash: 298f5d93
|
||||
- Classes: 799B, 26 lines, hash: 187ad676
|
||||
- Difference: +0 bytes, +0 lines
|
||||
|
||||
### `ApiManager/TtsApi.ts` (3% different)
|
||||
- Classes: 1.7KB, 64 lines, hash: 5feb5cad
|
||||
- Classes: 1.7KB, 64 lines, hash: 6228b278
|
||||
- Difference: +2 bytes, +0 lines
|
||||
|
||||
### `ApiManager/index.ts` (2% different)
|
||||
- Classes: 564B, 18 lines, hash: 55a9094b
|
||||
- Classes: 597B, 19 lines, hash: 1fe59701
|
||||
- Difference: +33 bytes, +1 lines
|
||||
|
||||
### `ApiManager/UserBookmarksApi.ts` (2% different)
|
||||
- Classes: 5.4KB, 201 lines, hash: e3e4cb19
|
||||
- Classes: 5.5KB, 202 lines, hash: fd3afc78
|
||||
- Difference: +56 bytes, +1 lines
|
||||
|
||||
### `ApiManager/WeightsApi.ts` (2% different)
|
||||
- Classes: 7.8KB, 295 lines, hash: c12a98df
|
||||
- Classes: 7.9KB, 296 lines, hash: 8a7dbb68
|
||||
- Difference: +39 bytes, +1 lines
|
||||
|
||||
### `ApiManager/VideoApi.ts` (1% different)
|
||||
- Classes: 1.9KB, 70 lines, hash: a9947328
|
||||
- Classes: 1.9KB, 70 lines, hash: cb947c07
|
||||
- Difference: -11 bytes, +0 lines
|
||||
|
||||
### `ApiManager/BetaKeysApi.ts` (1% different)
|
||||
- Classes: 4.3KB, 167 lines, hash: 8d4ec6f1
|
||||
- Classes: 4.3KB, 167 lines, hash: 33f1e4b3
|
||||
- Difference: -3 bytes, +0 lines
|
||||
|
||||
### `ApiManager/UsersApi.ts` (0% different)
|
||||
- Classes: 3.9KB, 161 lines, hash: 65121217
|
||||
- Classes: 3.9KB, 161 lines, hash: 72db0eae
|
||||
- Difference: -6 bytes, +0 lines
|
||||
|
||||
|
||||
## Summary
|
||||
- **Total Unique Files**: 49
|
||||
- **Files in Classes**: 45
|
||||
- **Files in Classes**: 26
|
||||
- **Identical Files**: 6
|
||||
- **Different Files**: 16
|
||||
- **Files Only in Classes**: 23
|
||||
- **Files Only in Classes**: 4
|
||||
|
||||
## Path Information
|
||||
- Classes: `/Users/michaelchung/storyteller-rust/frontend/apps/editor2d/src/Classes/`
|
||||
- Classes: `/Users/michaelchung/storyteller-rust/frontend/apps/editor3d/app/Classes/`
|
||||
Reference in new issue
Block a user