mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 09:28:11 +00:00
update
This commit is contained in:
1 parent
5d6ab1fef0
commit
df569a9180
6 files changed
+462
-281
No files matched your search
@@ -335,6 +335,14 @@ styles with important tags:
|
||||
.content p:not(:last-child) {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
@for $i from 1 through 12 {
|
||||
&:nth-of-type(#{$i}) {
|
||||
animation-delay: $i * 20ms !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { MigrationTopNavSession } from "../../migration/MigrationTopNav_Session"
|
||||
import { FrontendUrlConfig } from "../../common/FrontendUrlConfig";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faGavel,
|
||||
faGavel,
|
||||
faGrinBeamSweat,
|
||||
faMicrophone,
|
||||
faVolumeUp,
|
||||
@@ -35,7 +35,8 @@ function NewTopNavFc(props: Props) {
|
||||
myDataLink = `/profile/${username}`;
|
||||
}
|
||||
|
||||
const [mobileHamburgerIsActive, setMobileHamburgerIsActive] = useState<boolean>(false);
|
||||
const [mobileHamburgerIsActive, setMobileHamburgerIsActive] =
|
||||
useState<boolean>(false);
|
||||
|
||||
const toggleHamburger = () => {
|
||||
setMobileHamburgerIsActive(!mobileHamburgerIsActive);
|
||||
@@ -47,18 +48,29 @@ function NewTopNavFc(props: Props) {
|
||||
setMobileHamburgerIsActive(false);
|
||||
};
|
||||
|
||||
const navbarClasses = mobileHamburgerIsActive ? "navbar-menu is-active" : "navbar-menu";
|
||||
const navbarBurgerClasses = mobileHamburgerIsActive ? "navbar-burger is-active" : "navbar-burger";
|
||||
const navbarClasses = mobileHamburgerIsActive
|
||||
? "navbar-menu is-active"
|
||||
: "navbar-menu";
|
||||
const navbarBurgerClasses = mobileHamburgerIsActive
|
||||
? "navbar-burger is-active"
|
||||
: "navbar-burger";
|
||||
|
||||
if (!USE_REFRESH) {
|
||||
return (
|
||||
<>
|
||||
<nav className="navbar is-transparent padding-bottom-1em">
|
||||
<div className="navbar-brand">
|
||||
<Link className="navbar-item" to="/">
|
||||
<img src="/fakeyou/fakeyou-nav-logo-mascot.webp" alt="FakeYou: Cartoon and Celebrity Text to Speech" />
|
||||
<div className="navbar-brand">
|
||||
<Link className="navbar-item" to="/">
|
||||
<img
|
||||
src="/fakeyou/fakeyou-nav-logo-mascot.webp"
|
||||
alt="FakeYou: Cartoon and Celebrity Text to Speech"
|
||||
/>
|
||||
</Link>
|
||||
<div className={navbarBurgerClasses} data-target="navbarExampleTransparentExample" onClick={() => toggleHamburger()}>
|
||||
<div
|
||||
className={navbarBurgerClasses}
|
||||
data-target="navbarExampleTransparentExample"
|
||||
onClick={() => toggleHamburger()}
|
||||
>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
@@ -67,93 +79,136 @@ function NewTopNavFc(props: Props) {
|
||||
|
||||
<div id="navbarExampleTransparentExample" className={navbarClasses}>
|
||||
<div className="navbar-start">
|
||||
|
||||
<Link to={FrontendUrlConfig.cloneRequestPage()}
|
||||
<Link
|
||||
to={FrontendUrlConfig.cloneRequestPage()}
|
||||
className="navbar-item "
|
||||
onClick={() => closeHamburger()}
|
||||
>Clone My Voice!</Link>
|
||||
>
|
||||
Clone My Voice!
|
||||
</Link>
|
||||
|
||||
{/* DROPDOWN: CREATE */}
|
||||
|
||||
<div className="navbar-item has-dropdown is-hoverable">
|
||||
<Link to={FrontendUrlConfig.indexPage()}
|
||||
<Link
|
||||
to={FrontendUrlConfig.indexPage()}
|
||||
className="navbar-link"
|
||||
onClick={() => closeHamburger()}
|
||||
>{t('coreUi.topNav.create')}</Link>
|
||||
>
|
||||
{t("coreUi.topNav.create")}
|
||||
</Link>
|
||||
|
||||
<div className="navbar-dropdown is-boxed">
|
||||
{/* NB: There's an "is-active" class that looks nice. */}
|
||||
|
||||
<Link to="/"
|
||||
<Link
|
||||
to="/"
|
||||
className="navbar-item"
|
||||
onClick={() => closeHamburger()}
|
||||
>TTS</Link>
|
||||
>
|
||||
TTS
|
||||
</Link>
|
||||
|
||||
<Link to="/video"
|
||||
<Link
|
||||
to="/video"
|
||||
className="navbar-item"
|
||||
onClick={() => closeHamburger()}
|
||||
>{t('coreUi.topNav.video')}</Link>
|
||||
|
||||
>
|
||||
{t("coreUi.topNav.video")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* DROPDOWN: COMMUNITY */}
|
||||
|
||||
<div className="navbar-item has-dropdown is-hoverable">
|
||||
<Link to={myDataLink}
|
||||
<Link
|
||||
to={myDataLink}
|
||||
className="navbar-link"
|
||||
onClick={() => closeHamburger()}
|
||||
>{t('coreUi.topNav.community')}</Link>
|
||||
>
|
||||
{t("coreUi.topNav.community")}
|
||||
</Link>
|
||||
|
||||
<div className="navbar-dropdown is-boxed">
|
||||
{/* NB: There's an "is-active" class that looks nice. */}
|
||||
|
||||
<Link to="/contribute"
|
||||
<Link
|
||||
to="/contribute"
|
||||
className="navbar-item"
|
||||
onClick={() => closeHamburger()}
|
||||
><FontAwesomeIcon icon={faUpload} /> {t('coreUi.topNav.contributeUpload')}</Link>
|
||||
>
|
||||
<FontAwesomeIcon icon={faUpload} />
|
||||
{t("coreUi.topNav.contributeUpload")}
|
||||
</Link>
|
||||
|
||||
<Link to="/leaderboard"
|
||||
<Link
|
||||
to="/leaderboard"
|
||||
className="navbar-item"
|
||||
onClick={() => closeHamburger()}
|
||||
><FontAwesomeIcon icon={faTrophy} /> {t('coreUi.topNav.leaderboard')}</Link>
|
||||
>
|
||||
<FontAwesomeIcon icon={faTrophy} />
|
||||
{t("coreUi.topNav.leaderboard")}
|
||||
</Link>
|
||||
|
||||
<Link to={FrontendUrlConfig.patronsPage()}
|
||||
<Link
|
||||
to={FrontendUrlConfig.patronsPage()}
|
||||
className="navbar-item"
|
||||
onClick={() => closeHamburger()}
|
||||
><FontAwesomeIcon icon={faPatreon}/> {t('coreUi.topNav.patrons')}</Link>
|
||||
>
|
||||
<FontAwesomeIcon icon={faPatreon} />
|
||||
{t("coreUi.topNav.patrons")}
|
||||
</Link>
|
||||
|
||||
<Link to="/firehose"
|
||||
<Link
|
||||
to="/firehose"
|
||||
className="navbar-item"
|
||||
onClick={() => closeHamburger()}
|
||||
><FontAwesomeIcon icon={faList} /> {t('coreUi.topNav.feed')}</Link>
|
||||
>
|
||||
<FontAwesomeIcon icon={faList} />
|
||||
{t("coreUi.topNav.feed")}
|
||||
</Link>
|
||||
|
||||
<hr className="navbar-divider" />
|
||||
|
||||
<Link to={myDataLink}
|
||||
<Link
|
||||
to={myDataLink}
|
||||
className="navbar-item"
|
||||
onClick={() => closeHamburger()}
|
||||
><FontAwesomeIcon icon={faUser} /> {t('coreUi.topNav.myData')}</Link>
|
||||
>
|
||||
<FontAwesomeIcon icon={faUser} />
|
||||
{t("coreUi.topNav.myData")}
|
||||
</Link>
|
||||
|
||||
<hr className="navbar-divider" />
|
||||
|
||||
<Link to={FrontendUrlConfig.aboutUsPage()}
|
||||
<Link
|
||||
to={FrontendUrlConfig.aboutUsPage()}
|
||||
className="navbar-item"
|
||||
onClick={() => closeHamburger()}
|
||||
><FontAwesomeIcon icon={faGrinBeamSweat} /> {t('coreUi.topNav.aboutUs')}</Link>
|
||||
>
|
||||
<FontAwesomeIcon icon={faGrinBeamSweat} />
|
||||
{t("coreUi.topNav.aboutUs")}
|
||||
</Link>
|
||||
|
||||
<Link to={FrontendUrlConfig.termsPage()}
|
||||
<Link
|
||||
to={FrontendUrlConfig.termsPage()}
|
||||
className="navbar-item"
|
||||
onClick={() => closeHamburger()}
|
||||
><FontAwesomeIcon icon={faGavel} /> {t('coreUi.topNav.terms')}</Link>
|
||||
>
|
||||
<FontAwesomeIcon icon={faGavel} />
|
||||
{t("coreUi.topNav.terms")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href={FrontendUrlConfig.developerDocs()}
|
||||
<a
|
||||
href={FrontendUrlConfig.developerDocs()}
|
||||
className="navbar-item"
|
||||
onClick={() => closeHamburger()}
|
||||
>{t('coreUi.topNav.developers')}</a>
|
||||
|
||||
>
|
||||
{t("coreUi.topNav.developers")}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="navbar-end">
|
||||
@@ -165,7 +220,7 @@ function NewTopNavFc(props: Props) {
|
||||
enableAlpha={true}
|
||||
querySessionAction={props.querySessionCallback}
|
||||
closeHamburgerAction={() => closeHamburger()}
|
||||
/>
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -211,7 +266,7 @@ function NewTopNavFc(props: Props) {
|
||||
<div className="container">
|
||||
<Link className="navbar-brand me-5 pr-8" to="/">
|
||||
<img
|
||||
src="fakeyou/FakeYou-Logo.png"
|
||||
src="/fakeyou/FakeYou-Logo.png"
|
||||
alt="FakeYou: Cartoon and Celebrity Text to Speech"
|
||||
height="34"
|
||||
/>
|
||||
@@ -232,9 +287,13 @@ function NewTopNavFc(props: Props) {
|
||||
aria-labelledby="offcanvasNavbar2Label"
|
||||
>
|
||||
<div className="offcanvas-header">
|
||||
<Link data-bs-toggle="offcanvas" className="navbar-brand me-5 pr-8" to="/">
|
||||
<Link
|
||||
data-bs-toggle="offcanvas"
|
||||
className="navbar-brand me-5 pr-8"
|
||||
to="/"
|
||||
>
|
||||
<img
|
||||
src="fakeyou/FakeYou-Logo.png"
|
||||
src="/fakeyou/FakeYou-Logo.png"
|
||||
alt="FakeYou: Cartoon and Celebrity Text to Speech"
|
||||
height="34"
|
||||
/>
|
||||
@@ -326,7 +385,7 @@ function NewTopNavFc(props: Props) {
|
||||
</Link>
|
||||
</li>
|
||||
<li data-bs-toggle="offcanvas">
|
||||
<Link className="dropdown-item" to="/firehose">
|
||||
<Link className="dropdown-item" to="/firehose">
|
||||
<FontAwesomeIcon icon={faList} className="me-2" />
|
||||
Feed
|
||||
</Link>
|
||||
@@ -357,11 +416,7 @@ function NewTopNavFc(props: Props) {
|
||||
|
||||
<li className="nav-item d-lg-none">
|
||||
{/* TODO(echelon): Fix the build warnings about href not being accessible. */}
|
||||
<a
|
||||
className="nav-link"
|
||||
aria-current="page"
|
||||
href="/"
|
||||
>
|
||||
<a className="nav-link" aria-current="page" href="/">
|
||||
Developers
|
||||
</a>
|
||||
</li>
|
||||
@@ -385,7 +440,11 @@ function NewTopNavFc(props: Props) {
|
||||
</li>
|
||||
</ul>
|
||||
<div className="d-grid gap-2 d-flex justify-content-start align-items-center pt-4 ps-3 pt-lg-0 ps-lg-0">
|
||||
<Link data-bs-toggle="offcanvas" className="nav-login me-3" to="/login">
|
||||
<Link
|
||||
data-bs-toggle="offcanvas"
|
||||
className="nav-login me-3"
|
||||
to="/login"
|
||||
>
|
||||
Login
|
||||
</Link>
|
||||
<Link data-bs-toggle="offcanvas" to="/signup">
|
||||
|
||||
@@ -297,14 +297,14 @@ function ProfileFc(props: Props) {
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="container content mb-5 text-center text-lg-start px-4 px-md-5 px-lg-3"
|
||||
className="container content mb-0 mb-lg-5 text-center text-lg-start px-4 px-md-5 px-lg-3"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: userData.profile_rendered_html || "",
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 p-lg-4 mt-5 mt-lg-0">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">
|
||||
<FontAwesomeIcon icon={faAward} className="me-3" />
|
||||
Badges{" "}
|
||||
@@ -315,7 +315,7 @@ function ProfileFc(props: Props) {
|
||||
</div>
|
||||
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4 mt-5 mt-lg-0">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">
|
||||
<FontAwesomeIcon icon={faVolumeHigh} className="me-3" />
|
||||
TTS Results
|
||||
@@ -327,7 +327,7 @@ function ProfileFc(props: Props) {
|
||||
</div>
|
||||
|
||||
<div className="container-panel pt-3 pb-5">
|
||||
<div className="panel p-3 p-lg-4 mt-5 mt-lg-0">
|
||||
<div className="panel p-3 p-lg-4">
|
||||
<h2 className="panel-title fw-bold">
|
||||
<FontAwesomeIcon icon={faVideo} className="me-3" />
|
||||
Lipsync Results
|
||||
|
||||
+145
-93
@@ -1,88 +1,100 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { ApiConfig, ListTtsInferenceResultsForUserArgs } from '@storyteller/components';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { formatDistance } from 'date-fns';
|
||||
import { VisibleIconFc } from '../../_icons/VisibleIcon';
|
||||
import { HiddenIconFc } from '../../_icons/HiddenIcon';
|
||||
import { PlayCircleIcon } from '../../_icons/PlayCircleIcon';
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import {
|
||||
ApiConfig,
|
||||
ListTtsInferenceResultsForUserArgs,
|
||||
} from "@storyteller/components";
|
||||
import { Link } from "react-router-dom";
|
||||
import { formatDistance } from "date-fns";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faCirclePlay,
|
||||
faArrowLeft,
|
||||
faArrowRight,
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
const Fade = require("react-reveal/Fade");
|
||||
|
||||
interface TtsInferenceResultListResponsePayload {
|
||||
success: boolean,
|
||||
results: Array<TtsInferenceResult>,
|
||||
cursor_next: string | null | undefined,
|
||||
cursor_previous: string | null | undefined,
|
||||
success: boolean;
|
||||
results: Array<TtsInferenceResult>;
|
||||
cursor_next: string | null | undefined;
|
||||
cursor_previous: string | null | undefined;
|
||||
}
|
||||
|
||||
interface TtsInferenceResult {
|
||||
tts_result_token: string,
|
||||
tts_result_token: string;
|
||||
|
||||
tts_model_token: string,
|
||||
tts_model_title: string,
|
||||
tts_model_token: string;
|
||||
tts_model_title: string;
|
||||
|
||||
raw_inference_text: string,
|
||||
raw_inference_text: string;
|
||||
|
||||
maybe_creator_user_token?: string,
|
||||
maybe_creator_username?: string,
|
||||
maybe_creator_display_name?: string,
|
||||
maybe_creator_user_token?: string;
|
||||
maybe_creator_username?: string;
|
||||
maybe_creator_display_name?: string;
|
||||
|
||||
maybe_creator_result_id: number | null,
|
||||
maybe_creator_result_id: number | null;
|
||||
|
||||
file_size_bytes: number,
|
||||
duration_millis: number,
|
||||
file_size_bytes: number;
|
||||
duration_millis: number;
|
||||
|
||||
visibility: string,
|
||||
visibility: string;
|
||||
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
username: string,
|
||||
username: string;
|
||||
}
|
||||
|
||||
function ProfileTtsInferenceResultsListFc(props: Props) {
|
||||
const [ttsResults, setTtsResults] = useState<Array<TtsInferenceResult>>([]);
|
||||
|
||||
const [nextCursor, setNextCursor] = useState<string|null>(null);
|
||||
const [previousCursor, setPreviousCursor] = useState<string|null>(null);
|
||||
const [nextCursor, setNextCursor] = useState<string | null>(null);
|
||||
const [previousCursor, setPreviousCursor] = useState<string | null>(null);
|
||||
|
||||
const getPage = useCallback((cursor : string|null, reverse: boolean) => {
|
||||
let args : ListTtsInferenceResultsForUserArgs = {
|
||||
username: props.username,
|
||||
limit: 25,
|
||||
};
|
||||
const getPage = useCallback(
|
||||
(cursor: string | null, reverse: boolean) => {
|
||||
let args: ListTtsInferenceResultsForUserArgs = {
|
||||
username: props.username,
|
||||
limit: 25,
|
||||
};
|
||||
|
||||
if (cursor !== null) {
|
||||
args.cursor = cursor;
|
||||
if (reverse) {
|
||||
args.cursor_is_reversed = true;
|
||||
}
|
||||
}
|
||||
|
||||
const api = new ApiConfig();
|
||||
const endpointUrl = api.listTtsInferenceResultsForUser(args);
|
||||
|
||||
fetch(endpointUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
const modelsResponse : TtsInferenceResultListResponsePayload = res;
|
||||
if (!modelsResponse.success) {
|
||||
return;
|
||||
if (cursor !== null) {
|
||||
args.cursor = cursor;
|
||||
if (reverse) {
|
||||
args.cursor_is_reversed = true;
|
||||
}
|
||||
}
|
||||
|
||||
setTtsResults(modelsResponse.results)
|
||||
setNextCursor(modelsResponse.cursor_next || null)
|
||||
setPreviousCursor(modelsResponse.cursor_previous || null)
|
||||
})
|
||||
.catch(e => {
|
||||
});
|
||||
}, [props.username]);
|
||||
const api = new ApiConfig();
|
||||
const endpointUrl = api.listTtsInferenceResultsForUser(args);
|
||||
|
||||
fetch(endpointUrl, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
const modelsResponse: TtsInferenceResultListResponsePayload = res;
|
||||
if (!modelsResponse.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTtsResults(modelsResponse.results);
|
||||
setNextCursor(modelsResponse.cursor_next || null);
|
||||
setPreviousCursor(modelsResponse.cursor_previous || null);
|
||||
})
|
||||
.catch((e) => {});
|
||||
},
|
||||
[props.username]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
getPage(null, false);
|
||||
@@ -90,35 +102,45 @@ function ProfileTtsInferenceResultsListFc(props: Props) {
|
||||
|
||||
const now = new Date();
|
||||
|
||||
let rows : Array<JSX.Element> = [];
|
||||
|
||||
ttsResults.forEach(result => {
|
||||
let rows: Array<JSX.Element> = [];
|
||||
|
||||
ttsResults.slice(0, 10).forEach((result) => {
|
||||
const duration_seconds = result.duration_millis / 1000;
|
||||
|
||||
const inferenceLink = `/tts/result/${result.tts_result_token}`;
|
||||
const modelLink = `/tts/${result.tts_model_token}`;
|
||||
|
||||
const text = result.raw_inference_text.length < 5 ? `Result: ${result.raw_inference_text}` : result.raw_inference_text;
|
||||
const text =
|
||||
result.raw_inference_text.length < 5
|
||||
? `Result: ${result.raw_inference_text}`
|
||||
: result.raw_inference_text;
|
||||
|
||||
const createTime = new Date(result.created_at);
|
||||
const relativeCreateTime = formatDistance(createTime, now, { addSuffix: true });
|
||||
const relativeCreateTime = formatDistance(createTime, now, {
|
||||
addSuffix: true,
|
||||
});
|
||||
|
||||
const visibilityIcon = (result.visibility === 'public') ? <VisibleIconFc /> : <HiddenIconFc /> ;
|
||||
const visibilityIcon =
|
||||
result.visibility === "public" ? (
|
||||
<FontAwesomeIcon icon={faEye} />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faEyeSlash} />
|
||||
);
|
||||
|
||||
rows.push(
|
||||
<tr key={result.tts_result_token}>
|
||||
<td>{result.maybe_creator_result_id}</td>
|
||||
<td>{visibilityIcon}</td>
|
||||
<th className="overflow-fix">
|
||||
|
||||
<Link to={inferenceLink}>
|
||||
<PlayCircleIcon title="play" />
|
||||
|
||||
<FontAwesomeIcon icon={faCirclePlay} className="me-2" />
|
||||
{text}
|
||||
</Link>
|
||||
|
||||
</th>
|
||||
<th><Link to={modelLink}>Model: {result.tts_model_title}</Link></th>
|
||||
<th>
|
||||
<Link to={modelLink}>Model: {result.tts_model_title}</Link>
|
||||
</th>
|
||||
<td>{duration_seconds} s</td>
|
||||
<td>{relativeCreateTime}</td>
|
||||
</tr>
|
||||
@@ -126,40 +148,70 @@ function ProfileTtsInferenceResultsListFc(props: Props) {
|
||||
});
|
||||
|
||||
// Disable if there is no "next" or "previous" cursor.
|
||||
// However, let the buttosn show up if there are no results (empty payload)
|
||||
// However, let the buttosn show up if there are no results (empty payload)
|
||||
// to get unstuck. Come up with a better fix for this.
|
||||
let prevDisabled = !previousCursor && rows.length !== 0;
|
||||
let nextDisabled = !nextCursor && rows.length !== 0;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><abbr title="Number">#</abbr></th>
|
||||
<th><abbr title="Visibility"><VisibleIconFc /></abbr></th>
|
||||
<th><abbr title="Download">Download & Play Link</abbr></th>
|
||||
<th><abbr title="Model">Model</abbr></th>
|
||||
<th><abbr title="Duration">Duration</abbr></th>
|
||||
<th><abbr title="Created">Creation Time</abbr></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="table-responsive">
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<abbr title="Number">#</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Visibility">
|
||||
<FontAwesomeIcon icon={faEye} />
|
||||
</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Download">Download & Play Link</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Model">Model</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Duration">Duration</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Created">Creation Time</abbr>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<Fade cascade bottom duration="200" distance="10px">
|
||||
<tbody>{rows}</tbody>
|
||||
</Fade>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Note: Results marked public (<VisibleIconFc />) are visible by anyone visiting your profile.
|
||||
<p className="text-center py-3">
|
||||
Note: Results marked public (<FontAwesomeIcon icon={faEye} />) are
|
||||
visible by anyone visiting your profile.
|
||||
{/*You can change this by editing results. You can also set a default preference for new results.*/}
|
||||
</p>
|
||||
|
||||
<div className="columns is-centered">
|
||||
<button className="button is-info" onClick={() => getPage(previousCursor, true)} disabled={prevDisabled}>< Get newer</button>
|
||||
<button className="button is-info" onClick={() => getPage(nextCursor, false)} disabled={nextDisabled}>Get older></button>
|
||||
<div className="justify-content-center d-flex gap-3">
|
||||
<button
|
||||
className="btn btn-secondary"
|
||||
onClick={() => getPage(previousCursor, true)}
|
||||
disabled={prevDisabled}
|
||||
>
|
||||
<FontAwesomeIcon icon={faArrowLeft} className="me-2" /> Get newer
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-secondary"
|
||||
onClick={() => getPage(nextCursor, false)}
|
||||
disabled={nextDisabled}
|
||||
>
|
||||
Get older
|
||||
<FontAwesomeIcon icon={faArrowRight} className="ms-2" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export { ProfileTtsInferenceResultsListFc };
|
||||
@@ -1,26 +1,26 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { ApiConfig } from '@storyteller/components';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { formatDistance } from 'date-fns';
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { ApiConfig } from "@storyteller/components";
|
||||
import { Link } from "react-router-dom";
|
||||
import { formatDistance } from "date-fns";
|
||||
|
||||
interface TtsModelListResponsePayload {
|
||||
success: boolean,
|
||||
models: Array<TtsModel>,
|
||||
success: boolean;
|
||||
models: Array<TtsModel>;
|
||||
}
|
||||
|
||||
interface TtsModel {
|
||||
model_token: string,
|
||||
tts_model_type: string,
|
||||
title: string,
|
||||
updatable_slug: string,
|
||||
model_token: string;
|
||||
tts_model_type: string;
|
||||
title: string;
|
||||
updatable_slug: string;
|
||||
// TODO: No need for "creator_*" fields. Remove them from backend.
|
||||
is_mod_disabled: boolean,
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
is_mod_disabled: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
username: string,
|
||||
username: string;
|
||||
}
|
||||
|
||||
function ProfileTtsModelListFc(props: Props) {
|
||||
@@ -31,40 +31,44 @@ function ProfileTtsModelListFc(props: Props) {
|
||||
const endpointUrl = api.listTtsModelsForUser(props.username);
|
||||
|
||||
fetch(endpointUrl, {
|
||||
method: 'GET',
|
||||
method: "GET",
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
const modelsResponse : TtsModelListResponsePayload = res;
|
||||
if (!modelsResponse.success) {
|
||||
return;
|
||||
}
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
const modelsResponse: TtsModelListResponsePayload = res;
|
||||
if (!modelsResponse.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTtsModels(modelsResponse.models)
|
||||
})
|
||||
.catch(e => {
|
||||
});
|
||||
setTtsModels(modelsResponse.models);
|
||||
})
|
||||
.catch((e) => {});
|
||||
}, [props.username]); // NB: Empty array dependency sets to run ONLY on mount
|
||||
|
||||
const now = new Date();
|
||||
|
||||
let rows : Array<JSX.Element> = [];
|
||||
|
||||
ttsModels.forEach(model => {
|
||||
const modelTitle = model.title.length < 5 ? `Model: ${model.title}` : model.title;
|
||||
let rows: Array<JSX.Element> = [];
|
||||
|
||||
ttsModels.slice(0, 10).forEach((model) => {
|
||||
const modelTitle =
|
||||
model.title.length < 5 ? `Model: ${model.title}` : model.title;
|
||||
|
||||
const modelLink = `/tts/${model.model_token}`;
|
||||
|
||||
const createTime = new Date(model.created_at);
|
||||
const relativeCreateTime = formatDistance(createTime, now, { addSuffix: true });
|
||||
const relativeCreateTime = formatDistance(createTime, now, {
|
||||
addSuffix: true,
|
||||
});
|
||||
|
||||
rows.push(
|
||||
<tr key={model.model_token}>
|
||||
<th><Link to={modelLink}>{modelTitle}</Link></th>
|
||||
<th>
|
||||
<Link to={modelLink}>{modelTitle}</Link>
|
||||
</th>
|
||||
<td>{relativeCreateTime}</td>
|
||||
</tr>
|
||||
);
|
||||
@@ -75,16 +79,19 @@ function ProfileTtsModelListFc(props: Props) {
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><abbr title="Model Name">Model Name</abbr></th>
|
||||
<th><abbr title="Creation Date">Creation Time</abbr></th>
|
||||
<th>
|
||||
<abbr title="Model Name">Model Name</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Creation Date">Creation Time</abbr>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
<tbody>{rows}</tbody>
|
||||
</table>
|
||||
<div className="text-center">ADD OLDER/NEWER PAGINATION BUTTON HERE</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export { ProfileTtsModelListFc };
|
||||
+152
-97
@@ -1,90 +1,102 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { ApiConfig, ListW2lInferenceResultsForUserArgs } from '@storyteller/components';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { formatDistance } from 'date-fns'
|
||||
import { VisibleIconFc } from '../../_icons/VisibleIcon';
|
||||
import { HiddenIconFc } from '../../_icons/HiddenIcon';
|
||||
import { FilmIcon } from '../../_icons/FilmIcon';
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import {
|
||||
ApiConfig,
|
||||
ListW2lInferenceResultsForUserArgs,
|
||||
} from "@storyteller/components";
|
||||
import { Link } from "react-router-dom";
|
||||
import { formatDistance } from "date-fns";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faFilm,
|
||||
faArrowLeft,
|
||||
faArrowRight,
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
const Fade = require("react-reveal/Fade");
|
||||
|
||||
interface W2lInferenceResultListResponsePayload {
|
||||
success: boolean,
|
||||
results: Array<W2lInferenceResult>,
|
||||
cursor_next: string | null | undefined,
|
||||
cursor_previous: string | null | undefined,
|
||||
success: boolean;
|
||||
results: Array<W2lInferenceResult>;
|
||||
cursor_next: string | null | undefined;
|
||||
cursor_previous: string | null | undefined;
|
||||
}
|
||||
|
||||
interface W2lInferenceResult {
|
||||
w2l_result_token: string,
|
||||
maybe_w2l_template_token?: string,
|
||||
maybe_tts_inference_result_token?: string,
|
||||
w2l_result_token: string;
|
||||
maybe_w2l_template_token?: string;
|
||||
maybe_tts_inference_result_token?: string;
|
||||
|
||||
template_type: string,
|
||||
template_title: string,
|
||||
template_type: string;
|
||||
template_title: string;
|
||||
|
||||
maybe_creator_user_token?: string,
|
||||
maybe_creator_username?: string,
|
||||
maybe_creator_display_name?: string,
|
||||
maybe_creator_user_token?: string;
|
||||
maybe_creator_username?: string;
|
||||
maybe_creator_display_name?: string;
|
||||
|
||||
maybe_creator_result_id: number | null,
|
||||
|
||||
file_size_bytes: number,
|
||||
frame_width: number,
|
||||
frame_height: number,
|
||||
duration_millis: number,
|
||||
maybe_creator_result_id: number | null;
|
||||
|
||||
visibility: string,
|
||||
file_size_bytes: number;
|
||||
frame_width: number;
|
||||
frame_height: number;
|
||||
duration_millis: number;
|
||||
|
||||
created_at: string,
|
||||
updated_at: string,
|
||||
visibility: string;
|
||||
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
username: string,
|
||||
username: string;
|
||||
}
|
||||
|
||||
function ProfileW2lInferenceResultsListFc(props: Props) {
|
||||
const [w2lResults, setW2lResults] = useState<Array<W2lInferenceResult>>([]);
|
||||
|
||||
const [nextCursor, setNextCursor] = useState<string|null>(null);
|
||||
const [previousCursor, setPreviousCursor] = useState<string|null>(null);
|
||||
const [nextCursor, setNextCursor] = useState<string | null>(null);
|
||||
const [previousCursor, setPreviousCursor] = useState<string | null>(null);
|
||||
|
||||
const getPage = useCallback((cursor : string|null, reverse: boolean) => {
|
||||
let args : ListW2lInferenceResultsForUserArgs = {
|
||||
username: props.username,
|
||||
limit: 5,
|
||||
};
|
||||
const getPage = useCallback(
|
||||
(cursor: string | null, reverse: boolean) => {
|
||||
let args: ListW2lInferenceResultsForUserArgs = {
|
||||
username: props.username,
|
||||
limit: 5,
|
||||
};
|
||||
|
||||
if (cursor !== null) {
|
||||
args.cursor = cursor;
|
||||
if (reverse) {
|
||||
args.cursor_is_reversed = true;
|
||||
}
|
||||
}
|
||||
|
||||
const api = new ApiConfig();
|
||||
const endpointUrl = api.listW2lInferenceResultsForUser(args);
|
||||
|
||||
fetch(endpointUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
const templatesResponse : W2lInferenceResultListResponsePayload = res;
|
||||
if (!templatesResponse.success) {
|
||||
return;
|
||||
if (cursor !== null) {
|
||||
args.cursor = cursor;
|
||||
if (reverse) {
|
||||
args.cursor_is_reversed = true;
|
||||
}
|
||||
}
|
||||
|
||||
setW2lResults(templatesResponse.results)
|
||||
setNextCursor(templatesResponse.cursor_next || null)
|
||||
setPreviousCursor(templatesResponse.cursor_previous || null)
|
||||
})
|
||||
.catch(e => {
|
||||
});
|
||||
}, [props.username]);
|
||||
const api = new ApiConfig();
|
||||
const endpointUrl = api.listW2lInferenceResultsForUser(args);
|
||||
|
||||
fetch(endpointUrl, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
const templatesResponse: W2lInferenceResultListResponsePayload = res;
|
||||
if (!templatesResponse.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
setW2lResults(templatesResponse.results);
|
||||
setNextCursor(templatesResponse.cursor_next || null);
|
||||
setPreviousCursor(templatesResponse.cursor_previous || null);
|
||||
})
|
||||
.catch((e) => {});
|
||||
},
|
||||
[props.username]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
getPage(null, false);
|
||||
@@ -92,19 +104,29 @@ function ProfileW2lInferenceResultsListFc(props: Props) {
|
||||
|
||||
const now = new Date();
|
||||
|
||||
let rows : Array<JSX.Element> = [];
|
||||
|
||||
w2lResults.forEach(result => {
|
||||
let rows: Array<JSX.Element> = [];
|
||||
|
||||
w2lResults.slice(0, 5).forEach((result) => {
|
||||
const duration_seconds = result.duration_millis / 1000;
|
||||
const templateTitle = result.template_title.length < 5 ? `Title: ${result.template_title}` : result.template_title;
|
||||
const templateTitle =
|
||||
result.template_title.length < 5
|
||||
? `Title: ${result.template_title}`
|
||||
: result.template_title;
|
||||
|
||||
const inferenceLink = `/w2l/result/${result.w2l_result_token}`;
|
||||
const templateLink = `/w2l/${result.maybe_w2l_template_token}`;
|
||||
|
||||
const createTime = new Date(result.created_at);
|
||||
const relativeCreateTime = formatDistance(createTime, now, { addSuffix: true });
|
||||
const relativeCreateTime = formatDistance(createTime, now, {
|
||||
addSuffix: true,
|
||||
});
|
||||
|
||||
const visibilityIcon = (result.visibility === 'public') ? <VisibleIconFc /> : <HiddenIconFc /> ;
|
||||
const visibilityIcon =
|
||||
result.visibility === "public" ? (
|
||||
<FontAwesomeIcon icon={faEye} />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faEyeSlash} />
|
||||
);
|
||||
|
||||
rows.push(
|
||||
<tr key={result.w2l_result_token}>
|
||||
@@ -112,12 +134,13 @@ function ProfileW2lInferenceResultsListFc(props: Props) {
|
||||
<td>{visibilityIcon}</td>
|
||||
<th>
|
||||
<Link to={inferenceLink}>
|
||||
<FilmIcon title="Play & Download" />
|
||||
|
||||
<FontAwesomeIcon icon={faFilm} className="me-2" />
|
||||
Result
|
||||
</Link>
|
||||
</th>
|
||||
<th><Link to={templateLink}>{templateTitle}</Link></th>
|
||||
<th>
|
||||
<Link to={templateLink}>{templateTitle}</Link>
|
||||
</th>
|
||||
<td>(custom audio)</td>
|
||||
<td>{duration_seconds} s</td>
|
||||
<td>{relativeCreateTime}</td>
|
||||
@@ -126,41 +149,73 @@ function ProfileW2lInferenceResultsListFc(props: Props) {
|
||||
});
|
||||
|
||||
// Disable if there is no "next" or "previous" cursor.
|
||||
// However, let the buttosn show up if there are no results (empty payload)
|
||||
// However, let the buttosn show up if there are no results (empty payload)
|
||||
// to get unstuck. Come up with a better fix for this.
|
||||
let prevDisabled = !previousCursor && rows.length !== 0;
|
||||
let nextDisabled = !nextCursor && rows.length !== 0;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><abbr title="Number">#</abbr></th>
|
||||
<th><abbr title="Visibility"><VisibleIconFc /></abbr></th>
|
||||
<th><abbr title="Result View">Result Link</abbr></th>
|
||||
<th><abbr title="Template">Template</abbr></th>
|
||||
<th><abbr title="Source">Audio Source</abbr></th>
|
||||
<th><abbr title="Duration">Duration</abbr></th>
|
||||
<th><abbr title="Created">Creation Time</abbr></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="table-responsive">
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<abbr title="Number">#</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Visibility">
|
||||
<FontAwesomeIcon icon={faEye} />
|
||||
</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Result View">Result Link</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Template">Template</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Source">Audio Source</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Duration">Duration</abbr>
|
||||
</th>
|
||||
<th>
|
||||
<abbr title="Created">Creation Time</abbr>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<Fade cascade bottom duration="200" distance="10px">
|
||||
<tbody>{rows}</tbody>
|
||||
</Fade>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Note: Results marked public (<VisibleIconFc />) are visible by anyone visiting your profile.
|
||||
<p className="text-center py-3">
|
||||
Note: Results marked public (<FontAwesomeIcon icon={faEye} />) are
|
||||
visible by anyone visiting your profile.
|
||||
{/*You can change this by editing results. You can also set a default preference for new results.*/}
|
||||
</p>
|
||||
|
||||
<div className="columns is-centered">
|
||||
<button className="button is-info" onClick={() => getPage(previousCursor, true)} disabled={prevDisabled}>< Get newer</button>
|
||||
<button className="button is-info" onClick={() => getPage(nextCursor, false)} disabled={nextDisabled}>Get older></button>
|
||||
<div className="justify-content-center d-flex gap-3">
|
||||
<button
|
||||
className="btn btn-secondary"
|
||||
onClick={() => getPage(previousCursor, true)}
|
||||
disabled={prevDisabled}
|
||||
>
|
||||
<FontAwesomeIcon icon={faArrowLeft} className="me-2" /> Get newer
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-secondary"
|
||||
onClick={() => getPage(nextCursor, false)}
|
||||
disabled={nextDisabled}
|
||||
>
|
||||
Get older
|
||||
<FontAwesomeIcon icon={faArrowRight} className="ms-2" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export { ProfileW2lInferenceResultsListFc };
|
||||
Reference in new issue
Block a user