voice clone page styling

This commit is contained in:
BFlat authored and Brandon Thomas committed 2022-07-10 18:38:31 -04:00
1 parent 997f4aca79
commit 89a97d4846
4 files changed
+411 -293

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

+10 -5
View File
@@ -179,6 +179,10 @@ nav {
}
}
a.top-bar-text:hover {
color: $primary !important;
}
.top-bar {
display: flex;
align-items: center;
@@ -188,7 +192,7 @@ nav {
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
border-bottom: 1px solid;
border-color: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.04);
.top-bar-text {
color: #fff;
@@ -290,10 +294,11 @@ nav {
// padding: 0 15px;
// }
// .git-sha {
// color: #999;
// font-size: 0.8rem;
// }
.git-sha {
color: #999;
font-size: 0.8rem;
margin-top: 10px;
}
// /* TAILWIND STYLE CLASSES */
+7 -5
View File
@@ -21,10 +21,6 @@ a {
}
}
a.top-bar-text:hover {
color: $primary !important;
}
hr {
border: 0;
border-top: 1px solid $white;
@@ -175,7 +171,12 @@ code {
}
.form-text {
color: lighten($primary, 5%);
margin-top: 10px;
color: darken($white, 10%);
&.red {
color: lighten($primary, 5%);
}
}
.alert {
@@ -247,6 +248,7 @@ code {
margin-left: auto;
max-width: 1080px;
border-radius: 8px;
backdrop-filter: blur(5px);
}
.panel {
@@ -1,17 +1,33 @@
import './VoiceCloneRequestPage.css';
import "./VoiceCloneRequestPage.css";
import { v4 as uuidv4 } from 'uuid';
import { faEnvelope, faMicrophone, faRedo, faUser } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React, { useCallback, useEffect, useState } from 'react';
import { faDiscord } from '@fortawesome/free-brands-svg-icons';
import { CreateVoiceCloneApplication, CreateVoiceCloneApplicationIsError, CreateVoiceCloneApplicationIsSuccess, CreateVoiceCloneApplicationRequest } from '@storyteller/components/src/api/clone_requests/CreateVoiceCloneApplicationRequest';
import { CheckVoiceCloneApplication, CheckVoiceCloneApplicationIsError, CheckVoiceCloneApplicationIsSuccess, CheckVoiceCloneApplicationRequest } from '@storyteller/components/src/api/clone_requests/CheckVoiceCloneApplication';
import { Link } from 'react-router-dom';
import { FrontendUrlConfig } from '../../../common/FrontendUrlConfig';
import { v4 as uuidv4 } from "uuid";
import {
faEnvelope,
faMicrophone,
faRedo,
faUser,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React, { useCallback, useEffect, useState } from "react";
import { faDiscord } from "@fortawesome/free-brands-svg-icons";
import {
CreateVoiceCloneApplication,
CreateVoiceCloneApplicationIsError,
CreateVoiceCloneApplicationIsSuccess,
CreateVoiceCloneApplicationRequest,
} from "@storyteller/components/src/api/clone_requests/CreateVoiceCloneApplicationRequest";
import {
CheckVoiceCloneApplication,
CheckVoiceCloneApplicationIsError,
CheckVoiceCloneApplicationIsSuccess,
CheckVoiceCloneApplicationRequest,
} from "@storyteller/components/src/api/clone_requests/CheckVoiceCloneApplication";
import { Link } from "react-router-dom";
import { FrontendUrlConfig } from "../../../common/FrontendUrlConfig";
import { distance, delay, delay2, duration } from "../../../data/animation";
const Fade = require("react-reveal/Fade");
interface Props {
}
interface Props {}
function VoiceCloneRequestPage(props: Props) {
// Contact
@@ -34,7 +50,7 @@ function VoiceCloneRequestPage(props: Props) {
const [isOwnVoice, setIsOwnVoice] = useState(false);
const [isThirdPartyVoice, setIsThirdPartyVoice] = useState(false);
const [notesOnSubject, setNotesOnSubject] = useState("");
// Equipment
const [hasCleanAudioRecordings, setHasCleanAudioRecordings] = useState(false);
const [hasGoodMicrophone, setHasGoodMicrophone] = useState(false);
@@ -48,12 +64,11 @@ function VoiceCloneRequestPage(props: Props) {
const [formWasSubmitted, setFormWasSubmitted] = useState(false);
// Previous form submission state
const [formWasPrevioiuslySubmitted, setFormWasPreviouslySubmitted] = useState(false);
const [formWasPrevioiuslySubmitted, setFormWasPreviouslySubmitted] =
useState(false);
const checkPreviousApplication = useCallback(async () => {
const request : CheckVoiceCloneApplicationRequest = {
};
const request: CheckVoiceCloneApplicationRequest = {};
const response = await CheckVoiceCloneApplication(request);
@@ -78,19 +93,19 @@ function VoiceCloneRequestPage(props: Props) {
const handleSubjectChange = (ev: React.FormEvent<HTMLInputElement>) => {
const value = (ev.target as HTMLInputElement).value;
switch (value) {
case 'mine':
case "mine":
setIsOwnVoice(true);
setIsThirdPartyVoice(false);
break;
case 'family':
case "family":
setIsOwnVoice(false);
setIsThirdPartyVoice(true);
break;
case 'client':
case "client":
setIsOwnVoice(false);
setIsThirdPartyVoice(true);
break;
case '3rd':
case "3rd":
setIsOwnVoice(false);
setIsThirdPartyVoice(true);
break;
@@ -121,7 +136,9 @@ function VoiceCloneRequestPage(props: Props) {
setIsForOther(!isForOther);
};
const handleOptionalNotesOnUseChange = (ev: React.FormEvent<HTMLInputElement>) => {
const handleOptionalNotesOnUseChange = (
ev: React.FormEvent<HTMLInputElement>
) => {
setOptionalNotesOnUse((ev.target as HTMLInputElement).value);
};
@@ -133,7 +150,7 @@ function VoiceCloneRequestPage(props: Props) {
setIsForPublicUse(!isForPublicUse);
};
const handleHasCleanAudioRecordingsChange= () => {
const handleHasCleanAudioRecordingsChange = () => {
setHasCleanAudioRecordings(!hasCleanAudioRecordings);
};
@@ -141,11 +158,15 @@ function VoiceCloneRequestPage(props: Props) {
setHasGoodMicrophone(!hasGoodMicrophone);
};
const handleOptionalExtraCommentsChange = (ev: React.FormEvent<HTMLTextAreaElement>) => {
const handleOptionalExtraCommentsChange = (
ev: React.FormEvent<HTMLTextAreaElement>
) => {
setOptionalExtraComments((ev.target as HTMLTextAreaElement).value);
};
const handleOptionalQuestionsChange = (ev: React.FormEvent<HTMLTextAreaElement>) => {
const handleOptionalQuestionsChange = (
ev: React.FormEvent<HTMLTextAreaElement>
) => {
setOptionalQuestions((ev.target as HTMLTextAreaElement).value);
};
@@ -158,11 +179,13 @@ function VoiceCloneRequestPage(props: Props) {
}
if (!!discord.trim() && !discord.includes("#")) {
setFormErrorMessage("Discord username is invalid. It needs the '#' number.");
setFormErrorMessage(
"Discord username is invalid. It needs the '#' number."
);
return false;
}
let request : CreateVoiceCloneApplicationRequest = {
let request: CreateVoiceCloneApplicationRequest = {
idempotency_token: uuidv4(),
// Contact
@@ -206,7 +229,7 @@ function VoiceCloneRequestPage(props: Props) {
request.optional_extra_comments = optionalExtraComments.trim();
}
const response = await CreateVoiceCloneApplication(request)
const response = await CreateVoiceCloneApplication(request);
if (CreateVoiceCloneApplicationIsSuccess(response)) {
setFormWasSubmitted(true);
@@ -216,33 +239,43 @@ function VoiceCloneRequestPage(props: Props) {
}
return false;
}
};
const header = (
<section className="hero is-small">
<div className="hero-body">
<div className="columns is-vcentered">
<div className="column is-one-third">
<div className="mascot">
<img src="/mascot/kitsune_pose4_black_2000.webp" alt="FakeYou's mascot!" />
<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">
<Fade right distance={distance} duration={duration} delay={delay}>
<img
src="/mascot/kitsune_pose4.png"
className="ani4 load-hidden img-fluid"
width="560"
loading="lazy"
alt="FakeYou Mascot"
/>
</Fade>
</div>
</div>
<div className="col-lg-6 px-md-2 px-lg-5 px-xl-2">
<Fade bottom cascade distance={distance} duration={duration}>
<div className="text-center text-lg-start">
<h1 className="display-5 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">
<h3>Want a Custom Voice You Can Use?</h3>
<p className="lead">
For Music, Videos, Twitch Rewards, API, Friends, Family…
whatever you want!
</p>
</div>
</div>
</div>
<div className="column">
<p className="title is-1">
Professionally Clone Your Voice
</p>
<p className="subtitle is-3">
(or any voice) for just $70
</p>
</div>
</Fade>
</div>
</div>
</section>
</div>
);
if (formWasSubmitted) {
@@ -262,22 +295,24 @@ function VoiceCloneRequestPage(props: Props) {
<Link
to={FrontendUrlConfig.indexPage()}
className="button is-info is-large is-fullwidth is-outlined"
>
Back to home&nbsp;<FontAwesomeIcon icon={faRedo} />
</Link>
>
Back to home&nbsp;
<FontAwesomeIcon icon={faRedo} />
</Link>
</section>
</div>
);
}
let previouslySubmittedNote = <></>;
if (formWasPrevioiuslySubmitted) {
previouslySubmittedNote = (
<>
<article className="message is-warning">
<div className="message-body">
It looks like you've already submitted a request, but feel free to submit another!
It looks like you've already submitted a request, but feel free to
submit another!
<br />
(Especially if you have another voice for us!)
</div>
@@ -301,279 +336,355 @@ function VoiceCloneRequestPage(props: Props) {
return (
<div>
{header}
<section className="section">
<div className="container">
<Fade bottom duration={duration} distance={distance} delay={delay2}>
<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">
{previouslySubmittedNote}
<div className="d-flex flex-column gap-4">
<p>
We have an extremely talented staff that will personally
handle your voice clone request. Please help us understand
more about your voice and how you want to use it, and we'll be
in touch shortly.
</p>
<h1 className="title is-2">Want a Custom Voice You Can Use?</h1>
<h1 className="subtitle is-4">For Music, Videos, Twitch Rewards, API, Friends, Family&hellip; whatever you want!</h1>
<h2>First, how should we get in touch?</h2>
{previouslySubmittedNote}
<div>
<label className="sub-title">Email Address</label>
<div className="form-group input-icon">
<span className="form-control-feedback">
<FontAwesomeIcon icon={faEnvelope} />
</span>
<input
className="form-control"
type="text"
placeholder="Email Address"
value={emailAddress}
onChange={handleEmailAddressChange}
/>
</div>
<p className="form-text"></p>
<p className="form-text red"></p>
</div>
<p>
We have an extremely talented staff that will personally handle your voice clone request.
Please help us understand more about your voice and how you want to use it, and we'll be in touch
shortly.
</p>
<div>
<label className="sub-title">
Discord Username (Optional, but an alternate way to reach
you.)
<br />
</label>
<div className="form-group input-icon">
<span className="form-control-feedback">
<FontAwesomeIcon icon={faDiscord} />
</span>
<input
className="form-control"
type="text"
placeholder="Discord"
value={discord}
onChange={handleDiscordChange}
/>
</div>
<p className="form-text">
Don't forget the <em>#0000</em> part of your username!
</p>
<p className="form-text red"></p>
</div>
<br />
<h1 className="title is-3">First, how should we get in touch?</h1>
<div className="field">
<label className="label">Email Address</label>
<div className="control has-icons-left">
<input
className="input is-medium is-fullwidth"
type="text"
placeholder="Email Address"
value={emailAddress}
onChange={handleEmailAddressChange}
/>
<span className="icon is-small is-left">
<FontAwesomeIcon icon={faEnvelope} />
</span>
<div>
<h2 className="mb-3">Who's voice is this?</h2>
<p>
If it's your voice, you'll be able to do anything you want
with it. If it's another person's voice, you may have limits
on how you can use it (eg. limits on commercialization.)
That doesn't mean we can't help you. Even if you just want
your favorite character so you can make Twitter memes,
that's fine!
</p>
</div>
</div>
</div>
<p className="help is-success"></p>
<p className="help is-danger"></p>
</div>
<div className="field">
<label className="label">
Discord Username (Optional, but an alternate way to reach you.)
<br />
<div className="checkbox-block">
<div className="control">
<label className="radio">
<input
type="radio"
name="subject"
value="mine"
onChange={handleSubjectChange}
/>
&nbsp;My own voice
</label>
<br />
<label className="radio">
<input
type="radio"
name="subject"
value="family"
onChange={handleSubjectChange}
/>
&nbsp;A family member's voice
</label>
<br />
<label className="radio">
<input
type="radio"
name="subject"
value="client"
onChange={handleSubjectChange}
/>
&nbsp;A client's voice
</label>
<br />
<label className="radio">
<input
type="radio"
name="subject"
value="3rd"
onChange={handleSubjectChange}
/>
&nbsp;Another person's voice
</label>
</div>
</div>
<br />
<div className="field">
<label className="label">
If it isn't your voice, tell us about who it is!
</label>
<div className="control has-icons-left">
<input
className="input is-medium is-fullwidth"
type="text"
placeholder="Notes on the person"
value={notesOnSubject}
onChange={handleSubjectNotesChange}
/>
<span className="icon is-small is-left">
<FontAwesomeIcon icon={faUser} />
</span>
</div>
<p className="help is-success"></p>
<p className="help is-danger"></p>
</div>
<br />
<h1 className="title is-3">How will you use it?</h1>
<p>Click as many as you plan to use!</p>
<br />
<div className="checkbox-block">
<label className="checkbox">
<input
type="checkbox"
checked={isForMusic}
onChange={handleIsForMusicChange}
/>
&nbsp;For Music (for creating new songs)
</label>
<br />
</label>
<div className="control has-icons-left">
<input className="input is-medium is-fullwidth"
type="text"
placeholder="Discord"
value={discord}
onChange={handleDiscordChange}
<label className="checkbox">
<input
type="checkbox"
checked={isForGames}
onChange={handleIsForGamesChange}
/>
<span className="icon is-small is-left">
<FontAwesomeIcon icon={faDiscord} />
</span>
&nbsp;For Games (because NPCs won't talk by themselves)
</label>
<br />
<label className="checkbox">
<input
type="checkbox"
checked={isForTwitchTts}
onChange={handleIsForTwitchTtsChange}
/>
&nbsp;For Twitch TTS (creating rewards for my stream, helping me
engage and monetize)
</label>
<br />
<label className="checkbox">
<input
type="checkbox"
checked={isForApiUse}
onChange={handleIsForApiUseChange}
/>
&nbsp;For API use (unlimited use of the FakeYou.com API for
anything you want to build)
</label>
<br />
<label className="checkbox">
<input
type="checkbox"
checked={isForOther}
onChange={handleIsForOtherChange}
/>
&nbsp;Other (Now we're curious!)
</label>
</div>
<p className="help">
Don't forget the <em>#0000</em> part of your username!
<br />
<div className="field">
<label className="label">
Let us know more about your use (optional)
</label>
<div className="control has-icons-left">
<input
className="input is-medium is-fullwidth"
type="text"
placeholder="Optional details"
value={optionalNotesOnUse}
onChange={handleOptionalNotesOnUseChange}
/>
<span className="icon is-small is-left">
<FontAwesomeIcon icon={faEnvelope} />
</span>
</div>
<p className="help is-success"></p>
<p className="help is-danger"></p>
</div>
<br />
<h1 className="title is-3">Do you want it to be private?</h1>
<p>
(We'll accept multiple answers here, because maybe you want to use
it multiple ways.)
</p>
<p className="help is-danger"></p>
</div>
<br />
<br />
<h1 className="title is-3">Who's voice is this?</h1>
<p>If it's your voice, you'll be able to do anything you want with it. If it's another person's voice, you may have
limits on how you can use it (eg. limits on commercialization.) That doesn't mean we can't help you. Even if you
just want your favorite character so you can make Twitter memes, that's fine!</p>
<br />
<div className="checkbox-block">
<div className="control">
<label className="radio">
<input type="radio" name="subject" value="mine" onChange={handleSubjectChange} />
&nbsp;My own voice
<div className="checkbox-block">
<label className="checkbox">
<input type="checkbox" />
&nbsp;This is for private use for just me
</label>
<br />
<label className="radio">
<input type="radio" name="subject" value="family" onChange={handleSubjectChange} />
&nbsp;A family member's voice
</label>
<br />
<label className="radio">
<input type="radio" name="subject" value="client" onChange={handleSubjectChange} />
&nbsp;A client's voice
</label>
<br />
<label className="radio">
<input type="radio" name="subject" value="3rd" onChange={handleSubjectChange} />
&nbsp;Another person's voice
</label>
</div>
</div>
<br />
<div className="field">
<label className="label">If it isn't your voice, tell us about who it is!</label>
<div className="control has-icons-left">
<input
className="input is-medium is-fullwidth"
type="text"
placeholder="Notes on the person"
value={notesOnSubject}
onChange={handleSubjectNotesChange}
<label className="checkbox">
<input
type="checkbox"
checked={isForPrivateUse}
onChange={handleIsForPrivateUseChange}
/>
<span className="icon is-small is-left">
<FontAwesomeIcon icon={faUser} />
</span>
</div>
<p className="help is-success"></p>
<p className="help is-danger"></p>
</div>
&nbsp;This is for private use amongst a group of people
</label>
<br />
<br />
<h1 className="title is-3">How will you use it?</h1>
<p>Click as many as you plan to use!</p>
<br />
<div className="checkbox-block">
<label className="checkbox">
<input type="checkbox" checked={isForMusic} onChange={handleIsForMusicChange} />
&nbsp;For Music (for creating new songs)
</label>
<br />
<label className="checkbox">
<input type="checkbox" checked={isForGames} onChange={handleIsForGamesChange} />
&nbsp;For Games (because NPCs won't talk by themselves)
</label>
<br />
<label className="checkbox">
<input type="checkbox" checked={isForTwitchTts} onChange={handleIsForTwitchTtsChange} />
&nbsp;For Twitch TTS (creating rewards for my stream, helping me engage and monetize)
</label>
<br />
<label className="checkbox">
<input type="checkbox" checked={isForApiUse} onChange={handleIsForApiUseChange} />
&nbsp;For API use (unlimited use of the FakeYou.com API for anything you want to build)
</label>
<br />
<label className="checkbox">
<input type="checkbox" checked={isForOther} onChange={handleIsForOtherChange} />
&nbsp;Other (Now we're curious!)
</label>
</div>
<br />
<div className="field">
<label className="label">Let us know more about your use (optional)</label>
<div className="control has-icons-left">
<input
className="input is-medium is-fullwidth"
type="text"
placeholder="Optional details"
value={optionalNotesOnUse}
onChange={handleOptionalNotesOnUseChange}
<label className="checkbox">
<input
type="checkbox"
checked={isForPublicUse}
onChange={handleIsForPublicUseChange}
/>
<span className="icon is-small is-left">
<FontAwesomeIcon icon={faEnvelope} />
</span>
&nbsp;This is for public use
</label>
</div>
<p className="help is-success"></p>
<p className="help is-danger"></p>
</div>
<br />
<h1 className="title is-3">Do you want it to be private?</h1>
<p>(We'll accept multiple answers here, because maybe you want to use it multiple ways.)</p>
<br />
<div className="checkbox-block">
<label className="checkbox">
<input type="checkbox" />
&nbsp;This is for private use for just me
</label>
<br />
<label className="checkbox">
<input type="checkbox" checked={isForPrivateUse} onChange={handleIsForPrivateUseChange} />
&nbsp;This is for private use amongst a group of people
</label>
<br />
<label className="checkbox">
<input type="checkbox" checked={isForPublicUse} onChange={handleIsForPublicUseChange} />
&nbsp;This is for public use
</label>
</div>
<h1 className="title is-3">How's your audio quality?</h1>
<br />
<h1 className="title is-3">How's your audio quality?</h1>
<p>It's okay if you don't have a quality source of audio, but the results are top notch only with a good recording setup.</p>
<br />
<div className="checkbox-block">
<label className="checkbox">
<input type="checkbox" checked={hasGoodMicrophone} onChange={handleHasGoodMicrophoneChange} />
&nbsp;I have a good microphone (and I know what a condenser microphone is)
</label>
<p>
It's okay if you don't have a quality source of audio, but the
results are top notch only with a good recording setup.
</p>
<br />
<label className="checkbox">
<input type="checkbox" checked={hasCleanAudioRecordings} onChange={handleHasCleanAudioRecordingsChange} />
&nbsp;I have really good preexisting recordings.
</label>
</div>
<div className="checkbox-block">
<label className="checkbox">
<input
type="checkbox"
checked={hasGoodMicrophone}
onChange={handleHasGoodMicrophoneChange}
/>
&nbsp;I have a good microphone (and I know what a condenser
microphone is)
</label>
<br />
<br />
<h1 className="title is-3">Anything else?</h1>
<label className="checkbox">
<input
type="checkbox"
checked={hasCleanAudioRecordings}
onChange={handleHasCleanAudioRecordingsChange}
/>
&nbsp;I have really good preexisting recordings.
</label>
</div>
<br />
<div className="field">
<label className="label">Do you have any questions for us?</label>
<div className="control">
<textarea
className="textarea"
placeholder="Optional Questions"
onChange={handleOptionalQuestionsChange}
value={optionalQuestions}
<h1 className="title is-3">Anything else?</h1>
<div className="field">
<label className="label">Do you have any questions for us?</label>
<div className="control">
<textarea
className="textarea"
placeholder="Optional Questions"
onChange={handleOptionalQuestionsChange}
value={optionalQuestions}
></textarea>
</div>
</div>
</div>
<div className="field">
<label className="label">Do you have any important notes or details?</label>
<div className="control">
<textarea
className="textarea"
placeholder="Optional Notes"
onChange={handleOptionalExtraCommentsChange}
value={optionalExtraComments}
<div className="field">
<label className="label">
Do you have any important notes or details?
</label>
<div className="control">
<textarea
className="textarea"
placeholder="Optional Notes"
onChange={handleOptionalExtraCommentsChange}
value={optionalExtraComments}
></textarea>
</div>
</div>
</div>
<br />
<br />
{errorMessage}
{errorMessage}
<button
className="button is-link is-large is-fullwidth"
onClick={handleSubmit}
<button
className="button is-link is-large is-fullwidth"
onClick={handleSubmit}
>
Clone my voice!&nbsp;<FontAwesomeIcon icon={faMicrophone} />
Clone my voice!&nbsp;
<FontAwesomeIcon icon={faMicrophone} />
</button>
</div>
</div>
</section>
</Fade>
</div>
);
}
export { VoiceCloneRequestPage }
export { VoiceCloneRequestPage };