From 5bd643e672a36f25a2d489677d73bc2032761165 Mon Sep 17 00:00:00 2001 From: zmeyer44 Date: Sun, 15 Oct 2023 08:40:36 -0400 Subject: [PATCH] added link preview card --- components/LinkCard/index.tsx | 77 +++++++++++++++++++++++++++++++++++ lib/fetchers/metadata.ts | 31 ++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 components/LinkCard/index.tsx create mode 100644 lib/fetchers/metadata.ts diff --git a/components/LinkCard/index.tsx b/components/LinkCard/index.tsx new file mode 100644 index 0000000..a78d2b6 --- /dev/null +++ b/components/LinkCard/index.tsx @@ -0,0 +1,77 @@ +"use client"; + +import { useState, useEffect } from "react"; +import Image from "next/image"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { cn } from "@/lib/utils"; +import { fetchMetadata } from "@/lib/fetchers/metadata"; +import { HiOutlineCheckBadge } from "react-icons/hi2"; + +type LinkCardProps = { + url: string; + metadata?: { + title: string; + image?: string; + description?: string; + creator?: string; + type?: string; + "theme-color"?: string; + }; + className?: string; +}; +export default function LinkCard({ + url, + metadata: _metadata, + className, +}: LinkCardProps) { + const [metadata, setMetadata] = useState(_metadata); + useEffect(() => { + if (!metadata) { + fetchMetadata(url) + ?.then((r) => { + if (r) { + setMetadata(r.data); + } + }) + .catch((e) => console.log("fetch error")); + } + }, [url]); + if (metadata) { + return ( + + + {metadata.image && ( +
+ {metadata.title} +
+ )} +
+ + {metadata.title} + + {metadata.description} + + +
+
+
+ ); + } + return null; +} diff --git a/lib/fetchers/metadata.ts b/lib/fetchers/metadata.ts new file mode 100644 index 0000000..da3d05a --- /dev/null +++ b/lib/fetchers/metadata.ts @@ -0,0 +1,31 @@ +import { z } from "zod"; +import { validateUrl } from "@/lib/utils"; +import { createZodFetcher } from "zod-fetch"; + +const fetchWithZod = createZodFetcher(); + +const metadataSchema = z.object({ + title: z.string(), + description: z.string().optional(), + image: z.string().optional(), + creator: z.string().optional(), + type: z.string().optional(), + "theme-color": z.string().optional(), +}); +const metadataSchemaResponse = z.object({ + data: metadataSchema, +}); + +export function fetchMetadata(url: string) { + if (!validateUrl(url)) return; + return fetchWithZod( + // The schema you want to validate with + metadataSchemaResponse, + // Any parameters you would usually pass to fetch + "/api/metadata", + { + method: "POST", + body: JSON.stringify({ url }), + }, + ); +}