Skip to content

Commit c859a6d

Browse files
committed
feat: md 拓展 link
1 parent bcd83b0 commit c859a6d

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

src/components/ui/markdown/Markdown.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { clsx } from 'clsx';
44
import type { MarkdownToJSX } from 'markdown-to-jsx';
5-
import { compiler } from 'markdown-to-jsx';
5+
import { compiler, sanitizeUrl } from 'markdown-to-jsx';
66
import Script from 'next/script';
77
import type React from 'react';
88
import type { FC, PropsWithChildren } from 'react';
@@ -11,6 +11,7 @@ import { memo, Suspense, useMemo, useRef } from 'react';
1111
import { MParagraph } from './renderbers/paragraph';
1212
import { MHeader } from './renderbers/heading';
1313
import { MarkdownImage } from './renderbers/images';
14+
import { MLink } from './renderbers/Mlink';
1415

1516
export interface MdProps {
1617
value?: string;
@@ -71,6 +72,26 @@ export const Markdown: FC<MdProps & MarkdownToJSX.Options & PropsWithChildren &
7172
);
7273
},
7374
},
75+
link: {
76+
react(node, output, state) {
77+
const { target, title } = node;
78+
79+
let realText = '';
80+
81+
for (const child of node.content) {
82+
if (child.type === 'text') {
83+
realText += child.content;
84+
}
85+
}
86+
87+
return (
88+
<MLink href={sanitizeUrl(target)!} title={title} key={state?.key} text={realText}>
89+
{output(node.content, state!)}
90+
</MLink>
91+
);
92+
},
93+
},
94+
7495
...extendsRules,
7596
...renderers,
7697
},
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use client';
2+
3+
import { useRouter } from 'next/navigation';
4+
import type { FC, ReactNode } from 'react';
5+
import { memo, useCallback } from 'react';
6+
7+
import { FloatPopover } from '@/components/ui/float-popover';
8+
9+
export const MLink: FC<{
10+
href: string;
11+
title?: string;
12+
children?: ReactNode;
13+
text?: string;
14+
popper?: boolean;
15+
}> = memo(({ href, children, title, popper = true }) => {
16+
const router = useRouter();
17+
18+
const handleRedirect = useCallback(
19+
(e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
20+
const toUrlParser = new URL(href);
21+
22+
e.preventDefault();
23+
24+
window.open(toUrlParser.pathname);
25+
},
26+
[href, router],
27+
);
28+
29+
const el = (
30+
<span className="inline items-center font-sans px-1 cursor-pointer">
31+
<span
32+
className=" relative before:content-[''] before:absolute before:bottom-[-2px] before:w-[0px] hover:before:w-[100%] before:h-[2px] before:bg-[var(--accent-color)] before:transition-all before:duration-300"
33+
onClick={handleRedirect}
34+
title={title}
35+
rel="noreferrer"
36+
>
37+
{children}
38+
</span>
39+
40+
<i className="i-mingcute-arrow-right-up-line ml-[1px] translate-y-[2px] opacity-70" />
41+
</span>
42+
);
43+
if (!popper) return el;
44+
45+
return (
46+
<FloatPopover as="span" wrapperClassName="!inline" type="tooltip" triggerElement={el}>
47+
<a href={href} target="_blank" rel="noreferrer">
48+
<span>{href}</span>
49+
</a>
50+
</FloatPopover>
51+
);
52+
});

src/styles/mdContainer.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
.mdImg span {
2222
display: inline-block !important;
2323
margin-left: 0 !important;
24-
margin-right: 0 auto;
25-
padding: 0;
24+
margin-right: 0 auto;
25+
padding: 0;
2626
text-align: center;
2727
}
2828

0 commit comments

Comments
 (0)