Added categories to search results #9

main
Guus van Meerveld 3 years ago
parent 7797677468
commit 9ac97b8fec
Signed by: Guusvanmeerveld
GPG Key ID: 2BA7D7912771966E

@ -32,9 +32,10 @@ export const drawerWidth = 240;
const Navbar: FC = () => {
const [drawerIsOpen, setDrawerState] = useState(false);
const router = useRouter();
const query = router.query["search_query"];
const [search, setSearch] = useState<string | undefined>();
const toggleDrawer =
(open: boolean) => (event: React.KeyboardEvent | React.MouseEvent) => {
@ -141,9 +142,20 @@ const Navbar: FC = () => {
<SearchIconWrapper>
<SearchIcon />
</SearchIconWrapper>
<form action={`${router.basePath}/results`} method="get">
<form
onSubmit={(e) => {
e.preventDefault();
router.push({
pathname: "/results",
query: { search_query: search }
});
}}
method="get"
>
<StyledInputBase
defaultValue={query ?? ""}
onChange={(e) => setSearch(e.target.value)}
value={search}
name="search_query"
placeholder="Search…"
inputProps={{ "aria-label": "search" }}

@ -7,7 +7,9 @@ import Box from "@mui/material/Box";
import CircularProgress from "@mui/material/CircularProgress";
import Grid from "@mui/material/Grid";
import Paper from "@mui/material/Paper";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
import { red } from "@mui/material/colors";
import { useTheme } from "@mui/material/styles";
import { abbreviateNumber } from "@src/utils/";
@ -28,7 +30,22 @@ const Video: FC<{ video: VideoModel }> = ({ video }) => {
return (
<Paper sx={{ my: 2 }}>
<Grid container spacing={0}>
<Grid item md={4}>
<Grid item md={4} sx={{ position: "relative" }}>
{video.live && (
<Box
sx={{
backgroundColor: red[600],
position: "absolute",
right: 5,
top: 5,
p: "3px",
borderRadius: "2px",
textTransform: "uppercase"
}}
>
Live
</Box>
)}
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
style={{
@ -45,9 +62,11 @@ const Video: FC<{ video: VideoModel }> = ({ video }) => {
<Grid item md={8} sx={{ padding: 3, width: "100%" }}>
<Link href={{ pathname: "/watch", query: { v: video.id } }}>
<a>
<Tooltip title={video.title}>
<Typography gutterBottom noWrap variant="h5">
{video.title}
</Typography>
</Tooltip>
</a>
</Link>
<Typography
@ -55,8 +74,21 @@ const Video: FC<{ video: VideoModel }> = ({ video }) => {
variant="subtitle1"
color={theme.palette.text.secondary}
>
{!(video.live || video.upcoming) && (
<>
{abbreviateNumber(video.views)} Views Published{" "}
{video.published.text}
</>
)}
{video.live && <>🔴 Live now</>}
{video.upcoming && video.premiereTimestamp && (
<>
Premiering on{" "}
{new Date(video.premiereTimestamp * 1000).toLocaleDateString()}{" "}
at{" "}
{new Date(video.premiereTimestamp * 1000).toLocaleTimeString()}
</>
)}
</Typography>
<Typography
gutterBottom

@ -75,8 +75,12 @@ const Video: FC<VideoModel> = (video) => {
color={theme.palette.text.secondary}
variant="body2"
>
{!(video.live || video.upcoming) && (
<>
{abbreviateNumber(video.views)} Views Published{" "}
{video.published.text}
</>
)}
</Typography>
</CardContent>
</CardActionArea>

@ -31,6 +31,8 @@ export interface VideoResult extends Results {
published: number;
publishedText: string;
lengthSeconds: number;
isUpcoming: boolean;
premiereTimestamp?: number;
liveNow: boolean;
premium: boolean;
}

@ -17,6 +17,7 @@ interface Trending {
liveNow: boolean;
premium: boolean;
isUpcoming: boolean;
premiereTimestamp?: number;
}
export default Trending;

@ -32,6 +32,8 @@ interface Video {
};
subscriptions?: string;
rating?: number;
upcoming?: boolean;
premiereTimestamp?: number;
premiered?: Date;
recommendedVideos?: RecommendedVideo[];
adaptiveFormats?: AdaptiveFormat[];

@ -4,13 +4,20 @@ import { NextPage } from "next";
import { NextSeo } from "next-seo";
import { useRouter } from "next/router";
import { FC, useState } from "react";
import { useQuery } from "react-query";
import axios from "axios";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Container from "@mui/material/Container";
import Divider from "@mui/material/Divider";
import Typography from "@mui/material/Typography";
import { useTheme } from "@mui/material/styles";
import Add from "@mui/icons-material/Add";
import Result, {
CategoryResult,
@ -49,6 +56,50 @@ const Results: NextPage = () => {
: undefined
);
const Category: FC<{ category: CategoryResult }> = ({ category }) => {
const initialCount = 3;
const [count, setCount] = useState(initialCount);
const shownVideos = category.contents.slice(0, count);
return (
<>
<Typography variant="h5">{category.title}</Typography>
{shownVideos.map((video, i) => (
<Video video={apiToVideo(video)} key={i} />
))}
{category.contents.length > initialCount && (
<Box
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
mt: 4
}}
>
<Button
variant="text"
onClick={() =>
setCount(
count > initialCount ? initialCount : category.contents.length
)
}
>
<Add />
Show {count > initialCount ? "less" : "more"} (
{category.contents.length - initialCount})
</Button>
</Box>
)}
<Divider sx={{ my: 4 }} />
</>
);
};
if (!router.isReady || isLoading)
return (
<>
@ -69,7 +120,9 @@ const Results: NextPage = () => {
| VideoResult[]
| undefined;
// const categories = data?.filter()
const categories = data?.filter((result) => result.type == "category") as
| CategoryResult[]
| undefined;
return (
<>
@ -85,6 +138,13 @@ const Results: NextPage = () => {
<Divider sx={{ my: 4 }} />
</>
)}
{categories && categories.length != 0 && (
<>
{categories.map((category, i) => (
<Category key={i} category={category} />
))}
</>
)}
{videos && videos.length != 0 && (
<>
<Typography variant="h5">Videos</Typography>

@ -1,4 +1,4 @@
import { NextPage } from "next";
import { GetStaticProps, NextPage } from "next";
import { NextSeo } from "next-seo";
import { useState } from "react";
@ -21,17 +21,9 @@ import Layout from "@components/Layout";
import Loading from "@components/Loading";
import Grid from "@components/Video/Grid";
const Trending: NextPage = () => {
const [selectedCategory, setCategory] = useState<string | undefined>();
const [settings] = useSettings();
const { isLoading, error, data } = useQuery<
VideoTrending[],
AxiosError<Error>
>("trendingData", () =>
const fetchTrending = (server: string, category = "") =>
axios
.get(`https://${settings.invidiousServer}/api/v1/trending`, {
.get(`https://${server}/api/v1/trending`, {
params: {
fields: [
"title",
@ -44,13 +36,31 @@ const Trending: NextPage = () => {
"lengthSeconds",
"published",
"publishedText",
"liveNow",
"premium",
"isUpcoming",
"viewCount",
"videoThumbnails"
].join(","),
type: selectedCategory
type: category
}
})
.then((res) => res.data)
.then((res) => res.data);
const Trending: NextPage<{ trending: VideoTrending[] }> = (props) => {
const [selectedCategory, setCategory] = useState<string | undefined>();
const [settings] = useSettings();
const { isLoading, error, data } = useQuery<
VideoTrending[],
AxiosError<Error>
>(
"trendingData",
() => fetchTrending(settings.invidiousServer, selectedCategory),
{
initialData: props.trending
}
);
return (
@ -93,4 +103,14 @@ const Trending: NextPage = () => {
);
};
export const getStaticProps: GetStaticProps = async ({}) => {
const trending = await fetchTrending(
process.env.NEXT_PUBLIC_DEFAULT_SERVER as string
);
return {
props: { trending }
};
};
export default Trending;

@ -25,6 +25,8 @@ export const apiToVideo = (item: VideoTrending | VideoResult): Video => {
views: item.viewCount,
live: item.liveNow,
premium: item.premium,
upcoming: item.isUpcoming,
premiereTimestamp: item.premiereTimestamp,
thumbnail: item.videoThumbnails.find(
(thumbnail) => thumbnail.quality == Quality.Maxresdefault
)?.url as string

Loading…
Cancel
Save