Skip to content

Commit

Permalink
Merge pull request #167 from life-itself/152-rhs-toc
Browse files Browse the repository at this point in the history
[Site/MDX]: Right hand side table of contents.
  • Loading branch information
khalilcodes authored Jun 7, 2022
2 parents e24873e + ba190c7 commit 6631b23
Show file tree
Hide file tree
Showing 12 changed files with 6,607 additions and 244 deletions.
2 changes: 1 addition & 1 deletion guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ Understand the deeper theoretical concepts behind the technical and economic cla
* [Predatory inclusion](../concepts/predatory-inclusion.md)
* [Enclosure](../concepts/enclosure.md)

**Meta**
#### Meta

* [Value](../concepts/value.md)
* [Risk](../concepts/risk.md)
Expand Down
18 changes: 18 additions & 0 deletions site/components/Heading.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { useEffect, useState } from 'react';


export const Heading = ({ level, observer }) => (props) => {
useEffect(() => {
/* start observing heading's intersection with the bounding box
* set by observer's `rootMargin` */
if (!observer) {
return
}
observer.observe(document.getElementById(props.id));
});

return React.createElement(`h${level}`, {
...props,
className: "c-heading scroll-mt-16 cursor-pointer"
})
}
41 changes: 24 additions & 17 deletions site/components/Layout.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import Head from 'next/head'
import Nav from './Nav'

import siteConfig from '../config/siteConfig'
import navLinks from '../config/navLinks.js'
import navLinks from '../config/navLinks'
import Nav from './Nav'
// import Sidebar from './Sidebar'


