diff --git a/package.json b/package.json
index 3800c69..879393a 100644
--- a/package.json
+++ b/package.json
@@ -1,33 +1,36 @@
{
- "name": "materialtube",
- "version": "0.1.0",
- "private": true,
- "scripts": {
- "dev": "next dev",
- "build": "next build",
- "start": "next start",
- "lint": "next lint"
- },
- "dependencies": {
- "@nextui-org/react": "^2.2.10",
- "framer-motion": "^11.0.12",
- "ky": "^1.2.2",
- "next": "14.1.3",
- "next-pwa": "^5.6.0",
- "react": "^18",
- "react-dom": "^18",
- "zod": "^3.22.4"
- },
- "devDependencies": {
- "@types/next-pwa": "^5.6.9",
- "@types/node": "^20",
- "@types/react": "^18",
- "@types/react-dom": "^18",
- "autoprefixer": "^10.0.1",
- "eslint": "^8",
- "eslint-config-next": "14.1.3",
- "postcss": "^8",
- "tailwindcss": "^3.3.0",
- "typescript": "^5"
- }
+ "name": "materialtube",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint"
+ },
+ "dependencies": {
+ "@nextui-org/react": "^2.2.10",
+ "@tanstack/react-query": "^5.27.5",
+ "framer-motion": "^11.0.12",
+ "ky": "^1.2.2",
+ "next": "14.1.3",
+ "next-pwa": "^5.6.0",
+ "react": "^18",
+ "react-dom": "^18",
+ "react-icons": "^5.0.1",
+ "zod": "^3.22.4"
+ },
+ "devDependencies": {
+ "@tanstack/react-query-devtools": "^5.27.8",
+ "@types/next-pwa": "^5.6.9",
+ "@types/node": "^20",
+ "@types/react": "^18",
+ "@types/react-dom": "^18",
+ "autoprefixer": "^10.0.1",
+ "eslint": "^8",
+ "eslint-config-next": "14.1.3",
+ "postcss": "^8",
+ "tailwindcss": "^3.3.0",
+ "typescript": "^5"
+ }
}
diff --git a/src/app/(trending)/Trending.tsx b/src/app/(trending)/Trending.tsx
new file mode 100644
index 0000000..066ea95
--- /dev/null
+++ b/src/app/(trending)/Trending.tsx
@@ -0,0 +1,73 @@
+"use client";
+
+import { Component } from "@/typings/component";
+import { useClient } from "@/hooks/useClient";
+import { useQuery } from "@tanstack/react-query";
+import { Card, CardFooter, CardBody } from "@nextui-org/card";
+import { Image } from "@nextui-org/image";
+import { Button } from "@nextui-org/button";
+import { CircularProgress } from "@nextui-org/progress";
+import { Divider } from "@nextui-org/divider";
+import Link from "next/link";
+import formatNumber from "@/utils/formatNumbers";
+
+export const Trending: Component = ({}) => {
+ const client = useClient();
+
+ const { isLoading, error, data } = useQuery({
+ queryKey: ["trending"],
+ queryFn: () => client.getTrending("NL")
+ });
+
+ return (
+
+ {isLoading && !data && (
+
+
+
+ )}
+ {data && (
+
+ {data.map((video) => (
+
+
+
+
+
+ 20:41
+
+
+
+
+
+
+ {video.title}
+
+
+
+ {video.author.name}
+
+
+ {video.uploaded.toLocaleDateString()}
+
+
+
+ Views: {formatNumber(video.views)}
+
+
+
+
+
+
+ ))}
+
+ )}
+
+ );
+};
diff --git a/src/app/(trending)/Video.tsx b/src/app/(trending)/Video.tsx
deleted file mode 100644
index 049892d..0000000
--- a/src/app/(trending)/Video.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-"use client";
-
-import Client from "@/client";
-import { ApiType } from "@/client/adapters";
-import { Component } from "@/typings/component";
-import { useEffect } from "react";
-
-export const Video: Component = ({}) => {
- useEffect(() => {
- const client = new Client([
- { baseUrl: "https://invidious.drgns.space", type: ApiType.Invidious },
- { baseUrl: "https://pipedapi.kavin.rocks", type: ApiType.Piped }
- ]);
-
- client.getTrending("US").then(console.log);
- }, []);
-
- return <>>;
-};
diff --git a/src/app/(trending)/page.tsx b/src/app/(trending)/page.tsx
index 4068cd6..31944c4 100644
--- a/src/app/(trending)/page.tsx
+++ b/src/app/(trending)/page.tsx
@@ -1,10 +1,9 @@
-import { Button } from "@nextui-org/button";
-import { Video } from "./Video";
+import { Trending } from "./Trending";
-export default function Home() {
+export default function Page() {
return (
<>
-
+
>
);
}
diff --git a/src/app/providers.tsx b/src/app/providers.tsx
index 279d01e..edc8fc6 100644
--- a/src/app/providers.tsx
+++ b/src/app/providers.tsx
@@ -1,7 +1,15 @@
"use client";
import { NextUIProvider } from "@nextui-org/react";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
export function Providers({ children }: { children: React.ReactNode }) {
- return {children};
+ const queryClient = new QueryClient();
+ return (
+
+
+ {children}
+
+ );
}
diff --git a/src/hooks/useClient.ts b/src/hooks/useClient.ts
new file mode 100644
index 0000000..d58e913
--- /dev/null
+++ b/src/hooks/useClient.ts
@@ -0,0 +1,16 @@
+import Client from "@/client";
+import { ApiType } from "@/client/adapters";
+
+import { useState } from "react";
+
+export const useClient = () => {
+ const [client] = useState(
+ () =>
+ new Client([
+ // { baseUrl: "https://invidious.drgns.space", type: ApiType.Invidious }
+ { baseUrl: "https://pipedapi.kavin.rocks", type: ApiType.Piped }
+ ])
+ );
+
+ return client;
+};
diff --git a/src/utils/formatNumbers.ts b/src/utils/formatNumbers.ts
new file mode 100644
index 0000000..5a486e7
--- /dev/null
+++ b/src/utils/formatNumbers.ts
@@ -0,0 +1,14 @@
+const formatNumber = (num: number): string => {
+ // Nine Zeroes for Billions
+ return Math.abs(num) >= 1.0e9
+ ? (Math.abs(num) / 1.0e9).toPrecision(3) + "B"
+ : // Six Zeroes for Millions
+ Math.abs(num) >= 1.0e6
+ ? (Math.abs(num) / 1.0e6).toPrecision(3) + "M"
+ : // Three Zeroes for Thousands
+ Math.abs(num) >= 1.0e3
+ ? (Math.abs(num) / 1.0e3).toPrecision(3) + "K"
+ : Math.abs(num).toString();
+};
+
+export default formatNumber;
diff --git a/yarn.lock b/yarn.lock
index 0f5d44d..6387f29 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2931,6 +2931,30 @@
dependencies:
tslib "^2.4.0"
+"@tanstack/query-core@5.27.5":
+ version "5.27.5"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.27.5.tgz#de4ede2094d490d0147e943212fcda51f09c0f69"
+ integrity sha512-HuYOo46NhzNX1SwXCmLf/Skr8B7T56cDHUN+iOhnu7+GOkUMThda64GwZpAqQzBT8TOTBQo6RQaNe0gi3Gi2fw==
+
+"@tanstack/query-devtools@5.27.8":
+ version "5.27.8"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.27.8.tgz#fa886ae72d0fe9fe5932af12ba0ba3ff484a1224"
+ integrity sha512-K94gnqvEe6TsDvi8eZYP2JrnQJOIymhVXRR+Xa0xcsryNqG+PeMIDmQQqjwIqbDq36qyUlPAyT6LxXVvVv1Nyw==
+
+"@tanstack/react-query-devtools@^5.27.8":
+ version "5.27.8"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.27.8.tgz#eac277afb80e077566ffba85278b8ce4632bac10"
+ integrity sha512-nWttSF5qhRxyIYh0D9ybZHgAWCOdsBNZf2s0EskYpAxDDrF3lgf/xTzPPzxoX7Z14bxKruVUEpwjQWZg3f/Z7g==
+ dependencies:
+ "@tanstack/query-devtools" "5.27.8"
+
+"@tanstack/react-query@^5.27.5":
+ version "5.27.5"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.27.5.tgz#2a431c28931bd821d9d96eaf7c6e59b4257ce023"
+ integrity sha512-VcuQo4CYRGsPsD8/rj9e4WnXN6eU4GKmAs0Yd9a1hLSx6DxAzRaBdrwu6P9lfjpz8bxaYkZRyb5NI+YtLipoYA==
+ dependencies:
+ "@tanstack/query-core" "5.27.5"
+
"@types/estree@0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
@@ -5537,6 +5561,11 @@ react-dom@^18:
loose-envify "^1.1.0"
scheduler "^0.23.0"
+react-icons@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.0.1.tgz#1694e11bfa2a2888cab47dcc30154ce90485feee"
+ integrity sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==
+
react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"