mirror of
https://github.com/DefectingCat/DefectingCat.github.io
synced 2025-07-15 16:51:37 +00:00
add url previewer in post content
This commit is contained in:
@ -1,5 +1,13 @@
|
||||
import React from 'react';
|
||||
import { HTMLAttributes } from 'react';
|
||||
import React, { HTMLAttributes } from 'react';
|
||||
import UrlPreviewer from './url-previewer';
|
||||
|
||||
type ChildType = {
|
||||
type: {
|
||||
render: {
|
||||
displayName: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const Paragraph = (props: HTMLAttributes<HTMLParagraphElement>) => {
|
||||
const { children, ...rest } = props;
|
||||
@ -8,7 +16,7 @@ const Paragraph = (props: HTMLAttributes<HTMLParagraphElement>) => {
|
||||
const links = React.Children.map(children, (child) => {
|
||||
if (!React.isValidElement(child)) return null;
|
||||
if (typeof child.type !== 'object') return null;
|
||||
const childType = child.type as any;
|
||||
const childType = child.type as ChildType;
|
||||
if (!childType?.type) return null;
|
||||
if (childType.type.render.displayName !== 'Anchor') return null;
|
||||
const props = child.props as { href: string };
|
||||
@ -18,7 +26,14 @@ const Paragraph = (props: HTMLAttributes<HTMLParagraphElement>) => {
|
||||
return (
|
||||
<>
|
||||
<p {...rest}>{children}</p>
|
||||
{links?.map((url, i) => <div key={i}>{url}</div>)}
|
||||
|
||||
{!!links?.length && (
|
||||
<div>
|
||||
{links?.map((url, i) => (
|
||||
<UrlPreviewer className="mb-4 last:mb-0" key={i} url={url} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
64
components/mdx/url-previewer.tsx
Normal file
64
components/mdx/url-previewer.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
import clsx from 'clsx';
|
||||
import { urlMeta } from 'lib/fetcher';
|
||||
import { isUrl } from 'lib/utils';
|
||||
import Image from 'next/image';
|
||||
|
||||
/**
|
||||
* Url card previewer
|
||||
*/
|
||||
const UrlPreviewer = async ({
|
||||
url,
|
||||
className,
|
||||
}: {
|
||||
url: string;
|
||||
className?: string;
|
||||
}) => {
|
||||
if (!isUrl(url)) return null;
|
||||
|
||||
const metadata = await urlMeta(url);
|
||||
const imageUrl =
|
||||
metadata.links.find((v) => v.type.startsWith('image/'))?.href ?? '';
|
||||
|
||||
return (
|
||||
<a href={url} target="_blank" className={clsx(className, 'block')}>
|
||||
<div
|
||||
className={clsx(
|
||||
'rounded-lg h-40',
|
||||
'bg-white',
|
||||
'flex cursor-pointer dark:bg-rua-gray-700',
|
||||
)}
|
||||
>
|
||||
<Image
|
||||
alt=""
|
||||
src={imageUrl}
|
||||
width={160}
|
||||
height={160}
|
||||
className="object-cover"
|
||||
/>
|
||||
<div className="py-4 px-5 md:p-7 overflow-hidden">
|
||||
<div className={clsx('text-xl mb-1 font-semibold')}>
|
||||
{metadata.meta.title}
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
'overflow-hidden whitespace-nowrap text-ellipsis',
|
||||
'mb-1',
|
||||
)}
|
||||
>
|
||||
{metadata.meta.description}
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
'overflow-hidden whitespace-nowrap text-ellipsis',
|
||||
'mb-1 text-gray-400 dark:text-gray-600',
|
||||
)}
|
||||
>
|
||||
{url}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export default UrlPreviewer;
|
Reference in New Issue
Block a user