1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-04-27 08:58:30 -04:00

directly (and still dynamically) assign a few of the mdx components

This commit is contained in:
Jake Jarvis 2022-01-05 15:07:54 -05:00
parent fb491d7337
commit 2d44b58242
Signed by: jake
GPG Key ID: 2B0C9CF251E69A39
9 changed files with 43 additions and 44 deletions

View File

@ -6,29 +6,17 @@ import { OctocatOcticon } from "./icons/octicons";
import type { LinkProps } from "next/link"; import type { LinkProps } from "next/link";
import type { ImageProps } from "next/image"; import type { ImageProps } from "next/image";
import type { GistProps } from "react-gist";
import type { ReactPlayerProps } from "react-player";
const TweetEmbed = dynamic(() => import("react-tweet-embed"));
const Gist = dynamic(() => import("react-gist"));
const Video = dynamic(() => import("./video/FullPageVideo"));
const CopyButton = dynamic(() => import("./clipboard/CopyButton"));
// The following components are all passed into <MDXProvider /> as replacement HTML tags or drop-in React components // The following components are all passed into <MDXProvider /> as replacement HTML tags or drop-in React components
// available in .mdx files containing post content, since they're not directly aware of the components in this folder. // available in .mdx files containing post content, since they're not directly aware of the components in this folder.
const CustomLink = ({ type CustomLinkProps = LinkProps & {
href,
target,
rel,
className,
children,
}: LinkProps & {
target?: string; target?: string;
rel?: string; rel?: string;
className?: string; className?: string;
children?: unknown; children?: unknown;
}) => ( };
const CustomLink = ({ href, target, rel, className, children }: CustomLinkProps) => (
<Link href={href} passHref={true}> <Link href={href} passHref={true}>
<a className={className} target={target} rel={rel}> <a className={className} target={target} rel={rel}>
{children} {children}
@ -36,18 +24,19 @@ const CustomLink = ({
</Link> </Link>
); );
const CustomImg = (props: ImageProps) => { const CustomImg = (props: ImageProps) => (
return ( // the required height and width are part of the props, so they get automatically passed here with {...props}
// height and width are part of the props, so they get automatically passed here with {...props}
<div className={props.className}> <div className={props.className}>
{/* eslint-disable-next-line jsx-a11y/alt-text */} {/* eslint-disable-next-line jsx-a11y/alt-text */}
<Image {...props} /> <Image {...props} />
</div> </div>
); );
};
const CustomCode = (props: any) => { const CustomCode = (props: any) => {
if (props.className?.split(" ").includes("hljs")) { if (props.className?.split(" ").includes("hljs")) {
const CopyButton = dynamic(() => import("./clipboard/CopyButton"));
// full multi-line code blocks with highlight.js and copy-to-clipboard button
return ( return (
<div> <div>
<CopyButton content={innerText(props.children)} /> <CopyButton content={innerText(props.children)} />
@ -63,13 +52,15 @@ const CustomCode = (props: any) => {
</div> </div>
); );
} else { } else {
// inline code in paragraphs, headings, etc. (not highlighted)
return <code {...props}>{props.children}</code>; return <code {...props}>{props.children}</code>;
} }
}; };
const CustomVideo = (props: ReactPlayerProps) => <Video {...props} />; const CustomTweet = (props: { id: string }) => {
const TweetEmbed = dynamic(() => import("react-tweet-embed"));
const CustomTweet = (props: { id: string }) => ( return (
<TweetEmbed <TweetEmbed
id={props.id} id={props.id}
options={{ options={{
@ -78,8 +69,11 @@ const CustomTweet = (props: { id: string }) => (
}} }}
/> />
); );
};
const CustomGist = (props: GistProps) => <Gist {...props} />; const CustomGist = dynamic(() => import("react-gist"));
const CustomVideo = dynamic(() => import("./video/Video"));
const CustomGitHubLink = (props: { repo: string }) => ( const CustomGitHubLink = (props: { repo: string }) => (
<a className="no-underline" href={`https://github.com/${props.repo}`} target="_blank" rel="noopener noreferrer"> <a className="no-underline" href={`https://github.com/${props.repo}`} target="_blank" rel="noopener noreferrer">
@ -97,6 +91,7 @@ const CustomGitHubLink = (props: { repo: string }) => (
</a> </a>
); );
// These are the actual tags referenced in mdx files:
const mdxComponents = { const mdxComponents = {
a: CustomLink, a: CustomLink,
img: CustomImg, img: CustomImg,

View File

@ -1,14 +1,14 @@
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import type { ReactPlayerProps } from "react-player"; import type { ReactPlayerProps } from "react-player";
import styles from "./FullPageVideo.module.scss"; import styles from "./Video.module.scss";
const ReactPlayer = dynamic(() => import("react-player")); const ReactPlayer = dynamic(() => import("react-player"));
const FullPageVideo = (props: ReactPlayerProps) => ( const Video = (props: ReactPlayerProps) => (
<div className={styles.wrapper}> <div className={styles.wrapper}>
<ReactPlayer className={styles.react_player} width="100%" height="100%" {...props} /> <ReactPlayer className={styles.react_player} width="100%" height="100%" {...props} />
</div> </div>
); );
export default FullPageVideo; export default Video;

View File

@ -1,3 +1,4 @@
// do not convert to ESM -- this needs to be imported in CJS files like next.config.js too
module.exports = { module.exports = {
// Site info // Site info
siteName: "Jake Jarvis", siteName: "Jake Jarvis",

View File

@ -3,6 +3,7 @@ import path from "path";
import matter from "gray-matter"; import matter from "gray-matter";
import { NOTES_DIR, baseUrl } from "./config"; import { NOTES_DIR, baseUrl } from "./config";
// returns front matter and/or *raw* markdown contents of a given slug
export const getNoteData = (slug: string) => { export const getNoteData = (slug: string) => {
const fullPath = path.join(process.cwd(), NOTES_DIR, `${slug}.mdx`); const fullPath = path.join(process.cwd(), NOTES_DIR, `${slug}.mdx`);
const rawContent = fs.readFileSync(fullPath, "utf8"); const rawContent = fs.readFileSync(fullPath, "utf8");
@ -19,15 +20,15 @@ export const getNoteData = (slug: string) => {
}; };
}; };
// all .mdx files in NOTES_DIR // returns all .mdx files in NOTES_DIR (without .mdx extension)
export const getNoteSlugs = () => export const getNoteSlugs = () =>
fs fs
.readdirSync(path.join(process.cwd(), NOTES_DIR)) .readdirSync(path.join(process.cwd(), NOTES_DIR))
.filter((file) => /\.mdx$/.test(file)) .filter((file) => /\.mdx$/.test(file))
.map((noteFile) => noteFile.replace(/\.mdx$/, "")); .map((noteFile) => noteFile.replace(/\.mdx$/, ""));
// returns the front matter of ALL notes, sorted reverse chronologically
export const getAllNotes = () => export const getAllNotes = () =>
getNoteSlugs() getNoteSlugs()
.map((slug) => getNoteData(slug).frontMatter) .map((slug) => getNoteData(slug).frontMatter)
// sort notes by date in descending order
.sort((note1: any, note2: any) => (note1.date > note2.date ? -1 : 1)); .sort((note1: any, note2: any) => (note1.date > note2.date ? -1 : 1));

View File

@ -30,7 +30,9 @@ const App = ({ Component, pageProps }: AppProps) => {
// https://usefathom.com/docs/integrations/next // https://usefathom.com/docs/integrations/next
// https://vercel.com/guides/deploying-nextjs-using-fathom-analytics-with-vercel // https://vercel.com/guides/deploying-nextjs-using-fathom-analytics-with-vercel
Fathom.load(config.fathomSiteId, { Fathom.load(config.fathomSiteId, {
// optional custom domain: https://usefathom.com/docs/script/custom-domains
url: `${config.fathomCustomDomain || "https://cdn.usefathom.com"}/script.js`, url: `${config.fathomCustomDomain || "https://cdn.usefathom.com"}/script.js`,
// don't track branch/deploy previews and localhost
includedDomains: [config.siteDomain], includedDomains: [config.siteDomain],
}); });
@ -38,7 +40,7 @@ const App = ({ Component, pageProps }: AppProps) => {
Fathom.trackPageview(); Fathom.trackPageview();
}; };
// send ping when route changes // needs to be triggered manually on link clicks (the page doesn't actually change)
router.events.on("routeChangeComplete", onRouteChangeComplete); router.events.on("routeChangeComplete", onRouteChangeComplete);
return () => { return () => {

View File

@ -2,7 +2,7 @@ import Layout from "../components/Layout";
import Container from "../components/Container"; import Container from "../components/Container";
import Content from "../components/Content"; import Content from "../components/Content";
import PageTitle from "../components/page/PageTitle"; import PageTitle from "../components/page/PageTitle";
import Video from "../components/video/FullPageVideo"; import Video from "../components/video/Video";
import { TapeIcon } from "../components/icons"; import { TapeIcon } from "../components/icons";
import thumbnail from "../public/static/images/birthday/thumb.png"; import thumbnail from "../public/static/images/birthday/thumb.png";

View File

@ -2,7 +2,7 @@ import Layout from "../components/Layout";
import Container from "../components/Container"; import Container from "../components/Container";
import Content from "../components/Content"; import Content from "../components/Content";
import PageTitle from "../components/page/PageTitle"; import PageTitle from "../components/page/PageTitle";
import Video from "../components/video/FullPageVideo"; import Video from "../components/video/Video";
import thumbnail from "../public/static/images/hillary/thumb.png"; import thumbnail from "../public/static/images/hillary/thumb.png";

View File

@ -2,7 +2,7 @@ import Layout from "../components/Layout";
import Container from "../components/Container"; import Container from "../components/Container";
import Content from "../components/Content"; import Content from "../components/Content";
import PageTitle from "../components/page/PageTitle"; import PageTitle from "../components/page/PageTitle";
import Video from "../components/video/FullPageVideo"; import Video from "../components/video/Video";
import thumbnail from "../public/static/images/leo/thumb.png"; import thumbnail from "../public/static/images/leo/thumb.png";