Skip to content

Commit

Permalink
[site/ToC][m]: separate ToC component created
Browse files Browse the repository at this point in the history
  • Loading branch information
olayway committed Jun 6, 2022
1 parent e0a316e commit 0e8b5a2
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 153 deletions.
20 changes: 13 additions & 7 deletions site/components/Anchor.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import { Tooltip } from './Tooltip';
import dynamic from "next/dynamic";

const Tooltip = dynamic(() => {
return import("./Tooltip").then((module) => module.Tooltip);
});

/**
* Component for adding previews on hovering over anchor tags with relative paths
*/
export const Anchor = (props) => {
/* Check if the path is relative */
const pathIsRelative = (path) => {
return path &&
return (
path &&
path.indexOf("http:") !== 0 &&
path.indexOf("https:") !== 0 &&
path.indexOf("#") !== 0
}
);
};

if (pathIsRelative(props.href)) {
return (
<Tooltip {...props} render={ tooltipTriggerProps => (
<a {...tooltipTriggerProps} />
)}
<Tooltip
{...props}
render={(tooltipTriggerProps) => <a {...tooltipTriggerProps} />}
/>
)
);
}
return <a {...props} />;
};
18 changes: 0 additions & 18 deletions site/components/Heading.js

This file was deleted.

94 changes: 41 additions & 53 deletions site/components/MDX.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
import { NextSeo } from 'next-seo'
import { NextSeo } from "next-seo";
import LiteYouTubeEmbed from "react-lite-youtube-embed";

import { YOUTUBE_REGEX } from "../lib/constants";
import siteConfig from "../config/siteConfig";
import MdxContent from './MdxContent'
import useHeadingsObserver from '../hooks/useHeadingsObserver'
// import dynamic from 'next/dynamic'

// import { Paragraph } from "./Paragraph";
// import { Anchor } from "./Anchor";

// const Anchor = dynamic(() => import('./Anchor').then(module => module.Anchor), {
// ssr: false
// })

// const Paragraph = dynamic(() => import("./Paragraph").then(mod => mod.Paragraph))
import MdxContent from "./MdxContent";
import TableOfContents from "./TableOfContents";

export default function MdxPage({ body, frontMatter }) {
const observer = useHeadingsObserver();

const {
title, description, date, keywords, youtube, podcast, image, _raw
} = frontMatter
const { title, description, date, keywords, youtube, podcast, image, _raw } =
frontMatter;

let youtubeThumnbnail;

Expand Down Expand Up @@ -97,58 +84,59 @@ export default function MdxPage({ body, frontMatter }) {
on {date}
</p>
)}
{description && <p className="">{description}</p>}
{youtubeId && <LiteYouTubeEmbed id={youtubeId} />}
{description && <p className="">{description}</p>}
{youtubeId && <LiteYouTubeEmbed id={youtubeId} />}
{podcast && (
<div className="pt-4">
<ul className="list-disc">
<li>
<a
className="flex items-center"
target="_blank"
rel="noopener"
href={podcast}
>
<div className="w-4 mr-2">
<PodcastIcon />
</div>
<p className="m-0">Listen to this podcast</p>
</a>
<a
className="flex items-center"
target="_blank"
rel="noopener"
href={podcast}
>
<div className="w-4 mr-2">
<PodcastIcon />
</div>
<p className="m-0">Listen to this podcast</p>
</a>
</li>
</ul>
</div>
)}
</div>
</header>
<main className="my-6">
<MdxContent body={body} observer={observer}/>
<MdxContent body={body} />
<TableOfContents />
{editUrl && (
<div className="mt-12 mb-6">
<a
className="flex no-underline font-semibold text-yellow-li"
href={editUrl}
target="_blank"
>
<div className="mt-12 mb-6">
<a
className="flex no-underline font-semibold text-yellow-li"
href={editUrl}
target="_blank"
>
Edit this page
<span className="mx-1">
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth="2"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
/>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth="2"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
/>
</svg>
</span>
</a>
</div>
)}
</div>
)}
</main>
</article>
</div>
Expand Down
26 changes: 8 additions & 18 deletions site/components/MdxContent.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
import React from 'react'
import Head from 'next/head'
import { useMDXComponent } from 'next-contentlayer/hooks';
import { Paragraph } from './Paragraph'
import { Anchor } from './Anchor'
import { Heading } from './Heading'
import Head from "next/head";
import { useMDXComponent } from "next-contentlayer/hooks";

import { Anchor } from "./Anchor";
import { Paragraph } from "./Paragraph";

const MdxContent = ({ body, observer }) => {
const MdxContent = ({ body }) => {
const customComponents = {
Head,
p: Paragraph,
a: Anchor,
h1: Heading({ level: 1, observer }),
h2: Heading({ level: 2, observer }),
h3: Heading({ level: 3, observer }),
h4: Heading({ level: 4, observer }),
h5: Heading({ level: 5, observer }),
h6: Heading({ level: 6, observer }),
}
};
const Component = useMDXComponent(body.code);

return <Component components={ customComponents }/>
return <Component components={customComponents} />;
};

// prevent rerendering of the component if it's props don't change
// i.e. re-render only when the observer is set
export default React.memo(MdxContent);
export default MdxContent;
64 changes: 64 additions & 0 deletions site/components/TableOfContents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useState, useEffect } from "react";

const TableOfContents = () => {
const [activeHeading, setActiveHeading] = useState("");

/* Runs only after the first render, in order to preserve the observer
* between component rerenderings (e.g. after activeHeading change). */
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setActiveHeading(entry.target.id);
}
});
},
{
root: null,
threshold: 0.55,
rootMargin: "-65px 0% -85% 0%", // 65px is a navbar height
}
);

const tocLinks = document.querySelectorAll(".toc-link");
tocLinks.forEach((link) => {
const headingId = link.href.split("#").pop();
const headingElement = document.getElementById(headingId);
// add custom classes
headingElement.classList.add(
"c-heading",
"scroll-mt-16",
"cursor-pointer"
);
// observe
observer.observe(headingElement);
});

return () => {
observer.disconnect();
};
}, []);

/* On initial render activeHeading will be `null`, since the observer
* has not been instantiated yet. However, we still want to highlight
* the current heading in the ToC based on the current url. */
useEffect(() => {
if (!activeHeading) {
return;
}

const tocLink = document.querySelector(
`.toc-link[href="#${activeHeading}"]`
);
tocLink.classList.add("active");

return () => {
tocLink.classList.remove("active");
};
}, [activeHeading]);

return null;
};

export default TableOfContents;
57 changes: 0 additions & 57 deletions site/hooks/useHeadingsObserver.js

This file was deleted.

0 comments on commit 0e8b5a2

Please sign in to comment.