Skip to content

Commit

Permalink
30: home page
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonioErdeljac committed Dec 10, 2023
1 parent 7ee3861 commit 2eecf8f
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 3 deletions.
68 changes: 68 additions & 0 deletions app/(browse)/(home)/_components/result-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import Link from "next/link";
import { Stream, User } from "@prisma/client";

import { Thumbnail, ThumbnailSkeleton } from "@/components/thumbnail";
import { Skeleton } from "@/components/ui/skeleton";
import { LiveBadge } from "@/components/live-badge";
import { UserAvatar, UserAvatarSkeleton } from "@/components/user-avatar";

interface ResultCardProps {
data: {
user: User,
isLive: boolean;
name: string;
thumbnailUrl: string | null;
};
};

export const ResultCard = ({
data,
}: ResultCardProps) => {
return (
<Link href={`/${data.user.username}`}>
<div className="h-full w-full space-y-4">
<Thumbnail
src={data.thumbnailUrl}
fallback={data.user.imageUrl}
isLive={data.isLive}
username={data.user.username}
/>
{data.isLive && (
<div className="absolute top-2 left-2 group-hover:translate-x-2 group-hover:-translate-y-2 transition-transform">
<LiveBadge />
</div>
)}
<div className="flex gap-x-3">
<UserAvatar
username={data.user.username}
imageUrl={data.user.imageUrl}
isLive={data.isLive}
/>
<div className="flex flex-col text-sm overflow-hidden">
<p className="trunacte font-semibold hover:text-blue-500">
{data.name}
</p>
<p className="text-muted-foreground">
{data.user.username}
</p>
</div>
</div>
</div>
</Link>
);
};

export const ResultCardSkeleton = () => {
return (
<div className="h-full w-full space-y-4">
<ThumbnailSkeleton />
<div className="flex gap-x-3">
<UserAvatarSkeleton />
<div className="flex flex-col gap-y-1">
<Skeleton className="h-4 w-32" />
<Skeleton className="h-3 w-24"/>
</div>
</div>
</div>
);
};
42 changes: 42 additions & 0 deletions app/(browse)/(home)/_components/results.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { getStreams } from "@/lib/feed-service";
import { Skeleton } from "@/components/ui/skeleton";

import { ResultCard, ResultCardSkeleton } from "./result-card";

export const Results = async () => {
const data = await getStreams();

return (
<div>
<h2 className="text-lg font-semibold mb-4">
Streams we think you&apos;ll like
</h2>
{data.length === 0 && (
<div className="text-muted-foreground text-sm">
No streams found.
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4">
{data.map((result) => (
<ResultCard
key={result.id}
data={result}
/>
))}
</div>
</div>
)
}

export const ResultsSkeleton = () => {
return (
<div>
<Skeleton className="h-8 w-[290px] mb-4" />
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4">
{[...Array(4)].map((_, i) => (
<ResultCardSkeleton key={i} />
))}
</div>
</div>
);
};
11 changes: 8 additions & 3 deletions app/(browse)/(home)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { Suspense } from "react";

import { Results, ResultsSkeleton } from "./_components/results";

export default function Page() {
return (
<div className="flex flex-col gap-y-4">
<h1>Home page</h1>
<div className="h-full p-8 max-w-screen-2xl mx-auto">
<Suspense fallback={<ResultsSkeleton />}>
<Results />
</Suspense>
</div>
);
};

58 changes: 58 additions & 0 deletions components/thumbnail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Image from "next/image";

import { Skeleton } from "@/components/ui/skeleton";
import { UserAvatar } from "@/components/user-avatar";

interface ThumbnailProps {
src: string | null;
fallback: string;
isLive: boolean;
username: string;
};

export const Thumbnail = ({
src,
fallback,
isLive,
username,
}: ThumbnailProps) => {
let content;

if (!src) {
content = (
<div className="bg-background flex flex-col items-center justify-center gap-y-4 h-full w-full transition-transform group-hover:translate-x-2 group-hover:-translate-y-1 rounded-md">
<UserAvatar
size="lg"
showBadge
username={username}
imageUrl={fallback}
isLive={isLive}
/>
</div>
)
} else {
content = (
<Image
src={src}
fill
alt="Thumbnail"
className="object-cover transition-transform group-hover:translate-x-2 group-hover:-translate-y-2 rounded-md"
/>
)
}

return (
<div className="group aspect-video relative rounded-md cursor-pointer">
<div className="rounded-md absolute inset-0 bg-blue-600 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center" />
{content}
</div>
);
};

export const ThumbnailSkeleton = () => {
return (
<div className="group aspect-video relative rounded-xl cursor-pointer">
<Skeleton className="h-full w-full" />
</div>
);
};
66 changes: 66 additions & 0 deletions lib/feed-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { db } from "@/lib/db"
import { getSelf } from "@/lib/auth-service"

export const getStreams = async () => {
let userId;

try {
const self = await getSelf();
userId = self.id;
} catch {
userId = null;
}

let streams = [];

if (userId) {
streams = await db.stream.findMany({
where: {
user: {
NOT: {
blocking: {
some: {
blockedId: userId,
}
}
}
}
},
select: {
id: true,
user: true,
isLive: true,
name: true,
thumbnailUrl: true,
},
orderBy: [
{
isLive: "desc",
},
{
updatedAt: "desc",
}
],
});
} else {
streams = await db.stream.findMany({
select: {
id: true,
user: true,
isLive: true,
name: true,
thumbnailUrl: true,
},
orderBy: [
{
isLive: "desc",
},
{
updatedAt: "desc",
}
]
});
}

return streams;
};

0 comments on commit 2eecf8f

Please sign in to comment.