mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 01:38:44 +00:00
Merge pull request #264 from storytold/bflat-fy-animation-removal
framer motion animation full removal
This commit is contained in:
56 files changed
+1134
-1310
No files matched your search
@@ -1,6 +1,4 @@
|
||||
import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { image } from "../../../data/animation";
|
||||
|
||||
interface Props {
|
||||
headerImage: string;
|
||||
@@ -17,11 +15,10 @@ function PageHeaderWithImage(props: Props) {
|
||||
<div className="panel">
|
||||
<div className="row gx-3 flex-md-row-reverse">
|
||||
<div className="col-12 col-md-5 hero-img-container d-none d-md-block">
|
||||
<motion.img
|
||||
<img
|
||||
src={props.headerImage}
|
||||
className="hero-img"
|
||||
alt="Hero Image"
|
||||
variants={image}
|
||||
alt="Hero Header"
|
||||
/>
|
||||
</div>
|
||||
<div className="col-12 col-md-7">
|
||||
|
||||
@@ -11,8 +11,7 @@ import {
|
||||
faLink,
|
||||
faHeadphonesSimple,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, sessionItem } from "../../../data/animation";
|
||||
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { Analytics } from "../../../common/Analytics";
|
||||
import { SessionTtsAudioPlayer } from "./SessionTtsAudioPlayer";
|
||||
@@ -56,7 +55,10 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
};
|
||||
// TODO: We're having an outage and need to lower this.
|
||||
//const interval = setInterval(async () => fetch(), 15000);
|
||||
const refreshInterval = Math.max(DEFAULT_QUEUE_REFRESH_INTERVAL_MILLIS, pendingTtsJobs.refresh_interval_millis);
|
||||
const refreshInterval = Math.max(
|
||||
DEFAULT_QUEUE_REFRESH_INTERVAL_MILLIS,
|
||||
pendingTtsJobs.refresh_interval_millis
|
||||
);
|
||||
const interval = setInterval(async () => fetch(), refreshInterval);
|
||||
fetch();
|
||||
return () => clearInterval(interval);
|
||||
@@ -66,7 +68,7 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
|
||||
// TODO(bt,2023-04-08): Clean this utter garbage duplication up.
|
||||
|
||||
// ============================= GENERIC INFERENCE =============================
|
||||
// ============================= GENERIC INFERENCE =============================
|
||||
|
||||
props.inferenceJobs.forEach((job) => {
|
||||
if (!job.maybeResultToken) {
|
||||
@@ -113,9 +115,7 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
<div key={job.jobToken}>
|
||||
<div>
|
||||
<div>
|
||||
<motion.div className={cssStyle} variants={sessionItem}>
|
||||
{stateDescription}
|
||||
</motion.div>
|
||||
<div className={cssStyle}>{stateDescription}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -135,10 +135,7 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
<button className="delete" aria-label="delete"></button>
|
||||
</div>*/}
|
||||
<div>
|
||||
<motion.div
|
||||
className="panel panel-tts-results p-4 gap-3 d-flex flex-column"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div className="panel panel-tts-results p-4 gap-3 d-flex flex-column">
|
||||
<div>
|
||||
<h5 className="mb-2">{job.maybeModelTitle}</h5>
|
||||
<p>{job.maybeRawInferenceText}</p>
|
||||
@@ -170,7 +167,7 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
{t("common.SessionTtsInferenceResults.result.shareDownload")}
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -179,7 +176,7 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
|
||||
// TODO(bt,2023-04-08): Clean this utter garbage duplication up.
|
||||
|
||||
// ============================= LEGACY TTS =============================
|
||||
// ============================= LEGACY TTS =============================
|
||||
|
||||
props.ttsInferenceJobs.forEach((job) => {
|
||||
if (!job.maybeResultToken) {
|
||||
@@ -226,9 +223,7 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
<div key={job.jobToken}>
|
||||
<div>
|
||||
<div>
|
||||
<motion.div className={cssStyle} variants={sessionItem}>
|
||||
{stateDescription}
|
||||
</motion.div>
|
||||
<div className={cssStyle}>{stateDescription}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -248,10 +243,7 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
<button className="delete" aria-label="delete"></button>
|
||||
</div>*/}
|
||||
<div>
|
||||
<motion.div
|
||||
className="panel panel-tts-results p-4 gap-3 d-flex flex-column"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div className="panel panel-tts-results p-4 gap-3 d-flex flex-column">
|
||||
<div>
|
||||
<h5 className="mb-2">{job.title}</h5>
|
||||
<p>{job.rawInferenceText}</p>
|
||||
@@ -283,14 +275,14 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
{t("common.SessionTtsInferenceResults.result.shareDownload")}
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// ============================= END LEGACY TTS =============================
|
||||
// ============================= END LEGACY TTS =============================
|
||||
|
||||
let noResultsSection = (
|
||||
<div className="panel panel-inner text-center p-5 rounded-5 h-100">
|
||||
@@ -317,10 +309,7 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
) {
|
||||
upgradeNotice = (
|
||||
<div className="d-flex flex-column gap-3 sticky-top zi-2">
|
||||
<motion.div
|
||||
className="alert alert-warning alert-cta mb-0"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div className="alert alert-warning alert-cta mb-0">
|
||||
<FontAwesomeIcon icon={faClock} className="me-2" />
|
||||
<Trans i18nKey="common.SessionTtsInferenceResults.premium.ad">
|
||||
Don't want to wait? Step to the back of the line with a{" "}
|
||||
@@ -336,7 +325,7 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
</Trans>{" "}
|
||||
(TTS Queued:{" "}
|
||||
<span className="text-red">~{pendingTtsJobs.pending_job_count}</span>)
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -345,14 +334,14 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
results.reverse();
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div>
|
||||
<div className="d-flex flex-column gap-3">
|
||||
{upgradeNotice}
|
||||
<div className="d-flex flex-column gap-3">{results}</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { JobState } from "@storyteller/components/src/jobs/JobStates";
|
||||
import { TtsModelUploadJob } from "@storyteller/components/src/jobs/TtsModelUploadJobs";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, sessionItem, item } from "../../../data/animation";
|
||||
|
||||
interface Props {
|
||||
modelUploadJobs: Array<TtsModelUploadJob>;
|
||||
@@ -53,15 +51,12 @@ function SessionTtsModelUploadResultList(props: Props) {
|
||||
|
||||
results.push(
|
||||
<div key={job.jobToken}>
|
||||
<motion.div
|
||||
className="panel py-4 p-3 p-lg-4 gap-4"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div className="panel py-4 p-3 p-lg-4 gap-4">
|
||||
Complete!
|
||||
<Link to={ttsPermalink} className="btn btn-primary ms-4">
|
||||
See & use TTS model
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -70,9 +65,9 @@ function SessionTtsModelUploadResultList(props: Props) {
|
||||
let title = <span />;
|
||||
if (results.length !== 0) {
|
||||
title = (
|
||||
<motion.h2 className="text-center text-lg-start fw-bold" variants={item}>
|
||||
<h2 className="text-center text-lg-start fw-bold">
|
||||
TTS Model Upload Status
|
||||
</motion.h2>
|
||||
</h2>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -83,12 +78,12 @@ function SessionTtsModelUploadResultList(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="pb-4">{title}</div>
|
||||
<div className="d-flex flex-column gap-4">{results}</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { JobState } from "@storyteller/components/src/jobs/JobStates";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, sessionItem, item } from "../../../data/animation";
|
||||
|
||||
import { VocoderUploadJob } from "@storyteller/components/src/jobs/VocoderUploadJobs";
|
||||
|
||||
interface Props {
|
||||
@@ -53,15 +52,12 @@ function SessionVocoderUploadResultList(props: Props) {
|
||||
|
||||
results.push(
|
||||
<div key={job.jobToken}>
|
||||
<motion.div
|
||||
className="panel py-4 p-3 p-lg-4 gap-4"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div className="panel py-4 p-3 p-lg-4 gap-4">
|
||||
Complete!
|
||||
<Link to={permalink} className="btn btn-primary ms-4">
|
||||
See & use vocoder model
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -70,19 +66,19 @@ function SessionVocoderUploadResultList(props: Props) {
|
||||
let title = <span />;
|
||||
if (results.length !== 0) {
|
||||
title = (
|
||||
<motion.h2 className="text-center text-lg-start fw-bold" variants={item}>
|
||||
<h2 className="text-center text-lg-start fw-bold">
|
||||
Vocoder Upload Status
|
||||
</motion.h2>
|
||||
</h2>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="pb-4">{title}</div>
|
||||
<div className="d-flex flex-column gap-4">{results}</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+7
-11
@@ -1,8 +1,7 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { JobState } from "@storyteller/components/src/jobs/JobStates";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, sessionItem, item } from "../../../data/animation";
|
||||
|
||||
import { VoiceConversionModelUploadJob } from "@storyteller/components/src/jobs/VoiceConversionModelUploadJob";
|
||||
|
||||
interface Props {
|
||||
@@ -53,15 +52,12 @@ function SessionVoiceConversionModelUploadResultList(props: Props) {
|
||||
|
||||
results.push(
|
||||
<div key={job.jobToken}>
|
||||
<motion.div
|
||||
className="panel py-4 p-3 p-lg-4 gap-4"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div className="panel py-4 p-3 p-lg-4 gap-4">
|
||||
Complete!
|
||||
<Link to={permalink} className="btn btn-primary ms-4">
|
||||
See & use voice conversion model
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -70,19 +66,19 @@ function SessionVoiceConversionModelUploadResultList(props: Props) {
|
||||
let title = <span />;
|
||||
if (results.length !== 0) {
|
||||
title = (
|
||||
<motion.h2 className="text-center text-lg-start fw-bold" variants={item}>
|
||||
<h2 className="text-center text-lg-start fw-bold">
|
||||
Voice Conversion Model Upload Status
|
||||
</motion.h2>
|
||||
</h2>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="pb-4">{title}</div>
|
||||
<div className="d-flex flex-column gap-4">{results}</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
faHeadphonesSimple,
|
||||
faDownload,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, sessionItem } from "../../../data/animation";
|
||||
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { Analytics } from "../../../common/Analytics";
|
||||
import { SessionTtsAudioPlayer } from "./SessionTtsAudioPlayer";
|
||||
@@ -54,7 +53,10 @@ function SessionVoiceConversionResultsList(props: Props) {
|
||||
};
|
||||
// TODO: We're having an outage and need to lower this.
|
||||
//const interval = setInterval(async () => fetch(), 15000);
|
||||
const refreshInterval = Math.max(DEFAULT_QUEUE_REFRESH_INTERVAL_MILLIS, pendingTtsJobs.refresh_interval_millis);
|
||||
const refreshInterval = Math.max(
|
||||
DEFAULT_QUEUE_REFRESH_INTERVAL_MILLIS,
|
||||
pendingTtsJobs.refresh_interval_millis
|
||||
);
|
||||
const interval = setInterval(async () => fetch(), refreshInterval);
|
||||
fetch();
|
||||
return () => clearInterval(interval);
|
||||
@@ -64,7 +66,7 @@ function SessionVoiceConversionResultsList(props: Props) {
|
||||
|
||||
// TODO(bt,2023-04-08): Clean this utter garbage duplication up.
|
||||
|
||||
// ============================= GENERIC INFERENCE =============================
|
||||
// ============================= GENERIC INFERENCE =============================
|
||||
|
||||
props.inferenceJobs.forEach((job) => {
|
||||
if (!job.maybeResultToken) {
|
||||
@@ -111,9 +113,7 @@ function SessionVoiceConversionResultsList(props: Props) {
|
||||
<div key={job.jobToken}>
|
||||
<div>
|
||||
<div>
|
||||
<motion.div className={cssStyle} variants={sessionItem}>
|
||||
{stateDescription}
|
||||
</motion.div>
|
||||
<div className={cssStyle}>{stateDescription}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -135,10 +135,7 @@ function SessionVoiceConversionResultsList(props: Props) {
|
||||
<button className="delete" aria-label="delete"></button>
|
||||
</div>*/}
|
||||
<div>
|
||||
<motion.div
|
||||
className="panel panel-tts-results p-4 gap-3 d-flex flex-column"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div className="panel panel-tts-results p-4 gap-3 d-flex flex-column">
|
||||
<div>
|
||||
<h5 className="mb-2">{job.maybeModelTitle}</h5>
|
||||
<p>{job.maybeRawInferenceText}</p>
|
||||
@@ -182,7 +179,7 @@ function SessionVoiceConversionResultsList(props: Props) {
|
||||
Download File{" "}
|
||||
</a>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -214,10 +211,7 @@ function SessionVoiceConversionResultsList(props: Props) {
|
||||
) {
|
||||
upgradeNotice = (
|
||||
<div className="d-flex flex-column gap-3 sticky-top zi-2">
|
||||
<motion.div
|
||||
className="alert alert-warning alert-cta mb-0"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div className="alert alert-warning alert-cta mb-0">
|
||||
<FontAwesomeIcon icon={faClock} className="me-2" />
|
||||
<Trans i18nKey="common.SessionTtsInferenceResults.premium.ad">
|
||||
Don't want to wait? Step to the back of the line with a{" "}
|
||||
@@ -233,7 +227,7 @@ function SessionVoiceConversionResultsList(props: Props) {
|
||||
</Trans>{" "}
|
||||
(TTS Queued:{" "}
|
||||
<span className="text-red">~{pendingTtsJobs.pending_job_count}</span>)
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -242,14 +236,14 @@ function SessionVoiceConversionResultsList(props: Props) {
|
||||
results.reverse();
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div>
|
||||
<div className="d-flex flex-column gap-3">
|
||||
{upgradeNotice}
|
||||
<div className="d-flex flex-column gap-3">{results}</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import { W2lInferenceJob } from "../../../App";
|
||||
import { JobState } from "@storyteller/components/src/jobs/JobStates";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faList } from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, sessionItem } from "../../../data/animation";
|
||||
|
||||
interface Props {
|
||||
w2lInferenceJobs: Array<W2lInferenceJob>;
|
||||
@@ -47,9 +45,7 @@ function SessionW2lInferenceResultList(props: Props) {
|
||||
|
||||
results.push(
|
||||
<div key={job.jobToken}>
|
||||
<motion.div className="alert alert-primary" variants={sessionItem}>
|
||||
{stateDescription}
|
||||
</motion.div>
|
||||
<div className="alert alert-primary">{stateDescription}</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
@@ -57,15 +53,12 @@ function SessionW2lInferenceResultList(props: Props) {
|
||||
|
||||
results.push(
|
||||
<div key={job.jobToken}>
|
||||
<motion.div
|
||||
className="panel py-4 p-3 p-lg-4 gap-4"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div className="panel py-4 p-3 p-lg-4 gap-4">
|
||||
Complete!{" "}
|
||||
<Link to={w2lPermalink} className="btn btn-primary ms-4">
|
||||
Permalink & download
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -74,10 +67,10 @@ function SessionW2lInferenceResultList(props: Props) {
|
||||
let title = <span />;
|
||||
if (results.length !== 0) {
|
||||
title = (
|
||||
<motion.h2 className="text-center text-lg-start fw-bold" variants={item}>
|
||||
<h2 className="text-center text-lg-start fw-bold">
|
||||
<FontAwesomeIcon icon={faList} className="me-3" />
|
||||
Session W2L Results
|
||||
</motion.h2>
|
||||
</h2>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -88,12 +81,12 @@ function SessionW2lInferenceResultList(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="pb-4">{title}</div>
|
||||
<div className="d-flex flex-column gap-4">{results}</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { JobState } from "@storyteller/components/src/jobs/JobStates";
|
||||
import { W2lTemplateUploadJob } from "@storyteller/components/src/jobs/W2lTemplateUploadJobs";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, sessionItem } from "../../../data/animation";
|
||||
|
||||
interface Props {
|
||||
w2lTemplateUploadJobs: Array<W2lTemplateUploadJob>;
|
||||
@@ -55,15 +53,12 @@ function SessionW2lTemplateUploadResultList(props: Props) {
|
||||
|
||||
results.push(
|
||||
<div key={job.jobToken}>
|
||||
<motion.div
|
||||
className="panel py-4 p-3 p-lg-4 gap-4"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div className="panel py-4 p-3 p-lg-4 gap-4">
|
||||
Complete!
|
||||
<Link to={w2lPermalink} className="btn btn-primary ms-4">
|
||||
See & use template
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -72,9 +67,9 @@ function SessionW2lTemplateUploadResultList(props: Props) {
|
||||
let title = <span />;
|
||||
if (results.length !== 0) {
|
||||
title = (
|
||||
<motion.h2 className="text-center text-lg-start fw-bold" variants={item}>
|
||||
<h2 className="text-center text-lg-start fw-bold">
|
||||
W2L Template Upload Status
|
||||
</motion.h2>
|
||||
</h2>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -85,12 +80,12 @@ function SessionW2lTemplateUploadResultList(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="pb-4">{title}</div>
|
||||
<div className="d-flex flex-column gap-4">{results}</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ import { formatDistance } from "date-fns";
|
||||
import { Comment } from "@storyteller/components/src/api/comments/ListComments";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { SafeDeleteCommentButton } from "./SafeDeleteCommentButton";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item } from "../../../../data/animation";
|
||||
|
||||
import { Gravatar } from "@storyteller/components/src/elements/Gravatar";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
@@ -60,7 +59,7 @@ function CommentList(props: Props) {
|
||||
let profileLink = `/profile/${comment.username}`;
|
||||
|
||||
rows.push(
|
||||
<motion.tr key={comment.token} variants={item}>
|
||||
<tr key={comment.token}>
|
||||
<td className="px-0">
|
||||
<div className="d-flex gap-3 py-3">
|
||||
<Gravatar size={40} email_hash={comment.user_gravatar_hash} />
|
||||
@@ -91,19 +90,14 @@ function CommentList(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</motion.tr>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<motion.table
|
||||
className="table mb-0"
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={container}
|
||||
>
|
||||
<table className="table mb-0">
|
||||
<tbody>{rows}</tbody>
|
||||
</motion.table>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, image, panel } from "../../../../../data/animation";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
@@ -12,40 +11,37 @@ function AboutPage(props: Props) {
|
||||
usePrefixedDocumentTitle("About Us");
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container mb-4">
|
||||
<div className="row gx-3 flex-lg-row-reverse align-items-center">
|
||||
<div className="col-lg-6">
|
||||
<div className="d-flex justify-content-center">
|
||||
<motion.img
|
||||
<img
|
||||
src="/mascot/kitsune_pose3.webp"
|
||||
className="img-fluid"
|
||||
width="516"
|
||||
height="444"
|
||||
alt="FakeYou Kitsune Mascot!"
|
||||
variants={image}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6 px-md-2 ps-lg-5 ps-xl-2">
|
||||
<div className="text-center text-lg-start">
|
||||
<div>
|
||||
<motion.h1 className=" fw-bold lh-1 mb-4" variants={item}>
|
||||
A Glimpse of the Future
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold lh-1 mb-4">A Glimpse of the Future</h1>
|
||||
</div>
|
||||
<div>
|
||||
<motion.p className="lead" variants={item}>
|
||||
<p className="lead">
|
||||
We're building FakeYou as just one component of a broad set of
|
||||
production and creative tooling.
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4 load-hidden mt-5 mt-lg-0">
|
||||
<h1 className="panel-title fw-bold">About FakeYou</h1>
|
||||
<div className="py-6 d-flex flex-column gap-4">
|
||||
@@ -306,8 +302,8 @@ function AboutPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel, image } from "../../../../../data/animation";
|
||||
|
||||
import { Link } from "react-router-dom";
|
||||
import { DiscordLink2 } from "@storyteller/components/src/elements/DiscordLink2";
|
||||
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
|
||||
@@ -13,51 +12,45 @@ function GuidePage(props: Props) {
|
||||
usePrefixedDocumentTitle("Guide to all things Deep Fake");
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container">
|
||||
<div className="row gx-3 flex-lg-row-reverse align-items-center">
|
||||
<div className="col-lg-6">
|
||||
<div className="d-flex justify-content-center">
|
||||
<motion.img
|
||||
<img
|
||||
src="/mascot/guide.webp"
|
||||
className="img-fluid"
|
||||
width="516"
|
||||
height="444"
|
||||
alt="FakeYou Kitsune Mascot!"
|
||||
variants={image}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6 px-md-2 ps-lg-5 ps-xl-2">
|
||||
<div className="text-center text-lg-start">
|
||||
<div>
|
||||
<motion.h1 className=" fw-bold lh-1 mb-3" variants={item}>
|
||||
FakeYou TTS Guide
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold lh-1 mb-3">FakeYou TTS Guide</h1>
|
||||
</div>
|
||||
<div className="mb-5">
|
||||
<motion.p className="lead px-5 px-lg-0" variants={item}>
|
||||
<p className="lead px-5 px-lg-0">
|
||||
<h4>How to generate the best sounding TTS</h4>
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<motion.div
|
||||
variants={item}
|
||||
className="d-flex justify-content-center justify-content-lg-start mb-5 mb-lg-0"
|
||||
>
|
||||
<div className="d-flex justify-content-center justify-content-lg-start mb-5 mb-lg-0">
|
||||
<Link to="/">
|
||||
<button className="btn btn-primary">
|
||||
Generate your TTS
|
||||
</button>
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4 load-hidden mt-5 mt-lg-0">
|
||||
<h1 className="panel-title fw-bold">Quick Tips</h1>
|
||||
<div className="py-6 d-flex flex-column gap-4">
|
||||
@@ -150,9 +143,9 @@ function GuidePage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4 load-hidden mt-5 mt-lg-0">
|
||||
<h2 className="panel-title fw-bold">Generate your TTS now!</h2>
|
||||
<div className="py-6 d-flex flex-column gap-4">
|
||||
@@ -165,8 +158,8 @@ function GuidePage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
@@ -11,25 +10,19 @@ function PrivacyPage(props: Props) {
|
||||
usePrefixedDocumentTitle("Privacy Statement");
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pb-0 pt-5 pb-lg-5 px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1
|
||||
className=" fw-bold text-center text-lg-start"
|
||||
variants={item}
|
||||
>
|
||||
<h1 className=" fw-bold text-center text-lg-start">
|
||||
FakeYou Privacy Statement
|
||||
</motion.h1>
|
||||
<motion.h4
|
||||
className="mt-1 mb-4 opacity-75 text-center text-lg-start"
|
||||
variants={item}
|
||||
>
|
||||
</h1>
|
||||
<h4 className="mt-1 mb-4 opacity-75 text-center text-lg-start">
|
||||
Updated: November 18, 2022
|
||||
</motion.h4>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4 load-hidden mt-5 mt-lg-0">
|
||||
<h1 className="panel-title fw-bold">FakeYou and You</h1>
|
||||
<div className="py-6 d-flex flex-column gap-4">
|
||||
@@ -1216,8 +1209,8 @@ function PrivacyPage(props: Props) {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel, image } from "../../../../../data/animation";
|
||||
|
||||
import { ThirdPartyLinks } from "@storyteller/components/src/constants/ThirdPartyLinks";
|
||||
import { Link } from "react-router-dom";
|
||||
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
|
||||
@@ -13,39 +12,36 @@ function TermsPage(props: Props) {
|
||||
usePrefixedDocumentTitle("Terms of Use");
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container">
|
||||
<div className="row gx-3 flex-lg-row-reverse align-items-center">
|
||||
<div className="col-lg-6">
|
||||
<div className="d-flex justify-content-center">
|
||||
<motion.img
|
||||
<img
|
||||
src="/mascot/tou.webp"
|
||||
className="img-fluid"
|
||||
width="516"
|
||||
height="444"
|
||||
alt="FakeYou Kitsune Mascot!"
|
||||
variants={image}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6 px-md-2 ps-lg-5 ps-xl-2">
|
||||
<div className="text-center text-lg-start">
|
||||
<div>
|
||||
<motion.h1 className=" fw-bold lh-1 mb-3" variants={item}>
|
||||
Terms and Conditions
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold lh-1 mb-3">Terms and Conditions</h1>
|
||||
</div>
|
||||
<div>
|
||||
<motion.p className="lead" variants={item}>
|
||||
<p className="lead">
|
||||
<h4>Please use this technology responsibly.</h4>
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4 load-hidden mt-5 mt-lg-0">
|
||||
<h1 className="panel-title fw-bold">Terms and Conditions of Use</h1>
|
||||
<div className="py-6 d-flex flex-column gap-4">
|
||||
@@ -1175,8 +1171,8 @@ function TermsPage(props: Props) {
|
||||
<p>support@storyteller.io</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
} from "@storyteller/components/src/api/category/CreateCategory";
|
||||
import { BackLink } from "../../_common/BackLink";
|
||||
import { WebUrl } from "../../../../common/WebUrl";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
const DEFAULT_CAN_DIRECTLY_HAVE_MODELS = true;
|
||||
@@ -195,35 +194,33 @@ function CreateCategoryPage(props: Props) {
|
||||
if (props.sessionWrapper.canEditCategories()) {
|
||||
moderateCategoriesLink = (
|
||||
<>
|
||||
<motion.div className="container pt-4 pb-5" variants={item}>
|
||||
<div className="container pt-4 pb-5">
|
||||
<Link
|
||||
to={WebUrl.moderationTtsCategoryList()}
|
||||
className="btn btn-secondary w-100"
|
||||
>
|
||||
Moderate categories
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pb-4 pt-5 px-md-4 px-lg-5 px-xl-3">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
{categoryActionName} Category
|
||||
</motion.h1>
|
||||
<motion.div className="pt-3" variants={item}>
|
||||
<h1 className=" fw-bold">{categoryActionName} Category</h1>
|
||||
<div className="pt-3">
|
||||
<BackLink
|
||||
link={WebUrl.contributePage()}
|
||||
text="Back to contribute page"
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{errorFlash}
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<div className="d-flex flex-column gap-4">
|
||||
@@ -259,15 +256,15 @@ function CreateCategoryPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container" variants={item}>
|
||||
<div className="container">
|
||||
<button className="btn btn-primary w-100">
|
||||
{categoryActionName}
|
||||
</button>
|
||||
</motion.div>
|
||||
</motion.form>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{moderateCategoriesLink}
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React from "react";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { usePrefixedDocumentTitle } from "../../../../common/UsePrefixedDocumentTitle";
|
||||
import { Link } from "react-router-dom";
|
||||
import { container, item } from "../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface Props {
|
||||
@@ -17,7 +17,7 @@ function ChannelsPage(props: Props) {
|
||||
PosthogClient.recordPageview();
|
||||
|
||||
let videoBlock = (
|
||||
<motion.div className="col-12 col-sm-6 col-md-4" variants={item}>
|
||||
<div className="col-12 col-sm-6 col-md-4">
|
||||
<Link to="/">
|
||||
<div className="ratio ratio-16x9 channel-thumbnail">
|
||||
<img
|
||||
@@ -40,19 +40,12 @@ function ChannelsPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className="container py-2 py-lg-5 px-md-4 px-lg-5 px-xl-3"
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={container}
|
||||
>
|
||||
<motion.h1 className=" fw-bold mb-4" variants={item}>
|
||||
Channels
|
||||
</motion.h1>
|
||||
<div className="container py-2 py-lg-5 px-md-4 px-lg-5 px-xl-3">
|
||||
<h1 className=" fw-bold mb-4">Channels</h1>
|
||||
|
||||
<div className="row gy-4">
|
||||
{videoBlock}
|
||||
@@ -65,7 +58,7 @@ function ChannelsPage(props: Props) {
|
||||
{videoBlock}
|
||||
{videoBlock}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,7 @@ import {
|
||||
faDeleteLeft,
|
||||
faVolumeHigh,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, panel } from "../../../../../data/animation";
|
||||
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { TtsPageHero } from "./TrumpTtsPageHero";
|
||||
import { Analytics } from "../../../../../common/Analytics";
|
||||
@@ -167,7 +166,7 @@ function TrumpTtsPage(props: Props) {
|
||||
|
||||
let trumpModels = models.filter((model) => {
|
||||
return PAGE_MODEL_TOKENS.has(model.model_token);
|
||||
})
|
||||
});
|
||||
|
||||
let model = trumpModels[Math.floor(Math.random() * trumpModels.length)];
|
||||
|
||||
@@ -366,24 +365,27 @@ function TrumpTtsPage(props: Props) {
|
||||
|
||||
let trumpModels = props.ttsModels.filter((model) => {
|
||||
return PAGE_MODEL_TOKENS.has(model.model_token);
|
||||
})
|
||||
});
|
||||
|
||||
let maybeSelectedModel = props.maybeSelectedTtsModel;
|
||||
|
||||
if (maybeSelectedModel !== undefined && !PAGE_MODEL_TOKENS.has(maybeSelectedModel.model_token)) {
|
||||
// If we don't select a trump model by default (which is rare), the list will be empty.
|
||||
if (
|
||||
maybeSelectedModel !== undefined &&
|
||||
!PAGE_MODEL_TOKENS.has(maybeSelectedModel.model_token)
|
||||
) {
|
||||
// If we don't select a trump model by default (which is rare), the list will be empty.
|
||||
// We'll set it here.
|
||||
maybeSelectedModel = trumpModels[0];
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<TtsPageHero
|
||||
sessionWrapper={props.sessionWrapper}
|
||||
sessionSubscriptionsWrapper={props.sessionSubscriptionsWrapper}
|
||||
/>
|
||||
|
||||
<motion.div className="container-panel pb-5 mb-4" variants={panel}>
|
||||
<div className="container-panel pb-5 mb-4">
|
||||
<div className="panel p-3 py-4 p-md-4">
|
||||
<i className="fas fa-volume-high"></i>
|
||||
|
||||
@@ -490,8 +492,8 @@ function TrumpTtsPage(props: Props) {
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+11
-18
@@ -23,8 +23,6 @@ import {
|
||||
} from "@storyteller/components/src/api/clone_requests/CheckVoiceCloneApplication";
|
||||
import { Link } from "react-router-dom";
|
||||
import { WebUrl } from "../../../../common/WebUrl";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, image, panel } from "../../../../data/animation";
|
||||
import { usePrefixedDocumentTitle } from "../../../../common/UsePrefixedDocumentTitle";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
@@ -251,32 +249,27 @@ function VoiceCloneRequestPage(props: Props) {
|
||||
<div className="row gx-3 flex-lg-row-reverse align-items-center">
|
||||
<div className="col-lg-6">
|
||||
<div className="d-flex justify-content-center">
|
||||
<motion.img
|
||||
<img
|
||||
src="/mascot/kitsune_pose4.webp"
|
||||
className="img-fluid"
|
||||
width="516"
|
||||
height="472"
|
||||
alt="FakeYou Mascot"
|
||||
variants={image}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6 px-3 px-md-2 px-lg-5 px-xl-2">
|
||||
<div className="text-center text-lg-start">
|
||||
<motion.h1 className=" fw-bold lh-1" variants={item}>
|
||||
Professionally Clone Your Voice
|
||||
</motion.h1>
|
||||
<motion.h3 className="mb-4" variants={item}>
|
||||
(or any voice) for just $70
|
||||
</motion.h3>
|
||||
<h1 className=" fw-bold lh-1">Professionally Clone Your Voice</h1>
|
||||
<h3 className="mb-4">(or any voice) for just $70</h3>
|
||||
<div className="d-flex flex-column justify-content-center">
|
||||
<motion.h3 className="px-5 px-md-0" variants={item}>
|
||||
<h3 className="px-5 px-md-0">
|
||||
Want a Custom Voice You Can Use?
|
||||
</motion.h3>
|
||||
<motion.p className="lead" variants={item}>
|
||||
</h3>
|
||||
<p className="lead">
|
||||
For Music, Videos, Twitch Rewards, API, Friends, Family…
|
||||
whatever you want!
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -342,10 +335,10 @@ function VoiceCloneRequestPage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
{header}
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4 load-hidden mt-5 mt-lg-0">
|
||||
<h1 className="panel-title fw-bold">Clone Your Voice</h1>
|
||||
<div className="py-6">
|
||||
@@ -658,8 +651,8 @@ function VoiceCloneRequestPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../data/animation";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../common/UsePrefixedDocumentTitle";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faWaveformLines } from "@fortawesome/pro-solid-svg-icons";
|
||||
@@ -15,7 +14,7 @@ function CommunityCommissionsPage(props: Props) {
|
||||
PosthogClient.recordPageview();
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-3 pt-lg-5 pb-5">
|
||||
<div className="row gx-3 align-items-center">
|
||||
<div className="col-lg-5">
|
||||
@@ -31,14 +30,11 @@ function CommunityCommissionsPage(props: Props) {
|
||||
<div className="col-lg-7 px-md-2 ps-lg-5 ps-xl-2">
|
||||
<div className="text-center text-lg-start">
|
||||
<div>
|
||||
<motion.h1
|
||||
className=" fw-bold lh-1 mb-4 display-5"
|
||||
variants={item}
|
||||
>
|
||||
<h1 className=" fw-bold lh-1 mb-4 display-5">
|
||||
Voice to Voice
|
||||
<br />
|
||||
Community Commissions
|
||||
</motion.h1>
|
||||
</h1>
|
||||
</div>
|
||||
<div>
|
||||
<p className="lead">
|
||||
@@ -70,7 +66,7 @@ function CommunityCommissionsPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-lg-5 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-lg-5 pb-5">
|
||||
<div className="panel p-3 p-lg-4 load-hidden mt-5 mt-lg-0">
|
||||
<h1 className="panel-title fw-bold">Details</h1>
|
||||
<div className="py-6 d-flex flex-column gap-4">
|
||||
@@ -108,8 +104,8 @@ function CommunityCommissionsPage(props: Props) {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@ import {
|
||||
faTags,
|
||||
faHandsHelping,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../data/animation";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../common/UsePrefixedDocumentTitle";
|
||||
import { PageHeader } from "../../_common/PageHeader";
|
||||
import {
|
||||
@@ -57,20 +56,20 @@ function ContributeIndexPage(props: Props) {
|
||||
);
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
{/* <div className="container py-5 px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
<h1 className=" fw-bold" >
|
||||
{t("pages.contributeIndex.heroTitle")}
|
||||
</motion.h1>
|
||||
<motion.h3 className="mb-4" variants={item}>
|
||||
</h1>
|
||||
<h3 className="mb-4" >
|
||||
<Trans i18nKey="pages.contributeIndex.heroSubtitle">
|
||||
You make FakeYou <strong>better</strong> by contributing
|
||||
</Trans>
|
||||
</motion.h3>
|
||||
<motion.p className="pb-4" variants={item}>
|
||||
</h3>
|
||||
<p className="pb-4" >
|
||||
{t("pages.contributeIndex.introText")}
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div> */}
|
||||
<PageHeader
|
||||
@@ -80,7 +79,7 @@ function ContributeIndexPage(props: Props) {
|
||||
titleIcon={titleIcon}
|
||||
/>
|
||||
|
||||
<motion.div className="container-panel pb-3" variants={panel}>
|
||||
<div className="container-panel pb-3">
|
||||
<div className="panel p-3 py-4 p-md-4 text-center text-lg-start">
|
||||
<h2 className="fw-bold">
|
||||
<FontAwesomeIcon icon={faFileArrowUp} className="me-3" />
|
||||
@@ -134,9 +133,9 @@ function ContributeIndexPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-3" variants={item}>
|
||||
<div className="container-panel pt-3 pb-3">
|
||||
<div className="panel p-3 py-4 p-md-4 text-center text-lg-start">
|
||||
<h2 className="fw-bold">
|
||||
<FontAwesomeIcon icon={faTags} className="me-3" />
|
||||
@@ -156,7 +155,7 @@ function ContributeIndexPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
<div className="container-panel pt-3">
|
||||
<div className="panel p-3 py-4 p-md-4 text-center text-lg-start">
|
||||
<h2 className="fw-bold">
|
||||
@@ -177,7 +176,7 @@ function ContributeIndexPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ import {
|
||||
faDiscord,
|
||||
faTwitch,
|
||||
} from "@fortawesome/free-brands-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { duration, delay, container, item } from "../../../../data/animation";
|
||||
import { duration, delay } from "../../../../data/animation";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../common/UsePrefixedDocumentTitle";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
@@ -60,7 +60,6 @@ function FirehoseEventListPage(props: Props) {
|
||||
[]
|
||||
);
|
||||
|
||||
|
||||
const fetchEvents = () => {
|
||||
const api = new ApiConfig();
|
||||
const endpointUrl = api.firehoseEvents();
|
||||
@@ -324,19 +323,17 @@ function FirehoseEventListPage(props: Props) {
|
||||
usePrefixedDocumentTitle("Firehose Event Feed");
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container py-5 px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Firehose Event Feed
|
||||
</motion.h1>
|
||||
<motion.h4 className="mb-4" variants={item}>
|
||||
<h1 className=" fw-bold">Firehose Event Feed</h1>
|
||||
<h4 className="mb-4">
|
||||
The latest FakeYou events refreshed every few seconds.
|
||||
</motion.h4>
|
||||
<motion.p className="lead" variants={item}>
|
||||
</h4>
|
||||
<p className="lead">
|
||||
As you can see, we're really popular. But we owe it to you, our
|
||||
users. Thank you!
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -345,7 +342,7 @@ function FirehoseEventListPage(props: Props) {
|
||||
<ul className="firehose-ul d-flex flex-column gap-3">{eventItems}</ul>
|
||||
</Fade>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { motion } from "framer-motion";
|
||||
import { container } from "../../../../data/animation";
|
||||
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { t } from "i18next";
|
||||
@@ -145,7 +144,7 @@ function LandingPage(props: Props) {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pb-5 pb-lg-0 pt-lg-4 px-md-5 px-lg-5 px-xl-3">
|
||||
{/* Community Commissions Alert */}
|
||||
{/* <div className="alert alert-info">
|
||||
@@ -516,7 +515,7 @@ function LandingPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ import {
|
||||
LeaderboardLookupError,
|
||||
} from "@storyteller/components/src/api/leaderboard/GetLeaderboard";
|
||||
import { DiscordLink2 } from "@storyteller/components/src/elements/DiscordLink2";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "data/animation";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
@@ -32,7 +31,7 @@ function LeaderboardPage(props: Props) {
|
||||
Array<LeaderboardRow> | undefined
|
||||
>(undefined);
|
||||
const [retryCount, setRetryCount] = useState(0);
|
||||
|
||||
|
||||
PosthogClient.recordPageview();
|
||||
|
||||
const getLeaderboard = useCallback(async () => {
|
||||
@@ -121,23 +120,19 @@ function LeaderboardPage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container py-5 px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Leaderboard
|
||||
</motion.h1>
|
||||
<motion.h3 className="mb-4" variants={item}>
|
||||
Our most frequent contributors!
|
||||
</motion.h3>
|
||||
<motion.p className="lead" variants={item}>
|
||||
<h1 className=" fw-bold">Leaderboard</h1>
|
||||
<h3 className="mb-4">Our most frequent contributors!</h3>
|
||||
<p className="lead">
|
||||
Want to be on the leaderboard?{" "}
|
||||
<DiscordLink2>Join our Discord</DiscordLink2> and learn more!
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-5 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-5 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">TTS Models Uploaded</h2>
|
||||
<div className="py-6">
|
||||
@@ -146,9 +141,9 @@ function LeaderboardPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">W2L Templates Uploaded</h2>
|
||||
<div className="py-6">
|
||||
@@ -157,8 +152,8 @@ function LeaderboardPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
} from "@storyteller/components/src/api/session/CreateSession";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faUser, faKey } from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, panel } from "../../../../data/animation";
|
||||
|
||||
import { Analytics } from "../../../../common/Analytics";
|
||||
import { usePrefixedDocumentTitle } from "../../../../common/UsePrefixedDocumentTitle";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
@@ -89,11 +88,8 @@ function LoginPage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<motion.div
|
||||
className="container-panel pb-5 pt-lg-5 my-lg-5 login-panel"
|
||||
variants={panel}
|
||||
>
|
||||
<div>
|
||||
<div className="container-panel pb-5 pt-lg-5 my-lg-5 login-panel">
|
||||
<div className="panel p-3 p-lg-4 load-hidden mt-5 mt-lg-0 px-md-4">
|
||||
<h1 className="panel-title fw-bold">Login</h1>
|
||||
<div className="py-6">
|
||||
@@ -138,10 +134,7 @@ function LoginPage(props: Props) {
|
||||
<button className="btn btn-primary w-100 mt-2">Login</button>
|
||||
<p>
|
||||
Don’t have an account?
|
||||
<Link
|
||||
to={WebUrl.signupPage()}
|
||||
className="text-link"
|
||||
>
|
||||
<Link to={WebUrl.signupPage()} className="text-link">
|
||||
Create an account now.
|
||||
</Link>
|
||||
</p>
|
||||
@@ -149,8 +142,8 @@ function LoginPage(props: Props) {
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { container, item } from "../../../../data/animation";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../common/UsePrefixedDocumentTitle";
|
||||
import { TwitchPlayer, TwitchChat } from "react-twitch-embed";
|
||||
import { Link } from "react-router-dom";
|
||||
@@ -112,18 +112,18 @@ function NewsPage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container-panel py-1 py-lg-4 px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="row gx-3 gy-3">
|
||||
<div className="col-12 col-lg-8 d-flex flex-column gap-3">
|
||||
{/* <div className="d-flex flex-column ms-3 ms-lg-0">
|
||||
<motion.h1 className="fw-bold" variants={item}>
|
||||
<h1 className="fw-bold" >
|
||||
Media Feed
|
||||
</motion.h1>
|
||||
</h1>
|
||||
</div> */}
|
||||
|
||||
{/* Feed Content */}
|
||||
<motion.div variants={item} className="d-flex flex-column gap-3">
|
||||
<div className="d-flex flex-column gap-3">
|
||||
<TwitchPlayer
|
||||
channel={TWITCH_CHANNEL}
|
||||
width="100%"
|
||||
@@ -177,7 +177,7 @@ function NewsPage(props: Props) {
|
||||
Want to give us feedback? Please join our <DiscordLink2 />.
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Side column */}
|
||||
@@ -191,7 +191,7 @@ function NewsPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@ import { PATRONS } from "../../../../data/Patrons";
|
||||
import { PatreonLink } from "@storyteller/components/src/elements/PatreonLink";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faPatreon } from "@fortawesome/free-brands-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, image, panel } from "../../../../data/animation";
|
||||
|
||||
import { ThirdPartyLinks } from "@storyteller/components/src/constants/ThirdPartyLinks";
|
||||
import { usePrefixedDocumentTitle } from "../../../../common/UsePrefixedDocumentTitle";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
@@ -19,25 +18,20 @@ function PatronPage(props: Props) {
|
||||
PosthogClient.recordPageview();
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container py-5 pt-lg-0">
|
||||
<div className="row">
|
||||
<div className="col-12 col-lg-7 d-flex flex-column justify-content-center text-center text-lg-start px-3 px-md-2 px-lg-5 px-xl-3">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Thanks to our Patrons!
|
||||
</motion.h1>
|
||||
<motion.h3 className="mb-4 px-4 px-md-0" variants={item}>
|
||||
<h1 className=" fw-bold">Thanks to our Patrons!</h1>
|
||||
<h3 className="mb-4 px-4 px-md-0">
|
||||
Our Patrons help support our work.
|
||||
</motion.h3>
|
||||
<motion.p className="lead mb-5" variants={item}>
|
||||
</h3>
|
||||
<p className="lead mb-5">
|
||||
Our Patrons help pay offset (but not completely cover) our
|
||||
expensive server bills.
|
||||
</motion.p>
|
||||
</p>
|
||||
|
||||
<motion.div
|
||||
className="d-flex justify-content-center justify-content-lg-start"
|
||||
variants={item}
|
||||
>
|
||||
<div className="d-flex justify-content-center justify-content-lg-start">
|
||||
<a
|
||||
href={ThirdPartyLinks.FAKEYOU_PATREON}
|
||||
target="_blank"
|
||||
@@ -47,22 +41,21 @@ function PatronPage(props: Props) {
|
||||
<FontAwesomeIcon icon={faPatreon} className="me-2" />
|
||||
Support us on Patreon
|
||||
</a>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-lg-5 d-flex flex-column align-items-center">
|
||||
<motion.img
|
||||
<img
|
||||
className="img-fluid mt-5 mw-50"
|
||||
src="/mascot/kitsune_pose7.webp"
|
||||
alt="FakeYou Mascot"
|
||||
width="423"
|
||||
height="387"
|
||||
variants={image}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pb-5" variants={panel}>
|
||||
<div className="container-panel pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h1 className="panel-title fw-bold">Our Patrons</h1>
|
||||
<div className="py-6">
|
||||
@@ -81,9 +74,9 @@ function PatronPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<div>
|
||||
<p>
|
||||
Patrons will get first looks at new features, get dedicated access
|
||||
@@ -95,8 +88,8 @@ function PatronPage(props: Props) {
|
||||
<PatreonLink text="donating on Patreon" iconAfterText={true} />
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, image } from "../../../../data/animation";
|
||||
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
@@ -14,44 +13,41 @@ function CheckoutCancelPage(props: Props) {
|
||||
PosthogClient.recordPageview();
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container mb-4">
|
||||
<div className="row gx-3 flex-lg-row-reverse align-items-center">
|
||||
<div className="col-lg-6">
|
||||
<div className="d-flex justify-content-center">
|
||||
<motion.img
|
||||
<img
|
||||
src="/mascot/kitsune_pose7.webp"
|
||||
className="img-fluid"
|
||||
width="516"
|
||||
height="444"
|
||||
alt="FakeYou Kitsune Mascot!"
|
||||
variants={image}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6 px-md-2 ps-lg-5 ps-xl-2">
|
||||
<div className="text-center text-lg-start">
|
||||
<div>
|
||||
<motion.h1 className=" fw-bold lh-1 mb-4" variants={item}>
|
||||
Oh no!
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold lh-1 mb-4">Oh no!</h1>
|
||||
</div>
|
||||
<div>
|
||||
<motion.p className="lead" variants={item}>
|
||||
<p className="lead">
|
||||
It's okay if you don't want to support FakeYou right now, but
|
||||
we'd appreciate it if you reconsider us in the future.
|
||||
</motion.p>
|
||||
</p>
|
||||
<br />
|
||||
<motion.p className="lead" variants={item}>
|
||||
<p className="lead">
|
||||
Paid plans go directly to helping us afford more GPUs,
|
||||
engineering, and research talent.
|
||||
</motion.p>
|
||||
</p>
|
||||
<br />
|
||||
<motion.p className="lead" variants={item}>
|
||||
<p className="lead">
|
||||
We're trying to build a film and music production system that
|
||||
you can use to make any content you dream up. Please consider
|
||||
supporting us monetarily.
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -71,7 +67,7 @@ function CheckoutCancelPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, image } from "../../../../data/animation";
|
||||
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
@@ -14,44 +13,39 @@ function CheckoutSuccessPage(props: Props) {
|
||||
PosthogClient.recordPageview();
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container mb-4">
|
||||
<div className="row gx-3 flex-lg-row-reverse align-items-center">
|
||||
<div className="col-lg-6">
|
||||
<div className="d-flex justify-content-center">
|
||||
<motion.img
|
||||
<img
|
||||
src="/mascot/kitsune_pose3.webp"
|
||||
className="img-fluid"
|
||||
width="516"
|
||||
height="444"
|
||||
alt="FakeYou Kitsune Mascot!"
|
||||
variants={image}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6 px-md-2 ps-lg-5 ps-xl-2">
|
||||
<div className="text-center text-lg-start">
|
||||
<div>
|
||||
<motion.h1 className=" fw-bold lh-1 mb-4" variants={item}>
|
||||
Thank you!
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold lh-1 mb-4">Thank you!</h1>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<motion.p className="lead" variants={item}>
|
||||
<p className="lead">
|
||||
We're grateful you're helping FakeYou build the future
|
||||
creative suite. We're building tools for small creators and
|
||||
have an eye on building a full AI-powered Hollywood and music
|
||||
production studio.
|
||||
</motion.p>
|
||||
</p>
|
||||
<br />
|
||||
<motion.p className="lead" variants={item}>
|
||||
Your support helps us immensely!
|
||||
</motion.p>
|
||||
<p className="lead">Your support helps us immensely!</p>
|
||||
<br />
|
||||
<motion.p className="lead" variants={item}>
|
||||
<p className="lead">
|
||||
Please give it a few minutes for your purchase to take effect.
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -64,7 +58,7 @@ function CheckoutSuccessPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, image } from "../../../../data/animation";
|
||||
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
@@ -14,35 +13,28 @@ function PortalSuccessPage(props: Props) {
|
||||
PosthogClient.recordPageview();
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container mb-4">
|
||||
<div className="row gx-3 flex-lg-row-reverse align-items-center">
|
||||
<div className="col-lg-6">
|
||||
<div className="d-flex justify-content-center">
|
||||
<motion.img
|
||||
<img
|
||||
src="/mascot/kitsune_pose3.webp"
|
||||
className="img-fluid"
|
||||
width="516"
|
||||
height="444"
|
||||
alt="FakeYou Kitsune Mascot!"
|
||||
variants={image}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-6 px-md-2 ps-lg-5 ps-xl-2">
|
||||
<div className="text-center text-lg-start">
|
||||
<div>
|
||||
<motion.h1 className=" fw-bold lh-1 mb-4" variants={item}>
|
||||
Thank You!
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold lh-1 mb-4">Thank You!</h1>
|
||||
</div>
|
||||
<div>
|
||||
<motion.p className="lead" variants={item}>
|
||||
Your support means a lot to us.
|
||||
</motion.p>
|
||||
<motion.p className="lead" variants={item}>
|
||||
Please continue to enjoy FakeYou!
|
||||
</motion.p>
|
||||
<p className="lead">Your support means a lot to us.</p>
|
||||
<p className="lead">Please continue to enjoy FakeYou!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -55,7 +47,7 @@ function PortalSuccessPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
CreateStripePortalRedirectIsError,
|
||||
CreateStripePortalRedirectIsSuccess,
|
||||
} from "@storyteller/components/src/api/premium/CreateStripePortalRedirect";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../data/animation";
|
||||
|
||||
import { FakeYouFrontendEnvironment } from "@storyteller/components/src/env/FakeYouFrontendEnvironment";
|
||||
import { Analytics } from "../../../../common/Analytics";
|
||||
import { WebUrl } from "../../../../common/WebUrl";
|
||||
@@ -148,26 +147,21 @@ function PricingPage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 text-center">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Pricing
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold">Pricing</h1>
|
||||
{/* <p className="fs-5">
|
||||
By purchasing FakeYou premium, you help us build more!
|
||||
</p> */}
|
||||
<motion.div
|
||||
className="alert alert-warning mt-4 alert-pricing mb-2"
|
||||
variants={item}
|
||||
>
|
||||
<div className="alert alert-warning mt-4 alert-pricing mb-2">
|
||||
<FontAwesomeIcon icon={faHeart} className="text-red me-3" />
|
||||
By purchasing FakeYou premium, you help us build more!
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="container mb-5">
|
||||
<div className="row gx-3 gy-4">
|
||||
{/* Starter Tier */}
|
||||
{/*<motion.div className="col-12 col-sm-6 col-lg-3" variants={panel}>
|
||||
{/*<div className="col-12 col-sm-6 col-lg-3" >
|
||||
<div className="rounded panel p-4 h-100">
|
||||
<h2 className="text-center my-2 fw-bold mb-4">
|
||||
{FYP.starter.tier}
|
||||
@@ -218,11 +212,11 @@ function PricingPage(props: Props) {
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
*/}
|
||||
|
||||
{/* Plus Tier */}
|
||||
<motion.div className="col-12 col-sm-6 col-lg-4" variants={panel}>
|
||||
<div className="col-12 col-sm-6 col-lg-4">
|
||||
<div className="rounded panel p-4 h-100">
|
||||
<h2 className="text-center my-2 fw-bold mb-4">{FYP.plus.tier}</h2>
|
||||
<button
|
||||
@@ -319,10 +313,10 @@ function PricingPage(props: Props) {
|
||||
+ Future feature updates
|
||||
</h6>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Pro Tier */}
|
||||
<motion.div className="col-12 col-sm-6 col-lg-4" variants={panel}>
|
||||
<div className="col-12 col-sm-6 col-lg-4">
|
||||
<div className={proBorderCss}>
|
||||
<h2 className="text-center my-2 fw-bold mb-4">{FYP.pro.tier}</h2>
|
||||
<button
|
||||
@@ -457,10 +451,10 @@ function PricingPage(props: Props) {
|
||||
+ Future feature updates
|
||||
</h6>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Elite Tier */}
|
||||
<motion.div className="col-12 col-sm-6 col-lg-4" variants={panel}>
|
||||
<div className="col-12 col-sm-6 col-lg-4">
|
||||
<div className="rounded panel p-4 h-100">
|
||||
<h2 className="text-center my-2 fw-bold mb-4">
|
||||
{FYP.elite.tier}
|
||||
@@ -609,7 +603,7 @@ function PricingPage(props: Props) {
|
||||
+ Future feature updates
|
||||
</h6>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{unsubscribeSection}
|
||||
@@ -719,7 +713,7 @@ function PricingPage(props: Props) {
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, panel } from "data/animation";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
@@ -61,11 +60,8 @@ function ProductUsageInfoPage(props: Props) {
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<motion.div
|
||||
className="container-panel pt-lg-5 my-lg-5 login-panel"
|
||||
variants={panel}
|
||||
>
|
||||
<div>
|
||||
<div className="container-panel pt-lg-5 my-lg-5 login-panel">
|
||||
<div className="panel p-4 p-lg-4 mt-5 mt-lg-0 px-md-4">
|
||||
<h2 className="fw-bold pb-0">Product Usage Survey</h2>
|
||||
<hr className="my-4" />
|
||||
@@ -138,8 +134,8 @@ function ProductUsageInfoPage(props: Props) {
|
||||
<button className="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
User,
|
||||
} from "@storyteller/components/src/api/user/GetUserByUsername";
|
||||
import { BackLink } from "../../../_common/BackLink";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface Props {
|
||||
@@ -111,17 +110,15 @@ function ProfileBanFc(props: Props) {
|
||||
let isDisabled = userData === undefined;
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-lg-5 px-xl-3">
|
||||
<motion.h1 className=" fw-bold mb-3" variants={item}>
|
||||
Profile & Preferences
|
||||
</motion.h1>
|
||||
<motion.div variants={item}>
|
||||
<h1 className=" fw-bold mb-3">Profile & Preferences</h1>
|
||||
<div>
|
||||
<BackLink link={viewLinkUrl} text="Back to profile" />
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<fieldset disabled={isDisabled}>
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
@@ -164,21 +161,21 @@ function ProfileBanFc(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container" variants={item}>
|
||||
<div className="container">
|
||||
<button className="btn btn-primary w-100">Update Ban</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</motion.form>
|
||||
</form>
|
||||
|
||||
<motion.div className="container py-5" variants={item}>
|
||||
<div className="container py-5">
|
||||
<p>Notes on banned users:</p>
|
||||
<ul>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
</ul>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,7 @@ import {
|
||||
faGlobe,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { BackLink } from "../../../_common/BackLink";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
const DEFAULT_VISIBILITY = "public";
|
||||
@@ -63,7 +62,7 @@ interface UserPayload {
|
||||
function ProfileEditFc(props: Props) {
|
||||
const { username } = useParams() as { username: string };
|
||||
PosthogClient.recordPageview();
|
||||
|
||||
|
||||
const userProfilePage = `/profile/${username}`;
|
||||
|
||||
const history = useHistory();
|
||||
@@ -237,17 +236,15 @@ function ProfileEditFc(props: Props) {
|
||||
);
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-lg-5 px-xl-3">
|
||||
<motion.h1 className=" fw-bold mb-3" variants={item}>
|
||||
Profile & Preferences
|
||||
</motion.h1>
|
||||
<motion.div variants={item}>
|
||||
<h1 className=" fw-bold mb-3">Profile & Preferences</h1>
|
||||
<div>
|
||||
<BackLink link={viewLinkUrl} text="Back to profile" />
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<fieldset disabled={isDisabled}>
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
@@ -301,7 +298,7 @@ function ProfileEditFc(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Profile Picture</h2>
|
||||
<div className="py-6">
|
||||
@@ -323,9 +320,9 @@ function ProfileEditFc(props: Props) {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Profile Details</h2>
|
||||
<div className="py-6">
|
||||
@@ -507,15 +504,15 @@ function ProfileEditFc(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container" variants={item}>
|
||||
<div className="container">
|
||||
<button className="btn btn-primary w-100">Update</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</motion.form>
|
||||
</form>
|
||||
|
||||
<motion.div className="container-panel pt-5" variants={item}>
|
||||
<div className="container-panel pt-5">
|
||||
<div className="panel p-4 mt-5">
|
||||
<h4 className="fw-semibold mb-3">Cancel My Subscription</h4>
|
||||
<p className="mb-4 fs-14">
|
||||
@@ -527,8 +524,8 @@ function ProfileEditFc(props: Props) {
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,43 +8,49 @@ import { ProfileW2lInferenceResultsListFc } from "./Profile_W2lInferenceResultLi
|
||||
import { ProfileW2lTemplateListFc } from "./Profile_W2lTemplateListFc";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { Route, Switch, useLocation, useParams, useRouteMatch } from "react-router-dom";
|
||||
import {
|
||||
Route,
|
||||
Switch,
|
||||
useLocation,
|
||||
useParams,
|
||||
useRouteMatch,
|
||||
} from "react-router-dom";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faDiscord,
|
||||
faGithub,
|
||||
faTwitch,
|
||||
faTwitter,
|
||||
faDiscord,
|
||||
faGithub,
|
||||
faTwitch,
|
||||
faTwitter,
|
||||
} from "@fortawesome/free-brands-svg-icons";
|
||||
import {
|
||||
faBan,
|
||||
faGear,
|
||||
faGlobe,
|
||||
faDollarSign,
|
||||
faStar,
|
||||
faBan,
|
||||
faGear,
|
||||
faGlobe,
|
||||
faDollarSign,
|
||||
faStar,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import {
|
||||
GetUserByUsername,
|
||||
GetUserByUsernameIsErr,
|
||||
GetUserByUsernameIsOk,
|
||||
User,
|
||||
UserLookupError,
|
||||
GetUserByUsername,
|
||||
GetUserByUsernameIsErr,
|
||||
GetUserByUsernameIsOk,
|
||||
User,
|
||||
UserLookupError,
|
||||
} from "@storyteller/components/src/api/user/GetUserByUsername";
|
||||
import { format } from "date-fns";
|
||||
import { WebUrl } from "../../../../../common/WebUrl";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import Tippy from "@tippyjs/react";
|
||||
import "tippy.js/dist/tippy.css";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
|
||||
import { faCalendarAlt } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { CommentComponent } from "../../../_common/comments/CommentComponent";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
sessionWrapper: SessionWrapper;
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
}
|
||||
|
||||
// function copyToClipboard(username: string): any {
|
||||
@@ -52,425 +58,474 @@ interface Props {
|
||||
// }
|
||||
|
||||
function ProfilePage(this: any, props: Props) {
|
||||
const { username }: { username: string } = useParams();
|
||||
PosthogClient.recordPageview();
|
||||
const { username }: { username: string } = useParams();
|
||||
PosthogClient.recordPageview();
|
||||
|
||||
const { pathname } = useLocation();
|
||||
const { url } = useRouteMatch();
|
||||
const { pathname } = useLocation();
|
||||
const { url } = useRouteMatch();
|
||||
|
||||
const [userData, setUserData] = useState<User | undefined>(undefined);
|
||||
const [notFoundState, setNotFoundState] = useState<boolean>(false);
|
||||
const [userData, setUserData] = useState<User | undefined>(undefined);
|
||||
const [notFoundState, setNotFoundState] = useState<boolean>(false);
|
||||
|
||||
const getUser = useCallback(async (username) => {
|
||||
const response = await GetUserByUsername(username);
|
||||
if (GetUserByUsernameIsOk(response)) {
|
||||
setUserData(response);
|
||||
} else if (GetUserByUsernameIsErr(response)) {
|
||||
switch (response) {
|
||||
case UserLookupError.NotFound:
|
||||
setNotFoundState(true);
|
||||
break;
|
||||
}
|
||||
const getUser = useCallback(async (username) => {
|
||||
const response = await GetUserByUsername(username);
|
||||
if (GetUserByUsernameIsOk(response)) {
|
||||
setUserData(response);
|
||||
} else if (GetUserByUsernameIsErr(response)) {
|
||||
switch (response) {
|
||||
case UserLookupError.NotFound:
|
||||
setNotFoundState(true);
|
||||
break;
|
||||
}
|
||||
}, []);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
getUser(username);
|
||||
}, [username, getUser]);
|
||||
useEffect(() => {
|
||||
getUser(username);
|
||||
}, [username, getUser]);
|
||||
|
||||
const documentTitle =
|
||||
userData?.display_name === undefined
|
||||
? undefined
|
||||
: `${userData.display_name}`;
|
||||
usePrefixedDocumentTitle(documentTitle);
|
||||
const documentTitle =
|
||||
userData?.display_name === undefined
|
||||
? undefined
|
||||
: `${userData.display_name}`;
|
||||
usePrefixedDocumentTitle(documentTitle);
|
||||
|
||||
if (notFoundState) {
|
||||
return (
|
||||
<div className="container py-5">
|
||||
<div className="py-5">
|
||||
<h1 className="fw-semibold text-center mb-4">User not found</h1>
|
||||
<div className="text-center">
|
||||
<Link className="btn btn-primary" to="/">
|
||||
Back to main
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!userData) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
let userEmailHash = userData.email_gravatar_hash;
|
||||
|
||||
let editProfileButton = undefined;
|
||||
|
||||
let banUserButton = undefined;
|
||||
|
||||
let upgradeButton = undefined;
|
||||
|
||||
if (props.sessionWrapper.isLoggedIn()) {
|
||||
if (props.sessionWrapper.userTokenMatches(userData.user_token)) {
|
||||
if (!props.sessionSubscriptionsWrapper.hasPaidFeatures()) {
|
||||
const upgradeLinkUrl = WebUrl.pricingPage();
|
||||
|
||||
upgradeButton = (
|
||||
<>
|
||||
<Link className="btn btn-primary" to={upgradeLinkUrl}>
|
||||
<FontAwesomeIcon icon={faStar} className="me-2" />
|
||||
<span>Upgrade</span>
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (props.sessionWrapper.canBanUsers()) {
|
||||
const currentlyBanned = userData.maybe_moderator_fields?.is_banned;
|
||||
const banLinkUrl = WebUrl.userProfileBanPage(userData.username);
|
||||
const buttonLabel = currentlyBanned ? "Unban" : "Ban";
|
||||
const banButtonCss = currentlyBanned
|
||||
? "btn btn-secondary"
|
||||
: "btn btn-destructive";
|
||||
|
||||
banUserButton = (
|
||||
<>
|
||||
<Link className={banButtonCss} to={banLinkUrl}>
|
||||
<FontAwesomeIcon icon={faBan} className="me-2" />
|
||||
{buttonLabel}
|
||||
if (notFoundState) {
|
||||
return (
|
||||
<div className="container py-5">
|
||||
<div className="py-5">
|
||||
<h1 className="fw-semibold text-center mb-4">User not found</h1>
|
||||
<div className="text-center">
|
||||
<Link className="btn btn-primary" to="/">
|
||||
Back to main
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
let profileButtonsMobile = <span />;
|
||||
|
||||
if (props.sessionWrapper.canEditUserProfile(userData.username)) {
|
||||
const editLinkUrl = WebUrl.userProfileEditPage(userData.username);
|
||||
|
||||
// Mods shouldn't edit preferences.
|
||||
const buttonLabel = props.sessionWrapper.userTokenMatches(
|
||||
userData.user_token
|
||||
)
|
||||
? "Edit Profile & Preferences"
|
||||
: "Edit Profile";
|
||||
|
||||
editProfileButton = (
|
||||
<>
|
||||
<Link className={"btn btn-secondary"} to={editLinkUrl}>
|
||||
<FontAwesomeIcon icon={faGear} className="me-2" />
|
||||
{buttonLabel}
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
|
||||
profileButtonsMobile = (
|
||||
<div className="container d-flex d-lg-none mb-4">
|
||||
<div className="d-flex w-100 gap-3 justify-content-center flex-column flex-md-row">
|
||||
{upgradeButton}
|
||||
{editProfileButton}
|
||||
{banUserButton}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let profileDesc = (
|
||||
<motion.div className="mt-3 text-center text-lg-start opacity-50">
|
||||
No profile description.
|
||||
</motion.div>
|
||||
);
|
||||
|
||||
if (!!userData.profile_rendered_html) {
|
||||
profileDesc = (
|
||||
<motion.div
|
||||
className="mt-3 text-center text-lg-start"
|
||||
variants={item}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: userData.profile_rendered_html || "",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let profileRows: Array<JSX.Element> = [];
|
||||
let profileJoinDate: Array<JSX.Element> = [];
|
||||
|
||||
const createdAt = new Date(userData.created_at);
|
||||
const joinDate = format(createdAt, "LLLL y");
|
||||
profileJoinDate.push(
|
||||
<div
|
||||
key="created"
|
||||
className="d-flex align-items-center justify-content-center justify-content-lg-start"
|
||||
>
|
||||
<FontAwesomeIcon icon={faCalendarAlt} className="me-2" />
|
||||
<p className="fw-normal">Joined {joinDate}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
if (userData.website_url !== undefined && userData.website_url !== null) {
|
||||
let websiteUrl = <span>{userData.website_url}</span>;
|
||||
if (
|
||||
userData.website_url?.startsWith("http://") ||
|
||||
userData.website_url?.startsWith("https://")
|
||||
) {
|
||||
websiteUrl = (
|
||||
<Tippy
|
||||
content="Website"
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a
|
||||
href={userData.website_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
>
|
||||
<FontAwesomeIcon icon={faGlobe} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
}
|
||||
if (!userData) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
profileRows.push(<div key="website">{websiteUrl}</div>);
|
||||
}
|
||||
let userEmailHash = userData.email_gravatar_hash;
|
||||
|
||||
if (userData.twitch_username) {
|
||||
let twitchUrl = `https://twitch.com/${userData.twitch_username}`;
|
||||
let twitchLink = (
|
||||
<Tippy
|
||||
content="Twitch"
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a href={twitchUrl} target="_blank" rel="noopener noreferrer nofollow">
|
||||
<FontAwesomeIcon icon={faTwitch} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
let editProfileButton = undefined;
|
||||
|
||||
profileRows.push(<div key="twitch">{twitchLink}</div>);
|
||||
}
|
||||
let banUserButton = undefined;
|
||||
|
||||
if (userData.twitter_username) {
|
||||
let twitterUrl = `https://twitter.com/${userData.twitter_username}`;
|
||||
let twitterLink = (
|
||||
<Tippy
|
||||
content="Twitter"
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a href={twitterUrl} target="_blank" rel="noopener noreferrer nofollow">
|
||||
<FontAwesomeIcon icon={faTwitter} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
profileRows.push(<div key="twitter">{twitterLink}</div>);
|
||||
}
|
||||
let upgradeButton = undefined;
|
||||
|
||||
if (userData.discord_username) {
|
||||
profileRows.push(
|
||||
<Tippy
|
||||
allowHTML
|
||||
content={
|
||||
<div className="text-center">
|
||||
Discord
|
||||
<br />
|
||||
<p className="fw-semibold fs-6">{userData.discord_username}</p>
|
||||
</div>
|
||||
}
|
||||
interactive
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a
|
||||
// eslint-disable-next-line no-script-url
|
||||
href="javascript:;"
|
||||
// onClick={copyToClipboard(userData.discord_username)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faDiscord} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
}
|
||||
if (props.sessionWrapper.isLoggedIn()) {
|
||||
if (props.sessionWrapper.userTokenMatches(userData.user_token)) {
|
||||
if (!props.sessionSubscriptionsWrapper.hasPaidFeatures()) {
|
||||
const upgradeLinkUrl = WebUrl.pricingPage();
|
||||
|
||||
if (userData.github_username) {
|
||||
let githubUrl = `https://github.com/${userData.github_username}`;
|
||||
let githubLink = (
|
||||
<Tippy
|
||||
content="GitHub"
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a
|
||||
href={githubUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
className="fw-normal"
|
||||
>
|
||||
<FontAwesomeIcon icon={faGithub} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
profileRows.push(<div key="github">{githubLink}</div>);
|
||||
}
|
||||
|
||||
if (userData.cashapp_username) {
|
||||
// NB: URL includes a dollar sign
|
||||
let cashAppUrl = `https://cash.me/$${userData.cashapp_username}`;
|
||||
let cashAppLink = (
|
||||
<Tippy
|
||||
content="CashApp"
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a href={cashAppUrl} target="_blank" rel="noopener noreferrer nofollow">
|
||||
<FontAwesomeIcon icon={faDollarSign} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
profileRows.push(<div key="cashapp">{cashAppLink}</div>);
|
||||
}
|
||||
|
||||
const Badges = () => {
|
||||
return userData.badges.length ? <ul>{userData.badges.map((badge) => <li key={badge.slug}>{badge.title}</li>)}</ul> : <div>None yet</div>
|
||||
};
|
||||
|
||||
const Comments = () => <div className="mt-3 mt-lg-0">
|
||||
<CommentComponent { ...{ entityType: 'user', entityToken: userData?.user_token, sessionWrapper: props.sessionWrapper }}/>
|
||||
</div>;
|
||||
|
||||
const tabs = [
|
||||
{ Component: ProfileTtsInferenceResultsListFc, val: 'ttsresults', txt: 'TTS Results' },
|
||||
{ Component: ProfileW2lInferenceResultsListFc, val: 'w2lresults', txt: 'Lipsync Results' },
|
||||
{ Component: ProfileTtsModelListFc, val: 'uploadedtts', txt: 'Uploaded TTS Models' },
|
||||
{ Component: ProfileW2lTemplateListFc, val: 'uploadedw2l', txt: 'Uploaded Templates' },
|
||||
{ Component: Badges, val: 'badges', txt: 'Badges' },
|
||||
{ Component: Comments, val: 'comments', txt: 'Comments' }
|
||||
];
|
||||
|
||||
const txtToUrl = (txt = '') => txt.replaceAll(' ','-').toLowerCase();
|
||||
|
||||
const tabLinks = tabs.map(({ val, txt },key) => {
|
||||
let subParam = pathname.split(url + '/')[1] || '';
|
||||
let isActive = txtToUrl(txt) === subParam || (!subParam && !key);
|
||||
|
||||
return <li {...{ className: 'nav-item', key, role: 'presentation' }}>
|
||||
<Link {...{
|
||||
'aria-controls': val,
|
||||
'aria-selected': isActive,
|
||||
className: `nav-link${ isActive ? ' active' : '' }`,
|
||||
id: `${val}-tab`,
|
||||
role: 'tab',
|
||||
to: `${url.replace(/\/$/, '')}/${txtToUrl(txt)}`
|
||||
}}>
|
||||
{ txt }
|
||||
upgradeButton = (
|
||||
<>
|
||||
<Link className="btn btn-primary" to={upgradeLinkUrl}>
|
||||
<FontAwesomeIcon icon={faStar} className="me-2" />
|
||||
<span>Upgrade</span>
|
||||
</Link>
|
||||
</li>;
|
||||
});
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const BaseRoute = ({ baseUrl }: { baseUrl?: string }) => {
|
||||
return <Route {...{ path: baseUrl || url }}>
|
||||
<motion.div {...{ 'aria-labelledby': 'ttsresults-tab', className: 'tab-pane fade show active', id: 'ttsresults', role: 'tabpanel', variants: panel }}>
|
||||
<ProfileTtsInferenceResultsListFc username={userData.username}/>
|
||||
</motion.div>
|
||||
</Route>;
|
||||
};
|
||||
if (props.sessionWrapper.canBanUsers()) {
|
||||
const currentlyBanned = userData.maybe_moderator_fields?.is_banned;
|
||||
const banLinkUrl = WebUrl.userProfileBanPage(userData.username);
|
||||
const buttonLabel = currentlyBanned ? "Unban" : "Ban";
|
||||
const banButtonCss = currentlyBanned
|
||||
? "btn btn-secondary"
|
||||
: "btn btn-destructive";
|
||||
|
||||
const tabPanels = tabs.map(({ Component, txt, val },key) => {
|
||||
let subRoute = `${url}/${txtToUrl(txt)}`
|
||||
return !key ? BaseRoute({ baseUrl: subRoute }) : <Route {...{ key, path: subRoute }}>
|
||||
<motion.div {...{ 'aria-labelledby': `${val}-tab`, id: 'val', role: 'tabpanel', variants: panel }}
|
||||
className="tab-pane fade show active p-3 p-lg-4"
|
||||
>
|
||||
<Component username={userData.username}/>
|
||||
</motion.div>
|
||||
banUserButton = (
|
||||
<>
|
||||
<Link className={banButtonCss} to={banLinkUrl}>
|
||||
<FontAwesomeIcon icon={faBan} className="me-2" />
|
||||
{buttonLabel}
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
let profileButtonsMobile = <span />;
|
||||
|
||||
if (props.sessionWrapper.canEditUserProfile(userData.username)) {
|
||||
const editLinkUrl = WebUrl.userProfileEditPage(userData.username);
|
||||
|
||||
// Mods shouldn't edit preferences.
|
||||
const buttonLabel = props.sessionWrapper.userTokenMatches(
|
||||
userData.user_token
|
||||
)
|
||||
? "Edit Profile & Preferences"
|
||||
: "Edit Profile";
|
||||
|
||||
editProfileButton = (
|
||||
<>
|
||||
<Link className={"btn btn-secondary"} to={editLinkUrl}>
|
||||
<FontAwesomeIcon icon={faGear} className="me-2" />
|
||||
{buttonLabel}
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
|
||||
profileButtonsMobile = (
|
||||
<div className="container d-flex d-lg-none mb-4">
|
||||
<div className="d-flex w-100 gap-3 justify-content-center flex-column flex-md-row">
|
||||
{upgradeButton}
|
||||
{editProfileButton}
|
||||
{banUserButton}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let profileDesc = (
|
||||
<div className="mt-3 text-center text-lg-start opacity-50">
|
||||
No profile description.
|
||||
</div>
|
||||
);
|
||||
|
||||
if (!!userData.profile_rendered_html) {
|
||||
profileDesc = (
|
||||
<div
|
||||
className="mt-3 text-center text-lg-start"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: userData.profile_rendered_html || "",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let profileRows: Array<JSX.Element> = [];
|
||||
let profileJoinDate: Array<JSX.Element> = [];
|
||||
|
||||
const createdAt = new Date(userData.created_at);
|
||||
const joinDate = format(createdAt, "LLLL y");
|
||||
profileJoinDate.push(
|
||||
<div
|
||||
key="created"
|
||||
className="d-flex align-items-center justify-content-center justify-content-lg-start"
|
||||
>
|
||||
<FontAwesomeIcon icon={faCalendarAlt} className="me-2" />
|
||||
<p className="fw-normal">Joined {joinDate}</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (userData.website_url !== undefined && userData.website_url !== null) {
|
||||
let websiteUrl = <span>{userData.website_url}</span>;
|
||||
if (
|
||||
userData.website_url?.startsWith("http://") ||
|
||||
userData.website_url?.startsWith("https://")
|
||||
) {
|
||||
websiteUrl = (
|
||||
<Tippy
|
||||
content="Website"
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a
|
||||
href={userData.website_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
>
|
||||
<FontAwesomeIcon icon={faGlobe} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
}
|
||||
|
||||
profileRows.push(<div key="website">{websiteUrl}</div>);
|
||||
}
|
||||
|
||||
if (userData.twitch_username) {
|
||||
let twitchUrl = `https://twitch.com/${userData.twitch_username}`;
|
||||
let twitchLink = (
|
||||
<Tippy
|
||||
content="Twitch"
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a href={twitchUrl} target="_blank" rel="noopener noreferrer nofollow">
|
||||
<FontAwesomeIcon icon={faTwitch} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
|
||||
profileRows.push(<div key="twitch">{twitchLink}</div>);
|
||||
}
|
||||
|
||||
if (userData.twitter_username) {
|
||||
let twitterUrl = `https://twitter.com/${userData.twitter_username}`;
|
||||
let twitterLink = (
|
||||
<Tippy
|
||||
content="Twitter"
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a href={twitterUrl} target="_blank" rel="noopener noreferrer nofollow">
|
||||
<FontAwesomeIcon icon={faTwitter} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
profileRows.push(<div key="twitter">{twitterLink}</div>);
|
||||
}
|
||||
|
||||
if (userData.discord_username) {
|
||||
profileRows.push(
|
||||
<Tippy
|
||||
allowHTML
|
||||
content={
|
||||
<div className="text-center">
|
||||
Discord
|
||||
<br />
|
||||
<p className="fw-semibold fs-6">{userData.discord_username}</p>
|
||||
</div>
|
||||
}
|
||||
interactive
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a
|
||||
// eslint-disable-next-line no-script-url
|
||||
href="javascript:;"
|
||||
// onClick={copyToClipboard(userData.discord_username)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faDiscord} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
}
|
||||
|
||||
if (userData.github_username) {
|
||||
let githubUrl = `https://github.com/${userData.github_username}`;
|
||||
let githubLink = (
|
||||
<Tippy
|
||||
content="GitHub"
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a
|
||||
href={githubUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
className="fw-normal"
|
||||
>
|
||||
<FontAwesomeIcon icon={faGithub} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
profileRows.push(<div key="github">{githubLink}</div>);
|
||||
}
|
||||
|
||||
if (userData.cashapp_username) {
|
||||
// NB: URL includes a dollar sign
|
||||
let cashAppUrl = `https://cash.me/$${userData.cashapp_username}`;
|
||||
let cashAppLink = (
|
||||
<Tippy
|
||||
content="CashApp"
|
||||
hideOnClick
|
||||
placement="bottom"
|
||||
theme="fakeyou"
|
||||
arrow={false}
|
||||
>
|
||||
<a href={cashAppUrl} target="_blank" rel="noopener noreferrer nofollow">
|
||||
<FontAwesomeIcon icon={faDollarSign} />
|
||||
</a>
|
||||
</Tippy>
|
||||
);
|
||||
profileRows.push(<div key="cashapp">{cashAppLink}</div>);
|
||||
}
|
||||
|
||||
const Badges = () => {
|
||||
return userData.badges.length ? (
|
||||
<ul>
|
||||
{userData.badges.map((badge) => (
|
||||
<li key={badge.slug}>{badge.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<div>None yet</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Comments = () => (
|
||||
<div className="mt-3 mt-lg-0">
|
||||
<CommentComponent
|
||||
{...{
|
||||
entityType: "user",
|
||||
entityToken: userData?.user_token,
|
||||
sessionWrapper: props.sessionWrapper,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
Component: ProfileTtsInferenceResultsListFc,
|
||||
val: "ttsresults",
|
||||
txt: "TTS Results",
|
||||
},
|
||||
{
|
||||
Component: ProfileW2lInferenceResultsListFc,
|
||||
val: "w2lresults",
|
||||
txt: "Lipsync Results",
|
||||
},
|
||||
{
|
||||
Component: ProfileTtsModelListFc,
|
||||
val: "uploadedtts",
|
||||
txt: "Uploaded TTS Models",
|
||||
},
|
||||
{
|
||||
Component: ProfileW2lTemplateListFc,
|
||||
val: "uploadedw2l",
|
||||
txt: "Uploaded Templates",
|
||||
},
|
||||
{ Component: Badges, val: "badges", txt: "Badges" },
|
||||
{ Component: Comments, val: "comments", txt: "Comments" },
|
||||
];
|
||||
|
||||
const txtToUrl = (txt = "") => txt.replaceAll(" ", "-").toLowerCase();
|
||||
|
||||
const tabLinks = tabs.map(({ val, txt }, key) => {
|
||||
let subParam = pathname.split(url + "/")[1] || "";
|
||||
let isActive = txtToUrl(txt) === subParam || (!subParam && !key);
|
||||
|
||||
return (
|
||||
<li {...{ className: "nav-item", key, role: "presentation" }}>
|
||||
<Link
|
||||
{...{
|
||||
"aria-controls": val,
|
||||
"aria-selected": isActive,
|
||||
className: `nav-link${isActive ? " active" : ""}`,
|
||||
id: `${val}-tab`,
|
||||
role: "tab",
|
||||
to: `${url.replace(/\/$/, "")}/${txtToUrl(txt)}`,
|
||||
}}
|
||||
>
|
||||
{txt}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
const BaseRoute = ({ baseUrl }: { baseUrl?: string }) => {
|
||||
return (
|
||||
<Route {...{ path: baseUrl || url }}>
|
||||
<div
|
||||
{...{
|
||||
"aria-labelledby": "ttsresults-tab",
|
||||
className: "tab-pane fade show active",
|
||||
id: "ttsresults",
|
||||
role: "tabpanel",
|
||||
}}
|
||||
>
|
||||
<ProfileTtsInferenceResultsListFc username={userData.username} />
|
||||
</div>
|
||||
</Route>
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div className="container pt-5 pb-4 px-lg-5 px-xl-3">
|
||||
<motion.div
|
||||
className="d-flex flex-column flex-lg-row w-100"
|
||||
variants={item}
|
||||
>
|
||||
<div className="mb-3 me-lg-4 mb-lg-0">
|
||||
<div className="border-3 d-none d-lg-block">
|
||||
<Gravatar
|
||||
size={150}
|
||||
username={userData.display_name}
|
||||
email_hash={userEmailHash}
|
||||
avatarIndex={userData.default_avatar_index}
|
||||
backgroundIndex={userData.default_avatar_color_index}
|
||||
/>
|
||||
</div>
|
||||
<div className="border-3 text-center d-lg-none">
|
||||
<Gravatar
|
||||
size={100}
|
||||
username={userData.display_name}
|
||||
email_hash={userEmailHash}
|
||||
avatarIndex={userData.default_avatar_index}
|
||||
backgroundIndex={userData.default_avatar_color_index}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex flex-column w-100">
|
||||
<div className="d-flex">
|
||||
<h1 className="fw-bold mb-0 flex-grow-1 text-center text-lg-start">
|
||||
{userData.display_name}
|
||||
</h1>
|
||||
<div className="gap-3 d-none d-lg-flex">
|
||||
{banUserButton}
|
||||
{upgradeButton}
|
||||
{editProfileButton}
|
||||
</div>
|
||||
</div>
|
||||
<div className="opacity-75 mt-1">{profileJoinDate}</div>
|
||||
<div>{profileDesc}</div>
|
||||
<div className="d-flex mt-3 gap-4 gap-lg-3 profile-social-icons justify-content-center justify-content-lg-start">
|
||||
{profileRows}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
const tabPanels = tabs.map(({ Component, txt, val }, key) => {
|
||||
let subRoute = `${url}/${txtToUrl(txt)}`;
|
||||
return !key ? (
|
||||
BaseRoute({ baseUrl: subRoute })
|
||||
) : (
|
||||
<Route {...{ key, path: subRoute }}>
|
||||
<div
|
||||
{...{
|
||||
"aria-labelledby": `${val}-tab`,
|
||||
id: "val",
|
||||
role: "tabpanel",
|
||||
}}
|
||||
className="tab-pane fade show active p-3 p-lg-4"
|
||||
>
|
||||
<Component username={userData.username} />
|
||||
</div>
|
||||
</Route>
|
||||
);
|
||||
});
|
||||
|
||||
{profileButtonsMobile}
|
||||
|
||||
<div className="container-panel mt-5">
|
||||
<div className="panel">
|
||||
<motion.ul
|
||||
className="nav nav-tabs nav-profile justify-content-lg-center"
|
||||
id="myTab"
|
||||
role="tablist"
|
||||
variants={panel}
|
||||
>
|
||||
{ tabLinks }
|
||||
</motion.ul>
|
||||
<div className="tab-content" id="myTabContent">
|
||||
<Switch>
|
||||
{ tabPanels }
|
||||
{<BaseRoute />}
|
||||
</Switch>
|
||||
</div>
|
||||
return (
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column flex-lg-row w-100">
|
||||
<div className="mb-3 me-lg-4 mb-lg-0">
|
||||
<div className="border-3 d-none d-lg-block">
|
||||
<Gravatar
|
||||
size={150}
|
||||
username={userData.display_name}
|
||||
email_hash={userEmailHash}
|
||||
avatarIndex={userData.default_avatar_index}
|
||||
backgroundIndex={userData.default_avatar_color_index}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
<div className="border-3 text-center d-lg-none">
|
||||
<Gravatar
|
||||
size={100}
|
||||
username={userData.display_name}
|
||||
email_hash={userEmailHash}
|
||||
avatarIndex={userData.default_avatar_index}
|
||||
backgroundIndex={userData.default_avatar_color_index}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex flex-column w-100">
|
||||
<div className="d-flex">
|
||||
<h1 className="fw-bold mb-0 flex-grow-1 text-center text-lg-start">
|
||||
{userData.display_name}
|
||||
</h1>
|
||||
<div className="gap-3 d-none d-lg-flex">
|
||||
{banUserButton}
|
||||
{upgradeButton}
|
||||
{editProfileButton}
|
||||
</div>
|
||||
</div>
|
||||
<div className="opacity-75 mt-1">{profileJoinDate}</div>
|
||||
<div>{profileDesc}</div>
|
||||
<div className="d-flex mt-3 gap-4 gap-lg-3 profile-social-icons justify-content-center justify-content-lg-start">
|
||||
{profileRows}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{profileButtonsMobile}
|
||||
|
||||
<div className="container-panel mt-5">
|
||||
<div className="panel">
|
||||
<ul
|
||||
className="nav nav-tabs nav-profile justify-content-lg-center"
|
||||
id="myTab"
|
||||
role="tablist"
|
||||
>
|
||||
{tabLinks}
|
||||
</ul>
|
||||
<div className="tab-content" id="myTabContent">
|
||||
<Switch>
|
||||
{tabPanels}
|
||||
{<BaseRoute />}
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { ProfilePage };
|
||||
@@ -10,8 +10,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faUser, faEnvelope, faKey } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Link, useHistory } from "react-router-dom";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, panel } from "../../../../data/animation";
|
||||
|
||||
import { Analytics } from "../../../../common/Analytics";
|
||||
import queryString from "query-string";
|
||||
import { WebUrl } from "../../../../common/WebUrl";
|
||||
@@ -71,8 +70,7 @@ function SignupPage(props: Props) {
|
||||
usernameInvalidReason = t("account.SignUpPage.errors.usernameTooShort");
|
||||
} else if (newUsername.length > 15) {
|
||||
usernameValid = FieldTriState.FALSE;
|
||||
usernameInvalidReason = t("account.SignUpPage.errors.usernameTooLong")
|
||||
|
||||
usernameInvalidReason = t("account.SignUpPage.errors.usernameTooLong");
|
||||
} else {
|
||||
usernameValid = FieldTriState.TRUE;
|
||||
}
|
||||
@@ -100,7 +98,6 @@ function SignupPage(props: Props) {
|
||||
} else if (!newEmail.includes("@")) {
|
||||
emailValid = FieldTriState.FALSE;
|
||||
emailInvalidReason = t("account.SignUpPage.errors.emailInvalid");
|
||||
|
||||
} else {
|
||||
emailValid = FieldTriState.TRUE;
|
||||
}
|
||||
@@ -133,8 +130,9 @@ function SignupPage(props: Props) {
|
||||
|
||||
if (newPassword !== passwordConfirmation) {
|
||||
passwordConfirmationValid = FieldTriState.FALSE;
|
||||
passwordConfirmationInvalidReason = t("account.SignUpPage.errors.passwordsDoNotMatch");
|
||||
|
||||
passwordConfirmationInvalidReason = t(
|
||||
"account.SignUpPage.errors.passwordsDoNotMatch"
|
||||
);
|
||||
} else {
|
||||
passwordConfirmationValid = FieldTriState.TRUE;
|
||||
passwordConfirmationInvalidReason = "";
|
||||
@@ -163,7 +161,9 @@ function SignupPage(props: Props) {
|
||||
if (newPasswordConfirmation.length > 1) {
|
||||
if (newPasswordConfirmation !== password) {
|
||||
passwordConfirmationValid = FieldTriState.FALSE;
|
||||
passwordConfirmationInvalidReason = t("account.SignUpPage.errors.passwordsDoNotMatch");
|
||||
passwordConfirmationInvalidReason = t(
|
||||
"account.SignUpPage.errors.passwordsDoNotMatch"
|
||||
);
|
||||
} else {
|
||||
passwordConfirmationValid = FieldTriState.TRUE;
|
||||
passwordConfirmationInvalidReason = "";
|
||||
@@ -254,7 +254,7 @@ function SignupPage(props: Props) {
|
||||
};
|
||||
|
||||
const afterSignupRedirect = async () => {
|
||||
const maybeInternalPlanKey = parsedQueryString['sub'] as string | undefined;
|
||||
const maybeInternalPlanKey = parsedQueryString["sub"] as string | undefined;
|
||||
|
||||
if (maybeInternalPlanKey !== undefined) {
|
||||
return await BeginStripeCheckoutFlow(maybeInternalPlanKey);
|
||||
@@ -264,7 +264,7 @@ function SignupPage(props: Props) {
|
||||
history.push(redirectUrl);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
usePrefixedDocumentTitle("Create an account");
|
||||
|
||||
@@ -346,11 +346,8 @@ function SignupPage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<motion.div
|
||||
className="container-panel pb-5 pt-lg-5 my-lg-5 login-panel"
|
||||
variants={panel}
|
||||
>
|
||||
<div>
|
||||
<div className="container-panel pb-5 pt-lg-5 my-lg-5 login-panel">
|
||||
<div className="panel p-3 p-lg-4 load-hidden mt-5 mt-lg-0 px-md-4">
|
||||
<h1 className="panel-title fw-bold ">
|
||||
{t("account.SignUpPage.signUpTitle")}
|
||||
@@ -369,7 +366,9 @@ function SignupPage(props: Props) {
|
||||
<input
|
||||
className={usernameInputClass}
|
||||
type="text"
|
||||
placeholder={t("account.SignUpPage.inputs.usernamePlaceholder")}
|
||||
placeholder={t(
|
||||
"account.SignUpPage.inputs.usernamePlaceholder"
|
||||
)}
|
||||
value={username}
|
||||
onChange={handleUsernameChange}
|
||||
/>
|
||||
@@ -387,7 +386,9 @@ function SignupPage(props: Props) {
|
||||
<input
|
||||
className={emailInputClass}
|
||||
type="email"
|
||||
placeholder={t("account.SignUpPage.inputs.emailPlaceholder")}
|
||||
placeholder={t(
|
||||
"account.SignUpPage.inputs.emailPlaceholder"
|
||||
)}
|
||||
value={email}
|
||||
onChange={handleEmailChange}
|
||||
/>
|
||||
@@ -405,7 +406,9 @@ function SignupPage(props: Props) {
|
||||
<input
|
||||
className={passwordInputClass}
|
||||
type="password"
|
||||
placeholder={t("account.SignUpPage.inputs.passwordPlaceholder")}
|
||||
placeholder={t(
|
||||
"account.SignUpPage.inputs.passwordPlaceholder"
|
||||
)}
|
||||
value={password}
|
||||
onChange={handlePasswordChange}
|
||||
/>
|
||||
@@ -423,7 +426,9 @@ function SignupPage(props: Props) {
|
||||
<input
|
||||
className={passwordConfirmationInputClass}
|
||||
type="password"
|
||||
placeholder={t("account.SignUpPage.inputs.passwordConfirmPlaceholder")}
|
||||
placeholder={t(
|
||||
"account.SignUpPage.inputs.passwordConfirmPlaceholder"
|
||||
)}
|
||||
value={passwordConfirmation}
|
||||
onChange={handlePasswordConfirmationChange}
|
||||
/>
|
||||
@@ -451,8 +456,8 @@ function SignupPage(props: Props) {
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+11
-17
@@ -32,8 +32,7 @@ import {
|
||||
faXmark,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { useParams, Link } from "react-router-dom";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface Props {
|
||||
@@ -259,25 +258,20 @@ function TtsEditCategoriesPage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container py-5 pb-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Edit Categories
|
||||
</motion.h1>
|
||||
<motion.h4 className="mb-4" variants={item}>
|
||||
{" "}
|
||||
TTS Model: {ttsModel.title}{" "}
|
||||
</motion.h4>
|
||||
<motion.p variants={item}>
|
||||
<h1 className=" fw-bold">Edit Categories</h1>
|
||||
<h4 className="mb-4"> TTS Model: {ttsModel.title} </h4>
|
||||
<p>
|
||||
<BackLink link={modelLink} text="Back to model" />
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{errorFlash}
|
||||
|
||||
<motion.div className="container-panel py-5" variants={panel}>
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Current categories</h2>
|
||||
<div className="py-6">
|
||||
@@ -287,9 +281,9 @@ function TtsEditCategoriesPage(props: Props) {
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Add new category</h2>
|
||||
<div className="py-6">
|
||||
@@ -307,8 +301,8 @@ function TtsEditCategoriesPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+11
-16
@@ -4,8 +4,7 @@ import { WebUrl } from "../../../../../common/WebUrl";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { useParams, Link, useHistory } from "react-router-dom";
|
||||
import { BackLink } from "../../../_common/BackLink";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface TtsModelViewResponsePayload {
|
||||
@@ -215,19 +214,17 @@ function TtsModelDeletePage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container py-5 pb-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold mb-3" variants={item}>
|
||||
{h1Title}
|
||||
</motion.h1>
|
||||
<motion.p variants={item}>
|
||||
<h1 className=" fw-bold mb-3">{h1Title}</h1>
|
||||
<p>
|
||||
<BackLink link={modelLink} text="Back to model" />
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleDeleteFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleDeleteFormSubmit}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<table className="table">
|
||||
@@ -273,14 +270,12 @@ function TtsModelDeletePage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className={buttonCss}>{buttonTitle}</button>
|
||||
<motion.label className="pt-4" variants={item}>
|
||||
{formLabel}
|
||||
</motion.label>
|
||||
</motion.div>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
<label className="pt-4">{formLabel}</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,7 @@ import {
|
||||
TEXT_PIPELINE_NAMES,
|
||||
TEXT_PIPELINE_NAMES_FOR_MODERATORS,
|
||||
} from "@storyteller/components/src/constants/TextPipeline";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { faFunction } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
@@ -468,19 +467,17 @@ function TtsModelEditPage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container py-5 pb-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold mb-3" variants={item}>
|
||||
Edit Model
|
||||
</motion.h1>
|
||||
<motion.p variants={item}>
|
||||
<h1 className=" fw-bold mb-3">Edit Model</h1>
|
||||
<p>
|
||||
<BackLink link={modelLink} text="Back to model" />
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<fieldset disabled={isDisabled}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
@@ -627,12 +624,12 @@ function TtsModelEditPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className="btn btn-primary w-100">Update</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,10 @@ import { SessionTtsModelUploadResultList } from "../../../_common/SessionTtsMode
|
||||
import { SessionW2lInferenceResultList } from "../../../_common/SessionW2lInferenceResultsList";
|
||||
import { SessionW2lTemplateUploadResultList } from "../../../_common/SessionW2lTemplateUploadResultsList";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { FrontendInferenceJobType, InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import {
|
||||
FrontendInferenceJobType,
|
||||
InferenceJob,
|
||||
} from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { TtsInferenceJob } from "@storyteller/components/src/jobs/TtsInferenceJobs";
|
||||
import { TtsModelUploadJob } from "@storyteller/components/src/jobs/TtsModelUploadJobs";
|
||||
import { W2lInferenceJob } from "@storyteller/components/src/jobs/W2lInferenceJobs";
|
||||
@@ -44,8 +47,7 @@ import {
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { GenericNotice } from "./notices/GenericNotice";
|
||||
import { DiscordLink2 } from "@storyteller/components/src/elements/DiscordLink2";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, panel } from "../../../../../data/animation";
|
||||
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { TtsPageHero } from "./TtsPageHero";
|
||||
import { Analytics } from "../../../../../common/Analytics";
|
||||
@@ -93,7 +95,10 @@ interface Props {
|
||||
isShowingBootstrapLanguageNotice: boolean;
|
||||
clearBootstrapLanguageNotice: () => void;
|
||||
|
||||
enqueueInferenceJob: (jobToken: string, frontendInferenceJobType: FrontendInferenceJobType) => void;
|
||||
enqueueInferenceJob: (
|
||||
jobToken: string,
|
||||
frontendInferenceJobType: FrontendInferenceJobType
|
||||
) => void;
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
inferenceJobsByCategory: Map<FrontendInferenceJobType, Array<InferenceJob>>;
|
||||
|
||||
@@ -303,11 +308,13 @@ function TtsModelListPage(props: Props) {
|
||||
setMaybeTtsError(undefined);
|
||||
|
||||
if (response.inference_job_token_type === "generic") {
|
||||
props.enqueueInferenceJob(response.inference_job_token, FrontendInferenceJobType.TextToSpeech);
|
||||
props.enqueueInferenceJob(
|
||||
response.inference_job_token,
|
||||
FrontendInferenceJobType.TextToSpeech
|
||||
);
|
||||
} else {
|
||||
props.enqueueTtsJob(response.inference_job_token);
|
||||
}
|
||||
|
||||
} else if (GenerateTtsAudioIsError(response)) {
|
||||
setMaybeTtsError(response.error);
|
||||
}
|
||||
@@ -469,7 +476,8 @@ function TtsModelListPage(props: Props) {
|
||||
}
|
||||
|
||||
// NB: If the text is too long, don't allow submission
|
||||
let remainingCharactersButtonDisabled = props.textBuffer.trim().length >
|
||||
let remainingCharactersButtonDisabled =
|
||||
props.textBuffer.trim().length >
|
||||
props.sessionSubscriptionsWrapper.ttsMaximumLength();
|
||||
|
||||
let noTextInputButtonDisabled = props.textBuffer.trim() === "";
|
||||
@@ -499,7 +507,7 @@ function TtsModelListPage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
{bootstrapLanguageNotice}
|
||||
|
||||
{pleaseFollowNotice}
|
||||
@@ -515,7 +523,7 @@ function TtsModelListPage(props: Props) {
|
||||
sessionSubscriptionsWrapper={props.sessionSubscriptionsWrapper}
|
||||
/>
|
||||
|
||||
<motion.div className="container-panel pb-5 mb-4" variants={panel}>
|
||||
<div className="container-panel pb-5 mb-4">
|
||||
<div className="panel p-3 py-4 p-md-4">
|
||||
<i className="fas fa-volume-high"></i>
|
||||
|
||||
@@ -615,7 +623,11 @@ function TtsModelListPage(props: Props) {
|
||||
</h4>
|
||||
<div className="d-flex flex-column gap-3 session-tts-section">
|
||||
<SessionTtsInferenceResultList
|
||||
inferenceJobs={props.inferenceJobsByCategory.get(FrontendInferenceJobType.TextToSpeech)!}
|
||||
inferenceJobs={
|
||||
props.inferenceJobsByCategory.get(
|
||||
FrontendInferenceJobType.TextToSpeech
|
||||
)!
|
||||
}
|
||||
ttsInferenceJobs={props.ttsInferenceJobs}
|
||||
sessionSubscriptionsWrapper={
|
||||
props.sessionSubscriptionsWrapper
|
||||
@@ -633,7 +645,7 @@ function TtsModelListPage(props: Props) {
|
||||
{/* <div className="pt-5">
|
||||
<BackLink link="/" text="Back to main page" />
|
||||
</div> */}
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<SessionW2lInferenceResultList
|
||||
w2lInferenceJobs={props.w2lInferenceJobs}
|
||||
@@ -646,7 +658,7 @@ function TtsModelListPage(props: Props) {
|
||||
<SessionTtsModelUploadResultList
|
||||
modelUploadJobs={props.ttsModelUploadJobs}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,7 @@ import {
|
||||
faBarsStaggered,
|
||||
faLock,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import {
|
||||
TwitterShareButton,
|
||||
@@ -344,7 +343,7 @@ function TtsModelViewPage(props: Props) {
|
||||
if (!!ttsModel?.description_rendered_html) {
|
||||
modelDescription = (
|
||||
<>
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Model Description</h2>
|
||||
<div className="py-6">
|
||||
@@ -355,7 +354,7 @@ function TtsModelViewPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -416,7 +415,7 @@ function TtsModelViewPage(props: Props) {
|
||||
|
||||
modelCategoriesSection = (
|
||||
<>
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Model Categories</h2>
|
||||
<div className="py-6">
|
||||
@@ -424,7 +423,7 @@ function TtsModelViewPage(props: Props) {
|
||||
{editModelCategoriesButton}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -706,12 +705,10 @@ function TtsModelViewPage(props: Props) {
|
||||
//const createdAtRelative = createdAt !== undefined ? formatDistance(createdAt, new Date(), { addSuffix: true }) : undefined;
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container py-5">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className="fw-bold mb-3" variants={item}>
|
||||
{title}
|
||||
</motion.h1>
|
||||
<h1 className="fw-bold mb-3">{title}</h1>
|
||||
{/* Rate Voice Model Buttons */}
|
||||
<div className="d-flex gap-3">
|
||||
{ratingButtons}
|
||||
@@ -723,16 +720,16 @@ function TtsModelViewPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<motion.div className="mb-3 mt-4 pt-2" variants={item}>
|
||||
<div className="mb-3 mt-4 pt-2">
|
||||
<BackLink link="/" text="Back to all models" />
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>{modelDescription}</div>
|
||||
|
||||
<div>{modelCategoriesSection}</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">TTS Model Details</h2>
|
||||
<div className="py-6">
|
||||
@@ -781,9 +778,9 @@ function TtsModelViewPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Vocoder Details</h2>
|
||||
<div className="py-6">
|
||||
@@ -792,18 +789,18 @@ function TtsModelViewPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div variants={panel}>{moderatorRows}</motion.div>
|
||||
<div>{moderatorRows}</div>
|
||||
|
||||
<motion.div className="container pb-4" variants={panel}>
|
||||
<div className="container pb-4">
|
||||
<div className="d-flex flex-column flex-md-row gap-3">
|
||||
{editModelButton}
|
||||
{deleteModelButton}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel py-5" variants={panel}>
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Use Model</h2>
|
||||
<div className="py-6">
|
||||
@@ -832,17 +829,15 @@ function TtsModelViewPage(props: Props) {
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={item}>
|
||||
{socialSharing}
|
||||
</motion.div>
|
||||
<div className="container-panel pt-4 pb-5">{socialSharing}</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<BackLink link="/" text="Back to all models" />
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={item}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="fw-bold panel-title">Comments</h2>
|
||||
<div className="py-6">
|
||||
@@ -853,9 +848,9 @@ function TtsModelViewPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container" variants={item}>
|
||||
<div className="container">
|
||||
<h4 className="text-center text-lg-start mb-4">
|
||||
<FontAwesomeIcon icon={faBarsStaggered} className="me-3" />
|
||||
Session TTS Results
|
||||
@@ -865,8 +860,8 @@ function TtsModelViewPage(props: Props) {
|
||||
ttsInferenceJobs={props.ttsInferenceJobs}
|
||||
sessionSubscriptionsWrapper={props.sessionSubscriptionsWrapper}
|
||||
/>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+11
-16
@@ -4,8 +4,7 @@ import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapp
|
||||
import { useParams, Link, useHistory } from "react-router-dom";
|
||||
import { Gravatar } from "@storyteller/components/src/elements/Gravatar";
|
||||
import { WebUrl } from "../../../../../common/WebUrl";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface TtsInferenceResultResponsePayload {
|
||||
@@ -187,17 +186,15 @@ function TtsResultDeletePage(props: Props) {
|
||||
: "Delete TTS Result (hides from everyone but mods)";
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-lg-5 px-xl-3">
|
||||
<motion.h1 className=" fw-bold mb-3" variants={item}>
|
||||
{h1Title}
|
||||
</motion.h1>
|
||||
<motion.div variants={item}>
|
||||
<h1 className=" fw-bold mb-3">{h1Title}</h1>
|
||||
<div>
|
||||
<Link to={resultLink}>< Back to result</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleDeleteFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleDeleteFormSubmit}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<table className="table tts-result-table">
|
||||
@@ -241,14 +238,12 @@ function TtsResultDeletePage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className=" btn btn-primary w-100">{buttonTitle}</button>
|
||||
<motion.p className="mt-4" variants={item}>
|
||||
{formLabel}
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
<p className="mt-4">{formLabel}</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@ import { useParams, Link, useHistory } from "react-router-dom";
|
||||
import { WebUrl } from "../../../../../common/WebUrl";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
const DEFAULT_VISIBILITY = "public";
|
||||
@@ -152,17 +151,15 @@ function TtsResultEditPage(props: Props) {
|
||||
);
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-lg-5 px-xl-3">
|
||||
<motion.h1 className=" fw-bold mb-3" variants={item}>
|
||||
Edit Result Visibility
|
||||
</motion.h1>
|
||||
<motion.div variants={item}>
|
||||
<h1 className=" fw-bold mb-3">Edit Result Visibility</h1>
|
||||
<div>
|
||||
<Link to={resultLink}>< Back to result</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<fieldset disabled={isDisabled}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
@@ -186,12 +183,12 @@ function TtsResultEditPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<motion.div className="container" variants={item}>
|
||||
<div className="container">
|
||||
<button className="btn btn-primary w-100 mb-5">Update</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,7 @@ import {
|
||||
faEyeSlash,
|
||||
faUser,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { Analytics } from "../../../../../common/Analytics";
|
||||
import {
|
||||
TwitterShareButton,
|
||||
@@ -431,12 +430,10 @@ function TtsResultViewPage(props: Props) {
|
||||
);
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container py-5">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold mb-2" variants={item}>
|
||||
{headingTitle}
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold mb-2">{headingTitle}</h1>
|
||||
{/* Rate Result Buttons */}
|
||||
{/* Commented out because not ready yet. */}
|
||||
{/*<div className="d-flex gap-3">
|
||||
@@ -478,16 +475,16 @@ function TtsResultViewPage(props: Props) {
|
||||
</div>
|
||||
</div>*/}
|
||||
|
||||
<motion.p className="mb-3 result-text pt-2">
|
||||
<p className="mb-3 result-text pt-2">
|
||||
<TextExpander
|
||||
text={ttsInferenceResult.raw_inference_text}
|
||||
cutLength={240}
|
||||
/>
|
||||
</motion.p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
{subtitle}
|
||||
<div className="py-6">
|
||||
@@ -495,7 +492,7 @@ function TtsResultViewPage(props: Props) {
|
||||
{downloadButton}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Without wavesurfer,
|
||||
<audio
|
||||
@@ -505,18 +502,16 @@ function TtsResultViewPage(props: Props) {
|
||||
<code>audio</code> element.
|
||||
</audio>*/}
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={item}>
|
||||
{socialSharing}
|
||||
</motion.div>
|
||||
<div className="container-panel pt-3 pb-5">{socialSharing}</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Spectrogram</h2>
|
||||
<SpectrogramImage spectrogramJsonLink={spectrogramLink} />
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Result Details</h2>
|
||||
<div className="py-6">
|
||||
@@ -552,9 +547,9 @@ function TtsResultViewPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Model Used</h2>
|
||||
<div className="py-6">
|
||||
@@ -584,25 +579,25 @@ function TtsResultViewPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div variants={panel}>{moderatorRows}</motion.div>
|
||||
<div>{moderatorRows}</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<div className="d-flex flex-column flex-md-row gap-3 mb-4">
|
||||
{editButton}
|
||||
{deleteButton}
|
||||
</div>
|
||||
<motion.p className="text-center text-lg-start" variants={item}>
|
||||
<p className="text-center text-lg-start">
|
||||
<ReportDiscordLink />
|
||||
</motion.p>
|
||||
</p>
|
||||
|
||||
<motion.div className="pt-5" variants={item}>
|
||||
<div className="pt-5">
|
||||
<BackLink link="/" text="Back to all models" />
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={item}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="fw-bold panel-title">Comments</h2>
|
||||
<div className="py-6">
|
||||
@@ -613,8 +608,8 @@ function TtsResultViewPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ import { v4 as uuidv4 } from "uuid";
|
||||
import { BackLink } from "../../_common/BackLink";
|
||||
import { Link } from "react-router-dom";
|
||||
import { WebUrl } from "../../../../common/WebUrl";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface Props {
|
||||
@@ -120,23 +119,21 @@ function UploadTtsModelPage(props: Props) {
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Upload Voice (TTS Model)
|
||||
</motion.h1>
|
||||
<motion.h4 variants={item}>This works just like YouTube!</motion.h4>
|
||||
<motion.div className="my-3" variants={item}>
|
||||
<h1 className=" fw-bold">Upload Voice (TTS Model)</h1>
|
||||
<h4>This works just like YouTube!</h4>
|
||||
<div className="my-3">
|
||||
<BackLink
|
||||
link={WebUrl.contributePage()}
|
||||
text="Back to contribute page"
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container px-md-4 px-lg-5 px-xl-3" variants={item}>
|
||||
<div className="container px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="alert alert-primary">
|
||||
<strong>Content Creator Rewards!</strong>
|
||||
{/*<p>You can help FakeYou grow by uploading Tacotron2 models.
|
||||
@@ -149,12 +146,9 @@ function UploadTtsModelPage(props: Props) {
|
||||
featured roles in Discord, queue priority, and more!
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
className="container pt-3 d-flex flex-column gap-3 px-md-4 px-lg-5 px-xl-3"
|
||||
variants={item}
|
||||
>
|
||||
<div className="container pt-3 d-flex flex-column gap-3 px-md-4 px-lg-5 px-xl-3">
|
||||
<p>
|
||||
If you're new to voice cloning, join our{" "}
|
||||
<span>
|
||||
@@ -180,18 +174,15 @@ function UploadTtsModelPage(props: Props) {
|
||||
Please do not upload voices that you didn't train yourself or voices of individuals
|
||||
who wish to not be voice cloned. We'll post a list of banned voices soon.
|
||||
</p>*/}
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<div className="d-flex flex-column gap-4">
|
||||
|
||||
{/* Model Type */}
|
||||
<div>
|
||||
<label className="sub-title">
|
||||
TTS Model Type
|
||||
</label>
|
||||
<label className="sub-title">TTS Model Type</label>
|
||||
<div className="control select">
|
||||
<select
|
||||
className="form-select"
|
||||
@@ -199,12 +190,8 @@ function UploadTtsModelPage(props: Props) {
|
||||
onChange={handleModelTypeChange}
|
||||
value={modelType}
|
||||
>
|
||||
<option value="tacotron2">
|
||||
Tacotron 2
|
||||
</option>
|
||||
<option value="vits">
|
||||
VITS
|
||||
</option>
|
||||
<option value="tacotron2">Tacotron 2</option>
|
||||
<option value="vits">VITS</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -242,20 +229,19 @@ function UploadTtsModelPage(props: Props) {
|
||||
</div>
|
||||
<p className="help">{downloadUrlInvalidReason}</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className="btn btn-primary w-100">Upload</button>
|
||||
</motion.div>
|
||||
</motion.form>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<SessionTtsModelUploadResultList
|
||||
modelUploadJobs={props.ttsModelUploadJobs}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,7 @@ import { v4 as uuidv4 } from "uuid";
|
||||
import { BackLink } from "../../_common/BackLink";
|
||||
import { Link } from "react-router-dom";
|
||||
import { WebUrl } from "../../../../common/WebUrl";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../data/animation";
|
||||
|
||||
import { VocoderUploadJob } from "@storyteller/components/src/jobs/VocoderUploadJobs";
|
||||
import { SessionVocoderUploadResultList } from "../../_common/SessionVocoderUploadResultsList";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
@@ -88,26 +87,21 @@ function UploadVocoderPage(props: Props) {
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Upload Vocoder Model
|
||||
</motion.h1>
|
||||
<motion.h4 variants={item}>Make your voice sound better!</motion.h4>
|
||||
<motion.div className="my-3" variants={item}>
|
||||
<h1 className=" fw-bold">Upload Vocoder Model</h1>
|
||||
<h4>Make your voice sound better!</h4>
|
||||
<div className="my-3">
|
||||
<BackLink
|
||||
link={WebUrl.contributePage()}
|
||||
text="Back to contribute page"
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
className="container pt-3 d-flex flex-column gap-3 px-md-4 px-lg-5 px-xl-3"
|
||||
variants={item}
|
||||
>
|
||||
<div className="container pt-3 d-flex flex-column gap-3 px-md-4 px-lg-5 px-xl-3">
|
||||
<p>
|
||||
If you're new to voice cloning, join our{" "}
|
||||
<span>
|
||||
@@ -127,9 +121,9 @@ function UploadVocoderPage(props: Props) {
|
||||
Please do not upload voices that you didn't train yourself or voices of individuals
|
||||
who wish to not be voice cloned. We'll post a list of banned voices soon.
|
||||
</p>*/}
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<div className="d-flex flex-column gap-4">
|
||||
@@ -172,15 +166,15 @@ function UploadVocoderPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className="btn btn-primary w-100">Upload</button>
|
||||
</motion.div>
|
||||
</motion.form>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<SessionVocoderUploadResultList
|
||||
vocoderUploadJobs={props.vocoderUploadJobs}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,7 @@ import { v4 as uuidv4 } from "uuid";
|
||||
import { BackLink } from "../../_common/BackLink";
|
||||
import { Link } from "react-router-dom";
|
||||
import { WebUrl } from "../../../../common/WebUrl";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../data/animation";
|
||||
|
||||
import { VoiceConversionModelUploadJob } from "@storyteller/components/src/jobs/VoiceConversionModelUploadJob";
|
||||
import { SessionVoiceConversionModelUploadResultList } from "../../_common/SessionVoiceConversionModelUploadResultsList";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
@@ -93,28 +92,21 @@ function UploadVoiceConversionModel(props: Props) {
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-3 px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Upload Voice to Voice Model
|
||||
</motion.h1>
|
||||
<motion.h4 variants={item}>
|
||||
Transform your voice into another!
|
||||
</motion.h4>
|
||||
<motion.div className="my-3" variants={item}>
|
||||
<h1 className=" fw-bold">Upload Voice to Voice Model</h1>
|
||||
<h4>Transform your voice into another!</h4>
|
||||
<div className="my-3">
|
||||
<BackLink
|
||||
link={WebUrl.contributePage()}
|
||||
text="Back to contribute page"
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
className="container pt-3 d-flex flex-column gap-3 px-md-4 px-lg-5 px-xl-3"
|
||||
variants={item}
|
||||
>
|
||||
<div className="container pt-3 d-flex flex-column gap-3 px-md-4 px-lg-5 px-xl-3">
|
||||
<p>
|
||||
If you're new to voice cloning, join our{" "}
|
||||
<span>
|
||||
@@ -129,18 +121,15 @@ function UploadVoiceConversionModel(props: Props) {
|
||||
able to use it from the main page. Others will be able to use it too,
|
||||
and you'll get credited.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<div className="d-flex flex-column gap-4">
|
||||
|
||||
{/* Model Type */}
|
||||
<div>
|
||||
<label className="sub-title">
|
||||
Voice-to-Voice Model Type
|
||||
</label>
|
||||
<label className="sub-title">Voice-to-Voice Model Type</label>
|
||||
<div className="control select">
|
||||
<select
|
||||
className="form-select"
|
||||
@@ -148,12 +137,8 @@ function UploadVoiceConversionModel(props: Props) {
|
||||
onChange={handleModelTypeChange}
|
||||
value={modelType}
|
||||
>
|
||||
<option value="so_vits_svc">
|
||||
so-vits-svc
|
||||
</option>
|
||||
<option value="rvc_v2">
|
||||
rvc (v2)
|
||||
</option>
|
||||
<option value="so_vits_svc">so-vits-svc</option>
|
||||
<option value="rvc_v2">rvc (v2)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -195,15 +180,15 @@ function UploadVoiceConversionModel(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className="btn btn-primary w-100">Upload</button>
|
||||
</motion.div>
|
||||
</motion.form>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<SessionVoiceConversionModelUploadResultList
|
||||
voiceConversionModelUploadJobs={props.voiceConversionModelUploadJobs}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,7 @@ import { v4 as uuidv4 } from "uuid";
|
||||
import { SessionW2lTemplateUploadResultList } from "../../_common/SessionW2lTemplateUploadResultsList";
|
||||
import { BackLink } from "../../_common/BackLink";
|
||||
import { WebUrl } from "../../../../common/WebUrl";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface W2lTemplateUploadJobResponsePayload {
|
||||
@@ -93,30 +92,28 @@ function UploadW2lPhotoPage(props: Props) {
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-3 px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Upload Photo (w2l template)
|
||||
</motion.h1>
|
||||
<motion.div className="my-3" variants={item}>
|
||||
<h1 className=" fw-bold">Upload Photo (w2l template)</h1>
|
||||
<div className="my-3">
|
||||
<BackLink
|
||||
link={WebUrl.contributePage()}
|
||||
text="Back to contribute page"
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container px-md-4 px-lg-5 px-xl-3" variants={item}>
|
||||
<div className="container px-md-4 px-lg-5 px-xl-3">
|
||||
<p>
|
||||
The photos you upload can be used for lipsyncing with audio using the
|
||||
Wav2Lip model. In the future, you'll be able to use these for
|
||||
first-order-model and much more!
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<div className="d-flex flex-column gap-4">
|
||||
@@ -158,21 +155,21 @@ function UploadW2lPhotoPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className="btn btn-primary w-100">Upload</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/*<div className="field is-grouped">
|
||||
<div className="control">
|
||||
<button className="button is-link is-large is-fullwidth">Upload</button>
|
||||
</div>
|
||||
</div>*/}
|
||||
</motion.form>
|
||||
</form>
|
||||
|
||||
<SessionW2lTemplateUploadResultList
|
||||
w2lTemplateUploadJobs={props.w2lTemplateUploadJobs}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,7 @@ import { useHistory } from "react-router-dom";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { BackLink } from "../../_common/BackLink";
|
||||
import { WebUrl } from "../../../../common/WebUrl";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface W2lTemplateUploadJobResponsePayload {
|
||||
@@ -93,29 +92,27 @@ function UploadW2lVideoPage(props: Props) {
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-3 px-md-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Upload Video (w2l template)
|
||||
</motion.h1>
|
||||
<motion.div className="my-3" variants={item}>
|
||||
<h1 className=" fw-bold">Upload Video (w2l template)</h1>
|
||||
<div className="my-3">
|
||||
<BackLink
|
||||
link={WebUrl.contributePage()}
|
||||
text="Back to contribute page"
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container px-md-4 px-lg-5 px-xl-3" variants={item}>
|
||||
<div className="container px-md-4 px-lg-5 px-xl-3">
|
||||
<p>
|
||||
The videos you upload can be used for lipsyncing with audio using the
|
||||
Wav2Lip model.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<div className="d-flex flex-column gap-4">
|
||||
@@ -157,21 +154,21 @@ function UploadW2lVideoPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className="btn btn-primary w-100">Upload</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/*<div className="field is-grouped">
|
||||
<div className="control">
|
||||
<button className="button is-link is-large is-fullwidth">Upload</button>
|
||||
</div>
|
||||
</div>*/}
|
||||
</motion.form>
|
||||
</form>
|
||||
|
||||
<SessionW2lTemplateUploadResultList
|
||||
w2lTemplateUploadJobs={props.w2lTemplateUploadJobs}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { container, panel } from "../../../../../data/animation";
|
||||
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { VcPageHero } from "./components/VcPageHero";
|
||||
import {
|
||||
@@ -74,8 +74,9 @@ function VcModelListPage(props: Props) {
|
||||
|
||||
const [autoConvertF0, setAutoConvertF0] = useState(false);
|
||||
|
||||
const [maybeF0MethodOverride, setMaybeF0MethodOverride] =
|
||||
useState<EnqueueVoiceConversionFrequencyMethod | undefined>(undefined);
|
||||
const [maybeF0MethodOverride, setMaybeF0MethodOverride] = useState<
|
||||
EnqueueVoiceConversionFrequencyMethod | undefined
|
||||
>(undefined);
|
||||
|
||||
const [semitones, setSemitones] = useState(0);
|
||||
|
||||
@@ -199,9 +200,7 @@ function VcModelListPage(props: Props) {
|
||||
changeConvertIdempotencyToken();
|
||||
};
|
||||
|
||||
const handleAutoF0Change = (
|
||||
ev: React.FormEvent<HTMLInputElement>
|
||||
) => {
|
||||
const handleAutoF0Change = (ev: React.FormEvent<HTMLInputElement>) => {
|
||||
const value = (ev.target as HTMLInputElement).checked;
|
||||
setAutoConvertF0(value);
|
||||
changeConvertIdempotencyToken();
|
||||
@@ -217,13 +216,13 @@ function VcModelListPage(props: Props) {
|
||||
props.maybeSelectedVoiceConversionModel !== undefined;
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<VcPageHero
|
||||
sessionWrapper={props.sessionWrapper}
|
||||
sessionSubscriptionsWrapper={props.sessionSubscriptionsWrapper}
|
||||
/>
|
||||
|
||||
{/* <motion.div variants={panel} className="container">
|
||||
{/* <div className="container">
|
||||
<div className="alert alert-info">
|
||||
<FontAwesomeIcon icon={faMoneyBill} className="me-2" />
|
||||
<span className="fw-medium">
|
||||
@@ -234,9 +233,9 @@ function VcModelListPage(props: Props) {
|
||||
See details <FontAwesomeIcon icon={faArrowRight} className="ms-1" />
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div> */}
|
||||
</div> */}
|
||||
|
||||
<motion.div className="container-panel pb-5 mb-4" variants={panel}>
|
||||
<div className="container-panel pb-5 mb-4">
|
||||
<div className="panel p-3 py-4 p-md-4">
|
||||
<div className="d-flex gap-4">
|
||||
<form
|
||||
@@ -339,14 +338,17 @@ function VcModelListPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
id="autoF0Checkbox"
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
<input
|
||||
id="autoF0Checkbox"
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
checked={autoConvertF0}
|
||||
onChange={handleAutoF0Change}
|
||||
/>
|
||||
<label className="form-check-label" htmlFor="autoF0Checkbox">
|
||||
/>
|
||||
<label
|
||||
className="form-check-label"
|
||||
htmlFor="autoF0Checkbox"
|
||||
>
|
||||
Auto F0 (off for singing, on for speech)
|
||||
</label>
|
||||
</div>
|
||||
@@ -440,14 +442,17 @@ function VcModelListPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
<div className="form-check">
|
||||
<input
|
||||
id="autoF0CheckboxMic"
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
<input
|
||||
id="autoF0CheckboxMic"
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
checked={autoConvertF0}
|
||||
onChange={handleAutoF0Change}
|
||||
/>
|
||||
<label className="form-check-label" htmlFor="autoF0CheckboxMic">
|
||||
/>
|
||||
<label
|
||||
className="form-check-label"
|
||||
htmlFor="autoF0CheckboxMic"
|
||||
>
|
||||
Auto F0 (off for singing, on for speech)
|
||||
</label>
|
||||
</div>
|
||||
@@ -508,8 +513,8 @@ function VcModelListPage(props: Props) {
|
||||
{/* <div className="pt-5">
|
||||
<BackLink link="/" text="Back to main page" />
|
||||
</div> */}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+11
-16
@@ -8,8 +8,7 @@ import {
|
||||
GetW2lResultIsOk,
|
||||
W2lResult,
|
||||
} from "@storyteller/components/src/api/w2l/GetW2lResult";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface Props {
|
||||
@@ -106,17 +105,15 @@ function W2lResultDeletePage(props: Props) {
|
||||
const durationSeconds = (w2lInferenceResult?.duration_millis || 0) / 1000;
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-md-4 px-lg-5 px-xl-3">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
{h1Title}
|
||||
</motion.h1>
|
||||
<motion.div className="pt-3" variants={item}>
|
||||
<h1 className=" fw-bold">{h1Title}</h1>
|
||||
<div className="pt-3">
|
||||
<Link to={templateResultLink}>< Back to result</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleDeleteFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleDeleteFormSubmit}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<table className="table">
|
||||
@@ -148,14 +145,12 @@ function W2lResultDeletePage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className={buttonCss}>{buttonTitle}</button>
|
||||
<motion.p className="pt-4" variants={item}>
|
||||
{formLabel}
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
<p className="pt-4">{formLabel}</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@ import { useParams, Link, useHistory } from "react-router-dom";
|
||||
import { WebUrl } from "../../../../../common/WebUrl";
|
||||
import { VisibleIconFc } from "../../../_icons/VisibleIcon";
|
||||
import { HiddenIconFc } from "../../../_icons/HiddenIcon";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
const DEFAULT_VISIBILITY = "public";
|
||||
@@ -148,17 +147,15 @@ function W2lResultEditPage(props: Props) {
|
||||
visibility === "public" ? <VisibleIconFc /> : <HiddenIconFc />;
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pb-4 pt-5 px-md-4 px-lg-5 px-xl-3">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Edit Result Visibility
|
||||
</motion.h1>
|
||||
<motion.div className="pt-3" variants={item}>
|
||||
<h1 className=" fw-bold">Edit Result Visibility</h1>
|
||||
<div className="pt-3">
|
||||
<Link to={resultLink}>< Back to result </Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<fieldset disabled={isDisabled}>
|
||||
@@ -183,11 +180,11 @@ function W2lResultEditPage(props: Props) {
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className="btn btn-primary w-100">Update</button>
|
||||
</motion.div>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,7 @@ import {
|
||||
import { MetaTags } from "../../../../../common/MetaTags";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faDownload, faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
|
||||
import { CommentComponent } from "../../../_common/comments/CommentComponent";
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
@@ -264,24 +263,19 @@ function W2lResultViewPage(props: Props) {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container py-5 px-md-4 px-lg-5 px-xl-3">
|
||||
<motion.h1
|
||||
className=" fw-bold text-center text-lg-start"
|
||||
variants={item}
|
||||
>
|
||||
Lipsync Result
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold text-center text-lg-start">Lipsync Result</h1>
|
||||
</div>
|
||||
|
||||
<motion.div className="container" variants={item}>
|
||||
<div className="container">
|
||||
<video width="100%" height="auto" controls={true} className="rounded">
|
||||
<source src={videoLink} />
|
||||
Your device doesn't support video.
|
||||
</video>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pt-4 pb-5" variants={item}>
|
||||
<div className="container pt-4 pb-5">
|
||||
<a
|
||||
className="btn btn-primary w-100"
|
||||
href={videoLink}
|
||||
@@ -291,9 +285,9 @@ function W2lResultViewPage(props: Props) {
|
||||
<FontAwesomeIcon icon={faDownload} className="me-2" />
|
||||
Download File
|
||||
</a>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-5 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-5 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Result Details</h2>
|
||||
<div className="py-6">
|
||||
@@ -315,9 +309,9 @@ function W2lResultViewPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold"> Template Details </h2>
|
||||
<div className="py-6">
|
||||
@@ -344,21 +338,21 @@ function W2lResultViewPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div variants={panel}>{moderatorRows}</motion.div>
|
||||
<div>{moderatorRows}</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<div className="d-flex gap-3 flex-column flex-md-row">
|
||||
{editButton}
|
||||
{deleteButton}
|
||||
</div>
|
||||
<motion.div className="mt-4" variants={item}>
|
||||
<div className="mt-4">
|
||||
<ReportDiscordLink />
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={item}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="fw-bold panel-title">Comments</h2>
|
||||
<div className="py-6">
|
||||
@@ -369,8 +363,8 @@ function W2lResultViewPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+12
-15
@@ -10,8 +10,7 @@ import {
|
||||
} from "@storyteller/components/src/api/w2l/GetW2lTemplate";
|
||||
import { GetW2lTemplateUseCount } from "@storyteller/components/src/api/w2l/GetW2lTemplateUseCount";
|
||||
import { BackLink } from "../../../_common/BackLink";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
const DEFAULT_APPROVED_STATE = true;
|
||||
@@ -121,19 +120,17 @@ function W2lTemplateApprovePage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
{h1Title}
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold">{h1Title}</h1>
|
||||
</div>
|
||||
<motion.div className="pt-3" variants={item}>
|
||||
<div className="pt-3">
|
||||
<BackLink link={templateLink} text="Back to template" />
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<table className="table">
|
||||
<thead>
|
||||
@@ -166,9 +163,9 @@ function W2lTemplateApprovePage(props: Props) {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleApproveFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleApproveFormSubmit}>
|
||||
<div className="container-panel pt-1 pb-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<label className="sub-title">
|
||||
@@ -190,11 +187,11 @@ function W2lTemplateApprovePage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className="btn btn-primary w-100">Moderate</button>
|
||||
</motion.div>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+12
-15
@@ -10,8 +10,7 @@ import {
|
||||
} from "@storyteller/components/src/api/w2l/GetW2lTemplate";
|
||||
import { GetW2lTemplateUseCount } from "@storyteller/components/src/api/w2l/GetW2lTemplateUseCount";
|
||||
import { BackLink } from "../../../_common/BackLink";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
interface Props {
|
||||
@@ -172,19 +171,17 @@ function W2lTemplateDeletePage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
{h1Title}
|
||||
</motion.h1>
|
||||
<h1 className=" fw-bold">{h1Title}</h1>
|
||||
</div>
|
||||
<motion.div className="pt-3" variants={item}>
|
||||
<div className="pt-3">
|
||||
<BackLink link={templateLink} text="Back to template" />
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleDeleteFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleDeleteFormSubmit}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<table className="table">
|
||||
@@ -222,14 +219,14 @@ function W2lTemplateDeletePage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container" variants={item}>
|
||||
<div className="container">
|
||||
<button className={buttonCss}>{buttonTitle}</button>
|
||||
</motion.div>
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
</div>
|
||||
<div className="container pb-5">
|
||||
<p className="pt-4">{formLabel}</p>
|
||||
</motion.div>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+7
-8
@@ -11,8 +11,7 @@ import {
|
||||
W2lTemplate,
|
||||
} from "@storyteller/components/src/api/w2l/GetW2lTemplate";
|
||||
import { BackLink } from "../../../_common/BackLink";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
|
||||
|
||||
const DEFAULT_VISIBILITY = "public";
|
||||
@@ -121,7 +120,7 @@ function W2lTemplateEditPage(props: Props) {
|
||||
visibility === "public" ? <VisibleIconFc /> : <HiddenIconFc />;
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container pt-5 pb-4 px-lg-5 px-xl-3">
|
||||
<div className="d-flex flex-column">
|
||||
<h1 className=" fw-bold">Edit Template</h1>
|
||||
@@ -131,7 +130,7 @@ function W2lTemplateEditPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<fieldset disabled={isDisabled}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
@@ -187,12 +186,12 @@ function W2lTemplateEditPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<button className="btn btn-primary w-100">Update Template</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+12
-18
@@ -3,19 +3,13 @@ import { ApiConfig } from "@storyteller/components";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { Link } from "react-router-dom";
|
||||
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
|
||||
import {
|
||||
distance,
|
||||
duration,
|
||||
container,
|
||||
item,
|
||||
panel,
|
||||
} from "../../../../../data/animation";
|
||||
import { distance, duration } from "../../../../../data/animation";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faChevronLeft,
|
||||
faChevronRight,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
|
||||
import { PageHeader } from "../../../_common/PageHeader";
|
||||
import { faVideo } from "@fortawesome/pro-solid-svg-icons";
|
||||
@@ -206,7 +200,7 @@ function W2lTemplateListPage(props: Props) {
|
||||
const titleIcon = <FontAwesomeIcon icon={faVideo} className="me-3 me-lg-4" />;
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<PageHeader
|
||||
title={title}
|
||||
subText={subText}
|
||||
@@ -214,7 +208,7 @@ function W2lTemplateListPage(props: Props) {
|
||||
titleIcon={titleIcon}
|
||||
/>
|
||||
|
||||
<motion.div className="container" variants={item}>
|
||||
<div className="container">
|
||||
<div className="d-flex w-100 gap-3 mb-4">
|
||||
<button
|
||||
className="btn btn-secondary w-100 d-flex align-items-center justify-content-center"
|
||||
@@ -234,9 +228,9 @@ function W2lTemplateListPage(props: Props) {
|
||||
<FontAwesomeIcon icon={faChevronRight} className="ms-2" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel" variants={panel}>
|
||||
<div className="container-panel">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<Fade bottom cascade duration={duration} distance={distance}>
|
||||
<div className="row gy-3 gx-3 gx-md-4 gy-md-4 w2l-ani">
|
||||
@@ -244,9 +238,9 @@ function W2lTemplateListPage(props: Props) {
|
||||
</div>
|
||||
</Fade>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container" variants={item}>
|
||||
<div className="container">
|
||||
<div className="d-flex w-100 gap-3 my-4">
|
||||
<button
|
||||
className="btn btn-secondary w-100 d-flex align-items-center justify-content-center"
|
||||
@@ -266,15 +260,15 @@ function W2lTemplateListPage(props: Props) {
|
||||
<FontAwesomeIcon icon={faChevronRight} className="ms-2" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container pb-5" variants={item}>
|
||||
<div className="container pb-5">
|
||||
<p>
|
||||
This feature is based on Wav2Lip by by Prajwal, K R and Mukhopadhyay,
|
||||
Rudrabha and Namboodiri, Vinay P. and Jawahar, C.V.
|
||||
</p>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+25
-28
@@ -23,8 +23,7 @@ import { GetW2lTemplateUseCount } from "@storyteller/components/src/api/w2l/GetW
|
||||
import { BackLink } from "../../../_common/BackLink";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
import { container, item, panel } from "../../../../../data/animation";
|
||||
|
||||
import { ThirdPartyLinks } from "@storyteller/components/src/constants/ThirdPartyLinks";
|
||||
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
|
||||
import { CommentComponent } from "../../../_common/comments/CommentComponent";
|
||||
@@ -228,7 +227,7 @@ function W2lTemplateViewPage(props: Props) {
|
||||
) {
|
||||
moderatorRows = (
|
||||
<>
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={item}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Moderator Details</h2>
|
||||
<div className="py-6">
|
||||
@@ -274,7 +273,7 @@ function W2lTemplateViewPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -384,7 +383,7 @@ function W2lTemplateViewPage(props: Props) {
|
||||
if (!!w2lTemplate?.description_rendered_html) {
|
||||
templateDescription = (
|
||||
<>
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Model Description</h2>
|
||||
<div className="py-6">
|
||||
@@ -396,7 +395,7 @@ function W2lTemplateViewPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -413,18 +412,16 @@ function W2lTemplateViewPage(props: Props) {
|
||||
);
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div>
|
||||
<div className="container py-5 px-md-4 px-lg-5 px-xl-3">
|
||||
<motion.h1 className=" fw-bold" variants={item}>
|
||||
Video Lip Sync Template
|
||||
</motion.h1>
|
||||
<motion.h4 variants={item}>Template: {w2lTemplate?.title}</motion.h4>
|
||||
<motion.div className="pt-3" variants={item}>
|
||||
<h1 className=" fw-bold">Video Lip Sync Template</h1>
|
||||
<h4>Template: {w2lTemplate?.title}</h4>
|
||||
<div className="pt-3">
|
||||
<BackLink link={WebUrl.w2lListPage()} text="Back to all templates" />
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<motion.form onSubmit={handleInferenceFormSubmit} variants={panel}>
|
||||
<form onSubmit={handleInferenceFormSubmit}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Upload Audio</h2>
|
||||
@@ -460,11 +457,11 @@ function W2lTemplateViewPage(props: Props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.form>
|
||||
</form>
|
||||
|
||||
<motion.div variants={panel}>{templateDescription}</motion.div>
|
||||
<div>{templateDescription}</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Template Details</h2>
|
||||
<div className="py-6">
|
||||
@@ -494,9 +491,9 @@ function W2lTemplateViewPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-3 pb-5" variants={panel}>
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">Media Details</h2>
|
||||
<div className="py-6">
|
||||
@@ -528,25 +525,25 @@ function W2lTemplateViewPage(props: Props) {
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div variants={panel}>{moderatorRows}</motion.div>
|
||||
<div>{moderatorRows}</div>
|
||||
|
||||
<motion.div className="container" variants={item}>
|
||||
<div className="container">
|
||||
<div className="d-flex flex-column flex-lg-row gap-3">
|
||||
{editButton}
|
||||
{approveButton}
|
||||
{deleteButton}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div variants={item}>
|
||||
<div>
|
||||
<div className="container pt-4 pb-5">
|
||||
<ReportDiscordLink />
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div className="container-panel pt-4 pb-5" variants={item}>
|
||||
<div className="container-panel pt-4 pb-5">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="fw-bold panel-title">Comments</h2>
|
||||
<div className="py-6">
|
||||
@@ -557,12 +554,12 @@ function W2lTemplateViewPage(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<SessionW2lInferenceResultList
|
||||
w2lInferenceJobs={props.w2lInferenceJobs}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user