mirror of
https://github.com/DefectingCat/DefectingCat.github.io
synced 2025-07-15 08:41: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;
|
@ -4,8 +4,6 @@ date: '2023-12-26'
|
||||
tags: [Rust, Linux]
|
||||
---
|
||||
|
||||
test [rua](https://rua.plus) test [rua](https://rua.plus) test [rua](https://rua.plus)
|
||||
|
||||
大多数 Linux 软件都是动态链接的,动态链接可以使我们的程序不需要将所有所需要的库都打包到自身当中去。不过这样也有弊处,当目标系统比较旧,或者压根就没有我们需要的库的时候,我们的二进制文件就无法在目标系统中运行。
|
||||
|
||||
## 安装交叉编译工具
|
||||
|
@ -132,3 +132,25 @@ export const getSignalGist = cache(async (id: string) => {
|
||||
|
||||
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;
|
||||
});
|
||||
|
@ -152,3 +152,10 @@ export const frameArea = (
|
||||
// point the camera to look at the center of the box
|
||||
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);
|
||||
};
|
||||
|
@ -12,7 +12,14 @@ const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true,
|
||||
output: 'standalone',
|
||||
// images: isExport ? { unoptimized: true } : {},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: '**',
|
||||
},
|
||||
],
|
||||
},
|
||||
experimental: {
|
||||
webpackBuildWorker: true,
|
||||
mdxRs: true,
|
||||
|
Reference in New Issue
Block a user