landing page sections updated

This commit is contained in:
BFlat committed 2024-03-12 12:50:44 +07:00
1 parent 9aca012998
commit e4e78037f4
13 files changed
+310 -281

No files matched your search

@@ -87,6 +87,17 @@
&:hover .card-video-play {
color: rgba($white, 0.7);
}
&.card-hover-border-red {
&:hover {
border: 1px solid $primary;
}
}
&.bottom-text-hover {
background-color: lighten($panel-inner, 2%);
border: 1px solid $primary;
}
}
h6 {
@@ -97,3 +108,14 @@
overflow: hidden;
}
}
.card-bottom-text {
padding-top: 0.75rem;
cursor: pointer;
}
.centered-row {
display: flex;
justify-content: center;
flex-wrap: wrap;
}
@@ -1,4 +1,4 @@
import React from "react";
import React, { useState } from "react";
import "./Card.scss";
interface CardProps {
@@ -8,6 +8,12 @@ interface CardProps {
canHover?: boolean;
onMouseEnter?: () => void;
onMouseLeave?: () => void;
backgroundImage?: string;
height?: string;
borderWidth?: string;
hoverPrimaryColor?: true;
aspectRatio?: string;
bottomText?: string;
}
export default function Card({
@@ -17,17 +23,48 @@ export default function Card({
canHover,
onMouseEnter,
onMouseLeave,
backgroundImage,
height,
borderWidth,
hoverPrimaryColor,
aspectRatio = "auto",
bottomText,
}: CardProps) {
const [textHovered, setTextHovered] = useState(false);
return (
<div
className={`card ${padding ? "p-3" : ""} ${
onClick || canHover ? "card-clickable" : ""
}`}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
{children}
</div>
<>
<div
className={`card ${padding ? "p-3" : ""} ${
onClick || canHover ? "card-clickable" : ""
} ${hoverPrimaryColor ? "card-hover-border-red" : ""} ${
textHovered ? "bottom-text-hover" : ""
}`.trim()}
style={{
backgroundImage: `url(${backgroundImage})`,
backgroundSize: "cover",
backgroundPosition: "center",
height: height || "auto",
borderWidth: borderWidth || "1px",
borderStyle: "solid",
aspectRatio: aspectRatio || "auto",
}}
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
{children}
</div>
{bottomText && (
<h6
className="card-bottom-text"
onClick={onClick}
onMouseEnter={() => setTextHovered(true)}
onMouseLeave={() => setTextHovered(false)}
>
{bottomText}
</h6>
)}
</>
);
}
@@ -4,20 +4,20 @@ export enum Website {
}
export interface DomainConfig {
website: Website,
logo: string,
title: string,
link: string,
website: Website;
logo: string;
title: string;
link: string;
}
const domainConfigs: Record<string, DomainConfig> = {
"storyteller": {
fakeyou: {
website: Website.StorytellerAi,
logo: "/fakeyou/Storyteller-Logo-1.png",
title: "Storyteller AI",
link: "https://storyteller.ai",
},
"fakeyou": {
storyteller: {
website: Website.FakeYou,
logo: "/fakeyou/FakeYou-Logo-2.png",
title: "FakeYou",
@@ -35,7 +35,7 @@ export const getCurrentDomainConfig = (): DomainConfig => {
}
if (window.location.hostname.includes("storyteller")) {
return domainConfigs.storyteller;
return domainConfigs.storyteller;
}
// Default fallback
@@ -2,14 +2,12 @@ import React from "react";
import { usePrefixedDocumentTitle } from "../../../../common/UsePrefixedDocumentTitle";
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
import {} from "@fortawesome/pro-solid-svg-icons";
import { PosthogClient } from "@storyteller/components/src/analytics/PosthogClient";
import { Container } from "components/common";
import FakeYouLandingHeader from "./fakeyou/FakeYouLandingHeader";
import Dashboard from "./Dashboard";
import { useDomainConfig } from "context/DomainConfigContext";
import StorytellerLanding from "./storyteller/StorytellerLanding";
import LandingVideoReel from "./components/LandingVideoReel";
import LandingVideoReel from "./components/LandingVideoReel/LandingVideoReel";
import {
FrontendInferenceJobType,
InferenceJob,
@@ -20,6 +18,8 @@ import "./LandingPage.scss";
import VstSectionV2 from "./components/VstSectionV2";
import FakeYouLandingBody from "./fakeyou/FakeYouLandingBody";
import { DomainConfig, Website } from "utils/domainConfig";
import OnboardingSelection from "./storyteller/OnboardingSelection";
import TtsDemoSection from "./components/TtsDemoSection/TtsDemoSection";
interface Props {
sessionWrapper: SessionWrapper;
@@ -39,13 +39,15 @@ function LandingPage(props: Props) {
PosthogClient.recordPageview();
const domain : DomainConfig = useDomainConfig();
const domain: DomainConfig = useDomainConfig();
const isLoggedIn = props.sessionWrapper.isLoggedIn();
return (
<>
{domain.website === Website.StorytellerAi && !isLoggedIn && <LandingVideoReel />}
{domain.website === Website.StorytellerAi && !isLoggedIn && (
<LandingVideoReel />
)}
<Container type="panel">
{domain.website === Website.FakeYou ? (
<>
@@ -76,15 +78,23 @@ function LandingPage(props: Props) {
<>
{/* STORYTELLER,AI */}
{!isLoggedIn ? (
<StorytellerLanding
sessionWrapper={props.sessionWrapper}
sessionSubscriptionsWrapper={props.sessionSubscriptionsWrapper}
inferenceJobs={props.inferenceJobs}
ttsInferenceJobs={props.ttsInferenceJobs}
enqueueInferenceJob={props.enqueueInferenceJob}
inferenceJobsByCategory={props.inferenceJobsByCategory}
enqueueTtsJob={props.enqueueTtsJob}
/>
<>
<OnboardingSelection />
<VstSectionV2 />
<TtsDemoSection
sessionWrapper={props.sessionWrapper}
sessionSubscriptionsWrapper={
props.sessionSubscriptionsWrapper
}
inferenceJobs={props.inferenceJobs}
ttsInferenceJobs={props.ttsInferenceJobs}
enqueueInferenceJob={props.enqueueInferenceJob}
inferenceJobsByCategory={props.inferenceJobsByCategory}
enqueueTtsJob={props.enqueueTtsJob}
/>
<Dashboard sessionWrapper={props.sessionWrapper} />
<FakeYouLandingBody />
</>
) : (
<Dashboard sessionWrapper={props.sessionWrapper} />
)}
@@ -0,0 +1,34 @@
@import "scss/colours.scss";
.storyteller-landing-reel {
display: flex;
height: 74vh;
justify-content: center;
position: relative;
video {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
}
.reel-overlay {
z-index: 0;
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(20, 20, 27, 0.6);
&:after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 20%;
background: linear-gradient(transparent, $bg);
z-index: 1;
}
}
}
@@ -1,5 +1,7 @@
import { faArrowRight } from "@fortawesome/pro-solid-svg-icons";
import { Button } from "components/common";
import React, { useEffect } from "react";
import "./LandingVideoReel.scss";
interface LandingVideoReelProps {}
@@ -42,27 +44,30 @@ export default function LandingVideoReel(props: LandingVideoReelProps) {
}, [isOnLandingPage]);
return (
<div className="vh-100 d-flex align-items-center justify-content-center position-relative">
<video
autoPlay
muted
loop
className="position-absolute w-100 h-100"
style={{ objectFit: "cover" }}
>
<div className="storyteller-landing-reel">
<video autoPlay muted loop>
<source src="/videos/landing-reel.mp4" type="video/mp4" />
</video>
<div
className="position-absolute w-100 h-100"
style={{ backgroundColor: "rgba(20, 20, 27, 0.6)", zIndex: 0 }}
/>
<div className="text-center text-white d-flex flex-column align-items-center zi-2">
<h1 className="display-2 fw-bolder">Enabling Anyone to Make Professional Film, Animation, and Music</h1>
<h5 className="fw-normal mb-3 mt-2 w-75 lh-base opacity-75">
StorytellerAI's powerful new engine combines Generative AI and
User Generated Content to radically democratize both audio and video production.
</h5>
<Button label="Sign Up Now" to="/signup" className="mt-5" />
<div className="reel-overlay">
<div className="container h-100">
<div className="text-center text-white d-flex flex-column justify-content-center align-items-center zi-2 h-100">
<h1 className="display-3 fw-bold">
Enabling Anyone to Make Professional Film, Animation, and Music
</h1>
<h5 className="fw-normal mb-2 mt-2 w-75 lh-base opacity-75">
StorytellerAI's powerful new engine combines Generative AI and
User Generated Content to radically democratize both audio and
video production.
</h5>
<Button
icon={faArrowRight}
iconFlip={true}
label="Sign Up Now"
to="/signup"
className="mt-4"
/>
</div>
</div>
</div>
</div>
);
@@ -0,0 +1 @@
export { default } from "./LandingVideoReel";
@@ -0,0 +1,60 @@
import { faArrowRight } from "@fortawesome/pro-solid-svg-icons";
import { Button, Panel } from "components/common";
import React from "react";
import LandingDemo from "../../fakeyou/LandingDemo/FakeYouLandingDemo";
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
import {
FrontendInferenceJobType,
InferenceJob,
} from "@storyteller/components/src/jobs/InferenceJob";
import { TtsInferenceJob } from "@storyteller/components/src/jobs/TtsInferenceJobs";
interface TtsDemoSectionProps {
sessionWrapper: SessionWrapper;
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
inferenceJobs: Array<InferenceJob>;
ttsInferenceJobs: Array<TtsInferenceJob>;
enqueueInferenceJob: (
jobToken: string,
frontendInferenceJobType: FrontendInferenceJobType
) => void;
inferenceJobsByCategory: Map<FrontendInferenceJobType, Array<InferenceJob>>;
enqueueTtsJob: (jobToken: string) => void;
}
export default function TtsDemoSection(props: TtsDemoSectionProps) {
return (
<Panel clear={true}>
<div className="row g-4 section">
<div className="col-12 col-lg-6 d-flex flex-column justify-content-center">
<h1 className="fw-bold">Generate Text to Speech</h1>
<p className="opacity-75 mb-0">
Create audio of any character saying anything you want.
</p>
<div className="d-flex mt-4">
<Button
label="Try all 3000+ TTS Voices"
icon={faArrowRight}
iconFlip={true}
to="/tts"
small={true}
/>
</div>
</div>
<div className="col-12 col-lg-6">
<LandingDemo
inferenceJobs={props.inferenceJobs}
sessionSubscriptionsWrapper={props.sessionSubscriptionsWrapper}
enqueueInferenceJob={props.enqueueInferenceJob}
inferenceJobsByCategory={props.inferenceJobsByCategory}
ttsInferenceJobs={props.ttsInferenceJobs}
enqueueTtsJob={props.enqueueTtsJob}
showHanashi={false}
autoFocusTextBox={false}
/>
</div>
</div>
</Panel>
);
}
@@ -79,7 +79,7 @@ export default function FakeYouLandingBody(props: FakeYouLandingBodyProps) {
<img
src="/images/landing/bg-dots.webp"
alt="background dots"
className="dots-left-bottom me-3"
className="dots-right-bottom me-3"
/>
</div>
</div>
@@ -35,6 +35,8 @@ interface TtsInferencePanelProps {
) => void;
inferenceJobsByCategory: Map<FrontendInferenceJobType, Array<InferenceJob>>;
enqueueTtsJob: (jobToken: string) => void;
showHanashi?: boolean;
autoFocusTextBox?: boolean;
}
export default function LandingDemo({
@@ -44,6 +46,8 @@ export default function LandingDemo({
enqueueInferenceJob,
enqueueTtsJob,
inferenceJobsByCategory,
showHanashi = true,
autoFocusTextBox = true,
}: TtsInferencePanelProps) {
const [textBuffer, setTextBuffer] = useState("");
const [maybeTtsError, setMaybeTtsError] = useState<
@@ -221,18 +225,21 @@ export default function LandingDemo({
return (
<div className="position-relative">
<img
src={
isHanashiHovered
? "/images/landing/hanashi-demo-2.webp"
: "/images/landing/hanashi-demo-1.webp"
}
alt="Hanashi Demo"
onMouseEnter={() => setIsHanashiHovered(true)}
onMouseLeave={() => setIsHanashiHovered(false)}
className="hanashi-demo-image"
draggable="false"
/>
{showHanashi && (
<img
src={
isHanashiHovered
? "/images/landing/hanashi-demo-2.webp"
: "/images/landing/hanashi-demo-1.webp"
}
alt="Hanashi Demo"
onMouseEnter={() => setIsHanashiHovered(true)}
onMouseLeave={() => setIsHanashiHovered(false)}
className="hanashi-demo-image"
draggable="false"
/>
)}
<Panel padding={true}>
<form className="d-flex flex-column">
<div>
@@ -265,7 +272,7 @@ export default function LandingDemo({
onChange={handleChangeText}
rows={4}
resize={false}
autoFocus={isMobile ? false : true}
autoFocus={isMobile ? false : autoFocusTextBox ? true : false}
/>
</div>
@@ -0,0 +1,67 @@
import { Panel } from "components/common";
import Card from "components/common/Card";
import React from "react";
import { useHistory } from "react-router-dom";
interface OnboardingSelectionProps {}
export default function OnboardingSelection(props: OnboardingSelectionProps) {
const history = useHistory();
const cards = [
{
text: "Scene 1",
backgroundImage: "",
onClick: () => {
history.push("/studio-intro/");
},
},
{
text: "Scene 2",
backgroundImage: "",
onClick: () => {
history.push("/studio-intro/");
},
},
{
text: "Scene 3",
backgroundImage: "",
onClick: () => {
history.push("/studio-intro/");
},
},
{
text: "Scene 4",
backgroundImage: "",
onClick: () => {
history.push("/studio-intro/");
},
},
];
return (
<Panel clear={true}>
<div className="text-center my-5 pb-5">
<h1 className="fw-bold">Explore scene examples</h1>
<p className="opacity-75">
Try generating a movie by clicking a scene below
</p>
<div className="row g-3 g-lg-4 mt-3 centered-row">
{cards.map((card, index) => (
<div className="col-6 col-lg-3" key={index}>
<Card
backgroundImage={card.backgroundImage}
aspectRatio="16/9"
canHover={true}
borderWidth="2px"
hoverPrimaryColor={true}
onClick={card.onClick}
bottomText={card.text}
/>
</div>
))}
</div>
</div>
</Panel>
);
}
@@ -0,0 +1 @@
export { default } from "./OnboardingSelection";
@@ -31,220 +31,5 @@ export default function StorytellerLanding({
}: StorytellerLandingProps) {
// const { t } = useLocalize("LandingPage");
return (
<>
{/* <Container type="panel" className="py-5">
<FakeYouLandingHeader
sessionWrapper={sessionWrapper}
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
inferenceJobs={inferenceJobs}
ttsInferenceJobs={ttsInferenceJobs}
enqueueInferenceJob={enqueueInferenceJob}
inferenceJobsByCategory={inferenceJobsByCategory}
enqueueTtsJob={enqueueTtsJob}
/>
{/* <Container type="panel" className="py-5">
<Panel clear={true} className="py-lg-5">
<div className="row g-5 g-lg-5 flex-row-reverse">
<div className="col-12 col-md-6">
<div className="position-relative">
<div className="ratio ratio-16x9 video-container">
<video
autoPlay={true}
playsInline={true}
loop={true}
muted={true}
>
<source src="/videos/tts-video.mp4" type="video/mp4" />
</video>
</div>
<img
src="/images/landing/bg-dots.webp"
alt="background dots"
className="dots-right-bottom"
/>
</div>
</div>
<div className="col-12 col-md-6 d-flex flex-column justify-content-center text-center text-lg-start gap-2">
<h1 className="fw-bold display-5">
Enabling Anyone to Create Quality Movies with AI
</h1>
<p className="opacity-75">
We are combining generative AI and User Generated Content to
radically democratize both audio and video production.
</p>
<div className="d-flex mt-3 mt-lg-4 gap-3 justify-content-center justify-content-lg-start">
<Button
icon={faArrowRight}
iconFlip={true}
label="Sign Up"
to="/signup"
/>
<Button
icon={faCompass}
label="Explore"
variant="secondary"
to="/explore"
/>
</div>
</div>
</div>
</Panel>
</Container> */}
{/* <div className="panel rounded-0 py-5 my-5">
<Container type="panel" className="py-lg-5">
<Panel clear={true}>
<div className="d-flex flex-column align-items-center rounded-0 mt-lg-4 pt-lg-4">
<div className="d-flex flex-column align-items-center text-center cta-container">
<h2 className="fw-bold">AI Audio Generation</h2>
<p className="mw-300 opacity-75">{t("ctaText")}</p>
<div className="d-flex d-lg-none align-items-center mt-2 cta-mobile">
<img
src="/images/landing/hanashi-before.webp"
alt="hanashi before"
width={200}
height={200}
/>
<img
src="/images/landing/chevrons-red.webp"
alt="red chevrons"
width={95}
height={80}
/>
<img
src="/images/landing/hanashi-after.webp"
alt="hanashi after"
width={200}
height={200}
/>
</div>
<img
src="/images/landing/hanashi-before.webp"
alt="hanashi before"
className="hanashi-before d-none d-lg-block"
width={311}
height={311}
/>
<img
src="/images/landing/chevrons-grey.webp"
alt="grey chevrons"
className="chevrons-grey d-none d-lg-block"
width={127}
height={108}
/>
<img
src="/images/landing/chevrons-red.webp"
alt="red chevrons"
className="chevrons-red d-none d-lg-block"
width={127}
height={108}
/>
<img
src="/images/landing/hanashi-after.webp"
alt="hanashi after"
className="hanashi-after d-none d-lg-block"
width={311}
height={311}
/>
</div>
</div>
<div className="row gy-4 mt-lg-3">
<div className="col-12 col-md-6">
<Panel padding={true} className="panel-inner rounded h-100">
<div className="d-flex gap-2">
<h4 className="fw-semibold mb-4 flex-grow-1">
<FontAwesomeIcon icon={faMessageDots} className="me-3" />
Text to Speech
</h4>
<Link to="/tts">
Try more voices{" "}
<FontAwesomeIcon icon={faArrowRight} className="ms-1" />
</Link>
</div>
<div className="d-flex flex-column gap-3">
<Select label="Select a Voice" />
<Input
label="Your Text"
placeholder="Type what you want your character to say"
/>
<div className="d-flex gap-2 justify-content-end">
<Button
label="Generate"
icon={faArrowRight}
iconFlip={true}
/>
</div>
</div>
</Panel>
</div>
<div className="col-12 col-md-6">
<Panel padding={true} className="panel-inner rounded h-100">
<div className="d-flex gap-2">
<h4 className="fw-semibold mb-4 flex-grow-1">
<FontAwesomeIcon
icon={faWaveformLines}
className="me-3"
/>
Voice to Voice
</h4>
<Link to="/voice-conversion">
Try more voices{" "}
<FontAwesomeIcon icon={faArrowRight} className="ms-1" />
</Link>
</div>
<div className="d-flex flex-column gap-3">
<Select label="Select a Voice" />
<div className="d-flex gap-2 justify-content-end">
<Button
label="Generate"
icon={faArrowRight}
iconFlip={true}
/>
</div>
</div>
</Panel>
</div>
</div>
</Panel>
</Container>
</div> */}
{/* <Container type="panel" className="pt-5 my-5">
<Panel padding={true}>
<div className="d-flex flex-column align-items-center py-5">
<h2 className="fw-bold mb-2">{t("communityTitle")}</h2>
<p className="opacity-75">{t("communityText")}</p>
<div className="d-flex mt-4 gap-3">
<a
href="https://discord.gg/fakeyou"
target="_blank"
rel="noreferrer"
className="btn btn-discord"
>
<FontAwesomeIcon icon={faDiscord} className="me-2" />
{t("communityButtonDiscord")}
</a>
<a
href="https://twitter.com/intent/follow?screen_name=FakeYouApp"
target="_blank"
rel="noreferrer"
className="btn btn-twitter"
>
<FontAwesomeIcon icon={faTwitter} className="me-2" />
{t("communityButtonTwitter")}
</a>
</div>
</div>
<img
src="/images/landing/bg-dots.webp"
alt="background dots"
className="dots-left-bottom me-3"
/>
</Panel>
</Container> */}
</>
);
return <>Test</>;
}