[feature] support video link with headings

This commit is contained in:
Yifei Gao 2024-07-03 01:05:04 +08:00
parent 78efa02ad0
commit 45717816a2
No known key found for this signature in database
3 changed files with 51 additions and 6 deletions

View file

@ -11,9 +11,13 @@ import { toString } from 'hast-util-to-string';
import { rehypeCodesplit } from './codesplit.mjs';
function isHeading(node) {
return node.type === 'element' && /^h[1-6]$/i.test(node.tagName);
}
export function parseContent(html) {
const replaceMedia = () => (tree) => {
visit(tree, { tagName: 'div' }, (node) => {
visit(tree, { tagName: 'div' }, (node, index, parent) => {
if (
node.properties.className &&
Array.isArray(node.properties.className) &&
@ -44,6 +48,19 @@ export function parseContent(html) {
node.tagName = 'embed-example';
}
if (
node.properties.dataType === 'video-link' &&
node.properties.dataTitle &&
index > 2 &&
isHeading(parent.children[index - 2])
) {
node.tagName = 'video-link';
// move the video-link node inside the last adjacent heading
parent.children[index - 2].children.push(node);
parent.children.splice(index, 1);
}
if (
node.properties.dataType === 'note' ||
node.properties.dataType === 'exercise' ||
@ -151,11 +168,6 @@ export function parseContent(html) {
const description = paragraphs.join(' ').trim().substring(0, 150);
const transformedAst = unified()
.use(replaceMedia)
.use(externalLinkInNewTab)
.use(rehypeCodesplit)
.use(rehypeHighlight)
.use(rehypeSlug)
.use(rehypeAutolinkHeadings, {
behavior: 'wrap',
test: ['h2', 'h3'],
@ -163,6 +175,11 @@ export function parseContent(html) {
class: 'heading-link',
},
})
.use(replaceMedia)
.use(externalLinkInNewTab)
.use(rehypeCodesplit)
.use(rehypeHighlight)
.use(rehypeSlug)
.use(rehypeKatex)
.runSync(ast);

View file

@ -0,0 +1,26 @@
import React from 'react';
import { FaYoutube } from 'react-icons/fa';
const VideoLink = (props) => {
return (
<div className="ml-6 inline-block">
<a
className="group relative flex items-center gap-2 text-base text-noc-400 no-underline"
href={props['href']}
>
<FaYoutube />
{props['data-title']}
{props.children && (
<div className="not-prose absolute top-0 hidden w-80 pt-10 group-hover:block">
<div className="rounded-lg bg-noc-500 bg-opacity-50 p-4">
{props.children}
</div>
</div>
)}
</a>
</div>
);
};
export default VideoLink;

View file

@ -8,6 +8,7 @@ import SideNavLayout from './SideNavLayout';
import PrevNextButtons from '../components/PrevNextButtons';
import Image from '../components/Image';
import Example from '../components/Example';
import VideoLink from '../components/VideoLink';
const renderAst = ({ ast, images }) => {
visit(ast, { tagName: 'img' }, (node) => {
@ -29,6 +30,7 @@ const renderAst = ({ ast, images }) => {
components: {
'gatsby-image': Image,
'embed-example': Example,
'video-link': VideoLink,
},
});