Browse Source

fix: update content, improve various components

fix/enable-imgix
Thomas Osmonson 4 years ago
parent
commit
6fab7ac380
  1. 6
      lib/md-loader.js
  2. 1
      next.config.js
  3. 1
      package.json
  4. 2
      src/common/constants.ts
  5. 4
      src/components/cli-reference.tsx
  6. 16
      src/components/code-block/index.tsx
  7. 4
      src/components/color-mode-button.tsx
  8. 61
      src/components/color-modes/styles.tsx
  9. 11
      src/components/feedback.tsx
  10. 12
      src/components/header.tsx
  11. 9
      src/components/highlighter/index.tsx
  12. 11
      src/components/home/card.tsx
  13. 12
      src/components/home/common.tsx
  14. 2
      src/components/home/sections/hero.tsx
  15. 5
      src/components/home/text.tsx
  16. 52
      src/components/layouts/base-layout.tsx
  17. 21
      src/components/layouts/default-layout.tsx
  18. 7
      src/components/layouts/externalurl.tsx
  19. 22
      src/components/layouts/index.tsx
  20. 18
      src/components/layouts/markdown-wrapper.tsx
  21. 6
      src/components/layouts/none.tsx
  22. 173
      src/components/mdx/components.tsx
  23. 41
      src/components/mdx/image.tsx
  24. 34
      src/components/mdx/md-contents.tsx
  25. 175
      src/components/mdx/mdx-components.tsx
  26. 104
      src/components/mdx/overrides.tsx
  27. 78
      src/components/pagination.tsx
  28. 8
      src/components/side-nav.tsx
  29. 97
      src/pages/_app.tsx
  30. 18
      src/pages/_document.tsx
  31. 4
      src/pages/browser/todo-list.md
  32. 4
      src/pages/contributing.md
  33. 5
      src/pages/core/atlas/howitworks.md
  34. 6
      src/pages/core/atlas/howtouse.md
  35. 14
      src/pages/core/atlas/overview.md
  36. 3
      src/pages/core/naming/architecture.md
  37. 3
      src/pages/core/naming/comparison.md
  38. 33
      src/pages/core/naming/creationhowto.md
  39. 5
      src/pages/core/naming/did.md
  40. 5
      src/pages/core/naming/forks.md
  41. 1
      src/pages/core/naming/introduction.md
  42. 16
      src/pages/core/naming/manage.md
  43. 3
      src/pages/core/naming/namespaces.md
  44. 16
      src/pages/core/naming/pickname.md
  45. 17
      src/pages/core/naming/register.md
  46. 3
      src/pages/core/naming/resolving.md
  47. 2
      src/pages/index.tsx
  48. 2
      yarn.lock

6
lib/md-loader.js

