Merge pull request #43 from ethereum/markdown-styling

Markdown styling
pull/26459/head^2
Corwin Smith 2 years ago committed by GitHub
commit bc030df0ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      package.json
  2. 106
      src/components/MDXComponents.tsx
  3. 85
      src/components/UI/docs/Code.tsx
  4. 2
      src/components/docs/Breadcrumbs.tsx
  5. 3
      src/constants.ts
  6. 22
      src/pages/[...slug].tsx
  7. 7
      src/theme/foundations/fonts.ts
  8. 1
      src/theme/foundations/index.ts
  9. 81
      src/theme/foundations/textStyles.ts
  10. 12
      src/theme/index.ts
  11. 30
      src/utils/getProgrammingLanguageName.ts
  12. 1
      src/utils/index.ts
  13. 6669
      yarn.lock

@ -19,6 +19,7 @@
"@mdx-js/loader": "^2.1.3", "@mdx-js/loader": "^2.1.3",
"@mdx-js/react": "^2.1.3", "@mdx-js/react": "^2.1.3",
"@next/mdx": "^12.3.0", "@next/mdx": "^12.3.0",
"chakra-ui-markdown-renderer": "^4.1.0",
"focus-visible": "^5.2.0", "focus-visible": "^5.2.0",
"framer-motion": "^7.3.2", "framer-motion": "^7.3.2",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
@ -27,7 +28,8 @@
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-markdown": "^8.0.3", "react-markdown": "^8.0.3",
"react-syntax-highlighter": "^15.5.0" "react-syntax-highlighter": "^15.5.0",
"remark-gfm": "^3.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/js-yaml": "^4.0.5", "@types/js-yaml": "^4.0.5",

