Compare commits

..

No commits in common. '927fca314e8d539bf13bef72ec189ca81ec2972d' and 'cb54d9f991a6ed06bed9cbe524be84cc4e6f1f3a' have entirely different histories.

@ -1,46 +1,48 @@
"use client"; "use client";
import NextImage from "next/image";
import Link from "next/link"; import Link from "next/link";
import { FC } from "react"; import { FC } from "react";
import { Avatar } from "@nextui-org/avatar";
import { Card, CardBody } from "@nextui-org/card"; import { Card, CardBody } from "@nextui-org/card";
import { Image } from "@nextui-org/image";
import { ChannelItem } from "@/client/typings/item"; import { ChannelItem } from "@/client/typings/item";
import formatBigNumber from "@/utils/formatBigNumber"; import formatBigNumber from "@/utils/formatBigNumber";
import { channelUrl } from "@/utils/urls";
export const Channel: FC<{ data: ChannelItem }> = ({ data }) => { export const Channel: FC<{ data: ChannelItem }> = ({ data }) => {
const url = channelUrl(data.id); const url = `/channel/${data.id}`;
const imageSize = 200;
return ( return (
<Link href={url}>
<Card> <Card>
<CardBody> <CardBody>
<div className="flex flex-row gap-4"> <div className="flex flex-row gap-4">
<Link href={url}> <Image
<Avatar width={imageSize}
className="w-32 h-32 text-2xl" height={imageSize}
src={data.thumbnail} src={data.thumbnail}
name={data.name} alt={data.name}
isBordered as={NextImage}
className="rounded-full"
unoptimized
/> />
</Link>
<div className="flex-1 gap-2 flex flex-col justify-center"> <div className="flex-1 flex flex-col justify-center">
<div className="flex flex-col"> <h1 className="text-lg">{data.name}</h1>
<Link href={url}> <div className="flex flex-row gap-4 items-center font-semibold text-default-600">
<p className="text-lg">{data.name}</p> <h1>{formatBigNumber(data.subscribers)} subscribers</h1>
</Link>
<div className="flex flex-row gap-4 items-center tracking-tight text-default-400">
<p>{formatBigNumber(data.subscribers)} subscribers</p>
{data.videos !== 0 && ( {data.videos !== 0 && (
<p>{formatBigNumber(data.videos)} videos</p> <h1>{formatBigNumber(data.videos)} videos</h1>
)} )}
</div> </div>
</div>
<p className="text-default-600">{data.description}</p> <p className="text-default-600">{data.description}</p>
</div> </div>
</div> </div>
</CardBody> </CardBody>
</Card> </Card>
</Link>
); );
}; };