@ -33,10 +33,10 @@ module.exports = async function (src) {
const { content, data } = fm(src);
const headings = getHeadings(content);
const code =
`import { Layout as DefaultLayout } from '@components/layouts/default-layout';
export const meta = ${JSON.stringify({ ...data, headings })};
`import { MDWrapper } from '@components/layouts/markdown-wrapper';
export const frontmatter = ${JSON.stringify({ ...data, headings })};
const Layout = ({ children, ...props }) => (
<DefaultLayout meta={meta} {...props}>{children}</DefaultLayout>
<MDWrapper frontmatter={frontmatter} {...props}>{children}</MDWrapper>
)
export default Layout;

1
next.config.js

@ -19,6 +19,7 @@ const remarkPlugins = [
require('remark-unwrap-images'),
require('remark-normalize-headings'),
require('remark-slug'),
require('remark-footnotes'),
];
module.exports = withBundleAnalyzer({

1
package.json

@ -60,6 +60,7 @@
"remark": "^12.0.1",
"remark-emoji": "2.1.0",
"remark-external-links": "^6.1.0",
"remark-footnotes": "^1.0.0",
"remark-frontmatter": "^2.0.0",
"remark-images": "2.0.0",
"remark-normalize-headings": "^2.0.0",

2
src/common/constants.ts

@ -3,3 +3,5 @@ export const TOC_WIDTH = 280;
export const CONTENT_MAX_WIDTH = 1104;
export const SHIKI_THEME = 'Material-Theme-Default';
export const THEME_STORAGE_KEY = 'theme';

4
src/components/cli-reference.tsx

@ -1,7 +1,7 @@
import React from 'react';
import { cliReferenceData } from '@common/../_data/cliRef';
import { MDXComponents } from '@components/mdx/mdx-components';
import { Grid, Box } from '@blockstack/ui';
import { Grid, Box, color } from '@blockstack/ui';
import { border } from '@common/utils';
import { hydrate } from '@common/hydrate-mdx';
@ -37,6 +37,7 @@ const ReferenceEntry = ({ entry, usage }) => (
borderBottom={border()}
gridGap="base"
gridTemplateColumns="repeat(4, minmax(0,25%))"
color={color('text-caption')}
>
<Box fontSize="14px" fontWeight="bold">
Name
@ -61,6 +62,7 @@ const ReferenceEntry = ({ entry, usage }) => (
gridGap="base"
gridTemplateColumns="repeat(4, minmax(0,25%))"
key={index}
color={color('text-body')}
>
<Box>
<InlineCode>${name}</InlineCode>

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

@ -1,6 +1,6 @@
import React from 'react';
import { Highlighter, HighlighterProps } from '../highlighter';
import { Box, BoxProps } from '@blockstack/ui';
import { Box, BoxProps, color } from '@blockstack/ui';
import { css } from '@styled-system/css';
// Languages used in docs
@ -55,18 +55,26 @@ const CodeBlock = React.memo(
) => {
const language = className && className.replace(/language-/, '');
const displayNumbers = showLineNumbers || (language && language !== 'bash');
return (
<Box
className={language && language !== 'bash' ? 'line-numbers' : ''}
className={displayNumbers ? 'line-numbers' : ''}
bg="ink"
border="1px solid"
borderColor={color('border')}
borderRightWidth={['0px', '0px', '1px']}
borderLeftWidth={['0px', '0px', '1px']}
borderRadius={[0, 0, '12px']}
overflowX="auto"
overflow="hidden"
>
<Box
ref={ref}
css={css({
...style,
// @ts-ignore
overflowX: 'auto',
// @ts-ignore
color: 'white',
// @ts-ignore
whiteSpace: 'pre',
@ -76,7 +84,7 @@ const CodeBlock = React.memo(
<Highlighter
language={language as any}
code={children.toString().trim()}
showLineNumbers={showLineNumbers || (language && language !== 'bash')}
showLineNumbers={displayNumbers}
highlightedLines={getHighlightLineNumbers(highlight)}
hideLineHover
/>

4
src/components/color-mode-button.tsx

@ -1,12 +1,12 @@
import React, { forwardRef, Ref } from 'react';
import { LinkProps } from '@components/typography';
import { useColorMode } from '@blockstack/ui';
import { DarkModeIcon } from '@components/icons/dark-mode';
import { LightModeIcon } from '@components/icons/light-mode';
import { IconButton } from '@components/icon-button';
import { useColorMode } from '@pages/_app';
export const ColorModeButton = forwardRef((props: LinkProps, ref: Ref<HTMLDivElement>) => {
const { colorMode, toggleColorMode } = useColorMode();
const [colorMode, toggleColorMode] = useColorMode();
return (
<IconButton onClick={toggleColorMode} title="Toggle color mode" {...props} ref={ref}>
{colorMode === 'dark' ? <DarkModeIcon /> : <LightModeIcon />}

61
src/components/color-modes/styles.tsx

@ -0,0 +1,61 @@
import { createGlobalStyle } from 'styled-components';
import { generateCssVariables } from '@blockstack/ui';
export const ColorModes = createGlobalStyle`
:root{
${generateCssVariables('light')};
}
@media (prefers-color-scheme: dark) {
:root {
${generateCssVariables('dark')};
}
}
@media (prefers-color-scheme: light) {
:root {
${generateCssVariables('light')};
}
}
html, body, #__next {
background: var(--colors-bg);
border-color: var(--colors-border);
&.light {
${generateCssVariables('light')};
}
&.dark {
${generateCssVariables('dark')};
}
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
textarea:-webkit-autofill:hover,
textarea:-webkit-autofill:focus,
select:-webkit-autofill,
select:-webkit-autofill:hover,
select:-webkit-autofill:focus {
-webkit-text-fill-color: var(--colors-text-body);
font-size: 16px !important;
transition: background-color 5000s ease-in-out 0s;
}
input:-ms-input-placeholder,
textarea:-ms-input-placeholder {
color: var(--colors-input-placeholder) !important;
}
input::-ms-input-placeholder,
textarea::-ms-input-placeholder {
color: var(--colors-input-placeholder) !important;
}
input::placeholder,
textarea::placeholder {
color: var(--colors-input-placeholder) !important;
}
`;

11
src/components/feedback.tsx

@ -21,8 +21,14 @@ import { useRouter } from 'next/router';
const Icon: React.FC<BoxProps & { icon: React.FC<any> }> = ({ icon: IconComponent, ...props }) => {
const [isHovered, bind] = useHover();
return (
<Box _hover={{ color: color('accent'), cursor: 'pointer' }} size="42px" {...props} {...bind}>
<IconComponent bg={isHovered ? themeColor('blue.200') : themeColor('ink.200')} />
<Box
color={color('text-caption')}
_hover={{ color: color('bg'), cursor: 'pointer' }}
size="42px"
{...props}
{...bind}
>
<IconComponent bg={isHovered ? color('accent') : color('bg-light')} />
</Box>
);
};
@ -60,6 +66,7 @@ const FeedbackCard = ({ show, onClose }) => {
Leave feedback
</Button>
<Box
color={color('text-body')}
_hover={{ color: color('accent'), textDecoration: 'underline', cursor: 'pointer' }}
onClick={onClose}
mt={space('tight')}

12
src/components/header.tsx

@ -6,7 +6,6 @@ import {
Stack,
color,
space,
themeColor,
transition,
ChevronIcon,
} from '@blockstack/ui';
@ -24,6 +23,7 @@ import { css } from '@styled-system/css';
import NextLink from 'next/link';
import MagnifyIcon from 'mdi-react/MagnifyIcon';
import { useRouter } from 'next/router';
import { ColorModeButton } from '@components/color-mode-button';
const MenuButton = ({ ...rest }: any) => {
const { isOpen, handleOpen, handleClose } = useMobileMenuState();
@ -142,7 +142,7 @@ const SubBar: React.FC<any> = props => (
height="60px"
width="100%"
px={['extra-loose', 'extra-loose', 'base', 'base']}
bg="rgba(255,255,255, 0.8)"
bg={color('bg')}
borderBottom={border()}
style={{
backdropFilter: 'blur(5px)',
@ -152,14 +152,15 @@ const SubBar: React.FC<any> = props => (
<Flex
align="center"
justifyContent="flex-end"
bg={themeColor('ink.150')}
bg={color('bg-alt')}
height="32px"
width="32px"
borderRadius="32px"
transition={transition}
px={space('tight')}
color={color('invert')}
_hover={{
bg: themeColor('ink.200'),
bg: color('bg-light'),
width: ['32px', '32px', '225px', '225px'],
cursor: 'pointer',
justifyContent: 'flex-end',
@ -180,7 +181,7 @@ const Header = ({ hideSubBar, ...rest }: any) => {
justifyContent="space-between"
align="center"
px={['extra-loose', 'extra-loose', 'base', 'base']}
bg="rgba(255,255,255, 0.8)"
bg={color('bg')}
borderBottom={border()}
style={{
backdropFilter: 'blur(5px)',
@ -234,6 +235,7 @@ const Header = ({ hideSubBar, ...rest }: any) => {
))}
</Stack>
</Box>
<ColorModeButton />
<GithubButton />
<MenuButton />
</Flex>

9
src/components/highlighter/index.tsx

@ -149,10 +149,11 @@ const Lines = ({
hideLineHover?: boolean;
highlightedLines?: number[];
} & RenderProps) => {
const displayNumbers = lines?.length > 2 && showLineNumbers;
return (
<Box display="block" className={className}>
<Box display="block" style={{ fontFamily: 'Fira Code' }}>
<Spacer showLineNumbers={showLineNumbers} />
<Box display="block">
<Spacer showLineNumbers={displayNumbers} />
{lines.map((tokens, i) => (
<Box
css={css({
@ -181,7 +182,7 @@ const Lines = ({
tokens={tokens}
getTokenProps={getTokenProps}
length={lines.length + 1}
showLineNumbers={showLineNumbers}
showLineNumbers={displayNumbers}
highlighted={
highlightedLines?.length &&
!!highlightedLines.find(lineNumber => lineNumber === i + 1)
@ -191,7 +192,7 @@ const Lines = ({
/>
</Box>
))}
<Spacer showLineNumbers={showLineNumbers} />
<Spacer showLineNumbers={displayNumbers} />
</Box>
</Box>
);

11
src/components/home/card.tsx

@ -1,7 +1,7 @@
import React from 'react';
import { Grid, Box, Flex, space, color, transition, FlexProps } from '@blockstack/ui';
import NextLink from 'next/link';
import { useActive, useHover } from 'use-events';
import { useTouchable } from 'touchable-hook';
interface CardProps extends FlexProps {
href?: string;
@ -15,16 +15,15 @@ const LinkComponent = ({ href }: { href: string }) =>
) : null;
export const Card: React.FC<CardProps> = ({ children, onClick, dark = false, href, ...rest }) => {
const [hover, hoverBind] = useHover();
const [active, activeBind] = useActive();
const { bind, hover, active } = useTouchable({
behavior: 'link',
});
return (
<Flex
width="100%"
cursor={(hover || active) && 'pointer'}
position="relative"
{...hoverBind}
{...activeBind}
{...bind}
{...rest}
>
<LinkComponent href={href} />

12
src/components/home/common.tsx

@ -1,5 +1,5 @@
import React from 'react';
import { Box, Grid, Flex, BoxProps, transition, space, themeColor } from '@blockstack/ui';
import { Box, Grid, Flex, BoxProps, transition, space, themeColor, color } from '@blockstack/ui';
import { GridProps } from '@blockstack/ui/dist/ui/src/grid/types';
import { CONTENT_MAX_WIDTH } from '@common/constants';
@ -11,17 +11,11 @@ export const CircleIcon: React.FC<
align="center"
justify="center"
borderRadius={size}
bg={
dark
? hover
? themeColor('blue.900')
: 'rgb(39, 41, 46)'
: themeColor(hover ? 'blue' : 'blue.100')
}
bg={color(hover ? 'accent' : 'bg-alt')}
transition={transition}
{...rest}
>
<Box size="34px" color={dark ? 'white' : hover ? 'white' : themeColor('blue')}>
<Box size="34px" color={color(hover ? 'bg' : 'invert')}>
<Icon transition={transition} />
</Box>
</Flex>

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

@ -39,7 +39,7 @@ export const Hero = ({ cards }: { cards?: any }) => {
<Box as="span">
<CircleIcon
as="span"
hover={hover}
hover={hover || active}
icon={Icon}
mx="auto"
mb={space('base-loose')}

5
src/components/home/text.tsx

@ -1,5 +1,5 @@
import React from 'react';
import { Box, BoxProps } from '@blockstack/ui';
import { Box, BoxProps, color } from '@blockstack/ui';
import { Text } from '@components/typography';
import { css } from '@styled-system/css';
@ -7,6 +7,7 @@ export const H1: React.FC<BoxProps> = ({ children, ...rest }) => (
<Box {...rest}>
<Text
css={css({
color: color('text-title'),
display: 'block',
fontWeight: 'bolder',
fontSize: ['44px', '44px', '66px'],
@ -40,6 +41,7 @@ export const H2: React.FC<BoxProps> = ({ children, ...rest }) => (
<Box {...rest}>
<Text
css={css({
color: color('text-title'),
display: 'block',
fontWeight: 'bold',
fontSize: '38.5px',
@ -68,6 +70,7 @@ export const BodyLarge: React.FC<BoxProps> = ({ children, ...rest }) => (
<Text
as="h2"
css={css({
color: color('text-body'),
display: 'block',
fontSize: '22px',
lineHeight: '32px',

52
src/components/layouts/base-layout.tsx

@ -0,0 +1,52 @@
import React from 'react';
import { Flex } from '@blockstack/ui';
import { SideNav } from '../side-nav';
import { Header, HEADER_HEIGHT } from '../header';
import { Main } from '../main';
import { Footer } from '../footer';
import NotFoundPage from '@pages/404';
import { SIDEBAR_WIDTH } from '@common/constants';
const BaseLayout: React.FC<{ isHome?: boolean }> = ({ children, isHome }) => {
let isErrorPage = false;
// get if NotFoundPage
React.Children.forEach(children, (child: any) => {
if (child?.type === NotFoundPage) {
isErrorPage = true;
}
});
return (
<Flex minHeight="100vh" flexDirection="column">
<Header hideSubBar={isHome || isErrorPage} />
<Flex width="100%" flexGrow={1}>
{!isHome && <SideNav display={['none', 'none', 'block']} />}
<Flex
flexGrow={1}
maxWidth={[
'100%',
'100%',
`calc(100% - ${isHome ? 0 : SIDEBAR_WIDTH}px)`,
`calc(100% - ${isHome ? 0 : SIDEBAR_WIDTH}px)`,
]}
mt={`${HEADER_HEIGHT}px`}
flexDirection="column"
>
<Main mx="unset" width={'100%'}>
<Flex
flexDirection={['column', 'column', 'row', 'row']}
maxWidth="108ch"
mx="auto"
flexGrow={1}
>
{children}
</Flex>
</Main>
{isErrorPage || isHome ? null : <Footer justifySelf="flex-end" />}
</Flex>
</Flex>
</Flex>
);
};
export { BaseLayout };

21
src/components/layouts/default-layout.tsx

@ -1,21 +0,0 @@
import React from 'react';
import { Contents } from '@components/layouts/docs-layout';
import Head from 'next/head';
export const Layout = ({ meta, dynamicHeadings = [], ...props }) => {
const {
title,
description = 'The Blockstack design system, built with React and styled-system.',
headings,
} = meta;
return (
<>
<Head>
<title>{title || (headings?.length && headings[0].content)} | Blockstack Docs</title>
<meta name="description" content={description} />
</Head>
<Contents headings={[...headings, ...dynamicHeadings]}>{props.children}</Contents>
</>
);
};
export default Layout;

7
src/components/layouts/externalurl.tsx

@ -1,7 +0,0 @@
import React from 'react';
export default function Layout(frontMatter) {
return ({ children }) => {
return <>{children}</>;
};
}

22
src/components/layouts/index.tsx

@ -1,22 +0,0 @@
import React from 'react';
import { Contents } from '@components/layouts/docs-layout';
import Head from 'next/head';
const Layout = frontMatter => props => {
const {
title,
description = 'The Blockstack design system, built with React and styled-system.',
headings,
} = frontMatter;
return (
<>
<Head>
<title>{title || headings[0].content} | Blockstack Docs</title>
<meta name="description" content={description} />
</Head>
<Contents headings={headings}>{props.children}</Contents>
</>
);
};
export default Layout;

18
src/components/layouts/markdown-wrapper.tsx

@ -0,0 +1,18 @@
import React from 'react';
import { MDContents } from '@components/mdx/md-contents';
import Head from 'next/head';
const getTitle = ({ title, headings }) => title || (headings?.length && headings[0].content);
export const MDWrapper = ({ frontmatter, dynamicHeadings = [], ...props }) => {
const { headings, description } = frontmatter;
return (
<>
<Head>
<title>{getTitle(frontmatter)} | Blockstack</title>
<meta name="description" content={description} />
</Head>
<MDContents headings={[...headings, ...dynamicHeadings]}>{props.children}</MDContents>
</>
);
};
export default MDWrapper;

6
src/components/layouts/none.tsx

@ -1,6 +0,0 @@
import React from 'react';
export default function Layout(frontMatter) {
return ({ children }) => {
return <>{children}</>;
};
}

173
src/components/mdx/components.tsx

@ -1,4 +1,13 @@
import { Box, Flex, FlexProps, BoxProps, color, useClipboard, space } from '@blockstack/ui';
import {
Box,
Flex,
FlexProps,
BoxProps,
color,
themeColor,
useClipboard,
space,
} from '@blockstack/ui';
import NextLink from 'next/link';
import React, { forwardRef, Ref } from 'react';
import LinkIcon from 'mdi-react/LinkVariantIcon';
@ -11,6 +20,11 @@ import { border } from '@common/utils';
import { css } from '@styled-system/css';
import { getHeadingStyles, baseTypeStyles } from '@components/mdx/typography';
import { useRouter } from 'next/router';
import { HEADER_HEIGHT } from '@components/header';
import { CheckCircleIcon } from '@components/icons/check-circle';
import { AlertTriangleIcon } from '@components/icons/alert-triangle';
import { AlertCircleIcon } from '@components/icons/alert-circle';
import { InfoCircleIcon } from '@components/icons/info-circle';
const preProps = {
display: 'inline-block',
@ -52,18 +66,15 @@ export const SmartLink = ({ href, ...rest }: { href: string }) => {
};
export const Table = ({ children, ...rest }: any) => (
<Box maxWidth="100%" overflow="auto" {...rest}>
<Box
color={color('text-body')}
textAlign="left"
my={space('extra-loose')}
width="100%"
as="table"
maxWidth="100%"
>
<Box my={space('extra-loose')} maxWidth="100%" {...rest}>
<Box borderRadius={[0, 0, '12px']} border={border()} overflow="hidden">
<Box overflowX="auto">
<Box color={color('text-body')} textAlign="left" width="100%" as="table" maxWidth="100%">
{children}
</Box>
</Box>
</Box>
</Box>
);
export const THead = (props: any) => {
@ -71,9 +82,12 @@ export const THead = (props: any) => {
<Box
as="th"
color="var(--colors-text-caption)"
bg="blue.50"
p={2}
textStyle={'body.small.medium'}
borderRight={border()}
bg={color('bg-alt')}
fontSize="12px"
px={space('base-tight')}
pt={space('tight')}
pb={space('extra-tight')}
{...props}
/>
);
@ -82,10 +96,13 @@ export const THead = (props: any) => {
export const TData = (props: any) => (
<Box
as="td"
p={2}
borderTopWidth="1px"
borderColor="var(--colors-border)"
textStyle="body.small"
fontSize="14px"
p={space('tight')}
px={space('base-tight')}
pt={space('base-tight')}
borderRight={border()}
borderTop={border()}
color={color('text-body')}
whiteSpace="normal"
{...props}
/>
@ -192,7 +209,7 @@ const AnchorOffset = ({ id }: BoxProps) =>
display="block"
position="absolute"
style={{ userSelect: 'none', pointerEvents: 'none' }}
top="-120px"
top={`-${HEADER_HEIGHT + 42}px`}
id={id}
/>
) : null;
@ -244,3 +261,123 @@ export const Heading = ({ as, children, id, ...rest }: FlexProps) => {
</Title>
);
};
const BaseHeading: React.FC<BoxProps> = React.memo(props => (
<Heading width="100%" mt={space('base-loose')} {...props} />
));
export const H1: React.FC<BoxProps> = props => <BaseHeading as="h1" {...props} />;
export const H2: React.FC<BoxProps> = props => <BaseHeading as="h2" {...props} />;
export const H3: React.FC<BoxProps> = props => <BaseHeading as="h3" {...props} />;
export const H4: React.FC<BoxProps> = props => <BaseHeading as="h4" {...props} />;
export const H5: React.FC<BoxProps> = props => <BaseHeading as="h5" {...props} />;
export const H6: React.FC<BoxProps> = props => <BaseHeading as="h6" {...props} />;
export const Br: React.FC<BoxProps> = props => <Box height="24px" {...props} />;
export const Hr: React.FC<BoxProps> = props => (
<Box
as="hr"
borderTopWidth="1px"
borderColor={color('border')}
my={space('extra-loose')}
mx={space('extra-loose')}
{...props}
/>
);
export const P: React.FC<BoxProps> = props => <Text as="p" {...props} />;
export const Ol: React.FC<BoxProps> = props => (
<Box pl={space('base')} mt={space('base')} mb={space('base-tight')} as="ol" {...props} />
);
export const Ul: React.FC<BoxProps> = props => (
<Box pl={space('base-loose')} mt={space('base')} mb={space('base-tight')} as="ul" {...props} />
);
export const Li: React.FC<BoxProps> = props => (
<Box as="li" color={color('text-body')} pb={space('tight')} {...props} />
);
const getAlertStyles = (className: string) => {
if (className?.includes('alert-success')) {
return {
borderTopColor: themeColor('green'),
borderTopWidth: '2px',
borderTopRightRadius: '0px',
borderTopLeftRadius: '0px',
accent: themeColor('green'),
icon: CheckCircleIcon,
};
}
if (className?.includes('alert-info')) {
return {
border: border(),
borderRadius: 'md',
boxShadow: 'mid',
accent: color('accent'),
icon: InfoCircleIcon,
};
}
if (className?.includes('alert-warning')) {
return {
borderTopColor: '#F7AA00',
borderTopWidth: '2px',
borderTopRightRadius: '0px',
borderTopLeftRadius: '0px',
accent: '#F7AA00',
icon: AlertTriangleIcon,
};
}
if (className?.includes('alert-danger')) {
return {
borderTopColor: themeColor('red'),
borderTopWidth: '2px',
borderTopRightRadius: '0px',
borderTopLeftRadius: '0px',
accent: themeColor('red'),
icon: AlertCircleIcon,
};
}
return {};
};
export const BlockQuote: React.FC<BoxProps> = ({ children, className, ...rest }) => {
const isAlert = className?.includes('alert');
const { accent, icon: Icon, ...styles } = getAlertStyles(className);
return (
<Box as="blockquote" display="block" my={space('extra-loose')} className={className} {...rest}>
<Box
border="1px solid"
css={css({
position: 'relative',
display: 'grid',
placeItems: 'center',
gridTemplateColumns: Icon ? '22px 1fr' : '1fr',
alignItems: 'flex-start',
border: isAlert ? border() : border(),
bg: isAlert ? color('bg') : color('bg-alt'),
borderRadius: 'md',
boxShadow: isAlert ? 'mid' : 'unset',
py: space('base'),
px: space('base'),
'& p': {
flexGrow: 1,
pt: '4px',
},
...styles,
})}
>
{Icon && (
<Flex align="center" height="28x" flexShrink={0} color={accent} width="22px">
<Box position="absolute" top="16px" size="22px">
<Icon />
</Box>
</Flex>
)}
<Box width="100%" pl={Icon && space('tight')} flexGrow={1}>
{children}
</Box>
</Box>
</Box>
);
};
export const Sup: React.FC<any> = props => <Text as="sup" mr={space('extra-tight')} {...props} />;

41
src/components/mdx/image.tsx

@ -0,0 +1,41 @@
import React from 'react';
import { Box, BoxProps } from '@blockstack/ui';
import { useRouter } from 'next/router';
const imgix = 'https://docs-stacks.imgix.net';
const params = '?auto=compress,format';
const getUrl = pathname => {
let url = '';
const levels = pathname.split('/');
levels.forEach((level, index) => {
if (index !== levels.length - 1) {
url += level + '/';
}
});
return url;
};
const useImgix = (src: string) => {
if (process.env.NODE_ENV !== 'production') return src;
let _src = src;
const router = useRouter();
if (!src.startsWith('http')) {
const path = src.startsWith('/') ? '' : getUrl(router.pathname);
_src = `${imgix + path + src + params}`;
}
return _src;
};
export const Img: React.FC<BoxProps & { loading?: string; src?: string; alt?: string }> = ({
src: _src,
...rest
}) => {
const src = useImgix(_src);
const props = {
src,
...rest,
};
return <Box loading="lazy" maxWidth="100%" display="block" as="img" {...props} />;
};

34
src/components/mdx/md-contents.tsx

@ -0,0 +1,34 @@
import React from 'react';
import { space } from '@blockstack/ui';
import { ContentWrapper } from '../content-wrapper';
import { TableOfContents } from '@components/toc';
import { css } from '@styled-system/css';
import { TOC_WIDTH } from '@common/constants';
import { styleOverwrites } from '@components/mdx/overrides';
export const MDContents: React.FC<any> = React.memo(({ headings, children }) => (
<>
<ContentWrapper
width={
headings?.length > 1 ? ['100%', '100%', '100%', `calc(100% - ${TOC_WIDTH}px)`] : '100%'
}
mx="unset"
pt="unset"
px="unset"
css={css(styleOverwrites)}
>
{children}
</ContentWrapper>
{headings?.length > 1 ? (
<TableOfContents
display={['none', 'none', 'none', 'block']}
position="sticky"
top="195px"
pl={space('extra-loose')}
headings={headings}
/>
) : null}
</>
));

175
src/components/mdx/mdx-components.tsx

@ -1,172 +1,30 @@
import React from 'react';
import { Box, space, BoxProps, color, themeColor } from '@blockstack/ui';
import css from '@styled-system/css';
import {
Heading,
Pre,
THead,
SmartLink,
TData,
Table,
InlineCode,
H1,
H2,
H3,
H4,
H5,
H6,
BlockQuote,
Br,
Ul,
P,
Ol,
Hr,
Li,
Sup,
} from '@components/mdx/components';
import { Text } from '@components/typography';
import { border } from '@common/utils';
import { useRouter } from 'next/router';
import { Img } from '@components/mdx/image';
import dynamic from 'next/dynamic';
import { CheckCircleIcon } from '@components/icons/check-circle';
import { AlertTriangleIcon } from '@components/icons/alert-triangle';
import { AlertCircleIcon } from '@components/icons/alert-circle';
import { InfoCircleIcon } from '@components/icons/info-circle';
const Code = dynamic(() => import('../code-block/index'));
const BaseHeading: React.FC<BoxProps> = React.memo(props => (
<Heading width="100%" mt={space('base-loose')} {...props} />
));
export const H1: React.FC<BoxProps> = props => <BaseHeading as="h1" {...props} />;
export const H2: React.FC<BoxProps> = props => <BaseHeading as="h2" {...props} />;
export const H3: React.FC<BoxProps> = props => <BaseHeading as="h3" {...props} />;
export const H4: React.FC<BoxProps> = props => <BaseHeading as="h4" {...props} />;
export const H5: React.FC<BoxProps> = props => <BaseHeading as="h5" {...props} />;
export const H6: React.FC<BoxProps> = props => <BaseHeading as="h6" {...props} />;
export const Br: React.FC<BoxProps> = props => <Box height="24px" {...props} />;
export const Hr: React.FC<BoxProps> = props => (
<Box
as="hr"
borderTopWidth="1px"
borderColor={color('border')}
my={space('extra-loose')}
mx={space('extra-loose')}
{...props}
/>
);
export const P: React.FC<BoxProps> = props => <Text as="p" {...props} />;
export const Ol: React.FC<BoxProps> = props => (
<Box pl={space('base')} mt={space('base')} mb={space('base-tight')} as="ol" {...props} />
);
export const Ul: React.FC<BoxProps> = props => (
<Box pl={space('base-loose')} mt={space('base')} mb={space('base-tight')} as="ul" {...props} />
);
export const Li: React.FC<BoxProps> = props => <Box as="li" pb={space('tight')} {...props} />;
const getAlertStyles = (className: string) => {
if (className?.includes('alert-success')) {
return {
borderTopColor: themeColor('green'),
borderTopWidth: '2px',
borderTopRightRadius: '0px',
borderTopLeftRadius: '0px',
accent: themeColor('green'),
icon: CheckCircleIcon,
};
}
if (className?.includes('alert-info')) {
return {
border: border(),
borderRadius: 'md',
boxShadow: 'mid',
bg: color('bg'),
accent: color('accent'),
icon: InfoCircleIcon,
};
}
if (className?.includes('alert-warning')) {
return {
borderTopColor: '#F7AA00',
borderTopWidth: '2px',
borderTopRightRadius: '0px',
borderTopLeftRadius: '0px',
accent: '#F7AA00',
icon: AlertTriangleIcon,
};
}
if (className?.includes('alert-danger')) {
return {
borderTopColor: themeColor('red'),
borderTopWidth: '2px',
borderTopRightRadius: '0px',
borderTopLeftRadius: '0px',
accent: themeColor('red'),
icon: AlertCircleIcon,
};
}
return {};
};
export const BlockQuote: React.FC<BoxProps> = ({ children, className, ...rest }) => {
const isAlert = className?.includes('alert');
const { accent, icon: Icon, ...styles } = getAlertStyles(className);
return (
<Box as="blockquote" display="block" my={space('extra-loose')} className={className} {...rest}>
<Box
border="1px solid"
css={css({
display: 'flex',
alignItems: 'flex-start',
border: isAlert ? border() : border(),
bg: isAlert ? color('bg') : themeColor('ink.150'),
borderRadius: 'md',
boxShadow: isAlert ? 'mid' : 'unset',
py: space('base'),
px: space('base'),
'& p': {
flexGrow: 1,
pt: '4px',
},
...styles,
})}
>
{Icon && (
<Box flexShrink={0} color={accent} mr={space('base-tight')} size="24px">
<Icon />
</Box>
)}
<Box>{children}</Box>
</Box>
</Box>
);
};
const imgix = 'https://docs-stacks.imgix.net';
const params = '?auto=compress,format';
const getUrl = pathname => {
let url = '';
const levels = pathname.split('/');
levels.forEach((level, index) => {
if (index !== levels.length - 1) {
url += level + '/';
}
});
return url;
};
const useImgix = (src: string) => {
let _src = src;
const router = useRouter();
if (!src.startsWith('http')) {
const path = src.startsWith('/') ? '' : getUrl(router.pathname);
_src = `${imgix + path + src + params}`;
}
return _src;
};
export const Img: React.FC<BoxProps & { loading?: string; src?: string; alt?: string }> = ({
src: _src,
...rest
}) => {
const src = useImgix(_src);
const props = {
src,
...rest,
};
return <Box loading="lazy" maxWidth="100%" display="block" as="img" {...props} />;
};
const Code = dynamic(() => import('../code-block'));
export const MDXComponents = {
h1: H1,
@ -190,4 +48,5 @@ export const MDXComponents = {
li: Li,
img: Img,
blockquote: BlockQuote,
sup: Sup,
};

104
src/components/layouts/docs-layout.tsx → src/components/mdx/overrides.tsx

@ -1,17 +1,8 @@
import React from 'react';
import { Flex, color, space, themeColor, ChevronIcon } from '@blockstack/ui';
import { SideNav } from '../side-nav';
import { Header, HEADER_HEIGHT } from '../header';
import { Main } from '../main';
import { Footer } from '../footer';
import { useRouter } from 'next/router';
import { ContentWrapper } from '../content-wrapper';
import NotFoundPage from '@pages/404';
import { color, space } from '@blockstack/ui';
import { createGlobalStyle } from 'styled-components';
import { TableOfContents } from '@components/toc';
import { getHeadingStyles } from '@components/mdx/typography';
import { css } from '@styled-system/css';
import { SIDEBAR_WIDTH, TOC_WIDTH } from '@common/constants';
export const MdxOverrides = createGlobalStyle`
.DocSearch-Container{
z-index: 99999;
@ -60,7 +51,7 @@ p, ul, ol, table {
}
`;
const styleOverwrites = {
export const styleOverwrites = {
'& > *:not(pre):not(ul):not(ol):not(img):not([data-reach-accordion])': {
px: space('extra-loose'),
},
@ -91,7 +82,7 @@ const styleOverwrites = {
mb: 0,
pb: 0,
},
'*:last-child': {
'*:last-child:not(pre):not(blockquote)': {
mb: 0,
},
pre: {
@ -126,9 +117,7 @@ const styleOverwrites = {
'& > *:not(pre) a > code': {
color: color('accent'),
'&:hover': {
textDecoration: 'underline',
},
textDecoration: 'inherit',
},
pre: {
'& + h2, & + h3': {
@ -211,6 +200,10 @@ const styleOverwrites = {
// mt: space('extra-tight'),
},
},
'.prism-code': {
width: '100%',
minWidth: 'fit-content',
},
blockquote: {
'& + blockquote': {
mt: space('extra-tight'),
@ -221,12 +214,14 @@ const styleOverwrites = {
'& + pre': {
mt: '0',
},
'& + h3, & + h4': {
mt: space('extra-loose'),
},
},
img: {
my: space('extra-loose'),
},
'& > pre > *:not(pre):not(.line-numbers)': {
border: 'none',
px: space(['extra-loose', 'extra-loose', 'none', 'none']),
},
'& > pre > div[style]': {
@ -237,7 +232,6 @@ const styleOverwrites = {
},
'& > pre': {
px: space(['none', 'none', 'extra-loose', 'extra-loose']),
border: 'none',
boxShadow: 'none',
my: space('extra-loose'),
},
@ -251,76 +245,8 @@ const styleOverwrites = {
overflowY: 'hidden',
whiteSpace: 'pre',
},
'td:last-child, th:last-child': {
borderRight: 0,
},
},
};
export const Contents = ({ headings, children }) => (
<>
<ContentWrapper
width={
headings?.length && headings.length > 1
? ['100%', '100%', `calc(100% - ${TOC_WIDTH}px)`, `calc(100% - ${TOC_WIDTH}px)`]
: '100%'
}
mx="unset"
pt="unset"
pr={space(['none', 'none', 'base-tight', 'base-tight'])}
css={css(styleOverwrites)}
>
{children}
</ContentWrapper>
{headings?.length && headings.length > 1 ? (
<TableOfContents
display={['none', 'none', 'block', 'block']}
position="sticky"
top="195px"
pl={space('extra-loose')}
headings={headings}
/>
) : null}
</>
);
const DocsLayout: React.FC<{ isHome?: boolean }> = ({ children, isHome }) => {
let isErrorPage = false;
// get if NotFoundPage
React.Children.forEach(children, (child: any) => {
if (child?.type === NotFoundPage) {
isErrorPage = true;
}
});
return (
<Flex minHeight="100vh" flexDirection="column">
<Header hideSubBar={isHome || isErrorPage} />
<Flex width="100%" flexGrow={1}>
{!isHome && <SideNav display={['none', 'none', 'block']} />}
<Flex
flexGrow={1}
maxWidth={[
'100%',
'100%',
`calc(100% - ${isHome ? 0 : SIDEBAR_WIDTH}px)`,
`calc(100% - ${isHome ? 0 : SIDEBAR_WIDTH}px)`,
]}
mt={`${HEADER_HEIGHT}px`}
flexDirection="column"
>
<Main mx="unset" width={'100%'}>
<Flex
flexDirection={['column', 'column', 'row', 'row']}
maxWidth="108ch"
mx="auto"
flexGrow={1}
>
{children}
</Flex>
</Main>
{isErrorPage || isHome ? null : <Footer justifySelf="flex-end" />}
</Flex>
</Flex>
</Flex>
);
};
export { DocsLayout };

78
src/components/pagination.tsx

@ -6,6 +6,8 @@ import { MDXComponents } from '@components/mdx';
import { border } from '@common/utils';
import NextLink from 'next/link';
import { Link } from '@components/typography';
import { useTouchable } from 'touchable-hook';
const usePaginateRoutes = () => {
const router = useRouter();
@ -30,7 +32,6 @@ const usePaginateRoutes = () => {
const isFirstSection = sectionIndex === 0;
const isLastSection = sectionIndex === routes.length - 1;
const route = sectionRoutes.find(getRoute);
const routeIndex: number = sectionRoutes.findIndex(getRoute);
const isFirstRouteInSection = routeIndex === 0;
@ -56,12 +57,16 @@ const usePaginateRoutes = () => {
};
const Description: React.FC<BoxProps> = props => (
<Box maxWidth="32ch" mt={space('extra-tight')}>
<Box maxWidth="42ch" mt={space('extra-tight')}>
<MDXComponents.p {...props} />
</Box>
);
const Card = props => (
const Card: React.FC<any> = ({ children, ...rest }) => {
const { bind, active, hover } = useTouchable({
behavior: 'link',
});
return (
<Flex
flexDirection="column"
width="100%"
@ -70,24 +75,26 @@ const Card = props => (
borderRadius="12px"
py={space('base')}
px={space('base-loose')}
boxShadow="mid"
boxShadow={active ? 'low' : hover ? 'high' : 'mid'}
transition={transition}
_hover={{ cursor: 'pointer', boxShadow: 'high' }}
justifyContent="center"
{...props}
/>
);
export const Pagination = ({ hidePagination, ...rest }: any) => {
const { next, prev } = usePaginateRoutes();
return (
<Grid
gridColumnGap={space('base-loose')}
gridRowGap={space('extra-loose')}
gridTemplateColumns={['repeat(1, 1fr)', 'repeat(1, 1fr)', 'repeat(2, 1fr)', 'repeat(2, 1fr)']}
bg={active ? color('bg-light') : color('bg')}
transform={active ? 'translateY(3px)' : hover ? 'translateY(-5px)' : 'none'}
{...bind}
{...rest}
>
{prev ? (
{children({ hover, active })}
</Flex>
);
};
const PrevCard: React.FC<any> = React.memo(props => {
const { prev } = usePaginateRoutes();
return prev ? (
<Card>
{({ hover, active }) => (
<>
<NextLink href={`/${prev.path}`} passHref>
<Link position="absolute" size="100%" zIndex={2} as="a" />
</NextLink>
@ -100,12 +107,20 @@ export const Pagination = ({ hidePagination, ...rest }: any) => {
<MDXComponents.h3 my={0}>{prev.title || prev.headings[0]}</MDXComponents.h3>
</Box>
{prev.description && <Description>{prev.description}</Description>}
</>
)}
</Card>
) : (
<Box />
)}
{next ? (
);
});
const NextCard: React.FC<any> = React.memo(props => {
const { next } = usePaginateRoutes();
return next ? (
<Card textAlign="right" align="flex-end">
{({ hover, active }) => (
<>
<NextLink href={`/${next.path}`} passHref>
<Link position="absolute" size="100%" zIndex={2} as="a" />
</NextLink>
@ -113,13 +128,30 @@ export const Pagination = ({ hidePagination, ...rest }: any) => {
Next
</MDXComponents.h5>
<Box maxWidth="38ch">
<MDXComponents.h3 my={0}>{next.title || next.headings[0]}</MDXComponents.h3>
<MDXComponents.h3
transition={transition}
color={hover ? color('accent') : color('text-title')}
my={0}
>
{next.title || next.headings[0]}
</MDXComponents.h3>
</Box>
{next.description && <Description>{next.description}</Description>}
</>
)}
</Card>
) : (
<Box />
)}
</Grid>
);
};
});
export const Pagination: React.FC<any> = React.memo(({ hidePagination, ...rest }: any) => (
<Grid
gridColumnGap={space('base-loose')}
gridRowGap={space('extra-loose')}
gridTemplateColumns={['repeat(1, 1fr)', 'repeat(1, 1fr)', 'repeat(2, 1fr)', 'repeat(2, 1fr)']}
>
<PrevCard />
<NextCard />
</Grid>
));

8
src/components/side-nav.tsx

@ -94,6 +94,12 @@ const Section = ({ section, isLast, ...rest }: any) => {
const isActive = section.routes.find(route => pathname === `/${route.path}`);
const [visible, setVisible] = React.useState(isActive);
React.useEffect(() => {
if (isActive && !visible) {
setVisible(true);
}
}, [router, isActive]);
return (
<Box width="100%" pt={space('base')} {...rest}>
{section.title ? (
@ -107,7 +113,9 @@ const Section = ({ section, isLast, ...rest }: any) => {
}}
>
<SectionTitle>{section.title}</SectionTitle>
<Box color={color('text-caption')}>
<ChevronIcon size="24px" direction={visible ? 'up' : 'down'} />
</Box>
</Flex>
) : null}
{visible && <Links routes={section.routes} />}

97
src/pages/_app.tsx

@ -1,51 +1,102 @@
import React from 'react';
import { CSSReset, ThemeProvider, theme, ColorModeProvider } from '@blockstack/ui';
import { CSSReset, ThemeProvider } from '@blockstack/ui';
import { useMediaQuery } from '@common/hooks/use-media-query';
import { MDXProvider } from '@mdx-js/react';
import { MDXComponents } from '@components/mdx';
import { AppStateProvider } from '@components/app-state';
import { MdxOverrides } from '@components/layouts/docs-layout';
import { MdxOverrides } from '@components/mdx/overrides';
import { ProgressBar } from '@components/progress-bar';
import engine from 'store/src/store-engine';
import cookieStorage from 'store/storages/cookieStorage';
import GoogleFonts from 'next-google-fonts';
import Head from 'next/head';
import '@docsearch/react/dist/style.css';
import { DocsLayout } from '@components/layouts/docs-layout';
import { BaseLayout } from '@components/layouts/base-layout';
import { THEME_STORAGE_KEY } from '@common/constants';
import { ColorModes } from '@components/color-modes/styles';
const COLOR_MODE_COOKIE = 'color_mode';
const setDarkMode = setColorMode => {
localStorage.setItem(THEME_STORAGE_KEY, 'dark');
setColorMode('dark');
document.documentElement.classList.add('dark');
document.documentElement.classList.remove('light');
};
const setLightMode = setColorMode => {
localStorage.setItem(THEME_STORAGE_KEY, 'light');
setColorMode('light');
document.documentElement.classList.add('light');
document.documentElement.classList.remove('dark');
};
export const useColorMode = () => {
const [darkmode] = useMediaQuery('(prefers-color-scheme: dark)');
const [lightmode] = useMediaQuery('(prefers-color-scheme: light)');
const setMode = typeof localStorage !== 'undefined' && localStorage.getItem(THEME_STORAGE_KEY);
const cookieSetter = engine.createStore([cookieStorage]);
const [colorMode, setColorMode] = React.useState(undefined);
const handleColorModeChange = (mode: string) => cookieSetter.set(COLOR_MODE_COOKIE, mode);
React.useEffect(() => {
if (setMode) {
if (setMode === 'dark') {
setColorMode('dark');
}
if (setMode === 'light') {
setColorMode('light');
}
} else {
if (darkmode) {
setDarkMode(setColorMode);
}
if (lightmode) {
setLightMode(setColorMode);
}
}
}, [setMode, lightmode, darkmode]);
const AppWrapper = ({ children, colorMode = 'light', isHome }: any) => (
const toggleColorMode = () => {
if (typeof document !== 'undefined') {
if (setMode) {
if (setMode === 'light') {
setDarkMode(setColorMode);
} else {
setLightMode(setColorMode);
}
} else if (darkmode) {
setLightMode(setColorMode);
} else {
setDarkMode(setColorMode);
}
}
};
return [colorMode, toggleColorMode, setColorMode];
};
const AppWrapper = ({ children, isHome }: any) => {
return (
<>
<GoogleFonts href="https://fonts.googleapis.com/css2?family=Fira+Code&family=Inter:wght@400;500;600;700&display=swap" />
<ThemeProvider theme={theme}>
<MdxOverrides />
<ColorModeProvider onChange={handleColorModeChange} colorMode={colorMode}>
<ColorModes />
<ProgressBar />
<MDXProvider components={MDXComponents}>
<AppStateProvider>
<Head>
<link rel="preconnect" href="https://bh4d9od16a-dsn.algolia.net" crossOrigin="true" />
<link rel="preconnect" href="https://cdn.usefathom.com" crossOrigin="true" />
</Head>
<CSSReset />
<DocsLayout isHome={isHome}>{children}</DocsLayout>
<BaseLayout isHome={isHome}>{children}</BaseLayout>
</AppStateProvider>
</MDXProvider>
</ColorModeProvider>
</ThemeProvider>
</>
);
);
};
const MyApp = ({ Component, pageProps, colorMode, ...rest }: any) => {
const { isHome } = pageProps;
return (
<AppWrapper isHome={isHome}>
<>
<GoogleFonts href="https://fonts.googleapis.com/css2?family=Fira+Code&family=Inter:wght@400;500;600;700&display=swap" />
<ThemeProvider>
<CSSReset />
<AppWrapper isHome={isHome} {...rest}>
<Component {...pageProps} />
</AppWrapper>
</ThemeProvider>
</>
);
};

18
src/pages/_document.tsx

@ -1,5 +1,5 @@
import Document, { DocumentContext, Html, Head, Main, NextScript } from 'next/document';
import { THEME_STORAGE_KEY } from '@common/constants';
import { ServerStyleSheet } from 'styled-components';
export default class MyDocument extends Document<any> {
@ -33,6 +33,22 @@ export default class MyDocument extends Document<any> {
<Html lang="en">
<Head />
<body>
<script
dangerouslySetInnerHTML={{
__html: `(function() {
try {
var mode = localStorage.getItem('${THEME_STORAGE_KEY}')
if (!mode) return
document.documentElement.classList.add(mode)
var bgValue = getComputedStyle(document.documentElement)
.getPropertyValue('--colors-bg')
document.documentElement.style.background = bgValue
} catch (e) {}
})()`,
}}
/>
<link rel="preconnect" href="https://bh4d9od16a-dsn.algolia.net" crossOrigin="true" />
<link rel="preconnect" href="https://cdn.usefathom.com" crossOrigin="true" />
<Main />
<NextScript />
</body>

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

@ -1,6 +1,6 @@
---
title: 'Integrate Blockstack'
description: Single-page application with Blockstack
title: Building a Todo app
description: In this tutorial, you will learn about Blockstack authentication and storage by installing, running and reviewing the code for a "Todos" web app built with Blockstack and React.
redirect_from:
- /develop/zero_to_dapp_1.html
- /browser/hello-blockstack.html

4
src/pages/contributing.md

@ -16,7 +16,7 @@ Markdown files. In addition to being able to write JSX in Markdown, it allows th
Markdown content with React components! This means that we are able to do some pretty complex things while a
contributor only has to know how to write Markdown.
-> Don't know what Markdown is? Here is a [helpful guide](https://guides.github.com/features/mastering-markdown/) for getting started with Markdown.
-> **Don't know what Markdown is?** Here is a [helpful guide](https://guides.github.com/features/mastering-markdown/) for learning it.
## Getting started
@ -103,7 +103,7 @@ description: A short, concise sentence describing what is on this page
Frontmatter gives us the ability to define some things within a page that the site can use, such as a page title or page description.
When adding any new page, please include a `title` and `description`.
-> **Did you know?** The term _Frontmatter_ comes from the section in a book at the beginning the details things like: Publisher’s name and address, Copyright information, Table of Contents, etc.
-> **Did you know?** The term _Frontmatter_ comes from the section in a book at the beginning detailing things like: publisher’s name and address, copyright information, table of contents, etc.
### Dynamic sidebar

5
src/pages/core/atlas/howitworks.md

@ -1,5 +1,6 @@
---
description: 'Blockstack Atlas network'
title: How Atlas works
description: Atlas was designed to overcome the structural weaknesses inherent to all distributed hash tables.
---
# How Atlas Works
@ -9,8 +10,6 @@ distributed hash tables. In particular, it uses an unstructured peer network to
maximize resilience against network link failure, and it uses the underlying
blockchain (through BNS) to rate-limit chunk announcements.
This section contains the following sections:
## Peer Selection
Atlas peers self-organize into an unstructured peer-to-peer network.

6
src/pages/core/atlas/howtouse.md

@ -1,12 +1,10 @@
---
description: 'Blockstack Atlas network'
title: How to use the Atlas network
description: This section teaches you how to use the Atlas network.
---
# How to Use the Atlas Network
This section teaches you how to use the Atlas network, it contains the
following sections:
## The API
While the Blockstack software stack expects that Atlas-hosted data is made up of

14
src/pages/core/atlas/overview.md

@ -1,5 +1,6 @@
---
description: 'Blockstack Atlas network'
title: Overview of the Atlas network
description: This document describes the Atlas network, a peer-to-peer content-addressed storage system whose chunks' hashes are announced on a public blockchain.
---
# Overview of the Atlas network
@ -10,11 +11,10 @@ allows users and developers to **permanently store** chunks of data that are
**replicated across every peer.** As long as at least one Atlas peer is online,
all chunks are available to clients.
This document is aimed at developers and technical users. The following
concepts are discussed:
This document is aimed at developers and technical users.
The reader of this document is expected to be familiar with the [Blockstack Naming Service](/core/naming/introduction)(BNS), as well as Blockstack's
storage system [Gaia](https://github.com/blockstack/gaia). We advise the reader
The reader of this document is expected to be familiar with the [Blockstack Naming Service](/core/naming/introduction)(BNS),
as well as Blockstack's storage system [Gaia](https://github.com/blockstack/gaia). We advise the reader
to familiarize themselves with both systems before approaching this document.
## Architecture
@ -112,11 +112,11 @@ feature table describes Atlas in relation to other popular chunk stores.
| **Features** | Atlas | BitTorrent | [DAT](https://datproject.org/) | [IPFS](https://ipfs.io) | [Swarm](https://github.com/ethersphere/swarm) |
| ------------------------------- | ----- | ---------- | ------------------------------ | ----------------------- | --------------------------------------------- |
| Each peer stores all chunks | X | X | | | |
| Replicas are permanent [1] | X | X | X | | |
| Replicas are permanent [^1] | X | X | X | | |
| Replicas are free | | X | X | X | |
| Sybil-resistant chunk discovery | X | X | | | X |
| Sybil-resistant peer discovery | X | | | | |
| Fixed chunk size | X | | X | X | X |
[1] Here, "permanent" means that once a peer has data, they will never evict it
[^1] Here, "permanent" means that once a peer has data, they will never evict it
as part of the protocol.

3
src/pages/core/naming/architecture.md

@ -1,5 +1,6 @@
---
description: 'Blockstack naming service (BNS)'
title: Blockstack naming service (BNS)
description: The BNS node is the heart of the system. It is responsible for building up and replicating global name state.
---
# Understand the Architecture

3
src/pages/core/naming/comparison.md

@ -1,5 +1,6 @@
---
description: 'Blockstack naming service (BNS)'
title: Feature comparison
description: This page describes some other naming systems in comparison to Blockstack.
---
# Naming system feature comparison

33
src/pages/core/naming/creationhowto.md

@ -1,10 +1,13 @@
---
description: 'Blockstack naming service (BNS)'
title: Creating a Namespace
description: Learn how to create a namespace in the Blockstack Naming Service.
---
# Creating a Namespace
Making a namespace is very expensive. Given the large amount of cryptocurrency at stake in name creation, developers wanting to create their own namespaces should read [Understand Namespaces](/core/naming/namespaces) first. You should also read this document thoroughly before creating a namespace.
Making a namespace is very expensive. Given the large amount of cryptocurrency at stake in name creation, developers
wanting to create their own namespaces should read [Understand Namespaces](/core/naming/namespaces) first. You should
also read this document thoroughly before creating a namespace.
## Creation process
@ -12,7 +15,9 @@ There are four steps to creating a namespace.
### Step 1. Send a `NAMESPACE_PREORDER` transaction
This step registers the _salted hash_ of the namespace with BNS nodes, and burns the requisite amount of cryptocurrency. Additionally, this step proves to the BNS nodes that user has honored the BNS consensus rules by including a recent _consensus hash_ in the transaction (see the section on [BNS forks](#bns-forks) for details).
This step registers the _salted hash_ of the namespace with BNS nodes, and burns the requisite amount of cryptocurrency.
Additionally, this step proves to the BNS nodes that user has honored the BNS consensus rules by including a recent
_consensus hash_ in the transaction (see the section on [BNS forks](#bns-forks) for details).
### Step 2. Send a `NAMESPACE_REVEAL` transaction
@ -21,7 +26,10 @@ This second step reveals the salt and the namespace ID (pairing it with its
they expire or must be renewed, and it sets a _price function_ for the namespace
that determines how cheap or expensive names its will be.
The price function takes a name in this namespace as input, and outputs the amount of cryptocurrency the name will cost. The function does this by examining how long the name is, and whether or not it has any vowels or non-alphabet characters. The namespace creator has the option to collect name registration fees for the first year of the namespace's existence by setting a _namespace creator address_.
The price function takes a name in this namespace as input, and outputs the amount of cryptocurrency the name will cost.
The function does this by examining how long the name is, and whether or not it has any vowels or non-alphabet characters.
The namespace creator has the option to collect name registration fees for the first year of the namespace's existence by
setting a _namespace creator address_.
### Step 3. Seed the namespace with `NAME_IMPORT` transactions
@ -38,11 +46,18 @@ revealed in step 2.
## Consensus rules and competition for namespaces
Namespaces are created on a first-come first-serve basis. The BNS consensus rules require a `NAMESPACE_REVEAL` to be paired with a previous `NAMESPACE_PREORDER` sent within the past 24 hours. If two people try to create the same namespace, the one that successfully confirms both the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL` wins. The fee burned in the `NAMESPACE_PREORDER` is spent either way.
Namespaces are created on a first-come first-serve basis. The BNS consensus rules require a `NAMESPACE_REVEAL` to be
paired with a previous `NAMESPACE_PREORDER` sent within the past 24 hours. If two people try to create the same namespace,
the one that successfully confirms both the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL` wins. The fee burned in the
`NAMESPACE_PREORDER` is spent either way.
Once a user issues the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL`, they have 1 year before they must send the `NAMESPACE_READY` transaction. If they do not do this, then the namespace they created disappears (along with all the names they imported).
Once a user issues the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL`, they have 1 year before they must send the `NAMESPACE_READY`
transaction. If they do not do this, then the namespace they created disappears (along with all the names they imported).
Pairing the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL` steps is designed to prevent frontrunning. Frontrunning is a practice where name registrar uses insider information to register domains for the purpose of re-selling them or earning revenue from them. By registering the domains, the registrar locks out other potential registrars. Thus, through this pairing, a malicious actor cannot watch the blockchain network and race a victim to claim a namespace.
Pairing the `NAMESPACE_PREORDER` and `NAMESPACE_REVEAL` steps is designed to prevent frontrunning. Frontrunning is a
practice where name registrar uses insider information to register domains for the purpose of re-selling them or earning
revenue from them. By registering the domains, the registrar locks out other potential registrars. Thus, through this
pairing, a malicious actor cannot watch the blockchain network and race a victim to claim a namespace.
## Explore the namespace creation history
@ -81,8 +96,8 @@ If you would like to navigate a namespace history, you can. To do this, do the f
"txid": "5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28",
"vtxindex": 178
}
],
...
]
}
}
```

5
src/pages/core/naming/did.md

@ -1,5 +1,6 @@
---
description: 'Blockstack naming service (BNS)'
title: Decentralized Identifiers (DIDs)
description: BNS nodes are compliant with the emerging Decentralized Identity Foundation protocol specification for decentralized identifiers.
---
# Decentralized Identifiers (DIDs)
@ -10,7 +11,7 @@ specification for decentralized identifiers (DIDs).
Each name in BNS has an associated DID. The DID format for BNS is:
```
```bash
did:stack:v0:{address}-{index}
```

5
src/pages/core/naming/forks.md

@ -1,5 +1,6 @@
---
description: 'Blockstack naming service (BNS)'
title: BNS forks
description: Learn about forks within the context of the BNS.
---
# BNS Forks
@ -15,7 +16,7 @@ the BNS peer needs to do so, and must know how to _reject_ both invalid transact
as well as well-formed transactions from dishonest peers (i.e. peers that do not
follow the same consensus rules).
BNS nodes do not directly communicate with one another---by design, the set of
BNS nodes do not directly communicate with one another--by design, the set of
BNS peers is not enumerable. The only shared communication medium between BNS
peers is the blockchain.

1
src/pages/core/naming/introduction.md

@ -1,4 +1,5 @@
---
title: Overview
description: 'Blockstack naming service (BNS)'
---

16
src/pages/core/naming/manage.md

@ -1,11 +1,11 @@
---
description: 'Blockstack naming service (BNS)'
title: Manage BNS Names
description: This section teaches you how to manage your namespace.
---
# Manage BNS Names
This section teaches you how to manage your namespace, it contains the
following sections:
This section teaches you how to manage your namespace.
## Overview of management
@ -30,7 +30,9 @@ The reference BNS clients---
Browser](https://github.com/blockstack/blockstack-browser)---can handle creating
and sending all of these transactions for you.
## NAME_UPDATE
## Transaction types
### NAME_UPDATE
See [live example](https://www.blocktrail.com/BTC/tx/e2029990fa75e9fc642f149dad196ac6b64b9c4a6db254f23a580b7508fc34d7).
@ -44,7 +46,7 @@ hash](#bns-forks), and the new zone file hash. The reference clients gather
this information automatically. See the [transaction format](/core/wire-format)
document for details on how to construct this transaction.
## NAME_TRANSFER
### NAME_TRANSFER
See [live example](https://www.blocktrail.com/BTC/tx/7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24).
@ -64,7 +66,7 @@ hash](#bns-forks), and the new public key hash. The reference clients gather
this information automatically. See the [transaction format](/core/wire-format)
document for details on how to construct this transaction.
## NAME_REVOKE
### NAME_REVOKE
See [live example](https://www.blocktrail.com/BTC/tx/eb2e84a45cf411e528185a98cd5fb45ed349843a83d39fd4dff2de47adad8c8f).
@ -80,7 +82,7 @@ The `NAME_REVOKE` operation is generated using only the name. See the
[transaction format](/core/wire-format) document for details on how to construct
it.
## NAME_RENEWAL
### NAME_RENEWAL
See [live example](https://www.blocktrail.com/BTC/tx/e543211b18e5d29fd3de7c0242cb017115f6a22ad5c6d51cf39e2b87447b7e65).

3
src/pages/core/naming/namespaces.md

@ -1,5 +1,6 @@
---
description: 'Blockstack naming service (BNS)'
title: Understand Namespaces
description: Namespaces are the top-level naming objects in BNS.
---
# Understand Namespaces

16
src/pages/core/naming/pickname.md

@ -1,11 +1,11 @@
---
description: 'Blockstack naming service (BNS)'
title: Choose a name
description: This section explains how to choose and create a namespace.
---
# Choose a name
This section explains how to choose and create a namespace, it contains the
following sections:
This section explains how to choose and create a namespace.
## Intended uses for a namespace
@ -118,7 +118,7 @@ requisite amount of cryptocurrency. In addition, it proves to the BNS nodes that
BNS consensus rules by including a recent _consensus hash_ in the transaction (see the section on
[BNS forks](#bns-forks) for details).
See `NAMESPACE_PREORDER` ([live example](https://www.blocktrail.com/BTC/tx/5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28)).
-> See `NAMESPACE_PREORDER` ([live example](https://www.blocktrail.com/BTC/tx/5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28)).
#### Step 2: Send a `NAMESPACE_REVEAL` transaction
@ -132,7 +132,7 @@ has any vowels or non-alphabet characters). The namespace creator
has the option to collect name registration fees for the first year of the
namespace's existence by setting a _namespace creator address_.
See `NAMESPACE_REVEAL` ([live example](https://www.blocktrail.com/BTC/tx/ab54b1c1dd5332dc86b24ca2f88b8ca0068485edf0c322416d104c5b84133a32)).
-> See `NAMESPACE_REVEAL` ([live example](https://www.blocktrail.com/BTC/tx/ab54b1c1dd5332dc86b24ca2f88b8ca0068485edf0c322416d104c5b84133a32)).
#### Step 3: Seed the namespace with `NAME_IMPORT` transactions
@ -140,7 +140,7 @@ Once the namespace has been revealed, the user has the option to populate it wit
names. Each imported name is given both an owner and some off-chain state.
This step is optional---namespace creators are not required to import names.
See `NAME_IMPORT` ([live example](https://www.blocktrail.com/BTC/tx/c698ac4b4a61c90b2c93dababde867dea359f971e2efcf415c37c9a4d9c4f312)).
-> See `NAME_IMPORT` ([live example](https://www.blocktrail.com/BTC/tx/c698ac4b4a61c90b2c93dababde867dea359f971e2efcf415c37c9a4d9c4f312)).
#### Step 4: Send a `NAMESPACE_READY` transaction
@ -149,9 +149,7 @@ public. Once a namespace is ready, anyone can register a name in it if they
pay the appropriate amount of cryptocurrency (according to the price funtion
revealed in step 2).
See `NAMESPACE_READY` ([live example](https://www.blocktrail.com/BTC/tx/2bf9a97e3081886f96c4def36d99a677059fafdbd6bdb6d626c0608a1e286032)).
---
-> See `NAMESPACE_READY` ([live example](https://www.blocktrail.com/BTC/tx/2bf9a97e3081886f96c4def36d99a677059fafdbd6bdb6d626c0608a1e286032)).
The reason for the `NAMESPACE_PREORDER/NAMESPACE_REVEAL` pairing is to prevent
frontrunning. The BNS consensus rules require a `NAMESPACE_REVEAL` to be

17
src/pages/core/naming/register.md

@ -1,11 +1,12 @@
---
description: 'Blockstack naming service (BNS)'
title: Register a name
description: This section explains registering BNS names and provides instructions for methods you can use to understand the cost of namespace registration.
---
# Register a name
This section explains registering BNS names and provides instructions for methods
you can use to understandt the cost of namespace registration.
you can use to understand the cost of namespace registration.
## Understand registration
@ -67,7 +68,7 @@ ignored.
## Getting a Name's Registration Fee
See [reference](https://core.blockstack.org/#price-checks-get-name-price).
-> See [reference](https://core.blockstack.org/#price-checks-get-name-price).
```bash
$ curl -sL https://core.blockstack.org/v1/prices/names/helloworld.id | jq -r ".name_price"
@ -83,7 +84,7 @@ but this is the only field guaranteed by this specification to be present.
## Getting the Current Consensus Hash
See [reference](https://core.blockstack.org/#blockchain-operations-get-consensus-hash).
-> See [reference](https://core.blockstack.org/#blockchain-operations-get-consensus-hash).
```bash
$ curl -sL https://core.blockstack.org/v1/blockchains/bitcoin/consensus
@ -93,9 +94,8 @@ $ curl -sL https://core.blockstack.org/v1/blockchains/bitcoin/consensus
```
The consensus hash must be included in the `NAME_PREORDER` transaction. The BNS
clients do this automatically. See the [transaction format
document](/core/wire-format) for details as to how to include this in the
transaction.
clients do this automatically. See the [transaction format document](/core/wire-format)
for details as to how to include this in the transaction.
## Registering a Name
@ -106,5 +106,4 @@ The reference BNS clients manage a local Bitcoin wallet, calculate transaction f
dynamically and automatically, and broadcast both the `NAME_PREORDER` and
`NAME_REGISTRATION` transactions at the right times.
If you want to make your own registration client, you should see the
[transaction format](/core/wire-format) document.
-> If you want to make your own registration client, you should see the [transaction format](/core/wire-format) document.

3
src/pages/core/naming/resolving.md

@ -1,5 +1,6 @@
---
description: 'Blockstack naming service (BNS)'
title: Resolve a name
description: This section explains resolving BNS names and provides instructions for methods you can use to accomplish namespace resolution.
---
## Resolve a name

2
src/pages/index.tsx

@ -53,7 +53,7 @@ const Homepage = () => {
return (
<>
<Head>
<title>Blockstack Docs</title>
<title>Documentation | Blockstack</title>
</Head>
<HomeLayout>
<Hero cards={cards} />

2
yarn.lock

@ -8392,7 +8392,7 @@ remark-external-links@^6.1.0:
space-separated-tokens "^1.0.0"
unist-util-visit "^2.0.0"
remark-footnotes@1.0.0:
remark-footnotes@1.0.0, remark-footnotes@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-1.0.0.tgz#9c7a97f9a89397858a50033373020b1ea2aad011"
integrity sha512-X9Ncj4cj3/CIvLI2Z9IobHtVi8FVdUrdJkCNaL9kdX8ohfsi18DXHsCVd/A7ssARBdccdDb5ODnt62WuEWaM/g==

Loading…
Cancel
Save