Link previewer in Next.js

7/9/2023, Published in Medium, DevTo and HashNode

Write API route in nextjs for getting the link preview

import mql from "@microlink/mql";

export default async function handler(req, res) {
  try {
    let { url } = req.query;
    const { data } = await mql(url, {
      screenshot: true,
    //   apiKey: process.env.NEXT_MICROLINK_API_KEY, 
      // @ts-ignore
      overlay: {
        background:
          "linear-gradient(225deg, #8ef472 0%, #4267ec 50%, #26F0C0 100%)",
        browser: "dark",
      },
    });
    res.status(200).json({
      image: data?.screenshot?.url,
    });
  } catch (error) {
    res.status(500).json({
      error: JSON.stringify(error),
    });
  }
}

Now, create the Link Previewer component.

import React, { useCallback, useEffect } from "react";

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

type Props = {
  children: any;
  href: string;
};

export default function LinkPreview({ children, href }: Props) {
  let [imagePreview, setImagePreview] = React.useState("");
  let [isHovering, setIsHovering] = React.useState(false);
  let inLink = false;

  let handleMouseEnterLink = () => {
    inLink = true;
    setIsHovering(true);
  };

  let handleMouseLeaveLink = () => {
    inLink = false;
    setIsHovering(false);
  };

  let handleFetchImage = useCallback(async (url: string) => {
    const res = await fetch(`/api/link-preview?url=${url}`);
    const data = await res.json();
    setImagePreview(data.image);
  }, []);

  useEffect(() => {
    handleFetchImage(href);
  }, []);

  return (
    <span>
      <span className="relative z-10 hidden md:inline-block">
        {/* Link itself */}
        <Link
          href={href}
          className={`${isHovering && "underline"}`}
          onMouseEnter={handleMouseEnterLink}
          onMouseLeave={handleMouseLeaveLink}
          onFocus={handleMouseEnterLink}
          onBlur={handleMouseLeaveLink}
        >
          {children}
        </Link>

        {/* Image Preview */}
        {isHovering && (
          <Link href={href} passHref>
            <span className="w-56 h-44 absolute top-[-255px] left-1/2 transform -translate-x-[7rem] translate-y-8 flex items-start justify-center">
              {imagePreview ? (
                <Image
                  fill
                  className="object-cover object-top w-56 h-40 bg-white rounded-md shadow-lg hover:ring-4 hover:ring-emerald-400"
                  src={imagePreview}
                  alt={children}
                />
              ) : (
                <span className="flex items-center justify-center w-56 h-40 bg-white rounded-md shadow-lg">
                  Loading...
                </span>
              )}
            </span>
          </Link>
        )}
      </span>

      {/* For mobile devices */}
      <a href={href} className={`${isHovering && "underline"} md:hidden`}>
        {children}
      </a>
    </span>
  );
}

ALL SYSTEMS ONLINE