From 27b0b9887f89159bde6fb07def7abcf4904c9411 Mon Sep 17 00:00:00 2001 From: Chandan SM Date: Mon, 17 Feb 2025 16:19:03 +0530 Subject: [PATCH 1/4] Added Clerk Authentication --- apps/client/src/app/globals.css | 3 + apps/client/src/app/layout.tsx | 37 +++- apps/client/src/components/home/index.tsx | 16 +- apps/client/src/components/theme.tsx | 2 +- ...utton.tsx => home-magic-border-button.tsx} | 6 + apps/client/src/middleware.ts | 12 ++ package.json | 1 + pnpm-lock.yaml | 202 +++++++++++++++++- 8 files changed, 248 insertions(+), 31 deletions(-) rename apps/client/src/components/ui/button/{magic-border-button.tsx => home-magic-border-button.tsx} (90%) create mode 100644 apps/client/src/middleware.ts diff --git a/apps/client/src/app/globals.css b/apps/client/src/app/globals.css index 6167036..33cb461 100644 --- a/apps/client/src/app/globals.css +++ b/apps/client/src/app/globals.css @@ -108,5 +108,8 @@ body { --sidebar-accent-foreground: 240 4.8% 95.9%; --sidebar-border: 240 3.7% 15.9%; --sidebar-ring: 217.2 91.2% 59.8%; + .cl-userButtonOuterIdentifier{ + color: white; + } } } diff --git a/apps/client/src/app/layout.tsx b/apps/client/src/app/layout.tsx index 9e284d4..690396e 100644 --- a/apps/client/src/app/layout.tsx +++ b/apps/client/src/app/layout.tsx @@ -7,6 +7,13 @@ import "./globals.css"; import { Theme } from "@/components/theme"; import { PostHogProvider } from "@/components/posthog/providers"; import TanstackProvider from "@/components/TanStackQuery/provider"; +import { + ClerkProvider, + SignedIn, + SignedOut, + SignIn, + UserButton, +} from "@clerk/nextjs"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -37,15 +44,27 @@ export default function RootLayout({ > - - - - {children} - - - - - + + + + + +
+ +
+
+ +
+ +
+ {children} +
+ +
+
+
+ +
diff --git a/apps/client/src/components/home/index.tsx b/apps/client/src/components/home/index.tsx index bc0d6dc..b8c4247 100644 --- a/apps/client/src/components/home/index.tsx +++ b/apps/client/src/components/home/index.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import { BackgroundLines } from "@/components/ui/background-lines"; -import { MagicBorderButton } from "@/components/ui/button/magic-border-button"; +import { MagicBorderButton } from "@/components/ui/button/home-magic-border-button"; import { CoolMode } from "@/components/ui/cool-mode"; import FanIcon from "@/assests/icon/fan"; import { useTheme } from "next-themes"; @@ -57,19 +57,7 @@ export function Home() { }} >
- -

{ - // Perform the action here - setTimeout(() => { - window.location.href = "/home"; - }, 2000); - }} - > - Turn on! -

-
+ Turn on!
diff --git a/apps/client/src/components/theme.tsx b/apps/client/src/components/theme.tsx index f90be7e..5cbec0b 100644 --- a/apps/client/src/components/theme.tsx +++ b/apps/client/src/components/theme.tsx @@ -15,7 +15,7 @@ export function Theme() { return ( diff --git a/apps/client/src/components/ui/button/magic-border-button.tsx b/apps/client/src/components/ui/button/home-magic-border-button.tsx similarity index 90% rename from apps/client/src/components/ui/button/magic-border-button.tsx rename to apps/client/src/components/ui/button/home-magic-border-button.tsx index 683f91d..8bc64eb 100644 --- a/apps/client/src/components/ui/button/magic-border-button.tsx +++ b/apps/client/src/components/ui/button/home-magic-border-button.tsx @@ -33,6 +33,12 @@ export const MagicBorderButton = ({ "relative inline-flex h-12 overflow-hidden rounded-full p-[2.5px] focus:ring-slate-400 focus:ring-offset-2 focus:ring-offset-slate-50", className, )} + onClick={() => { + // Perform the action here + setTimeout(() => { + window.location.href = "/home"; + }, 2000); + }} > =18" }, "dependencies": { + "@clerk/nextjs": "^6.11.3", "nuxt": "^3.13.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9a14913..f1aecb6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,12 @@ importers: .: dependencies: + '@clerk/nextjs': + specifier: ^6.11.3 + version: 6.11.3(next@15.1.6(@babel/core@7.26.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) nuxt: specifier: ^3.13.2 - version: 3.15.4(@parcel/watcher@2.5.1)(@types/node@20.17.19)(db0@0.2.4)(ioredis@5.5.0)(magicast@0.3.5)(rollup@4.34.7)(terser@5.39.0)(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3))(yaml@2.7.0) + version: 3.15.4(@parcel/watcher@2.5.1)(@types/node@20.17.19)(db0@0.2.4)(eslint@9.20.1(jiti@2.4.2))(ioredis@5.5.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.7)(terser@5.39.0)(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3))(yaml@2.7.0) devDependencies: prettier: specifier: ^3.5.0 @@ -129,7 +132,7 @@ importers: version: 11.3.0(vue@3.5.13(typescript@5.7.3)) nuxt: specifier: ^3.13.2 - version: 3.15.4(@parcel/watcher@2.5.1)(@types/node@20.17.19)(db0@0.2.4)(ioredis@5.5.0)(magicast@0.3.5)(rollup@4.34.7)(terser@5.39.0)(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3))(yaml@2.7.0) + version: 3.15.4(@parcel/watcher@2.5.1)(@types/node@20.17.19)(db0@0.2.4)(eslint@9.20.1(jiti@2.4.2))(ioredis@5.5.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.7)(terser@5.39.0)(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3))(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -309,6 +312,41 @@ packages: resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} engines: {node: '>=6.9.0'} + '@clerk/backend@1.24.1': + resolution: {integrity: sha512-yxHgvtGePC67o8gJcLCP8S4ETeDGjnphGdQ+J8upmgsQ1GFt58pAZVXznpjwpLSkdOXa6XpvyAyV9mc6gFNfgw==} + engines: {node: '>=18.17.0'} + + '@clerk/clerk-react@5.22.13': + resolution: {integrity: sha512-8jU9QrXCRagDS2DHYJ2hd5ZNYloxtHyFRRs5Z24P+oAX+UGezyPSasMpMNpaLbCqVAy8Wy4i+dgPLukM2bQ/NQ==} + engines: {node: '>=18.17.0'} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + + '@clerk/nextjs@6.11.3': + resolution: {integrity: sha512-2qNxVr9adUf+vxecjfNYU8ol/2H+S56eqtAcyHpVS2YsM/C46UpprznTFb9EVmLj5q6lx2NZ+nkzCvKnzK9oIA==} + engines: {node: '>=18.17.0'} + peerDependencies: + next: ^13.5.4 || ^14.0.3 || ^15.0.0 + react: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + + '@clerk/shared@2.21.1': + resolution: {integrity: sha512-uwdxPI6RVa6f2YiOP8c1yDIjwTXB4IGG9BWKyiDGB5328UvPpEXnxutHUppXwLupM/XD/hNN9Npf+5CDbrR0wg==} + engines: {node: '>=18.17.0'} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@clerk/types@4.46.0': + resolution: {integrity: sha512-HsY3OCS9T4YP95skfoxwDQ41axXaCkjq67JoXoXxh0VTdvFXVzHwAoRiCvv9dLJeoapf1bfwJjGEMnDuNi3gbw==} + engines: {node: '>=18.17.0'} + '@cloudflare/kv-asset-handler@0.3.4': resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} engines: {node: '>=16.13'} @@ -2354,6 +2392,10 @@ packages: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + cookies@0.9.1: resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} engines: {node: '>= 0.8'} @@ -2392,6 +2434,9 @@ packages: crossws@0.3.4: resolution: {integrity: sha512-uj0O1ETYX1Bh6uSgktfPvwDiPYGQ3aI4qVsaC/LWpkIzGj1nUYm5FK3K+t11oOlpN01lGbprFCH4wBlKdJjVgw==} + crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + css-declaration-sorter@7.2.0: resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==} engines: {node: ^14 || ^16 || >=18} @@ -2541,6 +2586,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + destr@2.0.3: resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} @@ -2586,6 +2635,9 @@ packages: domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dot-prop@9.0.0: resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==} engines: {node: '>=18'} @@ -3187,6 +3239,10 @@ packages: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + js-levenshtein@1.1.6: resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} engines: {node: '>=0.10.0'} @@ -3324,6 +3380,9 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -3348,6 +3407,10 @@ packages: magicast@0.3.5: resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + map-obj@4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -3567,6 +3630,9 @@ packages: xml2js: optional: true + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} @@ -4265,6 +4331,9 @@ packages: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} + server-only@0.0.1: + resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} + setprototypeof@1.1.0: resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} @@ -4314,6 +4383,13 @@ packages: smob@1.5.0: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + + snakecase-keys@8.0.1: + resolution: {integrity: sha512-Sj51kE1zC7zh6TDlNNz0/Jn1n5HiHdoQErxO8jLtnyrkJW/M5PrI7x05uDgY3BO7OUQYKCvmeMurW6BPUdwEOw==} + engines: {node: '>=18'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -4449,6 +4525,11 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + swr@2.3.2: + resolution: {integrity: sha512-RosxFpiabojs75IwQ316DGoDRmOqtiAj0tg8wCcbEu4CiLZBs/a9QNtHV7TUfDXmmlgqij/NqzKq/eLelyv9xA==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + system-architecture@0.1.0: resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} engines: {node: '>=18'} @@ -4540,6 +4621,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@2.4.1: + resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -4777,6 +4861,11 @@ packages: '@types/react': optional: true + use-sync-external-store@1.4.0: + resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -5270,6 +5359,54 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@clerk/backend@1.24.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@clerk/shared': 2.21.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@clerk/types': 4.46.0 + cookie: 1.0.2 + snakecase-keys: 8.0.1 + tslib: 2.4.1 + transitivePeerDependencies: + - react + - react-dom + + '@clerk/clerk-react@5.22.13(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@clerk/shared': 2.21.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@clerk/types': 4.46.0 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + tslib: 2.4.1 + + '@clerk/nextjs@6.11.3(next@15.1.6(@babel/core@7.26.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@clerk/backend': 1.24.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@clerk/clerk-react': 5.22.13(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@clerk/shared': 2.21.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@clerk/types': 4.46.0 + crypto-js: 4.2.0 + next: 15.1.6(@babel/core@7.26.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + server-only: 0.0.1 + tslib: 2.4.1 + + '@clerk/shared@2.21.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@clerk/types': 4.46.0 + dequal: 2.0.3 + glob-to-regexp: 0.4.1 + js-cookie: 3.0.5 + std-env: 3.8.0 + swr: 2.3.2(react@19.0.0) + optionalDependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + + '@clerk/types@4.46.0': + dependencies: + csstype: 3.1.3 + '@cloudflare/kv-asset-handler@0.3.4': dependencies: mime: 3.0.0 @@ -5992,7 +6129,7 @@ snapshots: - vite - vue - '@nuxt/vite-builder@3.15.4(@types/node@20.17.19)(magicast@0.3.5)(rollup@4.34.7)(terser@5.39.0)(typescript@5.7.3)(vue-tsc@2.2.0(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))(yaml@2.7.0)': + '@nuxt/vite-builder@3.15.4(@types/node@20.17.19)(eslint@9.20.1(jiti@2.4.2))(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.7)(terser@5.39.0)(typescript@5.7.3)(vue-tsc@2.2.0(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))(yaml@2.7.0)': dependencies: '@nuxt/kit': 3.15.4(magicast@0.3.5) '@rollup/plugin-replace': 6.0.2(rollup@4.34.7) @@ -6023,7 +6160,7 @@ snapshots: unplugin: 2.2.0 vite: 6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0) vite-node: 3.0.5(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0) - vite-plugin-checker: 0.8.0(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3)) + vite-plugin-checker: 0.8.0(eslint@9.20.1(jiti@2.4.2))(optionator@0.9.4)(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3)) vue: 3.5.13(typescript@5.7.3) vue-bundle-renderer: 2.1.1 transitivePeerDependencies: @@ -7429,6 +7566,8 @@ snapshots: cookie@0.5.0: {} + cookie@1.0.2: {} + cookies@0.9.1: dependencies: depd: 2.0.0 @@ -7463,6 +7602,8 @@ snapshots: dependencies: uncrypto: 0.1.3 + crypto-js@4.2.0: {} + css-declaration-sorter@7.2.0(postcss@8.5.2): dependencies: postcss: 8.5.2 @@ -7586,6 +7727,8 @@ snapshots: depd@2.0.0: {} + dequal@2.0.3: {} + destr@2.0.3: {} destroy@1.2.0: {} @@ -7622,6 +7765,11 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + dot-prop@9.0.0: dependencies: type-fest: 4.34.1 @@ -8275,6 +8423,8 @@ snapshots: jiti@2.4.2: {} + js-cookie@3.0.5: {} + js-levenshtein@1.1.6: {} js-tokens@4.0.0: {} @@ -8438,6 +8588,10 @@ snapshots: lodash@4.17.21: {} + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + lru-cache@10.4.3: {} lru-cache@5.1.1: @@ -8466,6 +8620,8 @@ snapshots: '@babel/types': 7.26.9 source-map-js: 1.2.1 + map-obj@4.3.0: {} + math-intrinsics@1.1.0: {} mdn-data@2.0.28: {} @@ -8741,6 +8897,11 @@ snapshots: - typescript - uploadthing + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + node-addon-api@7.1.1: {} node-fetch-native@1.6.6: {} @@ -8777,7 +8938,7 @@ snapshots: dependencies: boolbase: 1.0.0 - nuxt@3.15.4(@parcel/watcher@2.5.1)(@types/node@20.17.19)(db0@0.2.4)(ioredis@5.5.0)(magicast@0.3.5)(rollup@4.34.7)(terser@5.39.0)(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3))(yaml@2.7.0): + nuxt@3.15.4(@parcel/watcher@2.5.1)(@types/node@20.17.19)(db0@0.2.4)(eslint@9.20.1(jiti@2.4.2))(ioredis@5.5.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.7)(terser@5.39.0)(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3))(yaml@2.7.0): dependencies: '@nuxt/cli': 3.21.1(magicast@0.3.5) '@nuxt/devalue': 2.0.2 @@ -8785,7 +8946,7 @@ snapshots: '@nuxt/kit': 3.15.4(magicast@0.3.5) '@nuxt/schema': 3.15.4 '@nuxt/telemetry': 2.6.5(magicast@0.3.5) - '@nuxt/vite-builder': 3.15.4(@types/node@20.17.19)(magicast@0.3.5)(rollup@4.34.7)(terser@5.39.0)(typescript@5.7.3)(vue-tsc@2.2.0(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))(yaml@2.7.0) + '@nuxt/vite-builder': 3.15.4(@types/node@20.17.19)(eslint@9.20.1(jiti@2.4.2))(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.7)(terser@5.39.0)(typescript@5.7.3)(vue-tsc@2.2.0(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))(yaml@2.7.0) '@unhead/dom': 1.11.19 '@unhead/shared': 1.11.19 '@unhead/ssr': 1.11.19 @@ -9539,6 +9700,8 @@ snapshots: transitivePeerDependencies: - supports-color + server-only@0.0.1: {} + setprototypeof@1.1.0: {} setprototypeof@1.2.0: {} @@ -9607,6 +9770,17 @@ snapshots: smob@1.5.0: {} + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + snakecase-keys@8.0.1: + dependencies: + map-obj: 4.3.0 + snake-case: 3.0.4 + type-fest: 4.34.1 + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -9733,6 +9907,12 @@ snapshots: csso: 5.0.5 picocolors: 1.1.1 + swr@2.3.2(react@19.0.0): + dependencies: + dequal: 2.0.3 + react: 19.0.0 + use-sync-external-store: 1.4.0(react@19.0.0) + system-architecture@0.1.0: {} tailwind-config-viewer@2.0.4(tailwindcss@3.4.17): @@ -9854,6 +10034,8 @@ snapshots: ts-interface-checker@0.1.13: {} + tslib@2.4.1: {} + tslib@2.8.1: {} tsscmp@1.0.6: {} @@ -10097,6 +10279,10 @@ snapshots: optionalDependencies: '@types/react': 19.0.8 + use-sync-external-store@1.4.0(react@19.0.0): + dependencies: + react: 19.0.0 + util-deprecate@1.0.2: {} vary@1.1.2: {} @@ -10126,7 +10312,7 @@ snapshots: - tsx - yaml - vite-plugin-checker@0.8.0(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3)): + vite-plugin-checker@0.8.0(eslint@9.20.1(jiti@2.4.2))(optionator@0.9.4)(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3)): dependencies: '@babel/code-frame': 7.26.2 ansi-escapes: 4.3.2 @@ -10144,6 +10330,8 @@ snapshots: vscode-languageserver-textdocument: 1.0.12 vscode-uri: 3.1.0 optionalDependencies: + eslint: 9.20.1(jiti@2.4.2) + optionator: 0.9.4 typescript: 5.7.3 vue-tsc: 2.2.0(typescript@5.7.3) From 3bcc27f7184e8fcb0cb846a78ce85e069d6b3af0 Mon Sep 17 00:00:00 2001 From: BalajiSriraman Date: Mon, 17 Feb 2025 22:04:56 +0530 Subject: [PATCH 2/4] Add fan page and contributors layout; refactor home layout and navigation --- .../src/app/{ => home}/contributers/page.tsx | 0 apps/client/src/app/{ => home}/fun/fan.tsx | 0 apps/client/src/app/{ => home}/fun/layout.tsx | 0 apps/client/src/app/{ => home}/fun/page.tsx | 0 apps/client/src/app/home/layout.tsx | 60 +++---- apps/client/src/app/layout.tsx | 36 +---- apps/client/src/app/page.tsx | 1 + apps/client/src/components/app-sidebar.tsx | 148 +++++++++--------- apps/client/src/components/nav-user.tsx | 68 ++++---- 9 files changed, 143 insertions(+), 170 deletions(-) rename apps/client/src/app/{ => home}/contributers/page.tsx (100%) rename apps/client/src/app/{ => home}/fun/fan.tsx (100%) rename apps/client/src/app/{ => home}/fun/layout.tsx (100%) rename apps/client/src/app/{ => home}/fun/page.tsx (100%) diff --git a/apps/client/src/app/contributers/page.tsx b/apps/client/src/app/home/contributers/page.tsx similarity index 100% rename from apps/client/src/app/contributers/page.tsx rename to apps/client/src/app/home/contributers/page.tsx diff --git a/apps/client/src/app/fun/fan.tsx b/apps/client/src/app/home/fun/fan.tsx similarity index 100% rename from apps/client/src/app/fun/fan.tsx rename to apps/client/src/app/home/fun/fan.tsx diff --git a/apps/client/src/app/fun/layout.tsx b/apps/client/src/app/home/fun/layout.tsx similarity index 100% rename from apps/client/src/app/fun/layout.tsx rename to apps/client/src/app/home/fun/layout.tsx diff --git a/apps/client/src/app/fun/page.tsx b/apps/client/src/app/home/fun/page.tsx similarity index 100% rename from apps/client/src/app/fun/page.tsx rename to apps/client/src/app/home/fun/page.tsx diff --git a/apps/client/src/app/home/layout.tsx b/apps/client/src/app/home/layout.tsx index a1ec9ce..4509e4d 100644 --- a/apps/client/src/app/home/layout.tsx +++ b/apps/client/src/app/home/layout.tsx @@ -1,5 +1,3 @@ -// TODO: Fix Dark and Light Mode - "use client"; import { AppSidebar } from "@/components/app-sidebar"; import { ReactNode, useEffect, useState } from "react"; @@ -9,41 +7,35 @@ import { SidebarProvider, SidebarTrigger, } from "@/components/ui/sidebar"; +import { ClerkProvider, SignedIn, SignedOut, SignIn } from "@clerk/nextjs"; +import TanstackProvider from "@/components/TanStackQuery/provider"; export default function Layout({ children }: { children: ReactNode }) { - // const { theme } = useTheme(); - const [mounted, setMounted] = useState(false); - - // Prevent hydration mismatch by mounting after first render - useEffect(() => { - setMounted(true); - }, []); - - // Default color while loading - const borderColor = ["#A07C", "#FE85", "#FBB"]; - - // const borderColor = mounted - // ? theme === "dark" - // ? "white" - // : "black" - // : "white"; - return ( - // - //
{children}
- - - -
-
- - + + {/* // ! Temp Show the page */} + {/* +
+
-
-
{children}
-
-
- - //
+ */} + + + {/* */} + + + +
+
+ + +
+
+
{children}
+
+
+ {/*
*/} +
+ ); } diff --git a/apps/client/src/app/layout.tsx b/apps/client/src/app/layout.tsx index 690396e..138d62f 100644 --- a/apps/client/src/app/layout.tsx +++ b/apps/client/src/app/layout.tsx @@ -6,14 +6,6 @@ import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import { Theme } from "@/components/theme"; import { PostHogProvider } from "@/components/posthog/providers"; -import TanstackProvider from "@/components/TanStackQuery/provider"; -import { - ClerkProvider, - SignedIn, - SignedOut, - SignIn, - UserButton, -} from "@clerk/nextjs"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -44,27 +36,13 @@ export default function RootLayout({ > - - - - - -
- -
-
- -
- -
- {children} -
- -
-
-
- -
+ + + {children} + + + + diff --git a/apps/client/src/app/page.tsx b/apps/client/src/app/page.tsx index b22012e..0ceae68 100644 --- a/apps/client/src/app/page.tsx +++ b/apps/client/src/app/page.tsx @@ -1,4 +1,5 @@ "use client"; +// ! Home Page import { Home as Main } from "@/components/home/index"; export default function Home() { return ( diff --git a/apps/client/src/components/app-sidebar.tsx b/apps/client/src/components/app-sidebar.tsx index b66a0df..b0e554d 100644 --- a/apps/client/src/components/app-sidebar.tsx +++ b/apps/client/src/components/app-sidebar.tsx @@ -1,20 +1,8 @@ -"use client"; - import * as React from "react"; -import { - AudioWaveform, - Command, - GalleryVerticalEnd, - Map, - PersonStandingIcon, - File, - Settings2, -} from "lucide-react"; +import { Map, PersonStandingIcon, File } from "lucide-react"; -import { NavMain } from "@/components/nav-main"; import { NavProjects } from "@/components/nav-projects"; import { NavUser } from "@/components/nav-user"; -import { TeamSwitcher } from "@/components/team-switcher"; import { Sidebar, SidebarContent, @@ -22,76 +10,80 @@ import { SidebarHeader, SidebarRail, } from "@/components/ui/sidebar"; -import FanIcon from "@/assests/icon/fan"; import { FanHandler } from "./common/FanHandler"; +import { useUser } from "@clerk/nextjs"; -// This is sample data. -const data = { - user: { - name: "Balaji Sriraman", - email: "balaji@mom.io", - avatar: "/avatars/shadcn.jpg", - }, - teams: [ - { - name: "Acme Inc", - logo: GalleryVerticalEnd, - plan: "Enterprise", - }, - { - name: "Acme Corp.", - logo: AudioWaveform, - plan: "Startup", - }, - { - name: "Evil Corp.", - logo: Command, - plan: "Free", - }, - ], - navMain: [ - { - title: "Playground", - url: "/", - icon: Settings2, +export function AppSidebar({ ...props }: React.ComponentProps) { + const { user } = useUser(); - isActive: true, - items: [ - { - title: "History", - url: "#", - }, - { - title: "Starred", - url: "#", - }, - { - title: "Settings", - url: "#", - }, - ], - }, - ], - projects: [ - { - name: "File Upload", - url: "/home/upload", - icon: File, - }, - { - name: "p2p Sharing", - url: "/home", - icon: PersonStandingIcon, - }, - { - name: "Video Streaming", - url: "/home/video", - icon: Map, + const data = { + projects: [ + { + name: "File Upload", + url: "/home/upload", + icon: File, + }, + { + name: "p2p Sharing", + url: "/home", + icon: PersonStandingIcon, + }, + { + name: "Video Streaming", + url: "/home/video", + icon: Map, + }, + ], + // TODO: v2 + // teams: [ + // { + // name: "Acme Inc", + // logo: GalleryVerticalEnd, + // plan: "Enterprise", + // }, + // { + // name: "Acme Corp.", + // logo: AudioWaveform, + // plan: "Startup", + // }, + // { + // name: "Evil Corp.", + // logo: Command, + // plan: "Free", + // }, + // ], + + // navMain: [ + // { + // title: "Playground", + // url: "/", + // icon: Settings2, + + // isActive: true, + // items: [ + // { + // title: "History", + // url: "#", + // }, + // { + // title: "Starred", + // url: "#", + // }, + // { + // title: "Settings", + // url: "#", + // }, + // ], + // }, + // ], + user: { + name: user?.fullName ?? "Guest User", + email: user?.primaryEmailAddress?.emailAddress ?? "", + avatar: user?.imageUrl ?? "", + guest: user ? false : true, }, - ], -}; + }; -export function AppSidebar({ ...props }: React.ComponentProps) { return ( diff --git a/apps/client/src/components/nav-user.tsx b/apps/client/src/components/nav-user.tsx index d12ef78..2d65240 100644 --- a/apps/client/src/components/nav-user.tsx +++ b/apps/client/src/components/nav-user.tsx @@ -1,19 +1,6 @@ -"use client" +import { ChevronsUpDown, Lock, LogOut } from "lucide-react"; -import { - BadgeCheck, - Bell, - ChevronsUpDown, - CreditCard, - LogOut, - Sparkles, -} from "lucide-react" - -import { - Avatar, - AvatarFallback, - AvatarImage, -} from "@/components/ui/avatar" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { DropdownMenu, DropdownMenuContent, @@ -22,24 +9,47 @@ import { DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" +} from "@/components/ui/dropdown-menu"; import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, useSidebar, -} from "@/components/ui/sidebar" +} from "@/components/ui/sidebar"; +import { useAuth, useClerk } from "@clerk/nextjs"; export function NavUser({ user, }: { user: { - name: string - email: string - avatar: string - } + name: string; + email: string; + avatar: string; + guest: boolean; + }; }) { - const { isMobile } = useSidebar() + const { isMobile } = useSidebar(); + const { signOut } = useAuth(); + const { openUserProfile } = useClerk(); + + if (user.guest) { + return ( + + + + + + CN + +
+ {user.name} + {user.email} +
+
+
+
+ ); + } return ( @@ -81,14 +91,14 @@ export function NavUser({ - - - Upgrade to Pro + openUserProfile()}> + + Manage Clerk - + {/* Account @@ -99,10 +109,10 @@ export function NavUser({ Notifications - + */} - + signOut()}> Log out @@ -110,5 +120,5 @@ export function NavUser({ - ) + ); } From db43e0ddd74c7d349938a77acd39dd61205b9ec9 Mon Sep 17 00:00:00 2001 From: BalajiSriraman Date: Mon, 17 Feb 2025 22:35:57 +0530 Subject: [PATCH 3/4] Implement file upload feature with UI and backend integration; refactor video page to gallery --- apps/client/package.json | 1 + apps/client/src/app/home/gallery/page.tsx | 17 +++ apps/client/src/app/home/layout.tsx | 4 +- apps/client/src/app/home/upload/page.tsx | 95 ++-------------- apps/client/src/app/home/video/page.tsx | 17 --- apps/client/src/components/app-sidebar.tsx | 2 +- apps/client/src/components/home/videoCard.tsx | 101 +++++++++++------- apps/client/src/components/ui/sonner.tsx | 31 ++++++ .../src/components/upload/upload-form.tsx | 79 ++++++++++++++ apps/client/src/utils/fileupload/index.ts | 0 apps/client/src/utils/index.ts | 35 ++++++ pnpm-lock.yaml | 14 +++ 12 files changed, 250 insertions(+), 146 deletions(-) create mode 100644 apps/client/src/app/home/gallery/page.tsx delete mode 100644 apps/client/src/app/home/video/page.tsx create mode 100644 apps/client/src/components/ui/sonner.tsx create mode 100644 apps/client/src/components/upload/upload-form.tsx create mode 100644 apps/client/src/utils/fileupload/index.ts create mode 100644 apps/client/src/utils/index.ts diff --git a/apps/client/package.json b/apps/client/package.json index 18504ec..eab0b0b 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -30,6 +30,7 @@ "posthog-js": "^1.217.4", "react": "^19.0.0", "react-dom": "^19.0.0", + "sonner": "^1.7.4", "tailwind-merge": "^3.0.1", "tailwindcss-animate": "^1.0.7" }, diff --git a/apps/client/src/app/home/gallery/page.tsx b/apps/client/src/app/home/gallery/page.tsx new file mode 100644 index 0000000..df80321 --- /dev/null +++ b/apps/client/src/app/home/gallery/page.tsx @@ -0,0 +1,17 @@ +import VideoGallery from "@/components/home/videoCard"; +import { Button } from "@/components/ui/button"; +import Link from "next/link"; +import React from "react"; + +function page() { + return ( +
+ + +
+ ); +} + +export default page; diff --git a/apps/client/src/app/home/layout.tsx b/apps/client/src/app/home/layout.tsx index 4509e4d..b37c97d 100644 --- a/apps/client/src/app/home/layout.tsx +++ b/apps/client/src/app/home/layout.tsx @@ -7,7 +7,8 @@ import { SidebarProvider, SidebarTrigger, } from "@/components/ui/sidebar"; -import { ClerkProvider, SignedIn, SignedOut, SignIn } from "@clerk/nextjs"; +import { ClerkProvider } from "@clerk/nextjs"; +import { Toaster } from "@/components/ui/sonner"; import TanstackProvider from "@/components/TanStackQuery/provider"; export default function Layout({ children }: { children: ReactNode }) { @@ -32,6 +33,7 @@ export default function Layout({ children }: { children: ReactNode }) {
{children}
+ {/* */} diff --git a/apps/client/src/app/home/upload/page.tsx b/apps/client/src/app/home/upload/page.tsx index 175ac68..cb587f0 100644 --- a/apps/client/src/app/home/upload/page.tsx +++ b/apps/client/src/app/home/upload/page.tsx @@ -1,88 +1,9 @@ -'use client' -import { Router } from 'lucide-react' -import { useRouter } from 'next/navigation' -import React from 'react' - -const Admin = () => { - const [file, setFile] = React.useState() - const Router = useRouter(); - - const handleFileChange = (event: React.ChangeEvent) => { - if (event.target.files) { - const currentFile = event.target.files[0] - setFile(currentFile) - } - } - - const handleUpload = async () => { - if (!file) return; - const formData = new FormData(); - formData.append("files", file); - // Request signed URL from the server - const response = await fetch(`${process.env.NEXT_PUBLIC_SERVER_LINK}/api/fileupload`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: formData, - mode:"no-cors" - }) - } - - - return ( -
-
-

- Admin Panel -

-

- Upload the latest version of the video file. -

- -
-
- -
-
-
- -
-

- {file?.name ? file.name : 'Video files up to 1GB'} -

-
-
-
-
-
- -
-
-
- ) +import { UploadForm } from "@/components/upload/upload-form"; + +export default function UploadPage() { + return ( +
+ +
+ ); } - -export default Admin; \ No newline at end of file diff --git a/apps/client/src/app/home/video/page.tsx b/apps/client/src/app/home/video/page.tsx deleted file mode 100644 index c4280ac..0000000 --- a/apps/client/src/app/home/video/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import VideoGallery from '@/components/home/videoCard' -import { Button } from '@/components/ui/button'; -import Link from 'next/link'; -import React from 'react' - -function page() { - return ( -
- - -
- ) -} - -export default page \ No newline at end of file diff --git a/apps/client/src/components/app-sidebar.tsx b/apps/client/src/components/app-sidebar.tsx index b0e554d..23598bc 100644 --- a/apps/client/src/components/app-sidebar.tsx +++ b/apps/client/src/components/app-sidebar.tsx @@ -30,7 +30,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { }, { name: "Video Streaming", - url: "/home/video", + url: "/home/gallery", icon: Map, }, ], diff --git a/apps/client/src/components/home/videoCard.tsx b/apps/client/src/components/home/videoCard.tsx index e8e54f5..17985c0 100644 --- a/apps/client/src/components/home/videoCard.tsx +++ b/apps/client/src/components/home/videoCard.tsx @@ -1,24 +1,24 @@ "use client"; -import React, { useState, useRef, useEffect } from 'react'; -import { Card, CardContent } from '@/components/ui/card'; -import { FileVideo, Clock, HardDrive, Calendar } from 'lucide-react'; -import { useQuery } from '@tanstack/react-query'; +import React, { useState, useRef, useEffect } from "react"; +import { Card, CardContent } from "@/components/ui/card"; +import { FileVideo, Clock, HardDrive, Calendar } from "lucide-react"; +import { useQuery } from "@tanstack/react-query"; // Utility function to format file size const formatFileSize = (bytes: number) => { - if (bytes === 0) return '0 Bytes'; + if (bytes === 0) return "0 Bytes"; const k = 1024; - const sizes = ['Bytes', 'KB', 'MB', 'GB']; + const sizes = ["Bytes", "KB", "MB", "GB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; }; // Utility function to format date const formatDate = (dateString: string) => { - return new Date(dateString).toLocaleDateString('en-US', { - year: 'numeric', - month: 'short', - day: 'numeric' + return new Date(dateString).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", }); }; @@ -39,12 +39,14 @@ interface Video { const VideoCard = ({ video }: { video: Video }) => { const [isHovering, setIsHovering] = useState(false); const videoRef = useRef(null); - const title = video.pathname?.split('.').slice(0, -1).join('.') || 'Untitled'; + const title = video.pathname?.split(".").slice(0, -1).join(".") || "Untitled"; const handleMouseEnter = () => { setIsHovering(true); if (videoRef.current) { - videoRef.current.play().catch(err => console.log('Video play failed:', err)); + videoRef.current + .play() + .catch((err) => console.log("Video play failed:", err)); } }; @@ -70,13 +72,17 @@ const VideoCard = ({ video }: { video: Video }) => { /> ) : (
- {(video.userName || 'U')[0].toUpperCase()} + {(video.userName || "U")[0].toUpperCase()}
)}
-

{video.userName || 'Anonymous User'}

-

{formatDate(video.uploadedAt)}

+

+ {video.userName || "Anonymous User"} +

+

+ {formatDate(video.uploadedAt)} +

@@ -87,18 +93,34 @@ const VideoCard = ({ video }: { video: Video }) => { onMouseLeave={handleMouseLeave} > {isHovering ? ( -