@ -1,37 +1,26 @@
import { Heading, Link, Stack, Text } from '@chakra-ui/react'; import {
Flex,
Heading,
Link,
ListItem,
OrderedList,
Stack,
Table,
Text,
UnorderedList
} from '@chakra-ui/react';
import NextLink from 'next/link'; import NextLink from 'next/link';
import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';
import { Code } from './UI/docs' import { Code } from './UI/docs';
import { textStyles } from '../theme/foundations';
import bash from 'react-syntax-highlighter/dist/cjs/languages/prism/bash'; const { header1, header2, header3, header4 } = textStyles;
import go from 'react-syntax-highlighter/dist/cjs/languages/prism/go';
import graphql from 'react-syntax-highlighter/dist/cjs/languages/prism/graphql';
import java from 'react-syntax-highlighter/dist/cjs/languages/prism/java';
import javascript from 'react-syntax-highlighter/dist/cjs/languages/prism/javascript';
import json from 'react-syntax-highlighter/dist/cjs/languages/prism/json';
import python from 'react-syntax-highlighter/dist/cjs/languages/prism/python';
import sh from 'react-syntax-highlighter/dist/cjs/languages/prism/shell-session';
import solidity from 'react-syntax-highlighter/dist/cjs/languages/prism/solidity';
import swift from 'react-syntax-highlighter/dist/cjs/languages/prism/swift';
// syntax highlighting languages supported
SyntaxHighlighter.registerLanguage('bash', bash);
SyntaxHighlighter.registerLanguage('go', go);
SyntaxHighlighter.registerLanguage('graphql', graphql);
SyntaxHighlighter.registerLanguage('java', java);
SyntaxHighlighter.registerLanguage('javascript', javascript);
SyntaxHighlighter.registerLanguage('json', json);
SyntaxHighlighter.registerLanguage('python', python);
SyntaxHighlighter.registerLanguage('sh', sh);
SyntaxHighlighter.registerLanguage('solidity', solidity);
SyntaxHighlighter.registerLanguage('swift', swift);
const MDXComponents = { const MDXComponents = {
// paragraphs // paragraphs
p: ({ children }: any) => { p: ({ children }: any) => {
return ( return (
<Text mb={7} _last={{ mb: 0 }} size='sm' lineHeight={1.5}> <Text mb={7} lineHeight={1.5}>
{children} {children}
</Text> </Text>
); );
@ -42,7 +31,7 @@ const MDXComponents = {
<NextLink href={href} passHref> <NextLink href={href} passHref>
<Link <Link
isExternal={href.startsWith('http') && !href.includes('geth.ethereum.org')} isExternal={href.startsWith('http') && !href.includes('geth.ethereum.org')}
color='primary' variant='light'
> >
{children} {children}
</Link> </Link>
@ -52,64 +41,65 @@ const MDXComponents = {
// headings // headings
h1: ({ children }: any) => { h1: ({ children }: any) => {
return ( return (
<Heading as='h1' textAlign='start' fontSize='4xl' mb={5}> <Heading as='h1' textAlign='start' mb={5} {...header1}>
{children} {children}
</Heading> </Heading>
); );
}, },
h2: ({ children }: any) => { h2: ({ children }: any) => {
return ( return (
<Heading as='h2' textAlign='start' fontSize='3xl' mb={4}> <Heading as='h2' textAlign='start' mt='16 !important' mb={4} {...header2}>
{children} {children}
</Heading> </Heading>
); );
}, },
h3: ({ children }: any) => { h3: ({ children }: any) => {
return ( return (
<Heading as='h3' fontSize='2xl' mt={5} mb={2.5}> <Heading as='h3' mt={5} mb={2.5} {...header3}>
{children} {children}
</Heading> </Heading>
); );
}, },
h4: ({ children }: any) => { h4: ({ children }: any) => {
return ( return (
<Heading as='h4' fontSize='lg' mb={2.5}> <Heading as='h4' mb={2.5} {...header4}>
{children} {children}
</Heading> </Heading>
); );
}, },
// tables
table: ({ children }: any) => (
<Flex maxW='min(100%, 100vw)' overflowX='scroll'>
<Table
variant='striped'
colorScheme='greenAlpha'
border='1px'
borderColor='blackAlpha.50'
my={6}
size={{ base: 'sm', lg: 'md' }}
w='auto'
>
{children}
</Table>
</Flex>
),
// pre // pre
pre: ({ children }: any) => { pre: ({ children }: any) => (
return (
<Stack mb={5}> <Stack mb={5}>
<pre>{children}</pre> <pre>{children}</pre>
</Stack> </Stack>
); ),
},
// code // code
code: (code: any) => { code: ({ children, ...props }: any) => <Code {...props}>{children}</Code>,
return ( // list
<Code code={code} /> ul: ({children}: any) => {
) return <UnorderedList mb={7} px={4}>{children}</UnorderedList>
},
// return !!code.inline ? ( ol: ({children}: any) => {
// <Text return <OrderedList mb={7} px={4}>{children}</OrderedList>
// as={'span'} },
// padding='0.125em 0.25em' li: ({ children }: any) => {
// color='red.300' return <ListItem color='primary'>{children}</ListItem>
// background='code-bg-contrast'
// borderRadius='0.25em'
// fontFamily='code'
// fontSize='sm'
// overflowY='scroll'
// >
// {code.children[0]}
// </Text>
// ) : (
// <Stack style={nightOwl}>
// {code.children[0]}
// </Stack>
// );
} }
}; };

@ -1,38 +1,77 @@
// Libraries // Libraries
import { Code as ChakraCode, Stack, Text } from '@chakra-ui/react'; import { Code as ChakraCode, Stack, Text, useColorMode } from '@chakra-ui/react';
import { FC } from 'react'; import { nightOwl, prism } from 'react-syntax-highlighter/dist/cjs/styles/prism';
import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';
// Constants, utilities
import { CLASSNAME_PREFIX } from '../../../constants';
import { getProgrammingLanguageName } from '../../../utils';
// Programming lang syntax highlighters
import bash from 'react-syntax-highlighter/dist/cjs/languages/prism/bash';
import go from 'react-syntax-highlighter/dist/cjs/languages/prism/go';
import graphql from 'react-syntax-highlighter/dist/cjs/languages/prism/graphql';
import java from 'react-syntax-highlighter/dist/cjs/languages/prism/java';
import javascript from 'react-syntax-highlighter/dist/cjs/languages/prism/javascript';
import json from 'react-syntax-highlighter/dist/cjs/languages/prism/json';
import python from 'react-syntax-highlighter/dist/cjs/languages/prism/python';
import sh from 'react-syntax-highlighter/dist/cjs/languages/prism/shell-session';
import solidity from 'react-syntax-highlighter/dist/cjs/languages/prism/solidity';
import swift from 'react-syntax-highlighter/dist/cjs/languages/prism/swift';
// syntax highlighting languages supported
SyntaxHighlighter.registerLanguage('bash', bash);
SyntaxHighlighter.registerLanguage('terminal', bash);
SyntaxHighlighter.registerLanguage('go', go);
SyntaxHighlighter.registerLanguage('graphql', graphql);
SyntaxHighlighter.registerLanguage('java', java);
SyntaxHighlighter.registerLanguage('javascript', javascript);
SyntaxHighlighter.registerLanguage('json', json);
SyntaxHighlighter.registerLanguage('python', python);
SyntaxHighlighter.registerLanguage('sh', sh);
SyntaxHighlighter.registerLanguage('solidity', solidity);
SyntaxHighlighter.registerLanguage('swift', swift);
interface Props { interface Props {
code: any; className: string;
children: string[];
inline?: boolean;
} }
export const Code: React.FC<Props> = ({ className, children, inline }) => {
export const Code: FC<Props> = ({ code }) => { const { colorMode } = useColorMode();
const isDark = colorMode === 'dark';
const isTerminal = className?.includes('terminal');
const [content] = children;
if (inline)
return ( return (
!!code.inline ?
(
<Text <Text
as='span' as='span'
background='code-bg' px={1}
color='primary'
bg='code-bg'
borderRadius='0.25em'
textStyle='inline-code-snippet' textStyle='inline-code-snippet'
pb={2}
mb={-2}
> >
{code.children[0]} {content}
</Text> </Text>
) );
: if (isTerminal)
( return (
<Stack> <Stack>
<ChakraCode <ChakraCode overflow='auto' p={6} background='terminal-bg' color='terminal-text'>
overflow='auto' {content}
p={6}
background='code-bg-contrast'
textStyle='code-block'
color='code-text'
>
{code.children[0]}
</ChakraCode> </ChakraCode>
</Stack> </Stack>
)
); );
if (className?.startsWith(CLASSNAME_PREFIX))
return (
<SyntaxHighlighter
language={getProgrammingLanguageName(className)}
style={isDark ? nightOwl : prism}
customStyle={{ borderRadius: '0.5rem', padding: '1rem' }}
>
{content}
</SyntaxHighlighter>
);
return <Stack>{content}</Stack>;
}; };

@ -10,7 +10,7 @@ export const Breadcrumbs: FC = () => {
pathSplit = pathSplit.splice(1, pathSplit.length); pathSplit = pathSplit.splice(1, pathSplit.length);
return ( return (
<Breadcrumb mb={10}> <Breadcrumb>
{pathSplit.map((path: string, idx: number) => { {pathSplit.map((path: string, idx: number) => {
return ( return (
<BreadcrumbItem key={path}> <BreadcrumbItem key={path}>

@ -104,3 +104,6 @@ export const WINDOWS_BINARY_BASE_URL =
export const LATEST_SOURCES_BASE_URL = 'https://github.com/ethereum/go-ethereum/archive/'; export const LATEST_SOURCES_BASE_URL = 'https://github.com/ethereum/go-ethereum/archive/';
export const RELEASE_NOTES_BASE_URL = 'https://github.com/ethereum/go-ethereum/releases/tag/'; export const RELEASE_NOTES_BASE_URL = 'https://github.com/ethereum/go-ethereum/releases/tag/';
// Code snippet class constants
export const CLASSNAME_PREFIX = 'language-';

@ -1,14 +1,17 @@
import fs from 'fs'; import fs from 'fs';
import matter from 'gray-matter'; import matter from 'gray-matter';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import { Stack, Heading } from '@chakra-ui/react';
import ChakraUIRenderer from 'chakra-ui-markdown-renderer';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import { Heading, Stack } from '@chakra-ui/react'; import gfm from 'remark-gfm';
import MDXComponents from '../components/';
import { ParsedUrlQuery } from 'querystring'; import { ParsedUrlQuery } from 'querystring';
import type { GetStaticPaths, GetStaticProps, NextPage } from 'next'; import type { GetStaticPaths, GetStaticProps, NextPage } from 'next';
import { Breadcrumbs } from '../components/docs';
import MDXComponents from '../components/';
import { Breadcrumbs } from '../components/docs';
import { PageMetadata } from '../components/UI'; import { PageMetadata } from '../components/UI';
import { textStyles } from '../theme/foundations';
const MATTER_OPTIONS = { const MATTER_OPTIONS = {
engines: { engines: {
@ -76,13 +79,16 @@ const DocPage: NextPage<Props> = ({ frontmatter, content }) => {
<PageMetadata title={frontmatter.title} description={frontmatter.description} /> <PageMetadata title={frontmatter.title} description={frontmatter.description} />
<main> <main>
<Stack py={8} px={4}> <Stack mb={16}>
<Breadcrumbs /> <Breadcrumbs />
<Heading as='h1' mt='4 !important' mb={0} {...textStyles.header1}>
<Heading as='h1'>{frontmatter.title}</Heading> {frontmatter.title}
</Heading>
<ReactMarkdown components={MDXComponents}>{content}</ReactMarkdown> {/* <Text as='span' mt='0 !important'>last edited {TODO: get last edited date}</Text> */}
</Stack> </Stack>
<ReactMarkdown remarkPlugins={[gfm]} components={ChakraUIRenderer(MDXComponents)}>
{content}
</ReactMarkdown>
</main> </main>
</> </>
); );

@ -0,0 +1,7 @@
export const fonts = {
// set base fonts as fallback
heading: '"JetBrains Mono", monospace',
button: '"JetBrains Mono", monospace',
code: '"JetBrains Mono", monospace',
body: '"Inter", sans-serif'
};

@ -1,5 +1,6 @@
export * from './colors'; export * from './colors';
export * from './config'; export * from './config';
export * from './fonts';
export * from './shadows'; export * from './shadows';
export * from './sizes'; export * from './sizes';
export * from './textStyles'; export * from './textStyles';

@ -1,51 +1,88 @@
export const textStyles = { export const textStyles = {
h1: { h1: {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 700, fontWeight: 700,
fontSize: '2.75rem', fontSize: '2.75rem',
lineHeight: '3.375rem', lineHeight: '3.375rem',
letterSpacing: '5%', letterSpacing: '0.05em',
color: 'body' color: 'body'
}, },
h2: { h2: {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 400, fontWeight: 400,
fontSize: '1.5rem', fontSize: '1.5rem',
lineHeight: 'auto', lineHeight: 'normal',
letterSpacing: '4%', letterSpacing: '0.04em',
color: 'body' color: 'body'
}, },
header1: {
fontFamily: 'heading',
fontWeight: 700,
fontSize: { base: '1.875rem', md: '2.125rem' },
letterSpacing: '0.04em',
lineHeight: 'normal'
},
header2: {
fontFamily: 'heading',
fontSize: { base: '1.5rem', md: '1.75rem' },
letterSpacing: '0.04em',
lineHeight: 'normal'
},
header3: {
fontFamily: 'heading',
fontSize: { base: '1.25rem', md: '1.375rem' },
letterSpacing: '0.04em',
lineHeight: 'normal'
},
header4: {
fontFamily: 'heading',
fontSize: '1.125rem',
letterSpacing: '0.04em',
lineHeight: 'normal'
},
header5: {
fontFamily: 'heading',
fontSize: '1rem',
letterSpacing: '0.02em',
lineHeight: 'normal'
},
header6: {
fontFamily: 'heading',
fontSize: '0.875rem',
letterSpacing: '0.02em',
lineHeight: 'normal'
},
'header-font': { 'header-font': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 700, fontWeight: 700,
fontSize: { base: '0.86rem', sm: '1rem' } fontSize: { base: '0.86rem', sm: '1rem' }
}, },
'homepage-description': { 'homepage-description': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 700, fontWeight: 700,
lineHeight: '21px', lineHeight: '21px',
letterSpacing: '0.05em', letterSpacing: '0.05em',
textAlign: { base: 'center', md: 'left' } textAlign: { base: 'center', md: 'left' }
}, },
'homepage-primary-label': { 'homepage-primary-label': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
color: 'bg', color: 'bg',
fontWeight: 700, fontWeight: 700,
textTransform: 'uppercase' textTransform: 'uppercase'
}, },
'home-section-link-label': { 'home-section-link-label': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 700, fontWeight: 700,
textTransform: 'uppercase', textTransform: 'uppercase',
textAlign: 'center', textAlign: 'center',
p: 4 p: 4
}, },
'quick-link-text': { 'quick-link-text': {
fontFamily: '"Inter", sans-serif', fontFamily: 'body',
lineHeight: '26px' lineHeight: '26px'
}, },
'quick-link-label': { 'quick-link-label': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 700, fontWeight: 700,
textTransform: 'uppercase', textTransform: 'uppercase',
textAlign: 'center', textAlign: 'center',
@ -56,35 +93,35 @@ export const textStyles = {
}, },
'hero-text-small': { 'hero-text-small': {
fontSize: '13px', fontSize: '13px',
fontFamily: '"Inter", sans-serif' fontFamily: 'body'
}, },
'footer-link-label': { 'footer-link-label': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: '"JetBrains Mono", monospace',
fontWeight: 700, fontWeight: 700,
textTransform: 'uppercase', textTransform: 'uppercase',
lineHeight: '21.12px', lineHeight: '21.12px',
letterSpacing: '2%' letterSpacing: '0.02em'
}, },
'footer-text': { 'footer-text': {
fontFamily: '"Inter", sans-serif', fontFamily: 'body',
lineHeight: '22px', lineHeight: '22px',
fontWeight: 400, fontWeight: 400,
fontSize: '12px' fontSize: '12px'
}, },
'downloads-button-label': { 'downloads-button-label': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
color: 'bg', color: 'bg',
fontSize: { base: 'md', lg: 'xl' }, fontSize: { base: 'md', lg: 'xl' },
textTransform: 'uppercase' textTransform: 'uppercase'
}, },
'downloads-button-sublabel': { 'downloads-button-sublabel': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
color: 'bg', color: 'bg',
fontSize: { base: 'xs', lg: 'sm' }, fontSize: { base: 'xs', lg: 'sm' },
textTransform: 'uppercase' textTransform: 'uppercase'
}, },
'download-tab-label': { 'download-tab-label': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 700, fontWeight: 700,
textTransform: 'uppercase', textTransform: 'uppercase',
textAlign: 'center', textAlign: 'center',
@ -93,7 +130,7 @@ export const textStyles = {
'header-button': { 'header-button': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: '"JetBrains Mono", monospace',
fontWeight: 700, fontWeight: 700,
fontSize: { base: '0.86rem', sm: '1rem' }, fontSize: { base: '0.86rem', sm: '1rem' }
}, },
'header-mobile-button': { 'header-mobile-button': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: '"JetBrains Mono", monospace',
@ -101,18 +138,18 @@ export const textStyles = {
fontSize: '2xl' fontSize: '2xl'
}, },
'inline-code-snippet': { 'inline-code-snippet': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 400, fontWeight: 400,
fontSize: 'md', fontSize: 'md',
lineHeight: 4, lineHeight: 4,
letterSpacing: '1%' letterSpacing: '0.01em'
}, },
'code-block': { 'code-block': {
fontFamily: '"JetBrains Mono", monospace', fontFamily: 'heading',
fontWeight: 400, fontWeight: 400,
fontSize: 'md', fontSize: 'md',
lineHeight: '21.12px', lineHeight: '21.12px',
letterSpacing: '1%' letterSpacing: '0.01em'
}, },
// TODO: refactor w/ semantic tokens for light/dark mode // TODO: refactor w/ semantic tokens for light/dark mode
'link-light': {}, 'link-light': {},

@ -1,6 +1,6 @@
import { extendTheme } from '@chakra-ui/react'; import { extendTheme } from '@chakra-ui/react';
import { config, colors, shadows, sizes, textStyles } from './foundations'; import { config, colors, fonts, shadows, sizes, textStyles } from './foundations';
import { Button, Link } from './components'; import { Button, Link } from './components';
const overrides = { const overrides = {
@ -10,6 +10,7 @@ const overrides = {
Button, Button,
Link Link
}, },
fonts,
shadows, shadows,
sizes, sizes,
styles: { styles: {
@ -17,6 +18,9 @@ const overrides = {
body: { body: {
bg: 'bg', bg: 'bg',
transition: 'all 200ms linear !important' transition: 'all 200ms linear !important'
},
code: {
fontFamily: 'code !important'
} }
}) })
}, },
@ -28,9 +32,9 @@ const overrides = {
'button-bg': { _light: 'green.50', _dark: 'green.900' }, 'button-bg': { _light: 'green.50', _dark: 'green.900' },
body: { _light: 'gray.800', _dark: 'yellow.50' }, body: { _light: 'gray.800', _dark: 'yellow.50' },
'code-bg': { _light: 'gray.200', _dark: 'gray.700' }, 'code-bg': { _light: 'gray.200', _dark: 'gray.700' },
'code-bg-contrast': { _light: 'gray.800', _dark: 'gray.900' }, 'terminal-bg': { _light: 'gray.800', _dark: 'gray.900' },
'code-text': { _light: 'green.50', _dark: 'green.50' }, 'terminal-text': { _light: 'green.50', _dark: 'green.200' },
bg: { _light: 'yellow.50', _dark: 'gray.800' }, bg: { _light: 'yellow.50', _dark: 'gray.800' }
} }
} }
}; };

@ -0,0 +1,30 @@
import { CLASSNAME_PREFIX } from '../constants';
const DEFAULT = 'bash';
const TERMINAL = 'terminal';
const JS = ['javascript', 'js', 'jsx', 'ts', 'tsx'];
const SH = ['sh', 'shell'];
const PY = ['python', 'py'];
const SOL = ['solidity', 'sol'];
const LANGS = [JS, SH, PY, SOL];
export const getProgrammingLanguageName = (code: string) => {
// If `code` argument matches any of the above, return the first value for the language
for (const lang of LANGS) {
if (lang.includes(code.toLowerCase())) return lang[0];
}
// Check if `code` argument starts with the CLASSNAME_PREFIX
const hasLanguageNameProperty = code.startsWith(CLASSNAME_PREFIX);
// If no matched so far, return default code formatting type
if (!hasLanguageNameProperty) return DEFAULT;
// `code` starts with the CLASSNAME_PREFIX, so we need to extract the language name
const newCode = code.replace(CLASSNAME_PREFIX, '').toLowerCase();
// If declared to be `terminal`, return the DEFAULT
if (newCode === TERMINAL) return DEFAULT;
// If `newCode` argument matches any of the above, return the first value for the language
for (const lang of LANGS) {
if (lang.includes(newCode.toLowerCase())) return lang[0];
}
// If no match from above, simply return the extracted language name
return newCode;
};

@ -0,0 +1 @@
export * from './getProgrammingLanguageName';

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save