This commit is contained in:
		| @@ -0,0 +1,7 @@ | |||||||
|  | -- CreateTable | ||||||
|  | CREATE TABLE "Clipboard" ( | ||||||
|  |     "id" SERIAL NOT NULL, | ||||||
|  |     "content" TEXT NOT NULL, | ||||||
|  |  | ||||||
|  |     CONSTRAINT "Clipboard_pkey" PRIMARY KEY ("id") | ||||||
|  | ); | ||||||
| @@ -30,3 +30,8 @@ model User { | |||||||
|     username String @unique |     username String @unique | ||||||
|     password String |     password String | ||||||
| } | } | ||||||
|  |  | ||||||
|  | model Clipboard { | ||||||
|  |     id      Int    @id @default(autoincrement()) | ||||||
|  |     content String @db.Text | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										46
									
								
								src/app/clipboard/ClipboardComponent.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/app/clipboard/ClipboardComponent.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | "use client"; | ||||||
|  | import { useState } from "react"; | ||||||
|  | import { updateClipboard } from "./action"; | ||||||
|  |  | ||||||
|  | export default function ClipboardComponent({ | ||||||
|  |   initialContent, | ||||||
|  | }: { | ||||||
|  |   initialContent: string; | ||||||
|  | }) { | ||||||
|  |   const [clipboardContent, setClipboardContent] = useState(initialContent); | ||||||
|  |   const [typingTimeout, setTypingTimeout] = useState<NodeJS.Timeout | null>( | ||||||
|  |     null | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   const contentChanged = (content: string) => { | ||||||
|  |     setClipboardContent(content); | ||||||
|  |     if (typingTimeout) { | ||||||
|  |       clearTimeout(typingTimeout); | ||||||
|  |     } | ||||||
|  |     const timeout = setTimeout(async () => { | ||||||
|  |       await updateClipboard(content); | ||||||
|  |     }, 500); | ||||||
|  |     setTypingTimeout(timeout); | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <> | ||||||
|  |       <textarea | ||||||
|  |         style={{ | ||||||
|  |           width: "100%", | ||||||
|  |           resize: "none", | ||||||
|  |           borderStyle: "none", | ||||||
|  |           backgroundColor: "#333", | ||||||
|  |           height: "20rem", | ||||||
|  |           maxHeight: "80vh", | ||||||
|  |           color: "#eee", | ||||||
|  |         }} | ||||||
|  |         onChange={(e) => contentChanged(e.target.value)} | ||||||
|  |         onBlur={async (e) => { | ||||||
|  |           await updateClipboard(e.target.value); | ||||||
|  |         }} | ||||||
|  |         value={clipboardContent} | ||||||
|  |       ></textarea> | ||||||
|  |     </> | ||||||
|  |   ); | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								src/app/clipboard/action.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/app/clipboard/action.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | "use server"; | ||||||
|  |  | ||||||
|  | import { PrismaClient } from "@prisma/client"; | ||||||
|  |  | ||||||
|  | export async function updateClipboard(content: string) { | ||||||
|  |   const prisma = new PrismaClient(); | ||||||
|  |   await prisma.clipboard.upsert({ | ||||||
|  |     where: { id: 1 }, | ||||||
|  |     update: { content }, | ||||||
|  |     create: { content }, | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | export async function getClipboard(): Promise<string> { | ||||||
|  |   const prisma = new PrismaClient(); | ||||||
|  |   const clipboard = await prisma.clipboard.findUnique({ | ||||||
|  |     where: { id: 1 }, | ||||||
|  |   }); | ||||||
|  |   return clipboard?.content || ""; | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								src/app/clipboard/page.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/app/clipboard/page.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | "use server"; | ||||||
|  |  | ||||||
|  | import { getClipboard } from "./action"; | ||||||
|  | import ClipboardComponent from "./ClipboardComponent"; | ||||||
|  |  | ||||||
|  | export default async function ClipboardPage() { | ||||||
|  |   const clipboard = await getClipboard(); | ||||||
|  |   return ( | ||||||
|  |     <> | ||||||
|  |       <ClipboardComponent initialContent={clipboard} /> | ||||||
|  |     </> | ||||||
|  |   ); | ||||||
|  | } | ||||||
| @@ -4,17 +4,20 @@ import Title from "@/components/Title"; | |||||||
| import Navbar from "@/components/Navbar"; | import Navbar from "@/components/Navbar"; | ||||||
| import { bodyFont } from "@/components/fonts"; | import { bodyFont } from "@/components/fonts"; | ||||||
| import Link from "next/link"; | import Link from "next/link"; | ||||||
|  | import { auth } from "@/auth"; | ||||||
|  |  | ||||||
| export const metadata: Metadata = { | export const metadata: Metadata = { | ||||||
|   title: "nrx.sh", |   title: "nrx.sh", | ||||||
|   description: "naresh's site", |   description: "naresh's site", | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export default function RootLayout({ | export default async function RootLayout({ | ||||||
|   children, |   children, | ||||||
| }: Readonly<{ | }: Readonly<{ | ||||||
|   children: React.ReactNode; |   children: React.ReactNode; | ||||||
| }>) { | }>) { | ||||||
|  |   const isLoggedIn = (await auth())?.user != null; | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <html lang="en"> |     <html lang="en"> | ||||||
|       <body> |       <body> | ||||||
| @@ -28,7 +31,7 @@ export default function RootLayout({ | |||||||
|         > |         > | ||||||
|           <Title /> |           <Title /> | ||||||
|  |  | ||||||
|           <Navbar /> |           <Navbar isLoggedIn={isLoggedIn} /> | ||||||
|           <div |           <div | ||||||
|             className={bodyFont.className} |             className={bodyFont.className} | ||||||
|             style={{ |             style={{ | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import { useState } from "react"; | |||||||
| import React from "react"; | import React from "react"; | ||||||
| import { navBarFont } from "./fonts"; | import { navBarFont } from "./fonts"; | ||||||
| import { | import { | ||||||
|  |   ADMIN_PAGES, | ||||||
|   PAGES, |   PAGES, | ||||||
|   Pages, |   Pages, | ||||||
|   pathNameFromSelectedPage, |   pathNameFromSelectedPage, | ||||||
| @@ -11,7 +12,7 @@ import { | |||||||
| } from "./pages"; | } from "./pages"; | ||||||
| import { usePathname, useRouter } from "next/navigation"; | import { usePathname, useRouter } from "next/navigation"; | ||||||
|  |  | ||||||
| export default function Navbar() { | export default function Navbar({ isLoggedIn }: { isLoggedIn: boolean }) { | ||||||
|   const [hoveredPage, setHoveredPage] = useState<Pages | null>(null); |   const [hoveredPage, setHoveredPage] = useState<Pages | null>(null); | ||||||
|  |  | ||||||
|   const pathName = usePathname(); |   const pathName = usePathname(); | ||||||
| @@ -41,7 +42,10 @@ export default function Navbar() { | |||||||
|         justifyContent: "center", |         justifyContent: "center", | ||||||
|       }} |       }} | ||||||
|     > |     > | ||||||
|       {PAGES.map((page, index) => ( |       {PAGES.filter((p) => { | ||||||
|  |         if (!isLoggedIn && ADMIN_PAGES.includes(p)) return false; | ||||||
|  |         return true; | ||||||
|  |       }).map((page, index) => ( | ||||||
|         <React.Fragment key={page}> |         <React.Fragment key={page}> | ||||||
|           <div |           <div | ||||||
|             style={navbarItem(page)} |             style={navbarItem(page)} | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| export type Pages = "home" | "about" | "links" | "contact" | "blog"; | export type Pages = "home" | "about" | "links" | "contact" | "blog" | "clipboard"; | ||||||
| export const PAGES: Pages[] = ["home", "about", "blog", "links", "contact"]; | export const PAGES: Pages[] = ["home", "about", "blog", "links", "contact", "clipboard"]; | ||||||
|  | export const ADMIN_PAGES: Pages[] = ["clipboard"] | ||||||
|  |  | ||||||
| export function selectedPageFromPathName(pathName: string): Pages { | export function selectedPageFromPathName(pathName: string): Pages { | ||||||
|   if (pathName === "/") { |   if (pathName === "/") { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user