@ -13,14 +13,11 @@ import { PlaylistItem } from "@/client/typings/item";
import { videoUrl } from "@/utils/urls"; import { videoUrl } from "@/utils/urls";
import { videoSize } from "@/utils/videoSize"; import { videoSize } from "@/utils/videoSize";
import { Author } from "@/components/Author";
import { imageSize } from "./constants";
export const Playlist: FC<{ data: PlaylistItem }> = ({ data }) => { export const Playlist: FC<{ data: PlaylistItem }> = ({ data }) => {
const url = `/playlist/${data.id}`; const url = `/playlist/${data.id}`;
const channelUrl = `/channel/${data.author.id}`;
const [width, height] = videoSize(imageSize); const [width, height] = videoSize(30);
const [playlistItemWidth, playlistItemHeight] = videoSize(5); const [playlistItemWidth, playlistItemHeight] = videoSize(5);
@ -46,15 +43,25 @@ export const Playlist: FC<{ data: PlaylistItem }> = ({ data }) => {
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div>
<Link as={NextLink} href={url}> <Link as={NextLink} href={url}>
<h1 className="text-xl text-default-foreground">{data.title}</h1> <h1 className="text-xl text-default-foreground">
{data.title}
</h1>
</Link> </Link>
<Author data={data.author} /> <Link
as={NextLink}
href={channelUrl}
className="flex flex-row gap-2 items-center"
>
<h1 className="text-lg text-default-600">{data.author.name}</h1>
</Link>
</div>
{data.videos && ( {data.videos && (
<Listbox> <Listbox>
{data.videos.slice(0, 2).map((video) => ( {data.videos.map((video) => (
<ListboxItem <ListboxItem
as={NextLink} as={NextLink}
startContent={ startContent={

@ -4,6 +4,7 @@ import NextImage from "next/image";
import NextLink from "next/link"; import NextLink from "next/link";
import { FC } from "react"; import { FC } from "react";
import { Avatar } from "@nextui-org/avatar";
import { Card, CardBody } from "@nextui-org/card"; import { Card, CardBody } from "@nextui-org/card";
import { Image } from "@nextui-org/image"; import { Image } from "@nextui-org/image";
import { Link } from "@nextui-org/link"; import { Link } from "@nextui-org/link";
@ -12,17 +13,13 @@ import { VideoItem } from "@/client/typings/item";
import formatBigNumber from "@/utils/formatBigNumber"; import formatBigNumber from "@/utils/formatBigNumber";
import formatDuration from "@/utils/formatDuration"; import formatDuration from "@/utils/formatDuration";
import formatUploadedTime from "@/utils/formatUploadedTime"; import formatUploadedTime from "@/utils/formatUploadedTime";
import { videoUrl } from "@/utils/urls";
import { videoSize } from "@/utils/videoSize"; import { videoSize } from "@/utils/videoSize";
import { Author } from "@/components/Author";
import { imageSize } from "./constants";
export const Video: FC<{ data: VideoItem }> = ({ data }) => { export const Video: FC<{ data: VideoItem }> = ({ data }) => {
const url = videoUrl(data.id); const url = `/watch?v=${data.id}`;
const channelUrl = `/channel/${data.author.id}`;
const [width, height] = videoSize(imageSize); const [width, height] = videoSize(30);
return ( return (
<Card> <Card>
@ -50,19 +47,30 @@ export const Video: FC<{ data: VideoItem }> = ({ data }) => {
)} )}
</div> </div>
<div className="flex flex-col gap-2 w-full"> <div className="flex flex-col gap-2">
<div>
<Link as={NextLink} href={url}> <Link as={NextLink} href={url}>
<h1 className="text-xl text-default-foreground"> <h1 className="text-xl text-default-foreground">{data.title}</h1>
{data.title}
</h1>
</Link> </Link>
<div className="flex flex-row gap-4 items-center tracking-tight text-default-400"> <div className="flex flex-row gap-4 items-center font-semibold text-default-600">
<h1>{formatBigNumber(data.views)} views</h1> <h1>{formatBigNumber(data.views)} views</h1>
{data.uploaded && <h1>{formatUploadedTime(data.uploaded)}</h1>} {data.uploaded && <h1>{formatUploadedTime(data.uploaded)}</h1>}
</div> </div>
</div> <Link
<Author data={data.author} /> as={NextLink}
href={channelUrl}
className="flex flex-row gap-2 items-center"
>
{data.author.avatar && (
<Avatar
isBordered
name={data.author.name}
size="lg"
src={data.author.avatar}
alt={data.author.name}
/>
)}
<h1 className="text-lg text-default-600">{data.author.name}</h1>
</Link>
<p className="text-default-600">{data.description}</p> <p className="text-default-600">{data.description}</p>
</div> </div>
</div> </div>

@ -1 +0,0 @@
export const imageSize = 30;

@ -49,10 +49,11 @@ export const SearchPageBody: FC<{ query: string; filter: SearchType }> = ({
return ( return (
<> <>
{error !== null && <ErrorPage data={error} refetch={refetch} />}
{isFetchingInitialData && ( {isFetchingInitialData && (
<LoadingPage text={`Fetching search results for query \`${query}\``} /> <LoadingPage text={`Fetching search results for query \`${query}\``} />
)} )}
{data && ( {error === null && data && (
<div className="flex flex-col gap-4 mt-4"> <div className="flex flex-col gap-4 mt-4">
{data.pages.map((page, i) => { {data.pages.map((page, i) => {
return ( return (
@ -72,15 +73,12 @@ export const SearchPageBody: FC<{ query: string; filter: SearchType }> = ({
</Fragment> </Fragment>
); );
})} })}
{error === null && (
<LoadingNextPage <LoadingNextPage
isFetching={isFetchingNewPage} isFetching={isFetchingNewPage}
onVisible={fetchNewData} onVisible={fetchNewData}
/> />
)}
</div> </div>
)} )}
{error !== null && <ErrorPage data={error} refetch={refetch} />}
</> </>
); );
}; };

@ -75,13 +75,8 @@ export const Trending: Component = ({}) => {
<h1 className="text-xl">Trending</h1> <h1 className="text-xl">Trending</h1>
</div> </div>
{isLoading && !data && ( {isLoading && !data && <LoadingPage />}
<LoadingPage {error && (
text={`Loading trending page for region \`${region?.name}\``}
/>
)}
{error !== null && (
<div className="flex-1 flex items-center justify-center"> <div className="flex-1 flex items-center justify-center">
<div className="text-center"> <div className="text-center">
<h1 className="text-xl"> <h1 className="text-xl">
@ -95,7 +90,7 @@ export const Trending: Component = ({}) => {
</div> </div>
</div> </div>
)} )}
{data && data.length !== 0 && error === null && ( {data && error === null && (
<div className="grid gap-4 py-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3"> <div className="grid gap-4 py-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
{data.map((video) => ( {data.map((video) => (
<Video key={video.id} data={video} /> <Video key={video.id} data={video} />

@ -12,7 +12,7 @@ const Page: NextPage = () => {
<Suspense <Suspense
fallback={ fallback={
<Container> <Container>
<LoadingPage text="Loading trending page" /> <LoadingPage />
</Container> </Container>
} }
> >

@ -68,19 +68,12 @@ const getSearch = async (
): Promise<Search> => { ): Promise<Search> => {
let url: URL; let url: URL;
const searchParams = new URLSearchParams(); if (options?.nextpage)
searchParams.append("q", query);
if (options?.nextpage) {
url = new URL(path.join("nextpage", "search"), apiBaseUrl); url = new URL(path.join("nextpage", "search"), apiBaseUrl);
searchParams.append("nextpage", options.nextpage); else url = new URL("search", apiBaseUrl);
} else url = new URL("search", apiBaseUrl);
if (options?.filter) searchParams.append("filter", options.filter);
const response = await ky.get(url, { const response = await ky.get(url, {
searchParams searchParams: { ...options, q: query }
}); });
const json = await response.json(); const json = await response.json();

@ -1,37 +0,0 @@
import NextLink from "next/link";
import { FC } from "react";
import { Avatar } from "@nextui-org/avatar";
import { Link } from "@nextui-org/link";
import { Author as AuthorProps } from "@/client/typings/author";
import formatBigNumber from "@/utils/formatBigNumber";
import { channelUrl } from "@/utils/urls";
export const Author: FC<{ data: AuthorProps }> = ({ data }) => {
return (
<Link
as={NextLink}
href={data.id ? channelUrl(data.id) : undefined}
className="flex flex-row gap-4 items-center"
>
{data.avatar && (
<Avatar
isBordered
name={data.name}
size="lg"
src={data.avatar}
alt={data.name}
/>
)}
<div className="flex flex-col gap-2">
<p className="text-lg text-default-600">{data.name}</p>
{data.subscribers && (
<p className="text-default-400 tracking-tight">
{formatBigNumber(data.subscribers)} subscribers
</p>
)}
</div>
</Link>
);
};
Loading…
Cancel
Save