Skip to content

Commit

Permalink
watch
Browse files Browse the repository at this point in the history
  • Loading branch information
noahgsolomon committed May 14, 2024
1 parent 7280aee commit 15adfa9
Show file tree
Hide file tree
Showing 6 changed files with 350 additions and 49 deletions.
70 changes: 25 additions & 45 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import { toast } from "sonner";
import {
Coins,
Crown,
Eye,
Folder,
Gem,
Github,
HeartCrack,
Loader2,
Skull,
Star,
StarIcon,
Wand,
Expand Down Expand Up @@ -155,58 +157,21 @@ export default function Home({
alt="brainrot"
className="cursor-pointer rounded-full border-[10px] border-card shadow-lg transition-all hover:scale-[101%] active:scale-[99%] dark:border-primary"
/>
<div className=" flex flex-col items-center gap-2">
<Badge
className="cursor-pointer text-sm md:hidden"
variant={userDB?.user?.subscribed ? "hard" : "blue"}
>
<Link
target="_blank"
className="flex flex-row items-center gap-2"
href={"https://github.com/noahgsolomon/brainrot.js"}
>
{userDB?.user?.subscribed ? (
<>
PRO <Gem className="size-4 fill-teal-500" />
</>
) : (
<>
Free Mode <HeartCrack className="size-4 fill-red-500" />
</>
)}
</Link>
</Badge>

<div className=" flex flex-col items-center gap-2">
<h1 className="relative max-w-[10ch] text-center text-5xl font-bold lg:text-6xl">
BRAINROT.JS
<Badge
className="absolute -top-8 hidden cursor-pointer text-sm md:-right-12 md:block"
variant={userDB?.user?.subscribed ? "hard" : "blue"}
>
<Link
className="flex flex-row items-center gap-2"
target="_blank"
href={"https://github.com/noahgsolomon/brainrot.js"}
>
{userDB?.user?.subscribed ? (
<>
PRO <Gem className="size-4 fill-teal-500" />
</>
) : (
<>
Free Mode <HeartCrack className="size-4 fill-red-500" />
</>
)}
</Link>
</Badge>
<p className="flex w-full flex-row items-center justify-center gap-1 p-2 text-sm font-normal italic">
5,000+ videos generated 💀
</p>
</h1>

<p className="max-w-[30ch] text-sm italic">
<Link
href={"https://github.com/noahgsolomon/brainrot.js"}
className="flex flex-col items-center gap-1 font-bold "
>
now open source!
<div className="flex flex-row items-center gap-2 underline transition-all hover:text-primary/80">
<div className="flex flex-row items-center gap-2 rounded-lg border border-yellow-500/60 bg-yellow-500/20 p-1 underline shadow-sm transition-all hover:text-primary/80">
<Star className="size-3 fill-yellow-500 text-yellow-400" />
star on github{" "}
<Star className="size-3 fill-yellow-500 text-yellow-400" />
Expand Down Expand Up @@ -300,7 +265,22 @@ export default function Home({
>
<Wand className="h-4 w-4" /> Create Video
</Button>
{userDB?.user?.id && !userDB?.user?.subscribed ? (
<Link
href={"/watch"}
className={buttonVariants({
variant: "outline",
className: "relative flex flex-row items-center gap-2",
})}
>
<Eye className="size-4" /> Watch
<Badge
className="absolute -right-3 -top-[0.4rem] px-[0.2rem] py-[0.1rem] text-xs opacity-90"
variant={"red"}
>
NEW
</Badge>
</Link>
{/* {userDB?.user?.id && !userDB?.user?.subscribed ? (
<ProButton>
<Button
className={"flex w-full flex-row items-center gap-2"}
Expand All @@ -309,7 +289,7 @@ export default function Home({
GO PRO <Crown className="size-4" />
</Button>
</ProButton>
) : null}
) : null} */}
{pendingVideo ? (
<Button
className="flex flex-row items-center gap-2 border border-red-500/60 bg-red-500/20"
Expand Down
265 changes: 265 additions & 0 deletions src/app/watch/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
"use client";

import XIcon from "@/components/svg/XIcon";
import { Avatar, AvatarImage } from "@/components/ui/avatar";
import { buttonVariants } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import {
Carousel,
CarouselApi,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
import { trpc } from "@/trpc/client";
import { DownloadCloud, Loader2 } from "lucide-react";
import Link from "next/link";
import { Suspense, useEffect, useState } from "react";

export default function Page() {
const [page, setPage] = useState(1);

const videosQuery = trpc.user.getVideos.useQuery({ page });

const [videos, setVideos] = useState<
{
id: number;
user_id: number;
agent1: string;
agent2: string;
title: string;
url: string;
videoId: string;
}[]
>([]);
const [api, setApi] = useState<CarouselApi | null>(null);
const [canScrollNext, setCanScrollNext] = useState(false);

useEffect(() => {
if (videosQuery.data?.videos) {
if (
videos.length > 0 &&
videosQuery.data?.videos[0]?.url !== videos[0]?.url
) {
setVideos((prev) => [...prev, ...videosQuery.data?.videos]);
} else if (videos.length === 0) {
setVideos((prev) => [...prev, ...videosQuery.data?.videos]);
}
}
}, [videosQuery.isFetching]);

useEffect(() => {
const handleIntersection = (entries: IntersectionObserverEntry[]) => {
entries.forEach((entry) => {
const video = entry.target as HTMLVideoElement;
if (entry.isIntersecting) {
video.play();
} else {
video.pause();
}
});
};

const observer = new IntersectionObserver(handleIntersection, {
threshold: 0.5,
});

const videoElements = document.querySelectorAll("video");
videoElements.forEach((video) => {
observer.observe(video);
});

return () => {
videoElements.forEach((video) => {
observer.unobserve(video);
});
};
}, [videos]);

const handleNext = () => {
api?.scrollNext();
};

useEffect(() => {
if (!canScrollNext) {
setPage((prev) => prev + 1);
}
}, [canScrollNext]);

useEffect(() => {
if (api) {
const checkCanScrollNext = () => {
setCanScrollNext(api.canScrollNext());
};

console.log(api.canScrollNext());

api.on("select", checkCanScrollNext);
api.on("reInit", checkCanScrollNext);

checkCanScrollNext();

return () => {
api.off("select", checkCanScrollNext);
api.off("reInit", checkCanScrollNext);
};
}
}, [api]);

useEffect(() => console.log(canScrollNext));

return (
<div>
<div className="flex flex-col items-center justify-center pt-16">
<Carousel
setApi={setApi}
opts={{
align: "start",
}}
orientation="vertical"
className="w-full"
>
<CarouselContent className="h-[750px]">
{videos.map((video, index) => {
const agent1 = video.agent1;

const agent2 = video.agent2;

const url = video.url;

const agent1Img =
agent1 === "JORDAN_PETERSON"
? "https://images.smart.wtf/JORDAN_PETERSON.png"
: agent1 === "JOE_ROGAN"
? "https://images.smart.wtf/JOE_ROGAN.png"
: agent1 === "BARACK_OBAMA"
? "https://images.smart.wtf/BARACK_OBAMA.png"
: agent1 === "BEN_SHAPIRO"
? "https://images.smart.wtf/BEN_SHAPIRO.png"
: agent1 === "DONALD_TRUMP"
? "https://images.smart.wtf/DONALD_TRUMP.png"
: agent1 === "LIL_YACHTY"
? "https://images.smart.wtf/LIL_YACHTY.png"
: agent1 === "JOE_BIDEN"
? "https://images.smart.wtf/JOE_BIDEN.png"
: agent1 === "MARK_ZUCKERBERG"
? "https://images.smart.wtf/MARK_ZUCKERBERG.png"
: "https://images.smart.wtf/BEN_SHAPIRO.png";

const agent2Img =
agent2 === "JORDAN_PETERSON"
? "https://images.smart.wtf/JORDAN_PETERSON.png"
: agent2 === "JOE_ROGAN"
? "https://images.smart.wtf/JOE_ROGAN.png"
: agent2 === "BARACK_OBAMA"
? "https://images.smart.wtf/BARACK_OBAMA.png"
: agent2 === "BEN_SHAPIRO"
? "https://images.smart.wtf/BEN_SHAPIRO.png"
: agent2 === "DONALD_TRUMP"
? "https://images.smart.wtf/DONALD_TRUMP.png"
: agent2 === "LIL_YACHTY"
? "https://images.smart.wtf/LIL_YACHTY.png"
: agent2 === "JOE_BIDEN"
? "https://images.smart.wtf/JOE_BIDEN.png"
: agent2 === "MARK_ZUCKERBERG"
? "https://images.smart.wtf/MARK_ZUCKERBERG.png"
: "https://images.smart.wtf/BEN_SHAPIRO.png";

return (
<CarouselItem key={video.id}>
<div className="flex h-full flex-col items-center justify-center">
{index > 0 && <div className="w-full"></div>}
<p
className={`max-w-[80%] text-center font-bold md:max-w-[400px]`}
>
{video.title}
</p>
<div className="flex w-full flex-row justify-center gap-2 py-2">
<Avatar className="border shadow-sm">
<AvatarImage src={agent1Img} alt="agent1" />
</Avatar>
<Avatar className="border shadow-sm">
<AvatarImage src={agent2Img} alt="agent2" />
</Avatar>
</div>

<div className="relative overflow-hidden rounded-lg">
<Suspense fallback={<Loader2 className="size-6" />}>
<video
src={url}
className={`rounded-lg shadow-md transition-all`}
width={300}
height={"100%"}
controls
></video>
</Suspense>
</div>
<div className="flex flex-row items-center gap-2">
<Link
target="_blank"
href={video.url}
download
className={buttonVariants({
variant: "outline",
className: "mt-2 flex w-[146px] flex-row gap-2",
})}
>
Download <DownloadCloud className="size-4" />
</Link>
<Link
href={`https://twitter.com/intent/tweet?text=${encodeURIComponent(
`${video.title} explained by ${video.agent1
.split("_")
.map(
(word) =>
word.charAt(0) + word.slice(1).toLowerCase(),
)
.join(" ")} AI and ${video.agent2
.split("_")
.map(
(word) =>
word.charAt(0) + word.slice(1).toLowerCase(),
)
.join(
" ",
)} AI with @brainrotjs \n\nhttps://brainrotjs.com/renders/${video.url
.replace(
"https://s3.us-east-1.amazonaws.com/remotionlambda-useast1-oaz2rkh49x/renders/",
"",
)
.replace(
"/out.mp4",
"",
)}?title=${encodeURIComponent(
video.title,
)}&agent1=${video.agent1}&agent2=${video.agent2}`,
)}`}
target="_blank"
rel="noopener noreferrer"
className={buttonVariants({
className: "mt-2 flex w-[146px] flex-row gap-2",
variant: "outline",
})}
>
Share on <XIcon className="size-4 fill-primary" />
</Link>
</div>
</div>
</CarouselItem>
);
})}
</CarouselContent>
<div className="fixed bottom-8 left-0 right-0 flex justify-center space-x-4">
<CarouselPrevious variant={"default"} />
<CarouselNext
disabled={!canScrollNext}
variant={"default"}
onClick={handleNext}
/>
</div>
</Carousel>
</div>
</div>
);
}
Loading

0 comments on commit 15adfa9

Please sign in to comment.