diff --git a/app/(protected)/admin/urls/page.tsx b/app/(protected)/admin/urls/page.tsx index 000e0c6..9dfed74 100644 --- a/app/(protected)/admin/urls/page.tsx +++ b/app/(protected)/admin/urls/page.tsx @@ -25,7 +25,7 @@ export default async function DashboardPage() { linkText="Short urls." /> > diff --git a/app/(protected)/dashboard/urls/page.tsx b/app/(protected)/dashboard/urls/page.tsx index 8578344..f38b6b0 100644 --- a/app/(protected)/dashboard/urls/page.tsx +++ b/app/(protected)/dashboard/urls/page.tsx @@ -25,7 +25,7 @@ export default async function DashboardPage() { linkText="Short urls." /> > diff --git a/app/(protected)/dashboard/urls/url-list.tsx b/app/(protected)/dashboard/urls/url-list.tsx index 2e93c16..f210302 100644 --- a/app/(protected)/dashboard/urls/url-list.tsx +++ b/app/(protected)/dashboard/urls/url-list.tsx @@ -50,7 +50,7 @@ import { PaginationWrapper } from "@/components/shared/pagination"; import UserUrlMetaInfo from "./meta"; export interface UrlListProps { - user: Pick; + user: Pick; action: string; } @@ -221,6 +221,7 @@ export default function UserUrlsList({ user, action }: UrlListProps) { diff --git a/app/api/scraping/screenshot/route.ts b/app/api/scraping/screenshot/route.ts index 971104b..bb47dec 100644 --- a/app/api/scraping/screenshot/route.ts +++ b/app/api/scraping/screenshot/route.ts @@ -1,7 +1,5 @@ import { env } from "@/env.mjs"; import { checkApiKey } from "@/lib/dto/api-key"; -import { checkUserStatus } from "@/lib/dto/user"; -import { getCurrentUser } from "@/lib/session"; import { isLink } from "@/lib/utils"; export const revalidate = 60; @@ -13,10 +11,10 @@ export async function GET(req: Request) { const url = new URL(req.url); const link = url.searchParams.get("url"); const full = url.searchParams.get("full") || "false"; - const width = url.searchParams.get("width") || "1600"; - const height = url.searchParams.get("height") || "1200"; - const viewportWidth = url.searchParams.get("viewportWidth") || "1080"; - const viewportHeight = url.searchParams.get("viewportHeight") || "1080"; + const width = url.searchParams.get("width") || "1200"; + const height = url.searchParams.get("height") || "750"; + const viewportWidth = url.searchParams.get("viewportWidth") || "1200"; + const viewportHeight = url.searchParams.get("viewportHeight") || "750"; const forceReload = url.searchParams.get("forceReload") || "false"; const isMobile = url.searchParams.get("isMobile") || "false"; const isDarkMode = url.searchParams.get("isDarkMode") || "false"; diff --git a/app/layout.tsx b/app/layout.tsx index 395b006..6626dff 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -40,7 +40,7 @@ export default function RootLayout({ children }: RootLayoutProps) { diff --git a/components/shared/icons.tsx b/components/shared/icons.tsx index 6349a02..04671e4 100644 --- a/components/shared/icons.tsx +++ b/components/shared/icons.tsx @@ -129,4 +129,23 @@ export const Icons = { link: Link, mail: Mail, bug: Bug, + outLink: ({ ...props }: LucideProps) => ( + + + + ), }; diff --git a/components/shared/link-previewer.tsx b/components/shared/link-previewer.tsx index 6d66caa..ce3f732 100644 --- a/components/shared/link-previewer.tsx +++ b/components/shared/link-previewer.tsx @@ -1,8 +1,5 @@ -import { useEffect, useState } from "react"; +import { useState } from "react"; import Link from "next/link"; -import BlogPost from "@/public/_static/illustrations/rocket-crashed.svg"; - -import { MetaScrapingProps } from "@/app/(protected)/dashboard/scrape/meta-scraping"; import { Skeleton } from "../ui/skeleton"; import { @@ -12,94 +9,72 @@ import { TooltipProvider, TooltipTrigger, } from "../ui/tooltip"; -import BlurImage, { BlurImg } from "./blur-image"; +import BlurImage from "./blur-image"; +import { Icons } from "./icons"; export function LinkPreviewer({ + apiKey, url, formatUrl, }: { + apiKey: string; url: string; formatUrl: string; }) { - const [open, setOpen] = useState(false); - const [isScraping, setIsScraping] = useState(false); - const [metaInfo, setMetaInfo] = useState(null); + const [screenshotInfo, setScreenshotInfo] = useState({ + tmp_url: "", + }); - const handleScrapingMeta = async () => { - if (url && open) { - setIsScraping(true); - const res = await fetch(`/api/scraping/meta?url=${url}`); + const handleScrapingScreenshot = async () => { + if (url) { + const res = await fetch( + `/api/scraping/screenshot?url=${url}&key=${apiKey}&width=1200&height=750&viewportWidth=1200&viewportHeight=750`, + ); if (!res.ok || res.status !== 200) { } else { - const data = await res.json(); - setMetaInfo(data); + const blob = await res.blob(); + const imageUrl = URL.createObjectURL(blob); + setScreenshotInfo({ + tmp_url: imageUrl, + }); } - setIsScraping(false); } }; - useEffect(() => { - handleScrapingMeta(); - }, [url, open]); - - const renderLink = (text: string) => ( - - {text} - - ); + const handleOpenChange = (open: boolean) => { + if (open) { + handleScrapingScreenshot(); + } + }; return ( - - setOpen(!open)} - > - {formatUrl} + + + + {formatUrl} + setOpen(false)} - onMouseLeave={() => setOpen(false)} + align="start" + className="group flex h-[187px] w-[300px] flex-col items-center justify-center rounded-lg bg-gradient-to-br from-black to-gray-500 p-0 shadow-inner transition-all duration-200" > - {isScraping ? ( - - - Previewing... - - ) : metaInfo?.title ? ( - - - - {renderLink(metaInfo?.title ?? url)} - - {metaInfo?.description} - - - + {screenshotInfo.tmp_url ? ( + ) : ( - - - Faild to preview link - - {renderLink(formatUrl ?? url)} - + )}
Previewing...
- {metaInfo?.description} -
- Faild to preview link -