Compare commits

...

2 Commits

Author SHA1 Message Date
Guus van Meerveld 927fca314e results: fixed minor oversights and made optimizations
continuous-integration/drone/push Build is passing Details
2 months ago
Guus van Meerveld 7e13dea3c1 trending: added texts to loading page
2 months ago

@ -1,48 +1,46 @@
"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 = `/channel/${data.id}`; const url = channelUrl(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}
alt={data.name} name={data.name}
as={NextImage} isBordered
className="rounded-full"
unoptimized
/> />
</Link>
<div className="flex-1 flex flex-col justify-center"> <div className="flex-1 gap-2 flex flex-col justify-center">
<h1 className="text-lg">{data.name}</h1> <div className="flex flex-col">
<div className="flex flex-row gap-4 items-center font-semibold text-default-600"> <Link href={url}>
<h1>{formatBigNumber(data.subscribers)} subscribers</h1> <p className="text-lg">{data.name}</p>
</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 && (
<h1>{formatBigNumber(data.videos)} videos</h1> <p>{formatBigNumber(data.videos)} videos</p>
)} )}
</div> </div>
<p className="text-default-600">{data.description}</p>
</div> </div>
<p className="text-default-600">{data.description}</p>
</div> </div>
</CardBody> </div>
</Card> </CardBody>
</Link> </Card>
); );
}; };

@ -13,11 +13,14 @@ 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(30); const [width, height] = videoSize(imageSize);
const [playlistItemWidth, playlistItemHeight] = videoSize(5); const [playlistItemWidth, playlistItemHeight] = videoSize(5);
@ -43,25 +46,15 @@ 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"> </Link>
{data.title}
</h1>
</Link>
<Link <Author data={data.author} />
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.map((video) => ( {data.videos.slice(0, 2).map((video) => (
<ListboxItem <ListboxItem
as={NextLink} as={NextLink}
startContent={ startContent={

@ -4,7 +4,6 @@ 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";
@ -13,13 +12,17 @@ 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 = `/watch?v=${data.id}`; const url = videoUrl(data.id);
const channelUrl = `/channel/${data.author.id}`;
const [width, height] = videoSize(30); const [width, height] = videoSize(imageSize);
return ( return (
<Card> <Card>
@ -47,30 +50,19 @@ export const Video: FC<{ data: VideoItem }> = ({ data }) => {
)} )}
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2 w-full">
<Link as={NextLink} href={url}> <div>
<h1 className="text-xl text-default-foreground">{data.title}</h1> <Link as={NextLink} href={url}>
</Link> <h1 className="text-xl text-default-foreground">
<div className="flex flex-row gap-4 items-center font-semibold text-default-600"> {data.title}
<h1>{formatBigNumber(data.views)} views</h1> </h1>
{data.uploaded && <h1>{formatUploadedTime(data.uploaded)}</h1>} </Link>
<div className="flex flex-row gap-4 items-center tracking-tight text-default-400">
<h1>{formatBigNumber(data.views)} views</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>

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

@ -49,11 +49,10 @@ 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}\``} />
)} )}
{error === null && data && ( {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 (
@ -73,12 +72,15 @@ export const SearchPageBody: FC<{ query: string; filter: SearchType }> = ({
</Fragment> </Fragment>
); );
})} })}
<LoadingNextPage {error === null && (
isFetching={isFetchingNewPage} <LoadingNextPage
onVisible={fetchNewData} isFetching={isFetchingNewPage}
/> onVisible={fetchNewData}
/>
)}
</div> </div>
)} )}
{error !== null && <ErrorPage data={error} refetch={refetch} />}
</> </>
); );
}; };

@ -75,8 +75,13 @@ export const Trending: Component = ({}) => {
<h1 className="text-xl">Trending</h1> <h1 className="text-xl">Trending</h1>
</div> </div>
{isLoading && !data && <LoadingPage />} {isLoading && !data && (
{error && ( <LoadingPage
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">
@ -90,7 +95,7 @@ export const Trending: Component = ({}) => {
</div> </div>
</div> </div>
)} )}
{data && error === null && ( {data && data.length !== 0 && 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 /> <LoadingPage text="Loading trending page" />
</Container> </Container>
} }
> >

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

@ -0,0 +1,37 @@
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