mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 01:38:44 +00:00
padding changes
This commit is contained in:
1 parent
4c57d367bc
commit
33a5e4252f
3 files changed
+319
-208
No files matched your search
+70
-39
@@ -1,59 +1,90 @@
|
||||
import React from 'react';
|
||||
import { animated, useSpring } from '@react-spring/web';
|
||||
import React from "react";
|
||||
import { animated, useSpring } from "@react-spring/web";
|
||||
import { Spinner } from "components/common";
|
||||
import { springs } from "resources";
|
||||
import DynamicButton from './DynamicButton';
|
||||
import DynamicButton from "./DynamicButton";
|
||||
|
||||
const ProgressLi = ({ children, disabled = false }: { children?: any, disabled?: boolean }) => {
|
||||
const ProgressLi = ({
|
||||
children,
|
||||
disabled = false,
|
||||
}: {
|
||||
children?: any;
|
||||
disabled?: boolean;
|
||||
}) => {
|
||||
const style = useSpring({
|
||||
...springs.soft,
|
||||
opacity: disabled ? .25 : 1
|
||||
opacity: disabled ? 0.25 : 1,
|
||||
});
|
||||
return <animated.li {...{ style }}>
|
||||
<svg>
|
||||
<circle {...{ cx: 16, cy: 16, r: 15, strokeWidth: "2", }}/>
|
||||
{ <polyline {...{
|
||||
fill: "none",
|
||||
points: "9.5 18 14.5 22 22.5 12",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "4",
|
||||
}}/> }
|
||||
</svg>
|
||||
{ children }
|
||||
</animated.li>
|
||||
return (
|
||||
<animated.li {...{ style }}>
|
||||
<svg>
|
||||
<circle {...{ cx: 16, cy: 16, r: 15, strokeWidth: "2" }} />
|
||||
{
|
||||
<polyline
|
||||
{...{
|
||||
fill: "none",
|
||||
points: "9.5 18 14.5 22 22.5 12",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "4",
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</svg>
|
||||
{children}
|
||||
</animated.li>
|
||||
);
|
||||
};
|
||||
|
||||
export default function FaceAnimatorTitle({ ...rest }) {
|
||||
const { audioProps, audioReady, imageProps, imageReady, indexSet, page, submit, t } = rest;
|
||||
const {
|
||||
audioProps,
|
||||
audioReady,
|
||||
imageProps,
|
||||
imageReady,
|
||||
indexSet,
|
||||
page,
|
||||
submit,
|
||||
t,
|
||||
} = rest;
|
||||
const noAudio = !audioReady || !audioProps.file;
|
||||
const noImg = !imageReady || !imageProps.file;
|
||||
const incomplete = noAudio || noImg;
|
||||
const working = imageProps.working && audioProps.working;
|
||||
|
||||
const slides = [t("inputs.generate"),<Spinner />,t("inputs.makeAnother")];
|
||||
const slides = [t("inputs.generate"), <Spinner />, t("inputs.makeAnother")];
|
||||
|
||||
const onClick = () => {
|
||||
if (page === 2) {
|
||||
imageProps.clear(); audioProps.clear(); indexSet(0);
|
||||
imageProps.clear();
|
||||
audioProps.clear();
|
||||
indexSet(0);
|
||||
} else if (!incomplete && !working) submit();
|
||||
};
|
||||
|
||||
return <div {...{ className: "progress-header" }}>
|
||||
<h1 {...{ className: "fw-bold text-center text-md-start progress-heading" }}>
|
||||
{ t("headings.title") }
|
||||
</h1>
|
||||
<ul {...{ className: 'async-progress-tracker' }}>
|
||||
<ProgressLi {...{ disabled: noImg }}>
|
||||
{ t("headings.image") }
|
||||
</ProgressLi>
|
||||
<ProgressLi {...{ disabled: noAudio }}>
|
||||
{ t("headings.audio") }
|
||||
</ProgressLi>
|
||||
</ul>
|
||||
<DynamicButton {...{ className: "face-animation-submit", disabled: incomplete || working, onClick, slides, index: page }}/>
|
||||
<p {...{ className: "progress-description" }}>
|
||||
{ t("headings.subtitle") }
|
||||
</p>
|
||||
</div>
|
||||
};
|
||||
return (
|
||||
<div {...{ className: "progress-header" }}>
|
||||
<h1
|
||||
{...{ className: "fw-bold text-center text-md-start progress-heading" }}
|
||||
>
|
||||
{t("headings.title")}
|
||||
</h1>
|
||||
<ul {...{ className: "async-progress-tracker py-3 py-lg-0" }}>
|
||||
<ProgressLi {...{ disabled: noImg }}>{t("headings.image")}</ProgressLi>
|
||||
<ProgressLi {...{ disabled: noAudio }}>
|
||||
{t("headings.audio")}
|
||||
</ProgressLi>
|
||||
</ul>
|
||||
<DynamicButton
|
||||
{...{
|
||||
className: "face-animation-submit",
|
||||
disabled: incomplete || working,
|
||||
onClick,
|
||||
slides,
|
||||
index: page,
|
||||
}}
|
||||
/>
|
||||
<p {...{ className: "progress-description" }}>{t("headings.subtitle")}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,98 +2,103 @@
|
||||
$under992: max-width 992px;
|
||||
|
||||
.lipsync-editor {
|
||||
padding: 1rem;
|
||||
padding-top: 2rem;
|
||||
|
||||
.media-input-column {
|
||||
display: inline-block;
|
||||
}
|
||||
@include breakpoint($under992) {
|
||||
.media-input-column:first-of-type { margin-bottom: 1rem }
|
||||
}
|
||||
.media-input-column {
|
||||
display: inline-block;
|
||||
}
|
||||
@include breakpoint($under992) {
|
||||
.media-input-column:first-of-type {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress-header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
// padding: 1rem;
|
||||
|
||||
.progress-heading {
|
||||
display: inline-block;
|
||||
margin: auto 1rem auto 0;
|
||||
}
|
||||
.progress-heading {
|
||||
display: inline-block;
|
||||
margin: auto 1rem auto 0;
|
||||
}
|
||||
|
||||
.async-progress-tracker {
|
||||
display: inline-flex;
|
||||
justify-content: space-around;
|
||||
flex-grow: 1;
|
||||
margin-right: 1rem;
|
||||
padding-left: 0;
|
||||
.async-progress-tracker {
|
||||
display: inline-flex;
|
||||
justify-content: space-around;
|
||||
flex-grow: 1;
|
||||
margin-right: 1rem;
|
||||
padding-left: 0;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
svg {
|
||||
margin-right: .5rem;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
svg {
|
||||
margin-right: 0.5rem;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-description {
|
||||
margin-top: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
.progress-description {
|
||||
margin-top: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0 0 0 auto;
|
||||
background-color: #ccccff;
|
||||
width: fit-content;
|
||||
button {
|
||||
margin: 0 0 0 auto;
|
||||
background-color: #ccccff;
|
||||
width: fit-content;
|
||||
|
||||
@include breakpoint($under992) {
|
||||
margin: 1rem 0 0;
|
||||
width: 100%;
|
||||
@include breakpoint($under992) {
|
||||
margin: 1rem 0 0;
|
||||
width: 100%;
|
||||
|
||||
.button-slide {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.button-slide {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lipsync-panel {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
.lipsync-panel {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.lipsync-working, .lipsync-working-notice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
.lipsync-working,
|
||||
.lipsync-working-notice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.lipsync-working-notice {
|
||||
flex-direction: column;
|
||||
margin: 5rem;
|
||||
flex-direction: column;
|
||||
margin: 5rem;
|
||||
|
||||
.working-title {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.working-title {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.lipsync-success {
|
||||
padding: .5rem 1rem 1rem;
|
||||
padding: 0.5rem 1rem 1rem;
|
||||
|
||||
h3 { margin: 1rem auto 0 0; }
|
||||
h3 {
|
||||
margin: 1rem auto 0 0;
|
||||
}
|
||||
|
||||
.job-id {
|
||||
color: rgba(#fff, .66);
|
||||
font-size: .75rem;
|
||||
}
|
||||
}
|
||||
.job-id {
|
||||
color: rgba(#fff, 0.66);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import { animated, useTransition } from '@react-spring/web';
|
||||
import { animated, useTransition } from "@react-spring/web";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { useFile, useLocalize } from "hooks";
|
||||
import { AudioInput, ImageInput, Spinner } from "components/common";
|
||||
@@ -20,15 +20,28 @@ import {
|
||||
// EnqueueFaceAnimationRequest,
|
||||
} from "@storyteller/components/src/api/face_animation/EnqueueFaceAnimation";
|
||||
// import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import FaceAnimatorTitle from './FaceAnimatorTitle';
|
||||
import FaceAnimatorSuccess from './FaceAnimatorSuccess';
|
||||
import './LipsyncEditor.scss';
|
||||
import FaceAnimatorTitle from "./FaceAnimatorTitle";
|
||||
import FaceAnimatorSuccess from "./FaceAnimatorSuccess";
|
||||
import "./LipsyncEditor.scss";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { FrontendInferenceJobType, InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import {
|
||||
FrontendInferenceJobType,
|
||||
InferenceJob,
|
||||
} from "@storyteller/components/src/jobs/InferenceJob";
|
||||
|
||||
|
||||
interface LipSyncProps { audioProps: any, children?: any, imageProps: any, index: number, toggle: any, style: any, enqueueInferenceJob: any, sessionSubscriptionsWrapper: any, t: any, inferenceJobsByCategory: any, };
|
||||
interface EditorProps {
|
||||
interface LipSyncProps {
|
||||
audioProps: any;
|
||||
children?: any;
|
||||
imageProps: any;
|
||||
index: number;
|
||||
toggle: any;
|
||||
style: any;
|
||||
enqueueInferenceJob: any;
|
||||
sessionSubscriptionsWrapper: any;
|
||||
t: any;
|
||||
inferenceJobsByCategory: any;
|
||||
}
|
||||
interface EditorProps {
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
enqueueInferenceJob: (
|
||||
jobToken: string,
|
||||
@@ -36,9 +49,9 @@ interface EditorProps {
|
||||
) => void;
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
inferenceJobsByCategory: Map<FrontendInferenceJobType, Array<InferenceJob>>;
|
||||
};
|
||||
}
|
||||
|
||||
const softSpring = { config: { mass: 1, tension: 80, friction: 10 } }
|
||||
const softSpring = { config: { mass: 1, tension: 80, friction: 10 } };
|
||||
|
||||
// const InputPage = ({ audioProps, imageProps, toggle, style, t }: LipSyncProps ) => {
|
||||
|
||||
@@ -59,60 +72,107 @@ const softSpring = { config: { mass: 1, tension: 80, friction: 10 } }
|
||||
// </div>
|
||||
// </animated.div>};
|
||||
|
||||
const InputPage = ({ audioProps, imageProps, toggle, style, t }: LipSyncProps ) => {
|
||||
const InputPage = ({
|
||||
audioProps,
|
||||
imageProps,
|
||||
toggle,
|
||||
style,
|
||||
t,
|
||||
}: LipSyncProps) => {
|
||||
return (
|
||||
<animated.div {...{ className: "lipsync-editor row", style }}>
|
||||
<div {...{ className: "media-input-column col-lg-6" }}>
|
||||
<h5>{t("headings.image")}</h5>
|
||||
<ImageInput
|
||||
{...{
|
||||
...imageProps,
|
||||
onRest: () => toggle.image(imageProps.file ? true : false),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div {...{ className: "media-input-column col-lg-6" }}>
|
||||
<h5>{t("headings.audio")}</h5>
|
||||
<AudioInput
|
||||
{...{
|
||||
...audioProps,
|
||||
onRest: (p: any, c: any, item: any, l: any) => {
|
||||
toggle.audio(!!audioProps.file);
|
||||
},
|
||||
hideActions: true,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</animated.div>
|
||||
);
|
||||
};
|
||||
|
||||
return <animated.div {...{ className: "lipsync-editor row", style }}>
|
||||
<div {...{ className: "media-input-column col-lg-6" }}>
|
||||
<h5>{ t("headings.image") }</h5>
|
||||
<ImageInput {...{ ...imageProps, onRest: () => toggle.image(imageProps.file ? true : false) }}/>
|
||||
</div>
|
||||
<div {...{ className: "media-input-column col-lg-6" }}>
|
||||
<h5>{ t("headings.audio") }</h5>
|
||||
<AudioInput {...{ ...audioProps, onRest: (p:any,c:any,item:any,l:any) => {
|
||||
toggle.audio(!!audioProps.file);
|
||||
}, hideActions: true } }/>
|
||||
</div>
|
||||
</animated.div>};
|
||||
|
||||
|
||||
const Working = ({ audioProps, imageProps, index, style, t }: LipSyncProps ) => {
|
||||
const workStatus = ["",t("status.uploadingAudio"),t("status.uploadingImage"),t("status.requestingAnimation"),""];
|
||||
const Working = ({ audioProps, imageProps, index, style, t }: LipSyncProps) => {
|
||||
const workStatus = [
|
||||
"",
|
||||
t("status.uploadingAudio"),
|
||||
t("status.uploadingImage"),
|
||||
t("status.requestingAnimation"),
|
||||
"",
|
||||
];
|
||||
const transitions = useTransition(index, {
|
||||
...springs.soft,
|
||||
from: { opacity: 0, position: "absolute" },
|
||||
enter: { opacity: 1, position: "relative" },
|
||||
leave: { opacity: 0, position: "absolute" },
|
||||
});
|
||||
return <animated.div {...{ className: "lipsync-working", style }}>
|
||||
<div {...{ className: "lipsync-working-notice" }}>
|
||||
<h2 {...{ className: "working-title" }}> { transitions(({ opacity, position }, i) => {
|
||||
return <animated.span {...{ className: "working-title-text", style: { opacity, position: position as any} }}>{ workStatus[index] } ...</animated.span>;
|
||||
}) }</h2>
|
||||
<Spinner />
|
||||
</div>
|
||||
</animated.div>;
|
||||
return (
|
||||
<animated.div {...{ className: "lipsync-working", style }}>
|
||||
<div {...{ className: "lipsync-working-notice" }}>
|
||||
<h2 {...{ className: "working-title" }}>
|
||||
{" "}
|
||||
{transitions(({ opacity, position }, i) => {
|
||||
return (
|
||||
<animated.span
|
||||
{...{
|
||||
className: "working-title-text",
|
||||
style: { opacity, position: position as any },
|
||||
}}
|
||||
>
|
||||
{workStatus[index]} ...
|
||||
</animated.span>
|
||||
);
|
||||
})}
|
||||
</h2>
|
||||
<Spinner />
|
||||
</div>
|
||||
</animated.div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function LipsyncEditor({ enqueueInferenceJob, sessionSubscriptionsWrapper, inferenceJobsByCategory, ...rest }: EditorProps) {
|
||||
export default function LipsyncEditor({
|
||||
enqueueInferenceJob,
|
||||
sessionSubscriptionsWrapper,
|
||||
inferenceJobsByCategory,
|
||||
...rest
|
||||
}: EditorProps) {
|
||||
const { t } = useLocalize("FaceAnimator");
|
||||
|
||||
// the ready states are set by functions which run after the upload input animation is completed, which then illuminates the respective checkmark in a staggered way to draw attention to the workflow, and reduces concurrent animations
|
||||
|
||||
const [imageReady,imageReadySet] = useState<boolean>(false);
|
||||
const [audioReady,audioReadySet] = useState<boolean>(false);
|
||||
const readyMedia = (m:number) => (t:boolean) => [imageReadySet,audioReadySet][m](t);
|
||||
const [imageReady, imageReadySet] = useState<boolean>(false);
|
||||
const [audioReady, audioReadySet] = useState<boolean>(false);
|
||||
const readyMedia = (m: number) => (t: boolean) =>
|
||||
[imageReadySet, audioReadySet][m](t);
|
||||
const audioProps = useFile({}); // contains upload inout state and controls, see docs
|
||||
const imageProps = useFile({}); // contains upload inout state and controls, see docs
|
||||
const [index,indexSet] = useState<number>(0); // index = slideshow slide position
|
||||
const [index, indexSet] = useState<number>(0); // index = slideshow slide position
|
||||
|
||||
const makeRequest = (mode: number) => ({
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
file: mode ? imageProps.file : audioProps.file,
|
||||
source: "file",
|
||||
type: mode ? "image" : "audio"
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
file: mode ? imageProps.file : audioProps.file,
|
||||
source: "file",
|
||||
type: mode ? "image" : "audio",
|
||||
});
|
||||
|
||||
const upImageAndMerge = async (audio: any) => ({ audio, image: await UploadImage(makeRequest(1)) });
|
||||
const upImageAndMerge = async (audio: any) => ({
|
||||
audio,
|
||||
image: await UploadImage(makeRequest(1)),
|
||||
});
|
||||
|
||||
const submit = async () => {
|
||||
if (!audioProps.file) return false;
|
||||
@@ -120,41 +180,50 @@ export default function LipsyncEditor({ enqueueInferenceJob, sessionSubscription
|
||||
indexSet(1); // set audio working page
|
||||
|
||||
UploadAudio(makeRequest(0)) // start audio (0) upload
|
||||
.then(res => {
|
||||
if ("upload_token" in res) {
|
||||
indexSet(2); // set image working page
|
||||
}
|
||||
return upImageAndMerge(res); // start image (1) upload, replace with Upload(imageRequest)
|
||||
})
|
||||
.then(responses => {
|
||||
if ("upload_token" in responses.image) {
|
||||
indexSet(3); // set face animator API working page
|
||||
return EnqueueFaceAnimation({
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
audio_source: {
|
||||
maybe_media_upload_token: responses.audio.upload_token,
|
||||
},
|
||||
image_source: {
|
||||
maybe_media_upload_token: responses.image.upload_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
if (res && res.inference_job_token) {
|
||||
enqueueInferenceJob(
|
||||
res.inference_job_token,
|
||||
FrontendInferenceJobType.FaceAnimation
|
||||
);
|
||||
indexSet(4); // set face animator API success page
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
return { success : false };
|
||||
});
|
||||
.then((res) => {
|
||||
if ("upload_token" in res) {
|
||||
indexSet(2); // set image working page
|
||||
}
|
||||
return upImageAndMerge(res); // start image (1) upload, replace with Upload(imageRequest)
|
||||
})
|
||||
.then((responses) => {
|
||||
if ("upload_token" in responses.image) {
|
||||
indexSet(3); // set face animator API working page
|
||||
return EnqueueFaceAnimation({
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
audio_source: {
|
||||
maybe_media_upload_token: responses.audio.upload_token,
|
||||
},
|
||||
image_source: {
|
||||
maybe_media_upload_token: responses.image.upload_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.inference_job_token) {
|
||||
enqueueInferenceJob(
|
||||
res.inference_job_token,
|
||||
FrontendInferenceJobType.FaceAnimation
|
||||
);
|
||||
indexSet(4); // set face animator API success page
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
return { success: false };
|
||||
});
|
||||
};
|
||||
const page = index === 0 ? 0 : index === 4 ? 2 : 1;
|
||||
const headerProps = { audioProps, audioReady, imageProps, imageReady, indexSet, page, submit , t};
|
||||
const headerProps = {
|
||||
audioProps,
|
||||
audioReady,
|
||||
imageProps,
|
||||
imageReady,
|
||||
indexSet,
|
||||
page,
|
||||
submit,
|
||||
t,
|
||||
};
|
||||
|
||||
const transitions = useTransition(index, {
|
||||
...softSpring,
|
||||
@@ -163,25 +232,31 @@ export default function LipsyncEditor({ enqueueInferenceJob, sessionSubscription
|
||||
leave: { opacity: 0, position: "absolute" },
|
||||
});
|
||||
|
||||
return <div>
|
||||
<div {...{ className: "container" }}>
|
||||
<div {...{ className: "panel lipsync-panel" }}>
|
||||
<FaceAnimatorTitle { ...headerProps }/>
|
||||
{ transitions((style, i) => {
|
||||
const Page = [InputPage,Working,FaceAnimatorSuccess][page];
|
||||
return Page ? <Page {...{
|
||||
audioProps,
|
||||
imageProps,
|
||||
enqueueInferenceJob,
|
||||
sessionSubscriptionsWrapper,
|
||||
inferenceJobsByCategory,
|
||||
index,
|
||||
t,
|
||||
toggle: { audio: readyMedia(1), image: readyMedia(0) },
|
||||
style
|
||||
}}/> : <></>
|
||||
}) }
|
||||
</div>
|
||||
return (
|
||||
<div {...{ className: "container-panel pt-4" }}>
|
||||
<div {...{ className: "panel lipsync-panel p-3 py-4 p-md-4" }}>
|
||||
<FaceAnimatorTitle {...headerProps} />
|
||||
{transitions((style, i) => {
|
||||
const Page = [InputPage, Working, FaceAnimatorSuccess][page];
|
||||
return Page ? (
|
||||
<Page
|
||||
{...{
|
||||
audioProps,
|
||||
imageProps,
|
||||
enqueueInferenceJob,
|
||||
sessionSubscriptionsWrapper,
|
||||
inferenceJobsByCategory,
|
||||
index,
|
||||
t,
|
||||
toggle: { audio: readyMedia(1), image: readyMedia(0) },
|
||||
style,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>;
|
||||
};
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user