export default function Layout({ children }) {
return (
Expand All @@ -18,11 +21,11 @@ export default function Layout({ children }) {
{children}
</main>
<footer className="w-full h-24 mt-16">
<div className="max-w-7xl mx-auto py-12 px-4 overflow-hidden sm:px-6 lg:px-8">
<div className="max-w-7xl mx-auto py-12 px-4 sm:px-6 md:px-8 overflow-hidden">
<nav className="-mx-5 -my-2 flex flex-wrap justify-center" aria-label="Footer">
{navLinks.map((item) => (
<div key={item.name} className="px-5 py-2">
<a href={item.href} className="text-base text-gray-500 hover:text-gray-900">
<a href={item.href} className="text-base text-gray-400 hover:text-gray-500">
{item.name}
</a>
</div>
Expand All @@ -36,21 +39,25 @@ export default function Layout({ children }) {
</a>
))}
</div>
<p className="flex items-center justify-center mt-8">
Created by
<a
href={siteConfig.authorUrl}
target="_blank"
rel="noopener noreferrer"
>
<img src={siteConfig.authorLogo} alt={siteConfig.author} width="20" height="20" className="mx-2 h-6 inline-block" />
{siteConfig.author}
{' '}
<div className="flex flex-col items-center mt-8 text-gray-400">
<p>
Created by
<a
href={siteConfig.authorUrl}
target="_blank"
rel="noopener noreferrer"
>
<img src={siteConfig.authorLogo} alt={siteConfig.author} width="20" height="20" className="mx-2 h-6 inline-block" />
{siteConfig.author}
{' '}
</a>
</p>
<p>
Licensed under a CC-By 4.0 International License
</a>
</p>
</p>
</div>
</div>
</footer>
</>
)
}
}
162 changes: 84 additions & 78 deletions site/components/MDX.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,15 @@
import Head from 'next/head'
import dynamic from 'next/dynamic'
import { NextSeo } from 'next-seo'
import siteConfig from "../config/siteConfig"
import LiteYouTubeEmbed from "react-lite-youtube-embed"
import { YOUTUBE_REGEX } from "../lib/constants"
import { NextSeo } from "next-seo";
import LiteYouTubeEmbed from "react-lite-youtube-embed";

const Anchor = dynamic(() => import('./Anchor').then(module => module.Anchor), {
ssr: false
})
import { YOUTUBE_REGEX } from "../lib/constants";
import siteConfig from "../config/siteConfig";
import MdxContent from "./MdxContent";

const Paragraph = dynamic(() => import("./Paragraph").then(mod => mod.Paragraph))
export default function MdxPage({ body, meta }) {
const { title, description, date, keywords, youtube, podcast, image, _raw } =
meta;

const components = {
Head,
p: Paragraph,
a: Anchor
}

export default function MdxPage({ children }) {
const { Component, frontmatter: {
title, description, date, keywords, youtube, podcast, image, _raw
}} = children

let youtubeThumnbnail
let youtubeThumnbnail;

const youtubeId =
youtube && YOUTUBE_REGEX.test(youtube) && youtube.split(/^|=|\//).pop();
Expand All @@ -47,12 +34,14 @@ export default function MdxPage({ children }) {
const SeoTitle = title ?? titleFromUrl;
const imageUrl = image
? siteConfig.url + image
: youtubeThumnbnail ? youtubeThumnbnail : null

: youtubeThumnbnail
? youtubeThumnbnail
: null;

// enable editing content only for claims, concepts, and guide for now
const editUrl = ['claims', 'concepts', 'guide'].includes(_raw.sourceFileDir)
? siteConfig.repoRoot + siteConfig.repoEditPath + _raw.sourceFilePath
: null
const editUrl = ["claims", "concepts", "guide"].includes(_raw.sourceFileDir)
? siteConfig.repoRoot + siteConfig.repoEditPath + _raw.sourceFilePath
: null;

return (
<>
Expand All @@ -66,72 +55,89 @@ export default function MdxPage({ children }) {
url: `${siteConfig.url}/${_raw.flattenedPath}`,
type: "article",
article: {
tags: keywords ? keywords.split(",") : []
tags: keywords ? keywords.split(",") : [],
},
images: imageUrl
? ([
? [
{
url: imageUrl,
width: 1200,
height: 627,
alt: title,
type: "image/png"
type: "image/png",
},
])
]
: siteConfig.nextSeo.openGraph.images,
}}
additionalMetaTags={[
{ name: "keywords", content: keywords ? keywords : "" }
{ name: "keywords", content: keywords ? keywords : "" },
]}
/>
<article className="prose dark:prose-invert prose-a:break-all mx-auto p-6">
<header>
<div className="mb-6">
{title && <h1 className="mb-0">{title}</h1>}
{date && (
<p className="text-gray-900 dark:text-gray-500 text-sm pl-2">
on {date}
</p>
)}
{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>
</li>
</ul>
<div className="max-w-7xl mx-auto px-2 sm:px-6 md:px-8">
<article className="prose dark:prose-invert prose-a:break-all mx-auto lg:mr-[20rem] p-6">
<header>
<div className="mb-6">
{title && <h1 className="mb-0">{title}</h1>}
{date && (
<p className="text-gray-900 dark:text-gray-500 text-sm pl-2">
on {date}
</p>
)}
{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>
</li>
</ul>
</div>
)}
</div>
</header>
<main className="my-6">
<MdxContent body={body} />
{editUrl && (
<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>
</span>
</a>
</div>
)}
</div>
</header>
<main>
<div className="my-6">
<Component components={components} />
</div>
{editUrl && (
<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>
</span>
</a>
</div>)}
</main>
</article>
</main>
</article>
</div>
</>
);
}
39 changes: 39 additions & 0 deletions site/components/MdxContent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react";
import Head from "next/head";
import dynamic from "next/dynamic";
import { useMDXComponent } from "next-contentlayer/hooks";

import { Heading } from "./Heading";
import useHeadingsObserver from "../hooks/useHeadingsObserver";

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

const Paragraph = dynamic(() =>
import("./Paragraph").then((module) => module.Paragraph)
);

const MdxContent = ({ body }) => {
const observer = useHeadingsObserver();

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} />;
};

export default MdxContent;
11 changes: 8 additions & 3 deletions site/contentlayer.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import remarkGfm from 'remark-gfm'
import rehypeSlug from 'rehype-slug'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import wikiLinkPlugin from "remark-wiki-link-plus"
import rehypeToc from "@jsdevtools/rehype-toc"

const isValidDate = dateObject => new Date(dateObject)
.toString() !== 'Invalid Date';
Expand Down Expand Up @@ -58,8 +59,12 @@ export default makeSource({
mdx: {
remarkPlugins: [
remarkGfm,
[wikiLinkPlugin, { markdownFolder: 'content' }]
[ wikiLinkPlugin, { markdownFolder: 'content' } ]
],
rehypePlugins: [rehypeSlug, rehypeAutolinkHeadings]
rehypePlugins: [
rehypeSlug,
[ rehypeAutolinkHeadings, { behavior: 'wrap' } ],
[ rehypeToc, { position: 'afterend' } ]
]
}
})
})
Loading

0 comments on commit 6631b23

Please sign in to comment.