mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-08 02:52:12 +00:00
Tabs / Anime Tab and Cartoons Tab (#615)
Tabs/ Anime and Cartoons - merge original character and animation into 1 tab - duplicate the Character + Animation combo tab because - we have anime & cartoon, 2 different types of character&animation combos --------- Co-authored-by: wil <wil@storyteller.ai>
This commit is contained in:
1 parent
a743199c56
commit
5bb656b980
15 files changed
+319
-101
No files matched your search
@@ -8,6 +8,9 @@ export enum FilterMediaType {
|
||||
SCENE_JSON = "scene_json",
|
||||
GLB = "glb",
|
||||
GLTF = "gltf",
|
||||
PMX = "pmx",
|
||||
PMD = "pmd",
|
||||
VMD = "vmd",
|
||||
}
|
||||
|
||||
export enum FilterEngineCategories {
|
||||
|
||||
+8
-6
@@ -1,11 +1,13 @@
|
||||
export enum TabTitles {
|
||||
SET_OBJECTS = "Film Sets",
|
||||
IMAGE_PLANE = "Image Panels",
|
||||
CHARACTERS = "Character",
|
||||
CREATURES = "Creatures",
|
||||
ANIMATION = "Animation",
|
||||
EXPRESSIONS = "Facial Expression",
|
||||
OBJECTS = "Set Dressings",
|
||||
AUDIO = "Audio",
|
||||
CHARACTERS = "Character",
|
||||
CHARACTERS_ANIME = "Anime",
|
||||
CHARACTERS_TOONS = "Cartoons",
|
||||
EXPRESSIONS = "Facial Expression",
|
||||
IMAGE_PLANE = "Image Panels",
|
||||
OBJECTS = "Set Dressings",
|
||||
OBJECTS_CREATURES = "Creatures",
|
||||
OBJECTS_SETS = "Film Sets",
|
||||
STYLIZE = "AI Stylize",
|
||||
}
|
||||
@@ -1,27 +1,29 @@
|
||||
import { ReactNode } from "react";
|
||||
import { FontAwesomeIconProps } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faGlobeSnow,
|
||||
faPeople,
|
||||
faRabbitRunning,
|
||||
faFaceSmileWink,
|
||||
faCube,
|
||||
faVolume,
|
||||
faBrush,
|
||||
faSpaghettiMonsterFlying,
|
||||
faCatSpace,
|
||||
faFaceSmileWink,
|
||||
faGlobeSnow,
|
||||
faPresentationScreen,
|
||||
faRaygun,
|
||||
faSpaghettiMonsterFlying,
|
||||
faUserAstronaut,
|
||||
faVolume,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
import { TabTitles } from "~/enums";
|
||||
import { ObjectsTab } from "~/pages/PageEnigma/comps/SidePanelTabs/tabComps/ObjectsTab";
|
||||
import { AnimationTab } from "~/pages/PageEnigma/comps/SidePanelTabs/tabComps/AnimationTab";
|
||||
import { AudioTab } from "~/pages/PageEnigma/comps/SidePanelTabs/tabComps/AudioTab";
|
||||
import { StylizeTab } from "~/pages/PageEnigma/comps/SidePanelTabs/tabComps/StylizeTab/StylizeTab";
|
||||
import { ExpressionTab } from "~/pages/PageEnigma/comps/SidePanelTabs/tabComps/ExpressionTab";
|
||||
import { CharactersTab } from "~/pages/PageEnigma/comps/SidePanelTabs/tabComps/CharactersTab";
|
||||
import { CreaturesTab } from "~/pages/PageEnigma/comps/SidePanelTabs/tabComps/CreaturesTab";
|
||||
import { SetsTab } from "~/pages/PageEnigma/comps/SidePanelTabs/tabComps/SetsTab";
|
||||
import { ImagePlanesTab } from "~/pages/PageEnigma/comps/SidePanelTabs/tabComps/ImagePlanesTab";
|
||||
import {
|
||||
AnimeTab,
|
||||
CartoonsTab,
|
||||
} from "../SidePanelTabs/tabComps/AnimationCharacterComboTabs";
|
||||
|
||||
export interface TabItem {
|
||||
icon: FontAwesomeIconProps["icon"];
|
||||
@@ -32,23 +34,23 @@ export interface TabItem {
|
||||
export const tabList = [
|
||||
{
|
||||
icon: faGlobeSnow,
|
||||
title: TabTitles.SET_OBJECTS,
|
||||
title: TabTitles.OBJECTS_SETS,
|
||||
component: <SetsTab />,
|
||||
},
|
||||
{
|
||||
icon: faPeople,
|
||||
title: TabTitles.CHARACTERS,
|
||||
component: <CharactersTab />,
|
||||
},
|
||||
{
|
||||
icon: faSpaghettiMonsterFlying,
|
||||
title: TabTitles.CREATURES,
|
||||
title: TabTitles.OBJECTS_CREATURES,
|
||||
component: <CreaturesTab />,
|
||||
},
|
||||
{
|
||||
icon: faRabbitRunning,
|
||||
title: TabTitles.ANIMATION,
|
||||
component: <AnimationTab />,
|
||||
icon: faUserAstronaut,
|
||||
title: TabTitles.CHARACTERS_ANIME,
|
||||
component: <AnimeTab />,
|
||||
},
|
||||
{
|
||||
icon: faCatSpace,
|
||||
title: TabTitles.CHARACTERS_TOONS,
|
||||
component: <CartoonsTab />,
|
||||
},
|
||||
{
|
||||
icon: faFaceSmileWink,
|
||||
@@ -56,7 +58,7 @@ export const tabList = [
|
||||
component: <ExpressionTab />,
|
||||
},
|
||||
{
|
||||
icon: faCube,
|
||||
icon: faRaygun,
|
||||
title: TabTitles.OBJECTS,
|
||||
component: <ObjectsTab />,
|
||||
},
|
||||
|
||||
@@ -45,13 +45,13 @@ export const SidePanelMenu = ({
|
||||
>
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
{(tabs ?? []).map((tab) => {
|
||||
if (tab.title === TabTitles.SET_OBJECTS && !showSetsTab) {
|
||||
if (tab.title === TabTitles.OBJECTS_SETS && !showSetsTab) {
|
||||
return;
|
||||
}
|
||||
if (tab.title === TabTitles.IMAGE_PLANE && !showImagePlaneTab) {
|
||||
return;
|
||||
}
|
||||
if (tab.title === TabTitles.CREATURES && !showCreaturesTab) {
|
||||
if (tab.title === TabTitles.OBJECTS_CREATURES && !showCreaturesTab) {
|
||||
return;
|
||||
}
|
||||
return (
|
||||
|
||||
@@ -10,6 +10,22 @@ interface Props {
|
||||
item: MediaItem;
|
||||
}
|
||||
|
||||
const mapObejctType = (mediaType: string) => {
|
||||
const typeCased = mediaType.toLowerCase();
|
||||
switch (typeCased) {
|
||||
case "fbx":
|
||||
case "glb": {
|
||||
return "Mixamo";
|
||||
}
|
||||
case "pmx": {
|
||||
return "MMD";
|
||||
}
|
||||
default: {
|
||||
return typeCased.toUpperCase();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const ItemElement = ({ item }: Props) => {
|
||||
useSignals();
|
||||
const defaultThumb = `/resources/images/default-covers/${(item.imageIndex || 0) % 24}.webp`;
|
||||
@@ -23,14 +39,9 @@ export const ItemElement = ({ item }: Props) => {
|
||||
{item.media_type && (
|
||||
<Badge
|
||||
label={
|
||||
item.type === AssetType.OBJECT
|
||||
? item.media_type.toUpperCase()
|
||||
: item.media_type === "fbx" ||
|
||||
item.media_type.toLowerCase() === "glb"
|
||||
? "Mixamo"
|
||||
: item.media_type === "pmx"
|
||||
? "MMD"
|
||||
: item.media_type.toUpperCase()
|
||||
item.type === AssetType.CHARACTER
|
||||
? mapObejctType(item.media_type)
|
||||
: item.media_type.toUpperCase()
|
||||
}
|
||||
className="absolute right-0 mr-[3px] mt-[3px]"
|
||||
/>
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { useState } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { MediaFileAnimationType, TabTitles } from "~/enums";
|
||||
import { TabTitle } from "../../sharedComps";
|
||||
import { AnimationTab } from "./subpageAnimation";
|
||||
import { CharactersTab } from "./subpageCharacters";
|
||||
|
||||
export const AnimeTab = () => {
|
||||
const [subPage, setSubPage] = useState<
|
||||
TabTitles.ANIMATION | TabTitles.CHARACTERS
|
||||
>(TabTitles.CHARACTERS);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TabTitle title="Anime Characters & Animations" />
|
||||
|
||||
<div className="mx-4">
|
||||
<button
|
||||
className={twMerge(
|
||||
"h-10 w-1/2 cursor-pointer rounded-l-lg bg-brand-secondary p-2 text-sm font-medium transition-all",
|
||||
subPage === TabTitles.CHARACTERS
|
||||
? "bg-ui-controls-button"
|
||||
: "hover:bg-ui-controls-button/50",
|
||||
)}
|
||||
disabled={subPage === TabTitles.CHARACTERS}
|
||||
onClick={() => setSubPage(TabTitles.CHARACTERS)}
|
||||
>
|
||||
Characters
|
||||
</button>
|
||||
<button
|
||||
className={twMerge(
|
||||
"h-10 w-1/2 cursor-pointer rounded-r-lg bg-brand-secondary p-2 text-sm font-medium transition-all",
|
||||
subPage === TabTitles.ANIMATION
|
||||
? "bg-ui-controls-button"
|
||||
: "hover:bg-ui-controls-button/50",
|
||||
)}
|
||||
disabled={subPage === TabTitles.ANIMATION}
|
||||
onClick={() => {
|
||||
setSubPage(TabTitles.ANIMATION);
|
||||
}}
|
||||
>
|
||||
Animations
|
||||
</button>
|
||||
</div>
|
||||
{subPage === TabTitles.ANIMATION && (
|
||||
<AnimationTab animationType={MediaFileAnimationType.MikuMikuDance} />
|
||||
)}
|
||||
{subPage === TabTitles.CHARACTERS && (
|
||||
<CharactersTab animationType={MediaFileAnimationType.MikuMikuDance} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
import { useState } from "react";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { MediaFileAnimationType, TabTitles } from "~/enums";
|
||||
import { TabTitle } from "../../sharedComps";
|
||||
import { AnimationTab } from "./subpageAnimation";
|
||||
import { CharactersTab } from "./subpageCharacters";
|
||||
import { characterItems, animationItems } from "~/pages/PageEnigma/signals";
|
||||
|
||||
export const CartoonsTab = () => {
|
||||
useSignals();
|
||||
|
||||
const [subPage, setSubPage] = useState<
|
||||
TabTitles.ANIMATION | TabTitles.CHARACTERS
|
||||
>(TabTitles.CHARACTERS);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TabTitle title="Cartoon Characters & Animations" />
|
||||
|
||||
<div className="mx-4">
|
||||
<button
|
||||
className={twMerge(
|
||||
"h-10 w-1/2 cursor-pointer rounded-l-lg bg-brand-secondary p-2 text-sm font-medium transition-all",
|
||||
subPage === TabTitles.CHARACTERS
|
||||
? "bg-ui-controls-button"
|
||||
: "hover:bg-ui-controls-button/50",
|
||||
)}
|
||||
disabled={subPage === TabTitles.CHARACTERS}
|
||||
onClick={() => setSubPage(TabTitles.CHARACTERS)}
|
||||
>
|
||||
Characters
|
||||
</button>
|
||||
<button
|
||||
className={twMerge(
|
||||
"h-10 w-1/2 cursor-pointer rounded-r-lg bg-brand-secondary p-2 text-sm font-medium transition-all",
|
||||
subPage === TabTitles.ANIMATION
|
||||
? "bg-ui-controls-button"
|
||||
: "hover:bg-ui-controls-button/50",
|
||||
)}
|
||||
disabled={subPage === TabTitles.ANIMATION}
|
||||
onClick={() => {
|
||||
setSubPage(TabTitles.ANIMATION);
|
||||
}}
|
||||
>
|
||||
Animations
|
||||
</button>
|
||||
</div>
|
||||
{subPage === TabTitles.CHARACTERS && (
|
||||
<CharactersTab
|
||||
animationType={MediaFileAnimationType.Mixamo}
|
||||
demoCharacterItems={characterItems.value}
|
||||
/>
|
||||
)}
|
||||
{subPage === TabTitles.ANIMATION && (
|
||||
<AnimationTab
|
||||
animationType={MediaFileAnimationType.Mixamo}
|
||||
demoAnimationItems={animationItems.value}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import { FilterMediaType, MediaFileAnimationType } from "~/enums";
|
||||
import { MediaItem } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const filterMMDCharacters = (item: MediaItem) => {
|
||||
return (
|
||||
item.maybe_animation_type === MediaFileAnimationType.MikuMikuDance ||
|
||||
item.media_type === FilterMediaType.PMD ||
|
||||
item.media_type === FilterMediaType.PMX
|
||||
);
|
||||
};
|
||||
|
||||
export const filterMixamoCharacters = (item: MediaItem) => {
|
||||
return (
|
||||
item.maybe_animation_type === MediaFileAnimationType.Mixamo ||
|
||||
(item.media_type !== FilterMediaType.PMD &&
|
||||
item.media_type !== FilterMediaType.PMX)
|
||||
);
|
||||
};
|
||||
|
||||
export const filterMMDAnimations = (item: MediaItem) => {
|
||||
return (
|
||||
item.maybe_animation_type === MediaFileAnimationType.MikuMikuDance ||
|
||||
item.media_type === FilterMediaType.VMD
|
||||
);
|
||||
};
|
||||
|
||||
export const filterMixamoAnimations = (item: MediaItem) => {
|
||||
return (
|
||||
item.maybe_animation_type === MediaFileAnimationType.Mixamo ||
|
||||
item.media_type !== FilterMediaType.VMD
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./AnimeTab";
|
||||
export * from "./CartoonsTab";
|
||||
+53
-32
@@ -1,5 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { faCirclePlus } from "@fortawesome/pro-solid-svg-icons";
|
||||
import {
|
||||
ANIMATION_FILE_TYPE,
|
||||
@@ -8,7 +7,6 @@ import {
|
||||
FilterEngineCategories,
|
||||
MediaFileAnimationType,
|
||||
} from "~/enums";
|
||||
import { animationItems } from "~/pages/PageEnigma/signals";
|
||||
import {
|
||||
Button,
|
||||
FilterButtons,
|
||||
@@ -16,10 +14,7 @@ import {
|
||||
SearchFilter,
|
||||
UploadModal,
|
||||
} from "~/components";
|
||||
import {
|
||||
TabTitle,
|
||||
ItemElements,
|
||||
} from "~/pages/PageEnigma/comps/SidePanelTabs/sharedComps";
|
||||
import { ItemElements } from "~/pages/PageEnigma/comps/SidePanelTabs/sharedComps";
|
||||
import { FetchStatus } from "~/pages/PageEnigma/enums";
|
||||
import {
|
||||
fetchFeaturedMediaItems,
|
||||
@@ -28,15 +23,32 @@ import {
|
||||
fetchUserMediaItems,
|
||||
fetchUserMediaItemsSearchResults,
|
||||
isAnyStatusFetching,
|
||||
} from "../utilities";
|
||||
} from "../../utilities";
|
||||
import { usePosthogFeatureFlag } from "~/hooks/usePosthogFeatureFlag";
|
||||
import {
|
||||
filterMixamoAnimations,
|
||||
filterMMDAnimations,
|
||||
} from "./filterCharacterTypes";
|
||||
import { MediaItem } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const AnimationTab = () => {
|
||||
useSignals();
|
||||
|
||||
export const AnimationTab = ({
|
||||
animationType,
|
||||
demoAnimationItems = [],
|
||||
}: {
|
||||
animationType: MediaFileAnimationType;
|
||||
demoAnimationItems?: MediaItem[];
|
||||
}) => {
|
||||
const showSearchObjectComponent = usePosthogFeatureFlag(
|
||||
FeatureFlags.SHOW_SEARCH_OBJECTS,
|
||||
);
|
||||
const showUploadButton = usePosthogFeatureFlag(FeatureFlags.DEV_ONLY);
|
||||
const filterAnimationType = useMemo(
|
||||
() =>
|
||||
animationType === MediaFileAnimationType.Mixamo
|
||||
? filterMixamoAnimations
|
||||
: filterMMDAnimations,
|
||||
[animationType],
|
||||
);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [searchTermFeatured, setSearchTermFeatured] = useState("");
|
||||
@@ -76,7 +88,7 @@ export const AnimationTab = () => {
|
||||
);
|
||||
const displayedItems =
|
||||
selectedFilter === AssetFilterOption.FEATURED
|
||||
? [...(featuredAnimations || []), ...animationItems.value]
|
||||
? [...(featuredAnimations || []), ...demoAnimationItems]
|
||||
: userAnimations ?? [];
|
||||
|
||||
const [currentPage, setCurrentPage] = useState<number>(0);
|
||||
@@ -96,10 +108,13 @@ export const AnimationTab = () => {
|
||||
fetchUserMediaItems({
|
||||
filterEngineCategories: [FilterEngineCategories.ANIMATION],
|
||||
setState: (newState: FetchMediaItemStates) => {
|
||||
const filterNewMediaItems = newState.mediaItems
|
||||
? newState.mediaItems.filter(filterAnimationType)
|
||||
: undefined;
|
||||
setUserFetch((curr) => ({
|
||||
status: newState.status,
|
||||
mediaItems: newState.mediaItems
|
||||
? newState.mediaItems
|
||||
mediaItems: filterNewMediaItems
|
||||
? filterNewMediaItems
|
||||
: curr.mediaItems,
|
||||
}));
|
||||
},
|
||||
@@ -113,10 +128,13 @@ export const AnimationTab = () => {
|
||||
fetchFeaturedMediaItems({
|
||||
filterEngineCategories: [FilterEngineCategories.ANIMATION],
|
||||
setState: (newState: FetchMediaItemStates) => {
|
||||
const filterNewMediaItems = newState.mediaItems
|
||||
? newState.mediaItems.filter(filterAnimationType)
|
||||
: undefined;
|
||||
setFeaturedFetch((curr) => ({
|
||||
status: newState.status,
|
||||
mediaItems: newState.mediaItems
|
||||
? newState.mediaItems
|
||||
mediaItems: filterNewMediaItems
|
||||
? filterNewMediaItems
|
||||
: curr.mediaItems,
|
||||
}));
|
||||
},
|
||||
@@ -126,7 +144,7 @@ export const AnimationTab = () => {
|
||||
);
|
||||
|
||||
const filterAnimationItems = (searchTerm: string) =>
|
||||
animationItems.value.filter((item) =>
|
||||
demoAnimationItems.filter((item) =>
|
||||
item.name.toLowerCase().includes(searchTerm.toLowerCase()),
|
||||
);
|
||||
|
||||
@@ -197,7 +215,7 @@ export const AnimationTab = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<TabTitle title="Animation" />
|
||||
{/* <TabTitle title="Animation" /> */}
|
||||
|
||||
<FilterButtons
|
||||
value={selectedFilter}
|
||||
@@ -208,14 +226,16 @@ export const AnimationTab = () => {
|
||||
/>
|
||||
|
||||
<div className="flex w-full flex-col gap-3 px-4">
|
||||
<Button
|
||||
icon={faCirclePlus}
|
||||
variant="action"
|
||||
onClick={() => setOpen(true)}
|
||||
className="w-full py-3 text-sm font-medium"
|
||||
>
|
||||
Upload Animation
|
||||
</Button>
|
||||
{showUploadButton && (
|
||||
<Button
|
||||
icon={faCirclePlus}
|
||||
variant="action"
|
||||
onClick={() => setOpen(true)}
|
||||
className="w-full py-3 text-sm font-medium"
|
||||
>
|
||||
Upload Animation (Dev Only)
|
||||
</Button>
|
||||
)}
|
||||
{showSearchObjectComponent && (
|
||||
<SearchFilter
|
||||
searchTerm={
|
||||
@@ -268,20 +288,21 @@ export const AnimationTab = () => {
|
||||
onClose={() => setOpen(false)}
|
||||
onSuccess={fetchUserAnimations}
|
||||
isOpen={open}
|
||||
type={FilterEngineCategories.ANIMATION}
|
||||
fileTypes={Object.values(ANIMATION_FILE_TYPE)}
|
||||
title="Upload Animation"
|
||||
options={{
|
||||
fileSubtypes: [
|
||||
{ Mixamo: MediaFileAnimationType.Mixamo },
|
||||
{ MikuMikuDance: MediaFileAnimationType.MikuMikuDance },
|
||||
{ MoveAi: MediaFileAnimationType.MoveAi },
|
||||
{ Rigify: MediaFileAnimationType.Rigify },
|
||||
{ Rokoko: MediaFileAnimationType.Rokoko },
|
||||
{ [animationType]: animationType },
|
||||
// { Mixamo: MediaFileAnimationType.Mixamo },
|
||||
// { MikuMikuDance: MediaFileAnimationType.MikuMikuDance },
|
||||
// { MoveAi: MediaFileAnimationType.MoveAi },
|
||||
// { Rigify: MediaFileAnimationType.Rigify },
|
||||
// { Rokoko: MediaFileAnimationType.Rokoko },
|
||||
],
|
||||
hasLength: true,
|
||||
hasThumbnailUpload: true,
|
||||
}}
|
||||
type={FilterEngineCategories.ANIMATION}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
+54
-30
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { faCirclePlus } from "@fortawesome/pro-solid-svg-icons";
|
||||
import {
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
MediaFileAnimationType,
|
||||
} from "~/enums";
|
||||
import { FetchStatus } from "~/pages/PageEnigma/enums";
|
||||
import { characterItems as demoCharacterItems } from "~/pages/PageEnigma/signals";
|
||||
import { MediaItem } from "~/pages/PageEnigma/models";
|
||||
import {
|
||||
Button,
|
||||
FilterButtons,
|
||||
@@ -17,10 +17,7 @@ import {
|
||||
SearchFilter,
|
||||
UploadModal,
|
||||
} from "~/components";
|
||||
import {
|
||||
ItemElements,
|
||||
TabTitle,
|
||||
} from "~/pages/PageEnigma/comps/SidePanelTabs/sharedComps";
|
||||
import { ItemElements } from "~/pages/PageEnigma/comps/SidePanelTabs/sharedComps";
|
||||
import { usePosthogFeatureFlag } from "~/hooks/usePosthogFeatureFlag";
|
||||
import {
|
||||
fetchFeaturedMediaItems,
|
||||
@@ -29,14 +26,32 @@ import {
|
||||
fetchUserMediaItems,
|
||||
fetchUserMediaItemsSearchResults,
|
||||
isAnyStatusFetching,
|
||||
} from "../utilities";
|
||||
} from "../../utilities";
|
||||
import {
|
||||
filterMixamoCharacters,
|
||||
filterMMDCharacters,
|
||||
} from "./filterCharacterTypes";
|
||||
|
||||
export const CharactersTab = () => {
|
||||
export const CharactersTab = ({
|
||||
animationType,
|
||||
demoCharacterItems = [],
|
||||
}: {
|
||||
animationType: MediaFileAnimationType;
|
||||
demoCharacterItems?: MediaItem[];
|
||||
}) => {
|
||||
useSignals();
|
||||
|
||||
const showSearchObjectComponent = usePosthogFeatureFlag(
|
||||
FeatureFlags.SHOW_SEARCH_OBJECTS,
|
||||
);
|
||||
const showUploadButton = usePosthogFeatureFlag(FeatureFlags.DEV_ONLY);
|
||||
const filterCharacterType = useMemo(
|
||||
() =>
|
||||
animationType === MediaFileAnimationType.Mixamo
|
||||
? filterMixamoCharacters
|
||||
: filterMMDCharacters,
|
||||
[animationType],
|
||||
);
|
||||
|
||||
const [openUploadModal, setOpenUploadModal] = useState(false);
|
||||
|
||||
@@ -76,7 +91,7 @@ export const CharactersTab = () => {
|
||||
AssetFilterOption.FEATURED,
|
||||
);
|
||||
const allFeaturedCharacters = [
|
||||
...demoCharacterItems.value,
|
||||
...demoCharacterItems,
|
||||
...(featuredCharacters ?? []),
|
||||
];
|
||||
const displayedItems =
|
||||
@@ -101,16 +116,19 @@ export const CharactersTab = () => {
|
||||
fetchUserMediaItems({
|
||||
filterEngineCategories: [FilterEngineCategories.CHARACTER],
|
||||
setState: (newState: FetchMediaItemStates) => {
|
||||
const filterNewMediaItems = newState.mediaItems
|
||||
? newState.mediaItems.filter(filterCharacterType)
|
||||
: undefined;
|
||||
setUserFetch((curr) => ({
|
||||
status: newState.status,
|
||||
mediaItems: newState.mediaItems
|
||||
? newState.mediaItems
|
||||
mediaItems: filterNewMediaItems
|
||||
? filterNewMediaItems
|
||||
: curr.mediaItems,
|
||||
}));
|
||||
},
|
||||
defaultErrorMessage: "Unknown Error in Fetching User Characters",
|
||||
}),
|
||||
[],
|
||||
[filterCharacterType],
|
||||
);
|
||||
|
||||
const fetchFeaturedCharacters = useCallback(
|
||||
@@ -118,20 +136,23 @@ export const CharactersTab = () => {
|
||||
fetchFeaturedMediaItems({
|
||||
filterEngineCategories: [FilterEngineCategories.CHARACTER],
|
||||
setState: (newState: FetchMediaItemStates) => {
|
||||
const filterNewMediaItems = newState.mediaItems
|
||||
? newState.mediaItems.filter(filterCharacterType)
|
||||
: undefined;
|
||||
setFeaturedFetch((curr) => ({
|
||||
status: newState.status,
|
||||
mediaItems: newState.mediaItems
|
||||
? newState.mediaItems
|
||||
mediaItems: filterNewMediaItems
|
||||
? filterNewMediaItems
|
||||
: curr.mediaItems,
|
||||
}));
|
||||
},
|
||||
defaultErrorMessage: "Unknown Error in Fetching Featured Characters",
|
||||
}),
|
||||
[],
|
||||
[filterCharacterType],
|
||||
);
|
||||
|
||||
const filterCharacterItems = (searchTerm: string) =>
|
||||
demoCharacterItems.value.filter((item) =>
|
||||
demoCharacterItems.filter((item) =>
|
||||
item.name.toLowerCase().includes(searchTerm.toLowerCase()),
|
||||
);
|
||||
|
||||
@@ -202,7 +223,7 @@ export const CharactersTab = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<TabTitle title="Characters" />
|
||||
{/* <TabTitle title="Characters" /> */}
|
||||
<div>
|
||||
<FilterButtons
|
||||
value={selectedFilter}
|
||||
@@ -213,14 +234,16 @@ export const CharactersTab = () => {
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-full flex-col gap-3 px-4">
|
||||
<Button
|
||||
icon={faCirclePlus}
|
||||
variant="action"
|
||||
onClick={() => setOpenUploadModal(true)}
|
||||
className="w-full py-3 text-sm font-medium"
|
||||
>
|
||||
Upload Characters
|
||||
</Button>
|
||||
{showUploadButton && (
|
||||
<Button
|
||||
icon={faCirclePlus}
|
||||
variant="action"
|
||||
onClick={() => setOpenUploadModal(true)}
|
||||
className="w-full py-3 text-sm font-medium"
|
||||
>
|
||||
Upload Character Model (Dev Only)
|
||||
</Button>
|
||||
)}
|
||||
{showSearchObjectComponent && (
|
||||
<SearchFilter
|
||||
searchTerm={
|
||||
@@ -277,11 +300,12 @@ export const CharactersTab = () => {
|
||||
options={{
|
||||
hasThumbnailUpload: true,
|
||||
fileSubtypes: [
|
||||
{ Mixamo: MediaFileAnimationType.Mixamo },
|
||||
{ MikuMikuDance: MediaFileAnimationType.MikuMikuDance },
|
||||
{ MoveAi: MediaFileAnimationType.MoveAi },
|
||||
{ Rigify: MediaFileAnimationType.Rigify },
|
||||
{ Rokoko: MediaFileAnimationType.Rokoko },
|
||||
{ [animationType]: animationType },
|
||||
// { Mixamo: MediaFileAnimationType.Mixamo },
|
||||
// { MikuMikuDance: MediaFileAnimationType.MikuMikuDance },
|
||||
// { MoveAi: MediaFileAnimationType.MoveAi },
|
||||
// { Rigify: MediaFileAnimationType.Rigify },
|
||||
// { Rokoko: MediaFileAnimationType.Rokoko },
|
||||
],
|
||||
}}
|
||||
fileTypes={Object.values(CHARACTER_FILE_TYPE)}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FilterEngineCategories, ToastTypes } from "~/enums";
|
||||
import { FilterEngineCategories, FilterMediaType, ToastTypes } from "~/enums";
|
||||
import { addToast } from "~/signals";
|
||||
import { FetchStatus } from "~/pages/PageEnigma/enums";
|
||||
import { MediaFilesApi } from "~/Classes/ApiManager";
|
||||
@@ -13,6 +13,7 @@ export interface FetchMediaItemStates {
|
||||
interface fetchMediaItemsInterface {
|
||||
setState: ({ mediaItems, status }: FetchMediaItemStates) => void;
|
||||
filterEngineCategories: FilterEngineCategories[];
|
||||
filterMediaType?: FilterMediaType[];
|
||||
defaultErrorMessage?: string;
|
||||
searchTerm?: string;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,9 @@ export const responseMapping = (
|
||||
name: item.maybe_title ?? "Unknown",
|
||||
type: assetType as AssetType,
|
||||
media_type: item.media_type,
|
||||
maybe_animation_type: item.maybe_animation_type
|
||||
? item.maybe_animation_type
|
||||
: undefined,
|
||||
length: ((item.maybe_duration_millis ?? 1000) / 1000) * 60,
|
||||
version: 1,
|
||||
...(item.cover_image.maybe_cover_image_public_bucket_path
|
||||
|
||||
@@ -3,7 +3,7 @@ import { AssetType } from "~/enums";
|
||||
export interface MediaItem {
|
||||
version: number;
|
||||
type: AssetType;
|
||||
// maybe_animation_type?: string;
|
||||
maybe_animation_type?: string;
|
||||
media_type?: string;
|
||||
media_id: string;
|
||||
object_uuid?: string;
|
||||
|
||||
@@ -12,7 +12,7 @@ export interface MediaInfo {
|
||||
token: string;
|
||||
media_type: MediaFileType;
|
||||
media_class: MediaFileClass | null;
|
||||
// maybe_animation_type: string | null;
|
||||
maybe_animation_type: string | null;
|
||||
maybe_media_subtype: MediaFileSubtype | null;
|
||||
maybe_engine_extension: string | null;
|
||||
maybe_batch_token: string;
|
||||
|
||||
Reference in new issue
Block a user