Browse Source

feat: better bundle size, new header, highlighter fixes

fix/enable-imgix
Thomas Osmonson 4 years ago
parent
commit
30d30374ac
  1. 5
      next.config.js
  2. 2
      package.json
  3. 100
      src/components/code-block/components.tsx
  4. 78
      src/components/code-block/index.tsx
  5. 82
      src/components/feedback.tsx
  6. 1
      src/components/footer.tsx
  7. 141
      src/components/header.tsx
  8. 230
      src/components/highlighter/index.tsx
  9. 117
      src/components/highlighter/language-definition.tsx
  10. 205
      src/components/highlighter/nord.css
  11. 140
      src/components/highlighter/prism-theme.ts
  12. 90
      src/components/highlighter/types.ts
  13. 3
      src/components/home/sections/hero.tsx
  14. 12
      src/components/layouts/docs-layout.tsx
  15. 2
      src/components/mdx/mdx-components.tsx
  16. 7
      src/components/side-nav.tsx
  17. 2
      src/pages/browser/todo-list.md
  18. 2
      yarn.lock

5
next.config.js

@ -2,6 +2,8 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true', enabled: process.env.ANALYZE === 'true',
}); });
const webpack = require('webpack');
const path = require('path'); const path = require('path');
const remarkPlugins = [ const remarkPlugins = [
@ -68,6 +70,9 @@ module.exports = withBundleAnalyzer({
aliases.react = aliases['react-dom'] = 'preact/compat'; aliases.react = aliases['react-dom'] = 'preact/compat';
aliases['react-ssr-prepass'] = 'preact-ssr-prepass'; aliases['react-ssr-prepass'] = 'preact-ssr-prepass';
// to fix a dupe dependency
config.externals.push('prismjs');
// https://github.com/FormidableLabs/react-live#what-bundle-size-can-i-expect // https://github.com/FormidableLabs/react-live#what-bundle-size-can-i-expect
aliases['buble'] = '@philpl/buble'; aliases['buble'] = '@philpl/buble';
} }

2
package.json

@ -46,7 +46,7 @@
"preact-ssr-prepass": "^1.1.0", "preact-ssr-prepass": "^1.1.0",
"prettier": "^2.0.5", "prettier": "^2.0.5",
"preval.macro": "^5.0.0", "preval.macro": "^5.0.0",
"prism-react-renderer": "^1.0.2", "prism-react-renderer": "^1.1.1",
"prismjs": "^1.20.0", "prismjs": "^1.20.0",
"react-children-utilities": "^2.1.3", "react-children-utilities": "^2.1.3",
"react-gesture-responder": "^2.1.0", "react-gesture-responder": "^2.1.0",

100
src/components/code-block/components.tsx

@ -1,100 +0,0 @@
import React, { useContext } from 'react';
import { LiveProvider, LiveContext, LivePreview } from 'react-live';
import {
Flex,
Button,
Box,
CodeBlock as BaseCodeBlock,
space,
useClipboard,
BoxProps,
} from '@blockstack/ui';
import { CodeEditor } from '@components/code-editor';
import { Text } from '@components/typography';
import { border } from '@common/utils';
const Error = () => {
const { error } = useContext(LiveContext);
return error ? <BaseCodeBlock mt={space('base')} code={error} /> : null;
};
export const liveEditorStyle = {
fontSize: 14,
marginBottom: 24,
marginTop: 24,
overflowX: 'auto',
fontFamily: 'Menlo,monospace',
borderRadius: 10,
};
export const liveErrorStyle = {
fontFamily: 'Fira Mono, monospace',
fontSize: 14,
padding: '1em',
overflowX: 'auto',
color: 'white',
marginTop: '16px',
border: '1px solid var(--colors-border)',
backgroundColor: 'var(--colors-bg-light)',
};
export const LiveCodePreview = (props: any) => (
<Box fontFamily="body">
<Box
as={LivePreview}
boxShadow="mid"
border={border()}
borderRadius="6px"
p={space('base')}
mb={space('base')}
{...props}
/>
</Box>
);
const Label = (props: BoxProps) => (
<Text fontWeight={500} fontFamily="body" fontSize="12px" {...props} />
);
export const JsxEditor = ({ liveProviderProps, editorCode, handleCodeChange, language }) => {
const { hasCopied, onCopy } = useClipboard(editorCode);
return (
<LiveProvider {...liveProviderProps}>
<Box mb={space('extra-tight')}>
<Label>Preview</Label>
</Box>
<LiveCodePreview />
<Flex justify="space-between" fontFamily="'Inter'" align="flex-end" mb={space('tight')}>
<Label>Editable example</Label>
<Button onClick={onCopy} size="sm" mode="secondary">
{hasCopied ? 'Copied!' : 'Copy example code'}
</Button>
</Flex>
<CodeEditor value={editorCode} onChange={handleCodeChange} language={language} />
<Error />
</LiveProvider>
);
};
export const Preview = ({ liveProviderProps }) => (
<Box>
<LiveProvider {...liveProviderProps}>
<LiveCodePreview />
</LiveProvider>
</Box>
);
export const SimpleCodeBlock = ({ editorCode, language, ...rest }) => (
<BaseCodeBlock
borderTop={'1px solid rgb(39, 41, 46)'}
borderBottom={'1px solid rgb(39, 41, 46)'}
borderLeft={['none', '1px solid rgb(39, 41, 46)', '1px solid rgb(39, 41, 46)']}
borderRight={['none', '1px solid rgb(39, 41, 46)', '1px solid rgb(39, 41, 46)']}
borderRadius={['unset', 'unset', '12px', '12px']}
code={editorCode}
language={language}
{...rest}
/>
);

78
src/components/code-block/index.tsx

@ -7,28 +7,80 @@ import 'prismjs/components/prism-json';
import 'prismjs/components/prism-toml'; import 'prismjs/components/prism-toml';
import 'prismjs/components/prism-python'; import 'prismjs/components/prism-python';
import 'prismjs/components/prism-kotlin'; import 'prismjs/components/prism-kotlin';
import { Highlighter, HighlighterProps } from '../highlighter';
import { Box, BoxProps } from '@blockstack/ui';
import { css } from '@styled-system/css';
import { SimpleCodeBlock } from '@components/code-block/components'; interface CodeBlock {
import { useForceUpdate } from '@blockstack/ui'; live?: boolean;
highlight?: string;
}
export const CodeBlock = React.memo( export type CodeBlockProps = CodeBlock & HighlighterProps & BoxProps;
({ className, live = true, isManual, render, children, ...props }: any) => {
const update = useForceUpdate();
React.useEffect(() => {
update();
}, []);
const getHighlightLineNumbers = str =>
str &&
str
.split(' ')
.join('')
.split(',')
.flatMap(s => {
if (!s.includes('-')) return +s;
const [min, max] = s.split('-');
return Array.from({ length: max - min + 1 }, (_, n) => n + +min);
});
const CodeBlock = React.memo(
React.forwardRef(
(
{
code,
showLineNumbers,
hideLineHover,
style = {},
highlightedLines,
className,
live = true,
highlight,
children,
...props
}: CodeBlockProps,
ref: React.Ref<HTMLDivElement>
) => {
const language = className && className.replace(/language-/, ''); const language = className && className.replace(/language-/, '');
return ( return (
<SimpleCodeBlock <Box
editorCode={children.toString()} className={language !== 'bash' ? 'line-numbers' : ''}
showLineNumbers={language !== 'bash'} bg="ink"
language={language} borderRadius={[0, 0, '12px']}
{...props} overflowX="auto"
>
<Box
ref={ref}
css={css({
...style,
// @ts-ignore
color: 'white',
// @ts-ignore
whiteSpace: 'pre',
...props,
})}
>
<Highlighter
language={language as any}
code={children.toString().trim()}
showLineNumbers={language && language !== 'bash'}
highlightedLines={getHighlightLineNumbers(highlight)}
hideLineHover
/> />
</Box>
</Box>
); );
} }
)
); );
export default CodeBlock; export default CodeBlock;

82
src/components/feedback.tsx

@ -1,5 +1,17 @@
import React from 'react'; import React from 'react';
import { Box, BoxProps, color, Flex, space, Stack, themeColor } from '@blockstack/ui'; import {
Box,
Button,
BoxProps,
color,
Flex,
space,
Stack,
themeColor,
transition,
SlideFade,
} from '@blockstack/ui';
import { Text } from '@components/typography';
import { MDXComponents, Link } from '@components/mdx'; import { MDXComponents, Link } from '@components/mdx';
import { SadIcon, NeutralIcon, HappyIcon } from '@components/icons/feedback'; import { SadIcon, NeutralIcon, HappyIcon } from '@components/icons/feedback';
import { useHover } from 'use-events'; import { useHover } from 'use-events';
@ -15,8 +27,63 @@ const Icon: React.FC<BoxProps & { icon: React.FC<any> }> = ({ icon: IconComponen
); );
}; };
const FeedbackCard = ({ show, onClose }) => {
return (
<SlideFade in={show}>
{styles => (
<Box ml={space('base-loose')} p={space('base')}>
<Flex
p={space('base')}
border={border()}
borderRadius="12px"
align="center"
justifyContent="center"
bg={color('bg')}
size="100%"
boxShadow="mid"
transition={transition}
_hover={{
transform: 'translateY(-5px)',
boxShadow: 'high',
}}
style={{
...styles,
}}
>
<Box>
<Button
as="a"
// @ts-ignore
href="https://forms.formium.io/f/5f174a3960b46d000139b62f"
target="_blank"
>
Leave feedback
</Button>
<Box
_hover={{ color: color('accent'), textDecoration: 'underline', cursor: 'pointer' }}
onClick={onClose}
mt={space('tight')}
textAlign="center"
mx="auto"
>
<Text color="currentColor" fontSize="14px">
Dismiss
</Text>
</Box>
</Box>
</Flex>
</Box>
)}
</SlideFade>
);
};
export const FeedbackSection: React.FC<BoxProps> = props => { export const FeedbackSection: React.FC<BoxProps> = props => {
const { pathname } = useRouter(); const { pathname } = useRouter();
const [showButton, setShowButton] = React.useState(false);
const handleShow = () => {
setShowButton(!showButton);
};
return ( return (
<Flex <Flex
flexDirection={['column', 'column', 'row']} flexDirection={['column', 'column', 'row']}
@ -24,14 +91,17 @@ export const FeedbackSection: React.FC<BoxProps> = props => {
borderTop={border()} borderTop={border()}
mt={space('extra-loose')} mt={space('extra-loose')}
> >
<Box> <Flex>
<MDXComponents.h3>Was this page helpful?</MDXComponents.h3> <Box position="relative">
<MDXComponents.h4>Was this page helpful?</MDXComponents.h4>
<Stack isInline spacing={space('base-loose')} mt={space('base-loose')}> <Stack isInline spacing={space('base-loose')} mt={space('base-loose')}>
<Icon icon={SadIcon} /> <Icon onClick={() => handleShow()} icon={SadIcon} />
<Icon icon={NeutralIcon} /> <Icon onClick={() => handleShow()} icon={NeutralIcon} />
<Icon icon={HappyIcon} /> <Icon onClick={() => handleShow()} icon={HappyIcon} />
</Stack> </Stack>
</Box> </Box>
<FeedbackCard show={showButton} onClose={() => setShowButton(false)} />
</Flex>
<Box mt={space(['extra-loose', 'extra-loose', 'base-loose'])}> <Box mt={space(['extra-loose', 'extra-loose', 'base-loose'])}>
<Link <Link
href={`https://github.com/blockstack/docs.blockstack/tree/feat/next/src/pages${pathname}.md`} href={`https://github.com/blockstack/docs.blockstack/tree/feat/next/src/pages${pathname}.md`}

1
src/components/footer.tsx

@ -3,7 +3,6 @@ import { Pagination } from '@components/pagination';
import { Section, SectionWrapper } from '@components/home/common'; import { Section, SectionWrapper } from '@components/home/common';
import { FeedbackSection } from '@components/feedback'; import { FeedbackSection } from '@components/feedback';
const Footer = ({ hidePagination, ...rest }: any) => { const Footer = ({ hidePagination, ...rest }: any) => {
return ( return (
<Section> <Section>

141
src/components/header.tsx

@ -1,6 +1,16 @@
import React from 'react'; import React from 'react';
import { Flex, Box, BlockstackIcon, Portal, Input, color, space } from '@blockstack/ui'; import {
import { Link, Text } from '@components/typography'; Flex,
Box,
BlockstackIcon,
Stack,
color,
space,
themeColor,
transition,
ChevronIcon,
} from '@blockstack/ui';
import { Link, Text, LinkProps } from '@components/typography';
import MenuIcon from 'mdi-react/MenuIcon'; import MenuIcon from 'mdi-react/MenuIcon';
import CloseIcon from 'mdi-react/CloseIcon'; import CloseIcon from 'mdi-react/CloseIcon';
import { useLockBodyScroll } from '@common/hooks/use-lock-body-scroll'; import { useLockBodyScroll } from '@common/hooks/use-lock-body-scroll';
@ -9,10 +19,12 @@ import { SideNav } from './side-nav';
import GithubIcon from 'mdi-react/GithubIcon'; import GithubIcon from 'mdi-react/GithubIcon';
import { IconButton } from '@components/icon-button'; import { IconButton } from '@components/icon-button';
import { border } from '@common/utils'; import { border } from '@common/utils';
import useSWR from 'swr'; import routes from '@common/routes';
import { useAppState } from '@common/hooks/use-app-state';
import { css } from '@styled-system/css'; import { css } from '@styled-system/css';
import NextLink from 'next/link'; import NextLink from 'next/link';
import MagnifyIcon from 'mdi-react/MagnifyIcon';
import { useRouter } from 'next/router';
const MenuButton = ({ ...rest }: any) => { const MenuButton = ({ ...rest }: any) => {
const { isOpen, handleOpen, handleClose } = useMobileMenuState(); const { isOpen, handleOpen, handleClose } = useMobileMenuState();
const Icon = isOpen ? CloseIcon : MenuIcon; const Icon = isOpen ? CloseIcon : MenuIcon;
@ -28,8 +40,50 @@ const MenuButton = ({ ...rest }: any) => {
</Flex> </Flex>
); );
}; };
const BreadCrumbs: React.FC<any> = props => {
const router = useRouter();
const [route, setRoute] = React.useState(undefined);
const [section, setSection] = React.useState(undefined);
React.useEffect(() => {
routes.forEach(_section => {
_section?.routes?.length &&
_section.routes.forEach(_route => {
if (router.route === `/${_route.path}`) {
setSection(_section);
setRoute(_route);
}
});
});
}, [router.route]);
const GithubButton = () => ( return (
<Flex align="center">
<Box>
<Text fontSize="14px" fontWeight="600">
Docs
</Text>
</Box>
<Box pt="3px" color={color('text-caption')}>
<ChevronIcon size="20px" />
</Box>
<Box>
<Text fontSize="14px" fontWeight="600">
{section?.title}
</Text>
</Box>
<Box pt="3px" color={color('text-caption')}>
<ChevronIcon size="20px" />
</Box>
<Box>
<Text fontSize="14px" fontWeight="600">
{route?.title || (route?.headings.length && route.headings[0])}
</Text>
</Box>
</Flex>
);
};
const GithubButton = (props: LinkProps) => (
<IconButton <IconButton
as="a" as="a"
href="https://github.com/blockstack/ux/tree/master/packages/ui#blockstack-ui" href="https://github.com/blockstack/ux/tree/master/packages/ui#blockstack-ui"
@ -42,6 +96,7 @@ const GithubButton = () => (
style={{ style={{
alignItems: 'center', alignItems: 'center',
}} }}
{...props}
> >
<Text position="absolute" opacity={0} as="label"> <Text position="absolute" opacity={0} as="label">
Find us on GitHub Find us on GitHub
@ -56,8 +111,8 @@ const MobileSideNav = () => {
return ( return (
<SideNav <SideNav
position="fixed" position="fixed"
top="50px" top={`${HEADER_HEIGHT}px`}
maxHeight="calc(100vh - 50px)" maxHeight={`calc(100vh - ${HEADER_HEIGHT}px)`}
width="100%" width="100%"
zIndex={99} zIndex={99}
bg={color('bg')} bg={color('bg')}
@ -67,23 +122,68 @@ const MobileSideNav = () => {
); );
}; };
const Header = ({ ...rest }: any) => { const HeaderWrapper: React.FC<any> = props => (
<Box position="fixed" zIndex={9999} width="100%" {...props} />
);
const nav = [
{
label: 'Developers',
},
{ label: 'Run a node' },
{ label: 'Build on Blockstack' },
];
const SubBar: React.FC<any> = props => (
<Flex
justifyContent="space-between"
align="center"
height="60px"
width="100%"
px={['extra-loose', 'extra-loose', 'base', 'base']}
bg="rgba(255,255,255, 0.8)"
borderBottom={border()}
style={{
backdropFilter: 'blur(5px)',
}}
>
<BreadCrumbs />
<Flex
align="center"
justifyContent="flex-end"
bg={themeColor('ink.150')}
height="32px"
width="32px"
borderRadius="32px"
transition={transition}
px={space('tight')}
_hover={{
bg: themeColor('ink.200'),
width: ['32px', '32px', '225px', '225px'],
cursor: 'pointer',
justifyContent: 'flex-end',
}}
>
<MagnifyIcon size="16px" />
</Flex>
</Flex>
);
export const HEADER_HEIGHT = 132;
const Header = ({ hideSubBar, ...rest }: any) => {
return ( return (
<> <>
<HeaderWrapper>
<Flex <Flex
justifyContent="space-between" justifyContent="space-between"
align="center" align="center"
px="base" px={['extra-loose', 'extra-loose', 'base', 'base']}
position="fixed"
zIndex={9999}
width="100%"
bg="rgba(255,255,255, 0.8)" bg="rgba(255,255,255, 0.8)"
borderBottom={border()} borderBottom={border()}
style={{ style={{
backdropFilter: 'blur(5px)', backdropFilter: 'blur(5px)',
}} }}
height="50px" height="72px"
boxShadow="mid"
{...rest} {...rest}
> >
<NextLink href="/" passHref> <NextLink href="/" passHref>
@ -121,10 +221,23 @@ const Header = ({ ...rest }: any) => {
</Link> </Link>
</NextLink> </NextLink>
<Flex align="center"> <Flex align="center">
<Box display={['none', 'none', 'block']}>
<Stack mr={space('base')} isInline spacing={space('base')}>
{nav.map(item => (
<Box>
<Text fontSize="14px" fontWeight="600">
{item.label}
</Text>
</Box>
))}
</Stack>
</Box>
<GithubButton /> <GithubButton />
<MenuButton /> <MenuButton />
</Flex> </Flex>
</Flex> </Flex>
{!hideSubBar && <SubBar />}
</HeaderWrapper>
<MobileSideNav /> <MobileSideNav />
</> </>
); );

230
src/components/highlighter/index.tsx

@ -0,0 +1,230 @@
import React from 'react';
import Highlight from 'prism-react-renderer';
import { Box, Flex, space, useTheme } from '@blockstack/ui';
import { GrammaticalToken, GetGrammaticalTokenProps, RenderProps, Language } from './types';
import Prism from 'prism-react-renderer/prism';
import { theme } from '@components/highlighter/prism-theme';
import './language-definition';
import { css } from '@styled-system/css';
const startPad = (n: number, z = 2, s = '0') =>
(n + '').length <= z ? ['', '-'][+(n < 0)] + (s.repeat(z) + Math.abs(n)).slice(-1 * z) : n + '';
const LINE_NUMBER_WIDTH = 50;
const getLineNumber = (n: number, length: number) => startPad(n + 1, length.toString().length);
const Tokens = ({
tokens,
getTokenProps,
showLineNumbers,
...rest
}: {
tokens: GrammaticalToken[];
getTokenProps: GetGrammaticalTokenProps;
showLineNumbers?: boolean;
}) => {
const bsTheme = useTheme();
const pl = showLineNumbers
? [`calc(${LINE_NUMBER_WIDTH}px + ${(bsTheme as any).sizes['base']})`]
: ['unset', 'unset', 'base', 'base'];
return (
<Box pl={pl} pr="base" position="relative" zIndex={2} {...rest}>
{tokens.map(
(token, key) =>
token.content !== '// highlight' && (
<Box py="2px" display="inline-block" {...getTokenProps({ token, key })} />
)
)}
</Box>
);
};
const LineNumber = ({ number, length, ...rest }: { number: number; length: number }) => (
<Flex
textAlign="right"
pr={space('tight')}
pl={space('tight')}
width={LINE_NUMBER_WIDTH}
borderRight="1px solid"
borderRightColor="inherit"
color="ink.400"
flexShrink={0}
style={{ userSelect: 'none' }}
position="absolute"
left={0}
height="100%"
align="baseline"
justify="center"
zIndex={1}
css={css({
color: 'rgba(255,255,255,0.6)',
whiteSpace: 'pre',
fontFamily: 'Fira Code, Consolata, monospace',
fontSize: '14.556040756914118px',
lineHeight: '24px',
padding: '2px 0',
'::before': {
content: "''",
marginTop: '-0.47483499999999995em',
display: 'block',
height: 0,
},
'::after': {
content: "''",
marginBottom: '-0.493835em',
display: 'block',
height: 0,
},
})}
{...rest}
>
{getLineNumber(number, length)}
</Flex>
);
const Line = ({
tokens,
getTokenProps,
index,
length,
showLineNumbers,
hideLineHover,
highlighted,
...rest
}: {
tokens: GrammaticalToken[];
index: number;
length: number;
getTokenProps: GetGrammaticalTokenProps;
showLineNumbers?: boolean;
hideLineHover?: boolean;
highlighted?: boolean;
}) => {
const highlightedStyle = {
bg: ['unset', 'unset', 'ink.900'],
borderColor: ['ink.900', 'ink.900', 'ink.600'],
};
const hasHighlightComment = !!tokens.find(token => token.content === '// highlight');
const isHighlighted = highlighted || hasHighlightComment;
const highlighedProps = isHighlighted ? highlightedStyle : {};
return (
<Flex
height="loose"
align="baseline"
borderColor="ink.900"
_hover={hideLineHover ? undefined : highlightedStyle}
position="relative"
{...highlighedProps}
{...rest}
>
{showLineNumbers ? <LineNumber number={index} length={length} /> : null}
<Tokens showLineNumbers={showLineNumbers} getTokenProps={getTokenProps} tokens={tokens} />
</Flex>
);
};
const Spacer = ({ showLineNumbers }: { showLineNumbers?: boolean }) => (
<Flex height="base-loose" bg="ink" width="100%">
{showLineNumbers && (
<Box
height="base-loose"
borderRight="1px solid"
borderRightColor="ink.900"
width={`${LINE_NUMBER_WIDTH}px`}
/>
)}
</Flex>
);
const Lines = ({
tokens: lines,
getLineProps,
getTokenProps,
className,
showLineNumbers,
hideLineHover,
highlightedLines,
}: {
showLineNumbers?: boolean;
hideLineHover?: boolean;
highlightedLines?: number[];
} & RenderProps) => {
return (
<Box display="block" className={className}>
<Box display="block" style={{ fontFamily: 'Fira Code' }}>
<Spacer showLineNumbers={showLineNumbers} />
{lines.map((tokens, i) => (
<Box
css={css({
'& > *': {
fontFamily: 'Fira Code, Consolata, monospace',
fontSize: '14.556040756914118px',
lineHeight: '24px',
padding: '0.05px 0',
'::before': {
content: "''",
marginTop: '-0.47483499999999995em',
display: 'block',
height: 0,
},
'::after': {
content: "''",
marginBottom: '-0.493835em',
display: 'block',
height: 0,
},
},
})}
>
<Line
index={i}
tokens={tokens}
getTokenProps={getTokenProps}
length={lines.length + 1}
showLineNumbers={showLineNumbers}
highlighted={
highlightedLines?.length && !!highlightedLines.find(lineNumber => lineNumber === i)
}
hideLineHover={hideLineHover || lines.length < 3}
{...getLineProps({ line: tokens, key: i })}
/>
</Box>
))}
<Spacer showLineNumbers={showLineNumbers} />
</Box>
</Box>
);
};
export interface HighlighterProps {
code: string;
language?: Language;
showLineNumbers?: boolean;
hideLineHover?: boolean;
highlightedLines?: number[];
}
export const Highlighter = React.memo(
({
code,
language = 'clarity',
showLineNumbers,
hideLineHover,
highlightedLines,
}: HighlighterProps) => {
return (
<Highlight Prism={Prism} theme={theme} code={code} language={language as any}>
{props => (
<Lines
showLineNumbers={showLineNumbers}
highlightedLines={highlightedLines}
hideLineHover={hideLineHover}
{...props}
/>
)}
</Highlight>
);
}
);
Highlighter.displayName = 'Highlighter';

117
src/components/highlighter/language-definition.tsx

@ -0,0 +1,117 @@
// @ts-nocheck
import Prism from 'prism-react-renderer/prism';
(function (Prism) {
// Functions to construct regular expressions
// simple form
// e.g. (interactive ... or (interactive)
function simple_form(name) {
return RegExp('(\\()' + name + '(?=[\\s\\)])');
}
// booleans and numbers
function primitive(pattern) {
return RegExp('([\\s([])' + pattern + '(?=[\\s)])');
}
// Patterns in regular expressions
// Open parenthesis for look-behind
const par = '(\\()';
const endpar = '(?=\\))';
// End the pattern with look-ahead space
const space = '(?=\\s)';
const language = {
// Three or four semicolons are considered a heading.
heading: {
pattern: /;;;.*/,
alias: ['comment', 'title'],
},
comment: /;;.*/,
string: [
{
pattern: /"(?:[^"\\]|\\.)*"/,
greedy: true,
},
{
pattern: /0x[0-9a-fA-F]*/,
greedy: true,
},
],
symbol: {
pattern: /'[^()#'\s]+/,
greedy: true,
},
keyword: [
{
pattern: RegExp(
par +
'(?:or|and|xor|not|begin|let|if|ok|err|unwrap\\!|unwrap-err\\!|unwrap-panic|unwrap-err-panic|match|try\\!|asserts\\!|\
map-get\\?|var-get|contract-map-get\\?|get|tuple|\
define-public|define-private|define-constant|define-map|define-data-var|\
define-fungible-token|define-non-fungible-token|\
define-read-only)' +
space
),
lookbehind: true,
},
{
pattern: RegExp(par + '(?:is-eq|is-some|is-none|is-ok|is-er)' + space),
lookbehind: true,
},
{
pattern: RegExp(
par +
'(?:var-set|map-set|map-delete|map-insert|\
ft-transfer\\?|nft-transfer\\?|nft-mint\\?|ft-mint\\?|nft-get-owner\\?|ft-get-balance\\?|\
contract-call\\?)' +
space
),
lookbehind: true,
},
{
pattern: RegExp(
par +
'(?:list|map|filter|fold|len|concat|append|as-max-len\\?|to-int|to-uint|\
buff|hash160|sha256|sha512|sha512/256|keccak256|true|false|none)' +
space
),
lookbehind: true,
},
{
pattern: RegExp(
par +
'(?:as-contract|contract-caller|tx-sender|block-height|at-block|get-block-info\\?)' +
space
),
lookbehind: true,
},
{
pattern: RegExp(par + '(?:is-eq|is-some|is-none|is-ok|is-err)' + space),
lookbehind: true,
},
],
boolean: /(?:false|true|none)/,
number: {
pattern: primitive('[-]?u?\\d+'),
lookbehind: true,
},
address: {
pattern: /([\s()])(?:\'[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{28,41})(?=[()\s]|$)/,
lookbehind: true,
},
operator: {
pattern: /(\()(?:[-+*\/]|[<>]=?|=>?)(?=[()\s]|$)/,
lookbehind: true,
},
function: {
pattern: /(\()[^()'\s]+(?=[()\s]|$)/,
lookbehind: true,
},
punctuation: /[()']/,
};
if (Prism && Prism.languages) {
Prism.languages.clarity = language;
}
})(Prism);

205
src/components/highlighter/nord.css

@ -0,0 +1,205 @@
code[class*="language-"],
pre[class*="language-"] {
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
color: #eee;
background: #2f2f2f;
font-family: Roboto Mono, monospace;
font-size: 1em;
line-height: 1.5em;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
code[class*="language-"]::-moz-selection,
pre[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection,
pre[class*="language-"] ::-moz-selection {
background: #363636;
}
code[class*="language-"]::selection,
pre[class*="language-"]::selection,
code[class*="language-"] ::selection,
pre[class*="language-"] ::selection {
background: #363636;
}
:not(pre) > code[class*="language-"] {
white-space: normal;
border-radius: 0.2em;
padding: 0.1em;
}
pre[class*="language-"] {
overflow: auto;
position: relative;
margin: 0.5em 0;
padding: 1.25em 1em;
}
.language-css > code,
.language-sass > code,
.language-scss > code {
color: #fd9170;
}
[class*="language-"] .namespace {
opacity: 0.7;
}
.token.atrule {
color: #c792ea;
}
.token.attr-name {
color: #ffcb6b;
}
.token.attr-value {
color: #a5e844;
}
.token.attribute {
color: #a5e844;
}
.token.boolean {
color: #c792ea;
}
.token.builtin {
color: #ffcb6b;
}
.token.cdata {
color: #80cbc4;
}
.token.char {
color: #80cbc4;
}
.token.class {
color: #ffcb6b;
}
.token.class-name {
color: #f2ff00;
}
.token.comment {
color: #616161;
}
.token.constant {
color: #c792ea;
}
.token.deleted {
color: #ff6666;
}
.token.doctype {
color: #616161;
}
.token.entity {
color: #ff6666;
}
.token.function {
color: #c792ea;
}
.token.hexcode {
color: #f2ff00;
}
.token.id {
color: #c792ea;
font-weight: bold;
}
.token.important {
color: #c792ea;
font-weight: bold;
}
.token.inserted {
color: #80cbc4;
}
.token.keyword {
color: #c792ea;
}
.token.number {
color: #fd9170;
}
.token.operator {
color: #89ddff;
}
.token.prolog {
color: #616161;
}
.token.property {
color: #80cbc4;
}
.token.pseudo-class {
color: #a5e844;
}
.token.pseudo-element {
color: #a5e844;
}
.token.punctuation {
color: #89ddff;
}
.token.regex {
color: #f2ff00;
}
.token.selector {
color: #ff6666;
}
.token.string {
color: #a5e844;
}
.token.symbol {
color: #c792ea;
}
.token.tag {
color: #ff6666;
}
.token.unit {
color: #fd9170;
}
.token.url {
color: #ff6666;
}
.token.variable {
color: #ff6666;
}

140
src/components/highlighter/prism-theme.ts

@ -0,0 +1,140 @@
import { PrismTheme } from 'prism-react-renderer';
export const theme: PrismTheme = {
plain: {
color: 'rgba(255,255,255,1)',
backgroundColor: '#0f111a',
},
styles: [
{
types: ['string'],
style: {
color: 'rgb(195, 232, 141)',
},
},
{
types: ['boolean'],
style: {
color: 'rgb(255, 156, 172)',
},
},
{
types: ['number', 'keyword', 'operator'],
style: {
color: 'rgb(247, 140, 108)',
},
},
{
types: ['comment'],
style: {
color: 'rgba(255,255,255,0.6)',
fontStyle: 'italic',
},
},
{
types: ['punctuation', 'builtin'],
style: {
color: 'rgb(137, 221, 255)',
},
},
{
types: ['tag'],
style: {
color: 'rgb(240, 113, 120)',
},
},
{
types: ['attr-name'],
style: {
color: 'rgb(255, 203, 107)',
},
},
{
types: ['function'],
style: {
color: 'rgb(130, 170, 255)',
},
},
{
types: ['constant'],
style: {
color: 'rgb(137, 221, 255)',
fontStyle: 'italic',
},
},
],
};
// export const theme: PrismTheme = {
// plain: {
// color: '#fff',
// backgroundColor: 'transparent',
// },
// styles: [
// {
// types: ['prolog'],
// style: {
// color: 'rgb(0, 0, 128)',
// },
// },
// {
// types: ['comment', 'punctuation'],
// style: {
// color: 'rgb(106, 153, 85)',
// },
// },
// {
// types: ['builtin', 'tag', 'changed', 'function', 'keyword'],
// style: {
// color: 'rgb(86, 156, 214)',
// },
// },
// {
// types: ['number', 'variable', 'inserted'],
// style: {
// color: '#A58FFF',
// },
// },
// {
// types: ['operator'],
// style: {
// color: 'rgb(212, 212, 212)',
// },
// },
// {
// types: ['constant'],
// style: {
// color: 'rgb(100, 102, 149)',
// },
// },
// {
// types: ['attr-name'],
// style: {
// color: 'rgb(156, 220, 254)',
// },
// },
// {
// types: ['car'],
// style: {
// color: 'rgb(156, 220, 254)',
// },
// },
// {
// types: ['deleted', 'string'],
// style: {
// color: '#FF7B48',
// },
// },
// {
// types: ['class-name'],
// style: {
// color: 'rgb(78, 201, 176)',
// },
// },
// {
// types: ['char'],
// style: {
// color: '#FF7B48',
// },
// },
// ],
// };

90
src/components/highlighter/types.ts

@ -0,0 +1,90 @@
import * as React from 'react';
export interface GrammaticalToken {
types: string[];
content: string;
empty?: boolean;
}
export interface StyleObj {
[key: string]: string | number | null;
}
export interface GrammaticalTokenOutputProps {
key?: React.Key;
style?: StyleObj;
className: string;
children: string;
[otherProp: string]: any;
}
export interface GrammaticalTokenInputProps {
key?: React.Key;
style?: StyleObj;
className?: string;
token: GrammaticalToken;
[otherProp: string]: any;
}
export interface LineInputProps {
key?: React.Key;
style?: StyleObj;
className?: string;
line: GrammaticalToken[];
[otherProp: string]: any;
}
export interface LineOutputProps {
key?: React.Key;
style?: StyleObj;
className: string;
[otherProps: string]: any;
}
export interface RenderProps {
tokens: GrammaticalToken[][];
className: string;
style: StyleObj;
getLineProps: (input: LineInputProps) => LineOutputProps;
getTokenProps: (input: GrammaticalTokenInputProps) => GrammaticalTokenOutputProps;
}
export type GetGrammaticalTokenProps = (
input: GrammaticalTokenInputProps
) => GrammaticalTokenOutputProps;
export type Language =
| 'markup'
| 'bash'
| 'clarity'
| 'clike'
| 'c'
| 'cpp'
| 'css'
| 'javascript'
| 'jsx'
| 'coffeescript'
| 'actionscript'
| 'css-extr'
| 'diff'
| 'git'
| 'go'
| 'graphql'
| 'handlebars'
| 'json'
| 'less'
| 'lisp'
| 'makefile'
| 'markdown'
| 'objectivec'
| 'ocaml'
| 'python'
| 'reason'
| 'sass'
| 'scss'
| 'sql'
| 'stylus'
| 'tsx'
| 'typescript'
| 'wasm'
| 'yaml';

3
src/components/home/sections/hero.tsx

@ -4,11 +4,12 @@ import { CircleIcon } from '@components/home/common';
import { CONTENT_MAX_WIDTH } from '@common/constants'; import { CONTENT_MAX_WIDTH } from '@common/constants';
import { Card } from '@components/home/card'; import { Card } from '@components/home/card';
import { Body, H1, BodyLarge, SubHeading } from '@components/home/text'; import { Body, H1, BodyLarge, SubHeading } from '@components/home/text';
import { HEADER_HEIGHT } from '@components/header';
export const Hero = ({ cards }: { cards?: any }) => { export const Hero = ({ cards }: { cards?: any }) => {
return ( return (
<> <>
<Grid pb="64px" pt="64px" style={{ placeItems: 'center' }} mt="50px"> <Grid pb="64px" pt="64px" style={{ placeItems: 'center' }}>
<Box maxWidth="62ch" textAlign="center"> <Box maxWidth="62ch" textAlign="center">
<H1 mb={space('base')}>Easily build decentralized apps</H1> <H1 mb={space('base')}>Easily build decentralized apps</H1>
<BodyLarge maxWidth="42ch" mt="64px" mx="auto"> <BodyLarge maxWidth="42ch" mt="64px" mx="auto">

12
src/components/layouts/docs-layout.tsx

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { Flex, color, space, themeColor } from '@blockstack/ui'; import { Flex, color, space, themeColor, ChevronIcon } from '@blockstack/ui';
import { SideNav } from '../side-nav'; import { SideNav } from '../side-nav';
import { Header } from '../header'; import { Header, HEADER_HEIGHT } from '../header';
import { Main } from '../main'; import { Main } from '../main';
import { Footer } from '../footer'; import { Footer } from '../footer';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
@ -225,7 +225,7 @@ const styleOverwrites = {
img: { img: {
my: space('extra-loose'), my: space('extra-loose'),
}, },
'& > pre > *:not(pre)': { '& > pre > *:not(pre):not(.line-numbers)': {
border: 'none', border: 'none',
px: space(['extra-loose', 'extra-loose', 'none', 'none']), px: space(['extra-loose', 'extra-loose', 'none', 'none']),
}, },
@ -273,7 +273,7 @@ export const Contents = ({ headings, children }) => (
<TableOfContents <TableOfContents
display={['none', 'none', 'block', 'block']} display={['none', 'none', 'block', 'block']}
position="sticky" position="sticky"
top="105px" top="195px"
pl={space('extra-loose')} pl={space('extra-loose')}
headings={headings} headings={headings}
/> />
@ -292,7 +292,7 @@ const DocsLayout: React.FC<{ isHome?: boolean }> = ({ children, isHome }) => {
}); });
return ( return (
<Flex minHeight="100vh" flexDirection="column"> <Flex minHeight="100vh" flexDirection="column">
<Header /> <Header hideSubBar={isHome || isErrorPage} />
<Flex width="100%" flexGrow={1}> <Flex width="100%" flexGrow={1}>
{!isHome && <SideNav display={['none', 'none', 'block']} />} {!isHome && <SideNav display={['none', 'none', 'block']} />}
<Flex <Flex
@ -303,7 +303,7 @@ const DocsLayout: React.FC<{ isHome?: boolean }> = ({ children, isHome }) => {
`calc(100% - ${isHome ? 0 : SIDEBAR_WIDTH}px)`, `calc(100% - ${isHome ? 0 : SIDEBAR_WIDTH}px)`,
`calc(100% - ${isHome ? 0 : SIDEBAR_WIDTH}px)`, `calc(100% - ${isHome ? 0 : SIDEBAR_WIDTH}px)`,
]} ]}
mt={'50px'} mt={`${HEADER_HEIGHT}px`}
flexDirection="column" flexDirection="column"
> >
<Main mx="unset" width={'100%'}> <Main mx="unset" width={'100%'}>

2
src/components/mdx/mdx-components.tsx

@ -14,7 +14,7 @@ import { Text } from '@components/typography';
import { border } from '@common/utils'; import { border } from '@common/utils';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
const Code = dynamic(() => import('../code-block')); const Code = dynamic(() => import('../code-block/index'));
const BaseHeading: React.FC<BoxProps> = React.memo(props => ( const BaseHeading: React.FC<BoxProps> = React.memo(props => (
<Heading width="100%" mt={space('base-loose')} {...props} /> <Heading width="100%" mt={space('base-loose')} {...props} />

7
src/components/side-nav.tsx

@ -9,13 +9,14 @@ import { useMobileMenuState } from '@common/hooks/use-mobile-menu';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
const SearchBox = dynamic(() => import('./search')); const SearchBox = dynamic(() => import('./search'));
import { SIDEBAR_WIDTH } from '@common/constants'; import { SIDEBAR_WIDTH } from '@common/constants';
import { HEADER_HEIGHT } from '@components/header';
const Wrapper = ({ width = `${SIDEBAR_WIDTH}px`, children, ...rest }: any) => ( const Wrapper = ({ width = `${SIDEBAR_WIDTH}px`, children, ...rest }: any) => (
<Box <Box
position="relative" position="relative"
width={width} width={width}
maxWidth={width} maxWidth={width}
height="calc(100vh - 50px)" height={`calc(100vh - ${HEADER_HEIGHT}px)`}
flexGrow={0} flexGrow={0}
flexShrink={0} flexShrink={0}
overflow="auto" overflow="auto"
@ -23,9 +24,9 @@ const Wrapper = ({ width = `${SIDEBAR_WIDTH}px`, children, ...rest }: any) => (
> >
<Box <Box
position="fixed" position="fixed"
top={50} top={HEADER_HEIGHT}
width={width} width={width}
height="calc(100vh - 50px)" height={`calc(100vh - ${HEADER_HEIGHT}px)`}
overflow="auto" overflow="auto"
borderRight={['none', border(), border()]} borderRight={['none', border(), border()]}
pb={space('base-loose')} pb={space('base-loose')}

2
src/pages/browser/todo-list.md

@ -154,7 +154,7 @@ Further down in the component we see in
that it checks upon mount to either process completion of authentication with `userSession.handlePendingSignIn()` that it checks upon mount to either process completion of authentication with `userSession.handlePendingSignIn()`
or otherwise load session data into app state as above with `userSession.isUserSignedIn()`: or otherwise load session data into app state as above with `userSession.isUserSignedIn()`:
```js ```jsx
// src/components/App.jsx // src/components/App.jsx
componentDidMount() { componentDidMount() {

2
yarn.lock

@ -7892,7 +7892,7 @@ preval.macro@^5.0.0:
dependencies: dependencies:
babel-plugin-preval "^5.0.0" babel-plugin-preval "^5.0.0"
prism-react-renderer@^1.0.1, prism-react-renderer@^1.0.2: prism-react-renderer@^1.0.1, prism-react-renderer@^1.0.2, prism-react-renderer@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.1.1.tgz#1c1be61b1eb9446a146ca7a50b7bcf36f2a70a44" resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.1.1.tgz#1c1be61b1eb9446a146ca7a50b7bcf36f2a70a44"
integrity sha512-MgMhSdHuHymNRqD6KM3eGS0PNqgK9q4QF5P0yoQQvpB6jNjeSAi3jcSAz0Sua/t9fa4xDOMar9HJbLa08gl9ug== integrity sha512-MgMhSdHuHymNRqD6KM3eGS0PNqgK9q4QF5P0yoQQvpB6jNjeSAi3jcSAz0Sua/t9fa4xDOMar9HJbLa08gl9ug==

Loading…
Cancel
Save