mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-03 08:57:54 +00:00
main tts page design updates
This commit is contained in:
1 parent
48c0f64898
commit
7663f00c84
7 files changed
+917
-169
No files matched your search
@@ -28,6 +28,7 @@
|
||||
"lerna": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-select": "^5.7.0",
|
||||
"yarn": "^1.22.19"
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ styles with important tags:
|
||||
|
||||
select {
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.no-wrap {
|
||||
@@ -81,6 +82,10 @@ styles with important tags:
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.rounded-5 {
|
||||
border-radius: 5px !important;
|
||||
}
|
||||
|
||||
code {
|
||||
color: $primary;
|
||||
background-color: rgba($white, 0.06);
|
||||
@@ -143,7 +148,7 @@ styles with important tags:
|
||||
|
||||
.alert-cta {
|
||||
font-weight: 500 !important;
|
||||
font-size: 18px !important;
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
.btn {
|
||||
@@ -220,6 +225,7 @@ styles with important tags:
|
||||
padding: 0 0.75rem;
|
||||
padding-top: 1px;
|
||||
font-size: 22px;
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
@@ -230,6 +236,10 @@ styles with important tags:
|
||||
border: 1px solid;
|
||||
border-radius: 0px;
|
||||
|
||||
.panel-inner {
|
||||
background-color: lighten($panel, 2%);
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
position: static;
|
||||
text-align: center;
|
||||
@@ -296,14 +306,22 @@ styles with important tags:
|
||||
|
||||
.form-select {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M2 5l6 6 6-6'/%3e%3c/svg%3e") !important;
|
||||
border-radius: 50px;
|
||||
|
||||
&.main-select {
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-control {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-select {
|
||||
border-width: 1px;
|
||||
border-color: $white;
|
||||
border-radius: 5px;
|
||||
padding: 0.5rem 0.75rem;
|
||||
padding: 11px 0.75rem;
|
||||
|
||||
&:focus {
|
||||
border-color: $primary;
|
||||
@@ -600,12 +618,38 @@ styles with important tags:
|
||||
.btn-close {
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.session-tts-section {
|
||||
height: 450px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.direct-view-link {
|
||||
background-color: lighten($panel, 2%);
|
||||
border: 1px solid #39394c;
|
||||
border-radius: 5px;
|
||||
padding: 11px 16px;
|
||||
|
||||
&:hover {
|
||||
border-color: lighten(#39394c, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
border-color: $input-dark !important;
|
||||
background-color: $input-dark !important;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-chevron-down' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E");
|
||||
transition: 0.1s !important;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten($input-dark, 5%) !important;
|
||||
}
|
||||
|
||||
option {
|
||||
background-color: $input-dark !important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-destructive {
|
||||
@@ -621,10 +665,16 @@ textarea {
|
||||
background-color: $input-dark !important;
|
||||
border-color: $input-dark !important;
|
||||
color: $white !important;
|
||||
|
||||
&.text-message {
|
||||
font-size: 18px;
|
||||
min-height: 200px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.form-select {
|
||||
color: $white !important;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.form-control::placeholder {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faClock,
|
||||
faLink,
|
||||
faList,
|
||||
faHeadphonesSimple,
|
||||
faMicrophone,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { motion } from "framer-motion";
|
||||
@@ -25,7 +25,7 @@ function SessionTtsInferenceResultListFc(props: Props) {
|
||||
|
||||
props.ttsInferenceJobs.forEach((job) => {
|
||||
if (!job.maybeResultToken) {
|
||||
let cssStyle = "alert alert-secondary mx-3 mx-md-0";
|
||||
let cssStyle = "alert alert-secondary mx-3 mx-md-0 mb-0";
|
||||
let stateDescription = "Pending...";
|
||||
|
||||
switch (job.jobState) {
|
||||
@@ -37,24 +37,24 @@ function SessionTtsInferenceResultListFc(props: Props) {
|
||||
: job.maybeExtraStatusDescription;
|
||||
break;
|
||||
case JobState.STARTED:
|
||||
cssStyle = "alert alert-success mx-3 mx-md-0";
|
||||
cssStyle = "alert alert-success mx-3 mx-md-0 mb-0";
|
||||
stateDescription =
|
||||
job.maybeExtraStatusDescription == null
|
||||
? "Started..."
|
||||
: job.maybeExtraStatusDescription;
|
||||
break;
|
||||
case JobState.ATTEMPT_FAILED:
|
||||
cssStyle = "alert alert-danger mx-3 mx-md-0";
|
||||
cssStyle = "alert alert-danger mx-3 mx-md-0 mb-0";
|
||||
stateDescription = `Failed ${job.attemptCount} attempt(s). Will retry...`;
|
||||
break;
|
||||
case JobState.COMPLETE_FAILURE:
|
||||
case JobState.DEAD:
|
||||
cssStyle = "alert alert-danger mx-3 mx-md-0";
|
||||
cssStyle = "alert alert-danger mx-3 mx-md-0 mb-0";
|
||||
stateDescription =
|
||||
"Failed Permanently. Please tell us in Discord so we can fix. :(";
|
||||
break;
|
||||
case JobState.COMPLETE_SUCCESS:
|
||||
cssStyle = "message is-success mx-3 mx-md-0";
|
||||
cssStyle = "message is-success mx-3 mx-md-0 mb-0";
|
||||
stateDescription = "Success!"; // Not sure why we're here instead of other branch!
|
||||
break;
|
||||
}
|
||||
@@ -83,35 +83,36 @@ function SessionTtsInferenceResultListFc(props: Props) {
|
||||
</div>*/}
|
||||
<div>
|
||||
<motion.div
|
||||
className="panel py-4 p-3 p-lg-4 gap-4 d-flex flex-column"
|
||||
className="panel panel-inner p-4 gap-3 d-flex flex-column"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div>
|
||||
<h4>
|
||||
<FontAwesomeIcon icon={faMicrophone} className="me-3" />
|
||||
{job.title}
|
||||
</h4>
|
||||
<h5 className="mb-1">{job.title}</h5>
|
||||
<p>{job.rawInferenceText}</p>
|
||||
</div>
|
||||
|
||||
<audio
|
||||
className="w-100"
|
||||
controls
|
||||
<audio
|
||||
className="w-100"
|
||||
controls
|
||||
src={audioLink}
|
||||
onClick={() => { Analytics.ttsClickResultInlinePlay() }}
|
||||
onClick={() => {
|
||||
Analytics.ttsClickResultInlinePlay();
|
||||
}}
|
||||
>
|
||||
Your browser does not support the
|
||||
<code>audio</code> element.
|
||||
</audio>
|
||||
|
||||
<div>
|
||||
<Link
|
||||
to={ttsPermalink}
|
||||
onClick={() => { Analytics.ttsClickResultLink() }}
|
||||
className="btn btn-primary"
|
||||
>
|
||||
<Link
|
||||
to={ttsPermalink}
|
||||
onClick={() => {
|
||||
Analytics.ttsClickResultLink();
|
||||
}}
|
||||
className="fw-semibold"
|
||||
>
|
||||
<FontAwesomeIcon icon={faLink} className="me-2" />
|
||||
Permalink & download
|
||||
Permalink / Download
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
@@ -121,18 +122,18 @@ function SessionTtsInferenceResultListFc(props: Props) {
|
||||
}
|
||||
});
|
||||
|
||||
if (results.length === 0) {
|
||||
return <span />;
|
||||
}
|
||||
let noResultsSection = (
|
||||
<div className="panel panel-inner text-center p-5 rounded-5 h-100">
|
||||
<div className="d-flex flex-column opacity-75 h-100 justify-content-center">
|
||||
<FontAwesomeIcon icon={faHeadphonesSimple} className="fs-3 mb-3" />
|
||||
<h5 className="fw-semibold">No results yet</h5>
|
||||
<p>Generated audio will appear here.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
let title = <span />;
|
||||
if (results.length !== 0) {
|
||||
title = (
|
||||
<motion.h2 className="text-center text-lg-start fw-bold" variants={item}>
|
||||
<FontAwesomeIcon icon={faList} className="me-3" />
|
||||
Session TTS Results
|
||||
</motion.h2>
|
||||
);
|
||||
if (results.length === 0) {
|
||||
return <>{noResultsSection}</>;
|
||||
}
|
||||
|
||||
let upgradeNotice = <></>;
|
||||
@@ -143,18 +144,20 @@ function SessionTtsInferenceResultListFc(props: Props) {
|
||||
!props.sessionSubscriptionsWrapper.hasPaidFeatures()
|
||||
) {
|
||||
upgradeNotice = (
|
||||
<div className="d-flex flex-column gap-4 mx-3 mx-md-0">
|
||||
<div className="d-flex flex-column gap-3 mx-3 mx-md-0 sticky-top">
|
||||
<motion.div
|
||||
className="alert alert-warning alert-cta"
|
||||
className="alert alert-warning alert-cta mb-0"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<FontAwesomeIcon icon={faClock} className="me-3" />
|
||||
<FontAwesomeIcon icon={faClock} className="me-2" />
|
||||
Don't want to wait? Step to the front of the line with a{" "}
|
||||
<Link
|
||||
to="/pricing"
|
||||
onClick={() => { Analytics.ttsTooSlowUpgradePremium() }}
|
||||
className="alert-link"
|
||||
>
|
||||
<Link
|
||||
to="/pricing"
|
||||
onClick={() => {
|
||||
Analytics.ttsTooSlowUpgradePremium();
|
||||
}}
|
||||
className="alert-link"
|
||||
>
|
||||
<span className="fw-semibold">FakeYou membership</span>.
|
||||
</Link>
|
||||
</motion.div>
|
||||
@@ -167,12 +170,10 @@ function SessionTtsInferenceResultListFc(props: Props) {
|
||||
|
||||
return (
|
||||
<motion.div initial="hidden" animate="visible" variants={container}>
|
||||
<div className="container-panel mb-5">
|
||||
<div className="d-flex flex-column gap-4">
|
||||
{title}
|
||||
<div>
|
||||
<div className="d-flex flex-column gap-3">
|
||||
{upgradeNotice}
|
||||
|
||||
<div className="d-flex flex-column gap-4">{results}</div>
|
||||
<div className="d-flex flex-column gap-3">{results}</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -203,7 +203,9 @@ export function MultiDropdownSearch(props: Props) {
|
||||
<div className="d-flex gap-3 align-items-center mb-4 w-100">
|
||||
<div className="form-group input-icon w-100">
|
||||
<select
|
||||
onClick={() => { Analytics.ttsClickSelectCategory() } }
|
||||
onClick={() => {
|
||||
Analytics.ttsClickSelectCategory();
|
||||
}}
|
||||
className={selectCssClasses}
|
||||
name={`categories-${i}`}
|
||||
onChange={(ev) => handleChangeCategory(ev, i)}
|
||||
@@ -295,10 +297,10 @@ export function MultiDropdownSearch(props: Props) {
|
||||
return (
|
||||
<div>
|
||||
{/* Category Dropdowns */}
|
||||
<label className="sub-title">
|
||||
{/* <label className="sub-title">
|
||||
{t("tts.TtsModelListPage.form.categoryFiltersLabel")}
|
||||
</label>
|
||||
{categoryFieldGroups}
|
||||
</label> */}
|
||||
{/* {categoryFieldGroups} */}
|
||||
|
||||
{/* Model Dropdown */}
|
||||
<label className="sub-title">
|
||||
@@ -317,7 +319,9 @@ export function MultiDropdownSearch(props: Props) {
|
||||
className={selectClasses}
|
||||
name="tts-model-select"
|
||||
onChange={handleChangeVoice}
|
||||
onClick={() => { Analytics.ttsSelectVoiceFromCategory() }}
|
||||
onClick={() => {
|
||||
Analytics.ttsSelectVoiceFromCategory();
|
||||
}}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading
|
||||
|
||||
@@ -38,7 +38,11 @@ import { TwitchTtsNotice } from "./notices/TwitchTtsNotice";
|
||||
import { PleaseFollowNotice } from "./notices/PleaseFollowNotice";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faTrash,
|
||||
faArrowRight,
|
||||
faBarsStaggered,
|
||||
faChevronRight,
|
||||
faDeleteLeft,
|
||||
faGlobe,
|
||||
faVolumeHigh,
|
||||
faVolumeUp,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
@@ -253,7 +257,7 @@ function TtsModelListPage(props: Props) {
|
||||
|
||||
if (props.maybeSelectedTtsModel) {
|
||||
let modelLink = `/tts/${props.maybeSelectedTtsModel.model_token}`;
|
||||
let modelName = props.maybeSelectedTtsModel.title;
|
||||
// let modelName = props.maybeSelectedTtsModel.title;
|
||||
let userName = props.maybeSelectedTtsModel.creator_display_name;
|
||||
directViewLink = (
|
||||
<Link
|
||||
@@ -261,18 +265,31 @@ function TtsModelListPage(props: Props) {
|
||||
onClick={() => {
|
||||
Analytics.ttsClickModelDetailsLink();
|
||||
}}
|
||||
className="py-2"
|
||||
className="d-flex flex-column flex-lg-row gap-3 direct-view-link zi-2 align-items-lg-center mb-4"
|
||||
>
|
||||
<Trans i18nKey="tts.TtsModelListPage.form.modelSeeMoreLink">
|
||||
See more details about the "
|
||||
<span className="fw-semibold">{{ modelName }}</span>" model by
|
||||
<span className="fw-semibold">{{ userName }}</span>
|
||||
</Trans>{" "}
|
||||
<Gravatar
|
||||
size={15}
|
||||
username={props.maybeSelectedTtsModel.creator_display_name}
|
||||
email_hash={props.maybeSelectedTtsModel.creator_gravatar_hash}
|
||||
/>
|
||||
<div className="flex-grow-1">
|
||||
<p>
|
||||
Model by{" "}
|
||||
<Link to="profile/Vegito1089" className="fw-semibold">
|
||||
{userName}{" "}
|
||||
<Gravatar
|
||||
size={20}
|
||||
username={props.maybeSelectedTtsModel.creator_display_name}
|
||||
email_hash={props.maybeSelectedTtsModel.creator_gravatar_hash}
|
||||
/>
|
||||
</Link>{" "}
|
||||
| <FontAwesomeIcon icon={faGlobe} className="me-2" />
|
||||
Language: <span className="fw-semibold">English</span> | Use count:{" "}
|
||||
<span className="fw-semibold">616400</span>
|
||||
</p>
|
||||
</div>
|
||||
{/* <Trans i18nKey="tts.TtsModelListPage.form.modelSeeMoreLink">
|
||||
See more details
|
||||
</Trans> */}
|
||||
<div className="fw-semibold">
|
||||
<span>See more details</span>
|
||||
<FontAwesomeIcon icon={faChevronRight} className="ms-2" />
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -401,7 +418,7 @@ function TtsModelListPage(props: Props) {
|
||||
setMaybeSelectedTtsModel={props.setMaybeSelectedTtsModel}
|
||||
/>
|
||||
|
||||
<AutocompleteSearch
|
||||
{/* <AutocompleteSearch
|
||||
allTtsCategories={props.allTtsCategories}
|
||||
allTtsModels={props.ttsModels}
|
||||
allTtsModelsByTokenMap={props.allTtsModelsByTokenMap}
|
||||
@@ -411,41 +428,81 @@ function TtsModelListPage(props: Props) {
|
||||
setSelectedCategories={props.setSelectedCategories}
|
||||
maybeSelectedTtsModel={props.maybeSelectedTtsModel}
|
||||
setMaybeSelectedTtsModel={props.setMaybeSelectedTtsModel}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
{directViewLink}
|
||||
|
||||
<div className="text-input">
|
||||
<textarea
|
||||
onClick={() => {
|
||||
Analytics.ttsClickTextInputBox();
|
||||
}}
|
||||
onChange={handleChangeText}
|
||||
className="form-control fs-5"
|
||||
style={{ minHeight: "200px" }}
|
||||
value={props.textBuffer}
|
||||
placeholder={t("tts.TtsModelListPage.form.textInputHint")}
|
||||
></textarea>
|
||||
<div className="row gx-5 gy-5">
|
||||
<div className="col-12 col-lg-6 d-flex flex-column gap-3">
|
||||
<div className="d-flex flex-column gap-3 h-100">
|
||||
<label className="sub-title pb-0">Your Text</label>
|
||||
<textarea
|
||||
onClick={() => {
|
||||
Analytics.ttsClickTextInputBox();
|
||||
}}
|
||||
onChange={handleChangeText}
|
||||
className="form-control text-message h-100"
|
||||
value={props.textBuffer}
|
||||
placeholder={t(
|
||||
"tts.TtsModelListPage.form.textInputHint"
|
||||
)}
|
||||
></textarea>
|
||||
<div className="d-flex gap-3">
|
||||
<button
|
||||
className="btn btn-primary w-100"
|
||||
disabled={remainingCharactersButtonDisabled}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faVolumeHigh}
|
||||
className="me-2"
|
||||
/>
|
||||
{t("tts.TtsModelListPage.form.buttons.speak")}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-destructive w-25"
|
||||
onClick={handleClearClick}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faDeleteLeft}
|
||||
className="me-2"
|
||||
/>
|
||||
{t("tts.TtsModelListPage.form.buttons.clear")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-lg-6">
|
||||
<div className="d-flex flex-column gap-3">
|
||||
<h4 className="text-center text-lg-start">
|
||||
<FontAwesomeIcon
|
||||
icon={faBarsStaggered}
|
||||
className="me-3"
|
||||
/>
|
||||
Session TTS Results
|
||||
</h4>
|
||||
<div className="d-flex flex-column gap-3 session-tts-section">
|
||||
{/* <div className="panel panel-inner text-center p-5 rounded-5">
|
||||
<div className="d-flex flex-column opacity-75 h-100 justify-content-center">
|
||||
<FontAwesomeIcon
|
||||
icon={faHeadphonesSimple}
|
||||
className="fs-3 mb-3"
|
||||
/>
|
||||
<h5 className="fw-semibold">No results yet</h5>
|
||||
<p>Generated audio will appear here.</p>
|
||||
</div>
|
||||
</div> */}
|
||||
<SessionTtsInferenceResultListFc
|
||||
ttsInferenceJobs={props.ttsInferenceJobs}
|
||||
sessionSubscriptionsWrapper={
|
||||
props.sessionSubscriptionsWrapper
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{maybeError}
|
||||
|
||||
<div className="d-flex flex-column flex-md-row w-100 gap-3 mt-3">
|
||||
<button
|
||||
className="btn btn-primary w-100"
|
||||
disabled={remainingCharactersButtonDisabled}
|
||||
>
|
||||
<FontAwesomeIcon icon={faVolumeHigh} className="me-2" />
|
||||
{t("tts.TtsModelListPage.form.buttons.speak")}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-destructive w-100"
|
||||
onClick={handleClearClick}
|
||||
>
|
||||
<FontAwesomeIcon icon={faTrash} className="me-2" />
|
||||
{t("tts.TtsModelListPage.form.buttons.clear")}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -456,11 +513,6 @@ function TtsModelListPage(props: Props) {
|
||||
</div> */}
|
||||
</motion.div>
|
||||
|
||||
<SessionTtsInferenceResultListFc
|
||||
ttsInferenceJobs={props.ttsInferenceJobs}
|
||||
sessionSubscriptionsWrapper={props.sessionSubscriptionsWrapper}
|
||||
/>
|
||||
|
||||
<SessionW2lInferenceResultListFc
|
||||
w2lInferenceJobs={props.w2lInferenceJobs}
|
||||
/>
|
||||
|
||||
@@ -59,7 +59,7 @@ export function TtsPageHero(props: Props) {
|
||||
);
|
||||
viewPricingButton = (
|
||||
<>
|
||||
<Link
|
||||
<Link
|
||||
to="/pricing"
|
||||
onClick={() => {
|
||||
Analytics.ttsClickHeroViewPricing();
|
||||
@@ -79,7 +79,7 @@ export function TtsPageHero(props: Props) {
|
||||
let url = `/profile/${displayName}`;
|
||||
myProfileButton = (
|
||||
<>
|
||||
<Link
|
||||
<Link
|
||||
to={url}
|
||||
onClick={() => {
|
||||
Analytics.ttsClickHeroViewProfile();
|
||||
|
||||
Reference in new issue
Block a user