Merge pull request #561 from storytold/feature/storyteller-prelaunch-landing

storyteller prelaunch landing
This commit is contained in:
Brandon Thomas authored and GitHub committed 2024-05-13 22:36:00 -07:00
commit 10e95365ce
5 files changed
+376 -48

No files matched your search

@@ -188,6 +188,22 @@ export default function TopNav({
// { id: 4, name: "Text to Image", link: "/text-to-image" },
];
useEffect(() => {
const pageContentWrapper = document.getElementById("page-content-wrapper");
if (pageContentWrapper) {
if (domain.titlePart === "Storyteller AI" && isOnLandingPage) {
pageContentWrapper.style.padding = "0px";
} else {
pageContentWrapper.style.padding = "";
}
}
}, [domain.titlePart, isOnLandingPage]);
if (domain.titlePart === "Storyteller AI" && isOnLandingPage) {
return null;
}
return (
<div
id="topbar-wrapper"
@@ -384,8 +384,7 @@ class PageContainer extends React.Component<
</Route>
<Route path="/media/rename/:media_file_token">
<MediaRenamePage
/>
<MediaRenamePage />
</Route>
<Route path="/media/:token">
@@ -681,7 +680,9 @@ class PageContainer extends React.Component<
</Route>
<Route path="/moderation">
<ModerationPage sessionWrapper={this.props.sessionWrapper} />
<ModerationPage
sessionWrapper={this.props.sessionWrapper}
/>
</Route>
<Route exact={true} path="/clone">
@@ -7,7 +7,7 @@ import { Container } from "components/common";
import FakeYouLandingHeader from "./fakeyou/FakeYouLandingHeader";
import Dashboard from "./Dashboard";
import { useDomainConfig } from "context/DomainConfigContext";
import LandingVideoReel from "./components/LandingVideoReel/LandingVideoReel";
// import LandingVideoReel from "./components/LandingVideoReel/LandingVideoReel";
import {
FrontendInferenceJobType,
InferenceJob,
@@ -17,9 +17,13 @@ import "./LandingPage.scss";
// import VstSectionV1 from "./components/VstSectionV1";
import VstSectionV2 from "./components/VstSectionV2";
import FakeYouLandingBody from "./fakeyou/FakeYouLandingBody";
import { WebsiteConfig, Website } from "@storyteller/components/src/env/GetWebsite";
import {
WebsiteConfig,
Website,
} from "@storyteller/components/src/env/GetWebsite";
import OnboardingSelection from "./storyteller/OnboardingSelection";
import TtsDemoSection from "./components/TtsDemoSection/TtsDemoSection";
// import TtsDemoSection from "./components/TtsDemoSection/TtsDemoSection";
import PrelaunchLanding from "./storyteller/PrelaunchLanding/PrelaunchLanding";
interface Props {
sessionWrapper: SessionWrapper;
@@ -62,56 +66,58 @@ function LandingPage(props: Props) {
return (
<>
{domain.website === Website.StorytellerAi && (
<LandingVideoReel sessionWrapper={props.sessionWrapper} />
// <LandingVideoReel sessionWrapper={props.sessionWrapper} />
<PrelaunchLanding />
)}
<Container type="panel">
{domain.website === Website.FakeYou ? (
<>
{/* FAKEYOU.COM */}
{!isLoggedIn && (
<>
<FakeYouLandingHeader
sessionWrapper={props.sessionWrapper}
sessionSubscriptionsWrapper={
props.sessionSubscriptionsWrapper
}
inferenceJobs={props.inferenceJobs}
ttsInferenceJobs={props.ttsInferenceJobs}
enqueueInferenceJob={props.enqueueInferenceJob}
inferenceJobsByCategory={props.inferenceJobsByCategory}
enqueueTtsJob={props.enqueueTtsJob}
/>
{/* <VstSectionV1 /> */}
<VstSectionV2 />
</>
)}
{
domain.website === Website.FakeYou ? (
<>
{/* FAKEYOU.COM */}
{!isLoggedIn && (
<>
<FakeYouLandingHeader
sessionWrapper={props.sessionWrapper}
sessionSubscriptionsWrapper={
props.sessionSubscriptionsWrapper
}
inferenceJobs={props.inferenceJobs}
ttsInferenceJobs={props.ttsInferenceJobs}
enqueueInferenceJob={props.enqueueInferenceJob}
inferenceJobsByCategory={props.inferenceJobsByCategory}
enqueueTtsJob={props.enqueueTtsJob}
/>
{/* <VstSectionV1 /> */}
<VstSectionV2 />
</>
)}
<Dashboard sessionWrapper={props.sessionWrapper} />
<Dashboard sessionWrapper={props.sessionWrapper} />
{!isLoggedIn && <FakeYouLandingBody />}
</>
) : (
<>
{/* STORYTELLER,AI */}
{!isLoggedIn && <FakeYouLandingBody />}
</>
) : null
// <>
// {/* STORYTELLER,AI */}
{protectedStudioOnboarding}
// {protectedStudioOnboarding}
<VstSectionV2 />
<TtsDemoSection
sessionWrapper={props.sessionWrapper}
sessionSubscriptionsWrapper={props.sessionSubscriptionsWrapper}
inferenceJobs={props.inferenceJobs}
ttsInferenceJobs={props.ttsInferenceJobs}
enqueueInferenceJob={props.enqueueInferenceJob}
inferenceJobsByCategory={props.inferenceJobsByCategory}
enqueueTtsJob={props.enqueueTtsJob}
/>
// <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} />
// <Dashboard sessionWrapper={props.sessionWrapper} />
<FakeYouLandingBody />
</>
)}
// <FakeYouLandingBody />
// </>
}
</Container>
</>
);
@@ -0,0 +1,121 @@
@import "scss/colours.scss";
.grid-container {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: repeat(7, calc(100vw / 7 * (9 / 16)));
gap: 16px;
padding: 16px;
position: relative;
@media (max-width: 992px) {
grid-template-columns: repeat(5, 1fr);
grid-template-rows: repeat(5, calc(100vw / 5 * (9 / 16)));
gap: 16px;
padding: 16px;
}
@media (max-width: 768px) {
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, calc(100vw / 3 * (9 / 16)));
gap: 12px;
padding: 12px;
}
}
.grid-item {
position: relative;
background-color: rgba($white, 0.06);
display: flex;
align-items: center;
justify-content: center;
border-radius: 0.5rem;
overflow: hidden;
transition: transform 0.2s;
pointer-events: all;
border: none;
&:hover {
transform: scale(1.1);
}
&.double-grid {
grid-column: span 2;
}
&.triple-grid {
grid-column: span 3;
height: 6rem;
}
&.grid-item-custom {
overflow: visible;
position: relative;
&:hover {
transform: none;
}
}
img {
cursor: pointer;
}
.logo {
position: absolute;
left: 0;
top: 0;
margin-left: 20%;
margin-top: 10%;
width: 270%;
cursor: default;
@media (max-width: 992px) {
margin-left: 22%;
margin-top: 15%;
}
}
.waitlist-button {
position: absolute;
left: 0;
top: 0;
margin-left: 10%;
margin-top: 4%;
font-size: 20px;
font-weight: 500;
color: #fff;
background-color: $primary;
border-radius: 50px;
cursor: pointer;
transition: all 0.2s;
width: 84%;
padding: 2.5%;
border: 4px solid lighten($primary, 12%);
box-shadow: 0 0 15px rgba(255, 255, 255, 0.7); // Soft white glow
animation: glow 1.5s infinite alternate;
&:hover {
background-color: lighten($primary, 5%);
}
@media (max-width: 992px) {
margin-left: 8%;
margin-top: 2%;
}
}
@keyframes glow {
from {
box-shadow: 0 0 50px rgba(255, 170, 168, 0.25);
}
to {
box-shadow: 0 0 25px rgba(255, 170, 168, 0.5);
}
}
}
.grid-item.blank {
background-color: transparent;
border: none;
}
@@ -0,0 +1,184 @@
import React, { useEffect, useState } from "react";
import "./PrelaunchLanding.scss";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowRight } from "@fortawesome/pro-solid-svg-icons";
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
interface MediaItem {
token: string;
public_bucket_path: string;
maybe_creator: {
username: string;
};
}
const PrelaunchLanding: React.FC = () => {
const totalGrids = 63;
const [mediaItems, setMediaItems] = useState<MediaItem[]>([]);
const [blankGrids, setBlankGrids] = useState<number[]>([15, 16, 17, 22, 23]);
const [screenSize, setScreenSize] = useState("lg");
useEffect(() => {
fetchMediaItems();
updateGridsForScreenSize();
window.addEventListener("resize", updateGridsForScreenSize);
return () => window.removeEventListener("resize", updateGridsForScreenSize);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const updateGridsForScreenSize = () => {
const screenWidth = window.innerWidth;
if (screenWidth < 768) {
setBlankGrids([7, 8, 9, 10, 11, 12]);
setScreenSize("sm");
} else if (screenWidth < 992) {
setBlankGrids([12, 13, 14, 17, 18, 19]);
setScreenSize("md");
} else {
setBlankGrids([15, 16, 17, 22, 23]);
setScreenSize("lg");
}
};
const getCustomGridItemIndex = () => {
switch (screenSize) {
case "lg":
return 15;
case "md":
return 12;
case "sm":
return 7;
default:
return 15;
}
};
const fetchMediaItems = async () => {
try {
const response = await fetch(
"https://api.storyteller.ai/v1/media_files/list_featured?page_size=63&filter_media_classes=video"
);
const data = await response.json();
if (data.success) {
setMediaItems(shuffleArray(data.results));
}
} catch (error) {
console.error("Error fetching media items:", error);
}
};
const shuffleArray = (array: any[]) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
};
const renderGridItems = () => {
const gridItems = [];
const customGridItemIndex = getCustomGridItemIndex();
for (let i = 1; i <= totalGrids; i++) {
const isBlank = blankGrids.includes(i);
if (screenSize === "sm") {
if (i === 10) {
gridItems.push(
<div
key="10-12"
className={`grid-item triple-grid grid-item-custom ${
isBlank ? "blank" : ""
}`}
>
<button className="waitlist-button">
Join the Waitlist
<FontAwesomeIcon icon={faArrowRight} className="ms-2 fs-6" />
</button>
</div>
);
i += 2;
continue;
}
} else if (screenSize === "md") {
if (i === 17) {
gridItems.push(
<div
key="17-19"
className={`grid-item triple-grid grid-item-custom ${
isBlank ? "blank" : ""
}`}
>
<button className="waitlist-button">
Join the Waitlist
<FontAwesomeIcon icon={faArrowRight} className="ms-2 fs-6" />
</button>
</div>
);
i += 2;
continue;
}
} else {
if (i === 22) {
gridItems.push(
<div
key="22-23"
className={`grid-item double-grid grid-item-custom ${
isBlank ? "blank" : ""
}`}
>
<button className="waitlist-button">
Join the Waitlist
<FontAwesomeIcon icon={faArrowRight} className="ms-2 fs-6" />
</button>
</div>
);
i++;
continue;
}
}
const mediaItem = mediaItems[i - 1];
const bucketConfig = new BucketConfig();
const gifUrl = mediaItem
? bucketConfig.getCdnUrl(
mediaItem.public_bucket_path + "-thumb.gif",
360,
20
)
: "";
gridItems.push(
<div
key={i}
className={`grid-item ${isBlank ? "blank" : ""} ${
i === customGridItemIndex ? "grid-item-custom" : ""
}`.trim()}
>
{isBlank ? (
i === customGridItemIndex ? (
<img
className="logo"
src="/fakeyou/Storyteller-Logo-1.png"
alt="Storyteller Logo"
/>
) : null
) : mediaItem ? (
<img
onClick={() =>
window.open(`https://storyteller.ai/media/${mediaItem.token}`)
}
src={gifUrl}
className="w-100 h-100 object-fit-cover"
alt={`Video by ${mediaItem.maybe_creator.username}`}
/>
) : null}
</div>
);
}
return gridItems;
};
return <div className="grid-container">{renderGridItems()}</div>;
};
export default PrelaunchLanding;