Add code blocks feature to content

This commit is contained in:
Hazem Krimi
2021-01-19 00:49:57 +01:00
parent eec6c529df
commit 913e57ec8f
6 changed files with 124 additions and 16 deletions
+37
View File
@@ -0,0 +1,37 @@
declare module '@mdx-js/react' {
import * as React from 'react';
type ComponentType =
| 'a'
| 'blockquote'
| 'code'
| 'del'
| 'em'
| 'h1'
| 'h2'
| 'h3'
| 'h4'
| 'h5'
| 'h6'
| 'hr'
| 'img'
| 'inlineCode'
| 'li'
| 'ol'
| 'p'
| 'pre'
| 'strong'
| 'sup'
| 'table'
| 'td'
| 'thematicBreak'
| 'tr'
| 'ul';
export type Components = {
[key in ComponentType]?: React.ComponentType<any>;
};
export interface MDXProviderProps {
children: React.ReactNode;
components: Components;
}
export class MDXProvider extends React.Component<MDXProviderProps> {}
}
+57
View File
@@ -0,0 +1,57 @@
import { FC } from 'react';
import styled from 'styled-components';
import Highlight, { defaultProps, Language } from 'prism-react-renderer';
import theme from 'prism-react-renderer/themes/vsDark';
const Pre = styled.pre`
text-align: left;
margin: 1em 0;
padding: 0.5em;
overflow: scroll;
`;
const Line = styled.div`
display: table-row;
`;
const LineNo = styled.span`
display: table-cell;
text-align: right;
padding-right: 1em;
user-select: none;
opacity: 0.5;
`;
const LineContent = styled.span`
display: table-cell;
`;
const CodeBlock: FC<{ className: string }> = ({ children, className }) => {
const language = className.replace(/language-/, '') as Language;
return (
<Highlight
{...defaultProps}
theme={theme}
code={(children as string).trim()}
language={language}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<Pre className={className} style={style}>
{tokens.map((line, i) => (
<Line key={i} {...getLineProps({ line, key: i })}>
<LineNo>{i + 1}</LineNo>
<LineContent>
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token, key })} />
))}
</LineContent>
</Line>
))}
</Pre>
)}
</Highlight>
);
};
export default CodeBlock;
+1
View File
@@ -14,6 +14,7 @@
"mdx-embed": "^0.0.17", "mdx-embed": "^0.0.17",
"next": "10.0.4", "next": "10.0.4",
"next-mdx-remote": "^2.1.1", "next-mdx-remote": "^2.1.1",
"prism-react-renderer": "^1.1.1",
"react": "17.0.1", "react": "17.0.1",
"react-dom": "17.0.1", "react-dom": "17.0.1",
"react-typing-animation": "^1.6.2", "react-typing-animation": "^1.6.2",
+6 -5
View File
@@ -2,6 +2,7 @@ import { FC, useEffect } from 'react';
import { getBlogPostsSlugs, getBlogPostdata } from '../../lib/blog'; import { getBlogPostsSlugs, getBlogPostdata } from '../../lib/blog';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { MdxRemote } from 'next-mdx-remote/types'; import { MdxRemote } from 'next-mdx-remote/types';
import { MDXProvider } from '@mdx-js/react';
import { MDXEmbedProvider } from 'mdx-embed'; import { MDXEmbedProvider } from 'mdx-embed';
import { GetStaticPaths, GetStaticProps } from 'next'; import { GetStaticPaths, GetStaticProps } from 'next';
import renderToString from 'next-mdx-remote/render-to-string'; import renderToString from 'next-mdx-remote/render-to-string';
@@ -11,6 +12,7 @@ import matter from 'gray-matter';
import AllComponents from '../../components/All'; import AllComponents from '../../components/All';
import Head from 'next/head'; import Head from 'next/head';
import IconButton from '../../components/IconButton'; import IconButton from '../../components/IconButton';
import CodeBlock from '../../components/CodeBlock';
interface Props { interface Props {
source: MdxRemote.Source; source: MdxRemote.Source;
@@ -89,11 +91,7 @@ const Wrapper = styled.div`
font-size: 1.1rem; font-size: 1.1rem;
} }
p, & > * {
h1,
h2,
h3,
button {
margin: 0.5rem 0rem; margin: 0.5rem 0rem;
} }
@@ -156,6 +154,7 @@ const BlogPost: FC<Props> = ({ source, frontMatter }) => {
<span>Back</span> <span>Back</span>
</div> </div>
<h1>{frontMatter.title}</h1> <h1>{frontMatter.title}</h1>
<p>{frontMatter.description}</p>
<p> <p>
Written by <b>{frontMatter.author}</b> on <b>{frontMatter.date}</b> Written by <b>{frontMatter.author}</b> on <b>{frontMatter.date}</b>
</p> </p>
@@ -168,9 +167,11 @@ const BlogPost: FC<Props> = ({ source, frontMatter }) => {
)} )}
<hr /> <hr />
</div> </div>
<MDXProvider components={{ code: CodeBlock }}>
<MDXEmbedProvider> <MDXEmbedProvider>
<div className='content'>{content}</div> <div className='content'>{content}</div>
</MDXEmbedProvider> </MDXEmbedProvider>
</MDXProvider>
</Wrapper> </Wrapper>
</> </>
); );
+12 -5
View File
@@ -2,6 +2,7 @@ import { FC, useEffect } from 'react';
import { getPortfolioPorjectsSlugs, getPortfolioProjectdata } from '../../lib/portfolio'; import { getPortfolioPorjectsSlugs, getPortfolioProjectdata } from '../../lib/portfolio';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { MdxRemote } from 'next-mdx-remote/types'; import { MdxRemote } from 'next-mdx-remote/types';
import { MDXProvider } from '@mdx-js/react';
import { MDXEmbedProvider } from 'mdx-embed'; import { MDXEmbedProvider } from 'mdx-embed';
import { GetStaticPaths, GetStaticProps } from 'next'; import { GetStaticPaths, GetStaticProps } from 'next';
import renderToString from 'next-mdx-remote/render-to-string'; import renderToString from 'next-mdx-remote/render-to-string';
@@ -11,6 +12,7 @@ import matter from 'gray-matter';
import AllComponents from '../../components/All'; import AllComponents from '../../components/All';
import Head from 'next/head'; import Head from 'next/head';
import IconButton from '../../components/IconButton'; import IconButton from '../../components/IconButton';
import CodeBlock from '../../components/CodeBlock';
interface Props { interface Props {
source: MdxRemote.Source; source: MdxRemote.Source;
@@ -80,11 +82,7 @@ const Wrapper = styled.div`
font-size: 1.1rem; font-size: 1.1rem;
} }
p, & > * {
h1,
h2,
h3,
button {
margin: 0.5rem 0rem; margin: 0.5rem 0rem;
} }
@@ -144,11 +142,20 @@ const PortfolioProject: FC<Props> = ({ source, frontMatter }) => {
</div> </div>
<h1>{frontMatter.title}</h1> <h1>{frontMatter.title}</h1>
<p>{frontMatter.description}</p> <p>{frontMatter.description}</p>
{frontMatter.tags && (
<div className='tags-wrapper'>
{frontMatter.tags.map((tag: string, index: number) => (
<span key={index}>#{tag}&nbsp;</span>
))}
</div>
)}
<hr /> <hr />
</div> </div>
<MDXProvider components={{ code: CodeBlock }}>
<MDXEmbedProvider> <MDXEmbedProvider>
<div className='content'>{content}</div> <div className='content'>{content}</div>
</MDXEmbedProvider> </MDXEmbedProvider>
</MDXProvider>
</Wrapper> </Wrapper>
</> </>
); );
+5
View File
@@ -4496,6 +4496,11 @@ prebuild-install@^5.3.5:
tunnel-agent "^0.6.0" tunnel-agent "^0.6.0"
which-pm-runs "^1.0.0" which-pm-runs "^1.0.0"
prism-react-renderer@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.1.1.tgz#1c1be61b1eb9446a146ca7a50b7bcf36f2a70a44"
integrity sha512-MgMhSdHuHymNRqD6KM3eGS0PNqgK9q4QF5P0yoQQvpB6jNjeSAi3jcSAz0Sua/t9fa4xDOMar9HJbLa08gl9ug==
process-nextick-args@~2.0.0: process-nextick-args@~2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"