2023-03-28 09:52:44 +00:00
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
|
2023-04-04 12:50:18 +00:00
|
|
|
import { ApiHost } from "Const";
|
|
|
|
import Spinner from "Icons/Spinner";
|
|
|
|
import { ProxyImg } from "Element/ProxyImg";
|
|
|
|
|
|
|
|
interface LinkPreviewData {
|
|
|
|
title?: string;
|
|
|
|
description?: string;
|
|
|
|
image?: string;
|
|
|
|
}
|
|
|
|
|
2023-03-28 09:52:44 +00:00
|
|
|
async function fetchUrlPreviewInfo(url: string) {
|
2023-04-04 12:50:18 +00:00
|
|
|
const res = await fetch(`${ApiHost}/api/v1/preview?url=${encodeURIComponent(url)}`);
|
|
|
|
if (res.ok) {
|
|
|
|
return (await res.json()) as LinkPreviewData;
|
2023-03-28 09:52:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const LinkPreview = ({ url }: { url: string }) => {
|
2023-04-04 12:50:18 +00:00
|
|
|
const [preview, setPreview] = useState<LinkPreviewData>();
|
|
|
|
|
2023-03-28 09:52:44 +00:00
|
|
|
useEffect(() => {
|
2023-04-04 12:50:18 +00:00
|
|
|
(async () => {
|
|
|
|
const data = await fetchUrlPreviewInfo(url);
|
|
|
|
if (data) {
|
|
|
|
setPreview(data);
|
|
|
|
}
|
|
|
|
})().catch(console.error);
|
2023-03-28 09:52:44 +00:00
|
|
|
}, [url]);
|
2023-04-04 12:50:18 +00:00
|
|
|
|
2023-03-28 09:52:44 +00:00
|
|
|
return (
|
2023-03-28 10:11:21 +00:00
|
|
|
<div className="link-preview-container">
|
2023-04-04 12:50:18 +00:00
|
|
|
{preview && (
|
|
|
|
<a href={url} onClick={e => e.stopPropagation()} target="_blank" rel="noreferrer" className="ext">
|
|
|
|
{preview?.image && <ProxyImg src={preview?.image} className="link-preview-image" />}
|
|
|
|
<p className="link-preview-title">
|
|
|
|
{preview?.title}
|
|
|
|
{preview?.description && (
|
|
|
|
<>
|
|
|
|
<br />
|
|
|
|
<small>{preview?.description}</small>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</p>
|
|
|
|
</a>
|
|
|
|
)}
|
|
|
|
{!preview && <Spinner className="f-center" />}
|
2023-03-28 10:11:21 +00:00
|
|
|
</div>
|
2023-03-28 09:52:44 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default LinkPreview;
|