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
8 months ago
Guus van Meerveld 7e13dea3c1 trending: added texts to loading page
8 months ago

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

@ -13,11 +13,14 @@ import { PlaylistItem } from "@/client/typings/item";
import { videoUrl } from "@/utils/urls";
import { videoSize } from "@/utils/videoSize";
import { Author } from "@/components/Author";
import { imageSize } from "./constants";
export const Playlist: FC<{ data: PlaylistItem }> = ({ data }) => {
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);
@ -43,25 +46,15 @@ export const Playlist: FC<{ data: PlaylistItem }> = ({ data }) => {
</div>
<div className="flex flex-col gap-2">
<div>
<Link as={NextLink} href={url}>
<h1 className="text-xl text-default-foreground">
{data.title}
</h1>
</Link>
<Link as={NextLink} href={url}>
<h1 className="text-xl text-default-foreground">{data.title}</h1>
</Link>
<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>
<Author data={data.author} />
{data.videos && (
<Listbox>
{data.videos.map((video) => (
{data.videos.slice(0, 2).map((video) => (
<ListboxItem
as={NextLink}
startContent={

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

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

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

@ -75,8 +75,13 @@ export const Trending: Component = ({}) => {
<h1 className="text-xl">Trending</h1>
</div>
{isLoading && !data && <LoadingPage />}
{error && (
{isLoading && !data && (
<LoadingPage
text={`Loading trending page for region \`${region?.name}\``}
/>
)}
{error !== null && (
<div className="flex-1 flex items-center justify-center">
<div className="text-center">
<h1 className="text-xl">
@ -90,7 +95,7 @@ export const Trending: Component = ({}) => {
</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">
{data.map((video) => (
<Video key={video.id} data={video} />

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

@ -68,12 +68,19 @@ const getSearch = async (
): Promise<Search> => {
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);
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, {
searchParams: { ...options, q: query }
searchParams
});
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