add url previewer in post content

This commit is contained in:
DefectingCat
2024-01-04 11:23:01 +08:00
parent 14c99275f7
commit d5607c0105
6 changed files with 120 additions and 7 deletions

View File

@ -1,5 +1,13 @@
import React from 'react'; import React, { HTMLAttributes } from 'react';
import { HTMLAttributes } from 'react'; import UrlPreviewer from './url-previewer';
type ChildType = {
type: {
render: {
displayName: string;
};
};
};
const Paragraph = (props: HTMLAttributes<HTMLParagraphElement>) => { const Paragraph = (props: HTMLAttributes<HTMLParagraphElement>) => {
const { children, ...rest } = props; const { children, ...rest } = props;
@ -8,7 +16,7 @@ const Paragraph = (props: HTMLAttributes<HTMLParagraphElement>) => {
const links = React.Children.map(children, (child) => { const links = React.Children.map(children, (child) => {
if (!React.isValidElement(child)) return null; if (!React.isValidElement(child)) return null;
if (typeof child.type !== 'object') 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) return null;
if (childType.type.render.displayName !== 'Anchor') return null; if (childType.type.render.displayName !== 'Anchor') return null;
const props = child.props as { href: string }; const props = child.props as { href: string };
@ -18,7 +26,14 @@ const Paragraph = (props: HTMLAttributes<HTMLParagraphElement>) => {
return ( return (
<> <>
<p {...rest}>{children}</p> <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>
)}
</> </>
); );
}; };

View 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;

View File

@ -4,8 +4,6 @@ date: '2023-12-26'
tags: [Rust, Linux] tags: [Rust, Linux]
--- ---
test [rua](https://rua.plus) test [rua](https://rua.plus) test [rua](https://rua.plus)
大多数 Linux 软件都是动态链接的,动态链接可以使我们的程序不需要将所有所需要的库都打包到自身当中去。不过这样也有弊处,当目标系统比较旧,或者压根就没有我们需要的库的时候,我们的二进制文件就无法在目标系统中运行。 大多数 Linux 软件都是动态链接的,动态链接可以使我们的程序不需要将所有所需要的库都打包到自身当中去。不过这样也有弊处,当目标系统比较旧,或者压根就没有我们需要的库的时候,我们的二进制文件就无法在目标系统中运行。
## 安装交叉编译工具 ## 安装交叉编译工具

View File

@ -132,3 +132,25 @@ export const getSignalGist = cache(async (id: string) => {
return data; return data;
}); });
export interface LinkResult {
meta: Meta;
links: Link[];
rel: [];
}
export interface Link {
href: string;
rel: string[];
type: string;
}
export interface Meta {
description: string;
title: string;
author: string;
canonical: string;
}
export const urlMeta = cache(async (url: string) => {
return (await (
await fetch(`http://iframely.server.crestify.com/iframely?url=${url}`)
).json()) as LinkResult;
});

View File

@ -152,3 +152,10 @@ export const frameArea = (
// point the camera to look at the center of the box // point the camera to look at the center of the box
camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z); camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z);
}; };
export const isUrl = (url: string) => {
const urlRegex = new RegExp(
'^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$',
);
return urlRegex.test(url);
};

View File

@ -12,7 +12,14 @@ const nextConfig = {
reactStrictMode: true, reactStrictMode: true,
swcMinify: true, swcMinify: true,
output: 'standalone', output: 'standalone',
// images: isExport ? { unoptimized: true } : {}, images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**',
},
],
},
experimental: { experimental: {
webpackBuildWorker: true, webpackBuildWorker: true,
mdxRs: true, mdxRs: true,