diff --git a/components/mdx/paragraph.tsx b/components/mdx/paragraph.tsx index 1f61c1a..2895091 100644 --- a/components/mdx/paragraph.tsx +++ b/components/mdx/paragraph.tsx @@ -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) => { const { children, ...rest } = props; @@ -8,7 +16,7 @@ const Paragraph = (props: HTMLAttributes) => { 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) => { return ( <>

{children}

- {links?.map((url, i) =>
{url}
)} + + {!!links?.length && ( +
+ {links?.map((url, i) => ( + + ))} +
+ )} ); }; diff --git a/components/mdx/url-previewer.tsx b/components/mdx/url-previewer.tsx new file mode 100644 index 0000000..88d5589 --- /dev/null +++ b/components/mdx/url-previewer.tsx @@ -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 ( + +
+ +
+
+ {metadata.meta.title} +
+
+ {metadata.meta.description} +
+
+ {url} +
+
+
+
+ ); +}; + +export default UrlPreviewer; diff --git a/content/posts/musl-cross-compilation.mdx b/content/posts/musl-cross-compilation.mdx index 189e752..8f58660 100644 --- a/content/posts/musl-cross-compilation.mdx +++ b/content/posts/musl-cross-compilation.mdx @@ -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 软件都是动态链接的,动态链接可以使我们的程序不需要将所有所需要的库都打包到自身当中去。不过这样也有弊处,当目标系统比较旧,或者压根就没有我们需要的库的时候,我们的二进制文件就无法在目标系统中运行。 ## 安装交叉编译工具 diff --git a/lib/fetcher.ts b/lib/fetcher.ts index 9224939..8b1a301 100644 --- a/lib/fetcher.ts +++ b/lib/fetcher.ts @@ -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; +}); diff --git a/lib/utils/index.ts b/lib/utils/index.ts index bc4da87..0220459 100644 --- a/lib/utils/index.ts +++ b/lib/utils/index.ts @@ -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); +}; diff --git a/next.config.js b/next.config.js index f8433a3..9a02295 100644 --- a/next.config.js +++ b/next.config.js @@ -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,