Skip to content

Commit

Permalink
feat: update link-preview
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-guoba committed Feb 24, 2024
1 parent 3ef8e18 commit 6162be0
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 69 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Most common block types are supported. But some blocks information not supported
|------------------------|-----------|-------------------------------------|
| Paragraph | ✅ Yes | |
| Headings | ✅ Yes | |
| Bookmark | ✅ Yes | No detail info, only link |
| Bookmark | ✅ Yes | Use unfurl.js |
| Breadcrumb | ❌ Missing | Not planned |
| Bulleted List | ✅ Yes | |
| Callout | ✅ Yes | |
Expand All @@ -59,7 +59,7 @@ Most common block types are supported. But some blocks information not supported
| Equation | ✅ Yes | Use [katex ](https://katex.org/) |
| File | ✅ Yes | |
| Image | ✅ Yes | No position、size info in API |
| Link Preview | ✅ Yes | |
| Link Preview | ✅ Yes | Use unfurl.js |
| Mention | ✅ Yes | Only Date |
| Numbered List | ✅ Yes | |
| PDF | ✅ Yes | |
Expand Down
3 changes: 1 addition & 2 deletions app/api/unfurl/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ export async function GET(

return unfurl(url)
.then((unfurlResponse) => {

console.log(unfurlResponse)
// console.log(unfurlResponse)

const response = {
title: unfurlResponse.title ?? null,
Expand Down
78 changes: 51 additions & 27 deletions app/notion/_components/bookmark.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ import { Icons } from "@/components/icons";
import { UrlData, useUnfurlUrl } from "@/lib/unfurl";
import { Skeleton } from "@/components/ui/skeleton";

import Image from "next/image";
// import Image from "next/image";
import Link from "next/link";

import { PlaceholderImage } from "@/components/placeholder-image";

import { AspectRatio } from "@/components/ui/aspect-ratio";
// import { PlaceholderImage } from "@/components/placeholder-image";
// import { AspectRatio } from "@/components/ui/aspect-ratio";
import {
CardContent,
CardDescription,
Expand All @@ -35,7 +34,7 @@ export function BookmarkRender({ block, className }: BookmarkBlockProps) {

return (
<div
className={cn(className, "inline-flex w-full items-center flex-wrap")}
className={cn(className, "inline-flex items-center flex-wrap")}
title="bookmark"
>
<Icons.bookmark className="h-6 w-6 p-[0.8] text-gray-600" />
Expand All @@ -60,12 +59,13 @@ export function BookmarkRender({ block, className }: BookmarkBlockProps) {

function LoadingSkeleton() {
return (
<div className="flex flex-col space-y-3">
<Skeleton className="h-[125px] w-[250px] rounded-xl" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
<div className="border border-gray-200 flex overflow-hidden w-full max-w-full">
<div className="flex-[4_1_180px] space-y-2 p-4">
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-full" />
</div>
<Skeleton className="flex-[1_1_180px] relative hidden md:flex max-h-32" />
</div>
);
}
Expand All @@ -91,34 +91,48 @@ function UnfurledBookmarkPreview({

return (
<div key={id} className={className}>
<Link href={url}>
<Link href={url} target="_blank">
<div className="border border-gray-200 flex overflow-hidden w-full max-w-full">
{/* <span className="sr-only">{url}</span> */}

<div className="flex-[4_1_180px] space-y-2 p-4">
<div className="flex-auto w-96 space-y-2 p-4">
<CardHeader className="p-0">
<CardContent className="line-clamp-1 font-normal p-0 text-sm">
{title}
</CardContent>
</CardHeader>
<CardDescription className="text-xs">{desc}</CardDescription>
<CardContent className="text-xs p-0">
{url}
</CardContent>
<CardDescription className="text-xs max-h-8 overflow-hidden">
{desc}
</CardDescription>

<div className="flex overflow-hidden w-full max-w-full">
{icon ? (
<div className="flex-none w-6 flex justify-center">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={icon}
alt={url}
className="px-1"
/>
</div>
) : null}
<CardContent className="text-xs p-0 max-h-4 overflow-hidden">
{url}
</CardContent>
</div>
</div>
<div className="flex-[1_1_180px] relative hidden md:flex max-h-32">
{image ? (
// eslint-disable-next-line @next/next/no-img-element
{image ? (
<div className="flex-auto w-32 relative md:block hidden max-h-32 h-full">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={image}
alt={url}
className="object-cover"
// priority={i <= 1}
/>
) : (
<PlaceholderImage asChild />
)}
</div>
</div>
) : // <PlaceholderImage asChild />
null}
</div>
</Link>

Expand All @@ -136,14 +150,24 @@ export function BookmarkPreviewRender({
className,
}: BookmarkBlockProps) {
const {
id,
bookmark: { caption, url },
bookmark: { url },
} = block;
const { status, data } = useUnfurlUrl(url);

console.log(status, data);
if (status == "error") {
return <BookmarkRender block={block} className={className} />;
const raw = new URL(url);
const empty: UrlData = {
title: raw.hostname,
description: "",
};
// return <BookmarkRender block={block} className={className} />;
return (
<UnfurledBookmarkPreview
block={block}
className={className}
data={empty}
/>
);
}
if (status == "success") {
return (
Expand Down
139 changes: 139 additions & 0 deletions app/notion/_components/link-preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
"use client"

import { cn } from "@/lib/utils";
import RichText from "../text";
// import { Icons } from "@/components/icons";
import { UrlData, useUnfurlUrl } from "@/lib/unfurl";
import { Skeleton } from "@/components/ui/skeleton";
import Link from "next/link";

// import { PlaceholderImage } from "@/components/placeholder-image";
// import { AspectRatio } from "@/components/ui/aspect-ratio";
import { CardContent, CardDescription, CardHeader } from "@/components/ui/card";

interface LinkPreviewBlockProps {
block: any;
className?: string | undefined;
}

// export function LinkPreviewRender({ block, className }: LinkPreviewBlockProps) {
// const {
// id,
// link_preview: { caption, url },
// } = block;
// if (!url) {
// return null;
// }

// return (
// <div className={cn(className, "inline-flex w-full items-center flex-wrap")} title="link preview">
// <Icons.linkpreview className="h-6 w-6 p-[0.8] text-gray-600"/>
// <a
// id={id}
// href={url}
// target="_blank"
// rel="noreferrer noopener"
// className="whitespace-pre-wrap break-words font-normal truncate"
// >
// {url}
// </a>
// </div>
// );
// }

function LoadingSkeleton() {
return (
<div className="border border-gray-200 flex overflow-hidden w-full max-w-full">
<div className="flex-[4_1_180px] space-y-2 p-4">
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-full" />
</div>
<Skeleton className="flex-[1_1_180px] relative hidden md:flex max-h-32" />
</div>
);
}

function UnfurledLinkPreview({
block,
data,
className,
}: {
block: any;
data: UrlData | null;
className?: string | undefined;
}) {
const {
id,
link_preview: { caption, url },
} = block;

// const image = data?.imageSrc;
const title = data?.title;
const desc = data?.description;
const icon = data?.favicon;

return (
<div key={id} className={className}>
<Link href={url} target="_blank">
<div className="border border-gray-200 flex overflow-hidden w-full max-w-full">
<span className="sr-only">{url}</span>
{icon ? (
<div className="flex-none w-12 flex justify-center">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={icon}
alt={url}
className="px-1.5"
/>
</div>
) : null}

<div className="flex-auto w-96 space-y-2 p-2">
{/* <CardHeader className="p-0"> */}
<CardContent className="line-clamp-1 font-bold p-0 text-sm overflow-hidden">
{title}
</CardContent>
{/* </CardHeader> */}
<CardDescription className="text-xs max-h-4 overflow-hidden">
{desc}
</CardDescription>
{/* <CardContent className="text-xs p-0 max-h-8 overflow-hidden">
{url}
</CardContent> */}
</div>
</div>
</Link>

{caption && caption.length > 0 ? (
<div className="px-1.5 font-light">
<RichText title={caption} />
</div>
) : null}
</div>
);
}

export function LinkPreviewRender({ block, className }: LinkPreviewBlockProps) {
const {
link_preview: { url },
} = block;
const { status, data } = useUnfurlUrl(url);

if (status == "error") {
const raw = new URL(url);
const empty: UrlData = {
title: raw.hostname,
description: "",
};

return (
<UnfurledLinkPreview block={block} className={className} data={empty} />
);
}
if (status == "success") {
return (
<UnfurledLinkPreview block={block} className={className} data={data} />
);
}
return <LoadingSkeleton />;
}
33 changes: 0 additions & 33 deletions app/notion/_components/link_preview.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion app/notion/_components/pdf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export function PDFRender({ block, className }: PDFBlockProps) {
}

return (
<div key={id} className={cn(className, "w-full max-w-ful min-w-full")}>
<div key={id} className={cn(className, "flex-wrap w-full max-w-ful min-w-full")}>
<Nav pageNumber={pageNumber} numPages={numPages} title={title} />
<div
hidden={loading}
Expand Down
2 changes: 1 addition & 1 deletion app/notion/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ColumnListRender, ColumnRender } from './_components/column';
import { QuoteRender } from './_components/quote';
import { TableRender } from './_components/table';
import { EquationRender } from './_components/equation';
import { LinkPreviewRender } from './_components/link_preview';
import { LinkPreviewRender } from './_components/link-preview';
import { PDFRender } from './_components/pdf';
import { SubPageRender } from './_components/sub_page';

Expand Down
6 changes: 3 additions & 3 deletions lib/unfurl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ type RequestStatus = "iddle" | "loading" | "success" | "error";

export type UrlData = {
title: string | null;
description: string | null;
favicon: string | null;
imageSrc: string | null;
description?: string | null;
favicon?: string | null;
imageSrc?: string | null;
};

export function useUnfurlUrl(url: string) {
Expand Down

0 comments on commit 6162be0

Please sign in to comment.