mirror of
https://github.com/zhigang1992/connect.git
synced 2026-04-24 05:05:50 +08:00
fix(ui-docs): improve typography, styles, write color-modes.mdx
This commit is contained in:
committed by
Thomas Osmonson
parent
67c7f31357
commit
7870a0f45e
39
.github/workflows/deploy-docs.yml
vendored
39
.github/workflows/deploy-docs.yml
vendored
@@ -6,32 +6,13 @@ jobs:
|
||||
docs-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set Node Version
|
||||
uses: actions/setup-node@v1
|
||||
env:
|
||||
RUNNER_TEMP: /tmp
|
||||
with:
|
||||
node-version: 12.16.1
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
- uses: actions/cache@v1
|
||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
- name: Monorepo Dependencies
|
||||
run: yarn
|
||||
- name: Lerna Bootstrap
|
||||
run: yarn lerna bootstrap
|
||||
- uses: amondnet/vercel-action@v19
|
||||
with:
|
||||
vercel-token: ${{ secrets.VERCEL_TOKEN }} # Required
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }} #Optional
|
||||
vercel-args: '--prod' #Optional
|
||||
vercel-org-id: ${{ secrets.ORG_ID}} #Required
|
||||
vercel-project-id: ${{ secrets.PROJECT_ID}} #Required
|
||||
working-directory: ./packages/ui-docs
|
||||
- uses: actions/checkout@v2
|
||||
- uses: amondnet/vercel-action@v19.0.1+1
|
||||
id: vercel-action
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
||||
vercel-org-id: ${{ secrets.ORG_ID }}
|
||||
vercel-project-id: ${{ secrets.PROJECT_ID }}
|
||||
working-directory: packages/ui-docs
|
||||
scope: ${{ secrets.VERCEL_SCOPE }}
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
const withTM = require('./with-tm')(['@blockstack/ui']);
|
||||
|
||||
const withPlugins = require('next-compose-plugins');
|
||||
|
||||
const withMdxEnhanced = require('next-mdx-enhanced');
|
||||
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
||||
enabled: process.env.ANALYZE === 'true',
|
||||
});
|
||||
const remarkPlugins = [
|
||||
require('remark-autolink-headings'),
|
||||
require('remark-external-links'),
|
||||
require('remark-emoji'),
|
||||
require('remark-images'),
|
||||
require('remark-slug'),
|
||||
require('remark-unwrap-images'),
|
||||
require('remark-slug'),
|
||||
];
|
||||
|
||||
const withMDX = require('@next/mdx')({
|
||||
extension: /\.mdx?$/,
|
||||
options: {
|
||||
module.exports = withBundleAnalyzer(
|
||||
withMdxEnhanced({
|
||||
layoutPath: 'src/components/layouts',
|
||||
defaultLayout: true,
|
||||
fileExtensions: ['mdx'],
|
||||
remarkPlugins,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = withMDX(
|
||||
withTM({
|
||||
extendFrontMatter: {
|
||||
process: mdxContent => {
|
||||
const regex = /\n(#+)(.*)/gm;
|
||||
const found = mdxContent.match(regex);
|
||||
const headings = found && found.length ? found.map(f => f.split('# ')[1]) : [];
|
||||
return {
|
||||
headings,
|
||||
};
|
||||
},
|
||||
},
|
||||
})({
|
||||
experimental: {
|
||||
modern: true,
|
||||
polyfillsOptimization: true,
|
||||
@@ -26,11 +34,36 @@ module.exports = withMDX(
|
||||
},
|
||||
pageExtensions: ['ts', 'tsx', 'md', 'mdx'],
|
||||
webpack: (config, options) => {
|
||||
const aliases = config.resolve.alias || (config.resolve.alias = {});
|
||||
aliases['@blockstack/ui'] = require.resolve('../ui');
|
||||
if (!options.isServer) {
|
||||
config.node['fs'] = 'empty';
|
||||
}
|
||||
if (!options.dev) {
|
||||
const splitChunks = config.optimization && config.optimization.splitChunks;
|
||||
if (splitChunks) {
|
||||
const cacheGroups = splitChunks.cacheGroups;
|
||||
const preactModules = /[\\/]node_modules[\\/](preact|preact-render-to-string|preact-context-provider)[\\/]/;
|
||||
if (cacheGroups.framework) {
|
||||
cacheGroups.preact = Object.assign({}, cacheGroups.framework, {
|
||||
test: preactModules,
|
||||
});
|
||||
cacheGroups.commons.name = 'framework';
|
||||
} else {
|
||||
cacheGroups.preact = {
|
||||
name: 'commons',
|
||||
chunks: 'all',
|
||||
test: preactModules,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Install webpack aliases:
|
||||
const aliases = config.resolve.alias || (config.resolve.alias = {});
|
||||
aliases.react = aliases['react-dom'] = 'preact/compat';
|
||||
|
||||
// https://github.com/FormidableLabs/react-live#what-bundle-size-can-i-expect
|
||||
aliases['buble'] = '@philpl/buble';
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
})
|
||||
|
||||
@@ -2,45 +2,47 @@
|
||||
"name": "@blockstack/ui-docs",
|
||||
"version": "0.1.9",
|
||||
"dependencies": {
|
||||
"@blockstack/ui": "2.7.0",
|
||||
"@blockstack/ui": "^2.7.2-beta.2",
|
||||
"@mdx-js/loader": "1.6.6",
|
||||
"@mdx-js/mdx": "^1.6.6",
|
||||
"@mdx-js/react": "^1.6.6",
|
||||
"@next/mdx": "^9.4.4",
|
||||
"@octokit/rest": "^17.9.2",
|
||||
"@philpl/buble": "^0.19.7",
|
||||
"@reach/tooltip": "^0.10.5",
|
||||
"@styled-system/theme-get": "^5.1.2",
|
||||
"@types/mdx-js__react": "^1.5.2",
|
||||
"@types/npm-registry-fetch": "^8.0.0",
|
||||
"anser": "^1.4.9",
|
||||
"formik": "^2.1.4",
|
||||
"js-levenshtein": "^1.1.6",
|
||||
"@types/node": "^14.0.14",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/reach__tooltip": "^0.2.0",
|
||||
"mdi-react": "^7.3.0",
|
||||
"next": "^9.4.5-canary.3",
|
||||
"next-compose-plugins": "^2.2.0",
|
||||
"next-seo": "4.5.0",
|
||||
"next-transpile-modules": "^3.3.0",
|
||||
"npm-registry-fetch": "^8.1.0",
|
||||
"next-mdx-enhanced": "^3.0.0",
|
||||
"nookies": "^2.3.2",
|
||||
"nprogress": "^0.2.0",
|
||||
"preact": "^10.4.4",
|
||||
"preact-render-to-string": "^5.1.4",
|
||||
"prettier": "^2.0.5",
|
||||
"prism-react-renderer": "^1.0.2",
|
||||
"react-children-utilities": "^2.1.2",
|
||||
"react-icons": "^3.9.0",
|
||||
"react-live": "^2.2.2",
|
||||
"react-simple-code-editor": "^0.11.0",
|
||||
"react-view": "^2.3.2",
|
||||
"remark-autolink-headings": "6.0.1",
|
||||
"react-ssr-prepass": "npm:preact-ssr-prepass@^1.0.1",
|
||||
"remark-emoji": "2.1.0",
|
||||
"remark-external-links": "^6.1.0",
|
||||
"remark-images": "2.0.0",
|
||||
"remark-slug": "6.0.0",
|
||||
"remark-unwrap-images": "2.0.0",
|
||||
"socks-proxy-agent": "^5.0.0",
|
||||
"stacktrace-parser": "^0.1.10",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"store": "^2.0.12",
|
||||
"typeface-fira-code": "^1.1.4",
|
||||
"typeface-inter": "^3.12.0",
|
||||
"typescript": "^3.9.5",
|
||||
"use-events": "^1.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^9.4.4",
|
||||
"babel-plugin-styled-components": "^1.10.7",
|
||||
"next-transpile-modules": "^3.3.0",
|
||||
"now": "^19.0.1",
|
||||
"react": "^16.13.0",
|
||||
"react-dom": "^16.13.0",
|
||||
"styled-components": "^5.0.1",
|
||||
@@ -48,10 +50,11 @@
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"build": "next build && next export -o build",
|
||||
"build:analyze": "next telemetry disable && ANALYZE=true next build",
|
||||
"start": "NODE_ENV=production next start",
|
||||
"dev": "next dev",
|
||||
"export": "next export",
|
||||
"start": "next start",
|
||||
"lint": "yarn run lint:eslint && yarn run lint:prettier",
|
||||
"lint:eslint": "eslint --ext .ts,.tsx ./src",
|
||||
"lint:fix": "eslint --ext .ts,.tsx ./src/ -f unix --fix && prettier --write src/**/*.{ts,tsx} *.js",
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
const SEO = {
|
||||
title: 'Waffle Design System',
|
||||
description:
|
||||
'Simple, Modular and Accessible UI Components for your React Applications. Built with Styled System',
|
||||
openGraph: {
|
||||
url: 'https://waffle.blockstack.sh',
|
||||
title: 'Blockstack UI',
|
||||
description:
|
||||
'Simple, Modular and Accessible UI Components for your React Applications. Built with Styled System',
|
||||
site_name: 'Blockstack UI',
|
||||
},
|
||||
};
|
||||
|
||||
export default SEO;
|
||||
@@ -1,41 +1,23 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useAppState } from '@common/hooks/use-app-state';
|
||||
import { State } from '@components/app-state/types';
|
||||
|
||||
interface ActiveHeadingProps {
|
||||
slug: string;
|
||||
}
|
||||
type ActiveHeadingReturn = [boolean, (value: any) => void];
|
||||
type ActiveHeadingReturn = [boolean, (value: string) => void, string];
|
||||
|
||||
export const useActiveHeading = ({ slug }: ActiveHeadingProps): ActiveHeadingReturn => {
|
||||
export const useActiveHeading = (_slug: string): ActiveHeadingReturn => {
|
||||
const router = useRouter();
|
||||
const state = useAppState();
|
||||
const { setState } = state;
|
||||
const { asPath } = router;
|
||||
const { activeSlug, doChangeActiveSlug } = useAppState();
|
||||
const urlHash = asPath?.includes('#') && asPath.split('#')[1];
|
||||
const location = typeof window !== 'undefined' && window.location.href;
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
asPath &&
|
||||
asPath.includes('#') &&
|
||||
asPath.split('#')[1] === slug &&
|
||||
state.activeSlug !== slug
|
||||
) {
|
||||
setState((s: State) => ({ ...s, activeSlug: slug }));
|
||||
if (urlHash && !activeSlug) {
|
||||
doChangeActiveSlug(urlHash);
|
||||
}
|
||||
if (asPath && !asPath.includes('#')) {
|
||||
setState((s: State) => ({ ...s, activeSlug: '' }));
|
||||
}
|
||||
}, [asPath]);
|
||||
}, [asPath, urlHash, location]);
|
||||
|
||||
const handleStateUpdate = useCallback(
|
||||
newSlug => setState((s: State) => ({ ...s, activeSlug: newSlug })),
|
||||
[state.activeSlug]
|
||||
);
|
||||
const isActive = _slug === activeSlug;
|
||||
|
||||
const selectActiveSlug = useCallback((state: State) => state && state.activeSlug, []);
|
||||
|
||||
const isActive = selectActiveSlug(state) === slug;
|
||||
|
||||
return [isActive, handleStateUpdate];
|
||||
return [isActive, doChangeActiveSlug, location];
|
||||
};
|
||||
|
||||
@@ -2,4 +2,25 @@ import React from 'react';
|
||||
import { AppStateContext } from '@components/app-state/context';
|
||||
import { State } from '@components/app-state/types';
|
||||
|
||||
export const useAppState = (): State => React.useContext(AppStateContext);
|
||||
interface UseAppStateReturn extends State {
|
||||
doChangeActiveSlug: (activeSlug: string) => void;
|
||||
}
|
||||
|
||||
export const useAppState = (): UseAppStateReturn => {
|
||||
const { setState, ...rest } = React.useContext(AppStateContext);
|
||||
|
||||
const doChangeActiveSlug = React.useCallback(
|
||||
(activeSlug: string) =>
|
||||
setState((state: State) => ({
|
||||
...state,
|
||||
activeSlug,
|
||||
})),
|
||||
[]
|
||||
);
|
||||
|
||||
return {
|
||||
...rest,
|
||||
doChangeActiveSlug,
|
||||
setState,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { useContext } from 'react';
|
||||
import { ColorModeContext } from '@components/color-modes';
|
||||
|
||||
export const useColorMode = () => {
|
||||
const { colorMode, toggleColorMode } = useContext(ColorModeContext);
|
||||
return { colorMode, toggleColorMode };
|
||||
};
|
||||
@@ -10,6 +10,7 @@ export const components = [
|
||||
'Box',
|
||||
'Button',
|
||||
'CodeBlock',
|
||||
'Color modes',
|
||||
'CSS Reset',
|
||||
'Flex',
|
||||
'Grid',
|
||||
@@ -35,11 +36,19 @@ export const hooks = [
|
||||
'useId',
|
||||
'useLatestRef',
|
||||
'useMergeRefs',
|
||||
'useTheme',
|
||||
];
|
||||
|
||||
export const bottomNavLinks = ['Contributing', 'Further reading', 'GitHub'];
|
||||
export const bottomNavLinks = ['Contributing', 'Further reading'];
|
||||
|
||||
export const routes = [...topNavLinks, ...components, ...bottomNavLinks];
|
||||
export const routes = [...topNavLinks, ...components, ...hooks, ...bottomNavLinks];
|
||||
|
||||
export const paginationRoutes = {
|
||||
top: topNavLinks,
|
||||
components,
|
||||
hooks,
|
||||
bottom: bottomNavLinks,
|
||||
};
|
||||
|
||||
export const links = {
|
||||
github: 'https://github.com/blockstack/ux',
|
||||
61
packages/ui-docs/src/common/utils.ts
Normal file
61
packages/ui-docs/src/common/utils.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Children, isValidElement, ReactNode, ReactElement, ReactText } from 'react';
|
||||
|
||||
import { BorderStyleProperty } from 'csstype';
|
||||
import { ColorsStringLiteral, color } from '@blockstack/ui';
|
||||
const camelToKebab = (string: string) =>
|
||||
string
|
||||
.toString()
|
||||
.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2')
|
||||
.toLowerCase();
|
||||
|
||||
export const slugify = (string: string) =>
|
||||
string
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, '-') // Replace spaces with -
|
||||
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
|
||||
.replace(/\-\-+/g, '-') // Replace multiple - with single -
|
||||
.replace(/^-+/, '') // Trim - from start of text
|
||||
.replace(/-+$/, ''); // Trim - from end of text
|
||||
|
||||
export const border = (
|
||||
width = 1,
|
||||
style: BorderStyleProperty = 'solid',
|
||||
_color: ColorsStringLiteral = 'border'
|
||||
): string => `${width}px ${style} ${color(_color)}`;
|
||||
|
||||
// https://github.com/fernandopasik/react-children-utilities/blob/master/src/lib/hasChildren.ts
|
||||
const hasChildren = (element: ReactNode): element is ReactElement<{ children: ReactNode[] }> =>
|
||||
isValidElement<{ children?: ReactNode[] }>(element) && Boolean(element.props.children);
|
||||
|
||||
// https://github.com/fernandopasik/react-children-utilities/blob/master/src/lib/onlyText.ts
|
||||
export const childToString = (child?: ReactText | boolean | {} | null): string => {
|
||||
if (typeof child === 'undefined' || child === null || typeof child === 'boolean') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (JSON.stringify(child) === '{}') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return (child as string | number).toString();
|
||||
};
|
||||
|
||||
export const onlyText = (children: ReactNode): string => {
|
||||
if (!(children instanceof Array) && !isValidElement(children)) {
|
||||
return childToString(children);
|
||||
}
|
||||
|
||||
return Children.toArray(children).reduce((text: string, child: ReactNode): string => {
|
||||
let newText = '';
|
||||
|
||||
if (isValidElement(child) && hasChildren(child)) {
|
||||
newText = onlyText(child.props.children);
|
||||
} else if (isValidElement(child) && !hasChildren(child)) {
|
||||
newText = '';
|
||||
} else {
|
||||
newText = childToString(child);
|
||||
}
|
||||
|
||||
return text.concat(newText);
|
||||
}, '') as string;
|
||||
};
|
||||
@@ -1,61 +0,0 @@
|
||||
import { BorderStyleProperty } from 'csstype';
|
||||
import { ColorsStringLiteral } from '@components/color-modes';
|
||||
|
||||
export const slugify = (string: string) =>
|
||||
string
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, '-') // Replace spaces with -
|
||||
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
|
||||
.replace(/\-\-+/g, '-') // Replace multiple - with single -
|
||||
.replace(/^-+/, '') // Trim - from start of text
|
||||
.replace(/-+$/, ''); // Trim - from end of text
|
||||
|
||||
/**
|
||||
* Style utils
|
||||
*
|
||||
* color={color('bg-alt')} // returns css var --var-colors-bg-alt
|
||||
* marginTop={space('extra-loose')} // maps to size in theme
|
||||
* border={border()} // default border
|
||||
*/
|
||||
|
||||
enum NamedSpacing {
|
||||
ExtraTight = 'extra-tight',
|
||||
Tight = 'tight',
|
||||
BaseTight = 'base-tight',
|
||||
Base = 'base',
|
||||
BaseLoose = 'base-loose',
|
||||
Loose = 'loose',
|
||||
ExtraLoose = 'extra-loose',
|
||||
}
|
||||
|
||||
type NamedSpacingLiteral =
|
||||
| 'none'
|
||||
| 'extra-tight'
|
||||
| 'tight'
|
||||
| 'base-tight'
|
||||
| 'base'
|
||||
| 'base-loose'
|
||||
| 'loose'
|
||||
| 'extra-loose';
|
||||
|
||||
type Spacing = NamedSpacingLiteral;
|
||||
|
||||
type SpacingTypes =
|
||||
| Spacing
|
||||
| [Spacing]
|
||||
| [Spacing, Spacing]
|
||||
| [Spacing, Spacing, Spacing]
|
||||
| [Spacing, Spacing, Spacing, Spacing];
|
||||
|
||||
export const space = (spacing: SpacingTypes): SpacingTypes => spacing;
|
||||
|
||||
export const color = (name: ColorsStringLiteral) => {
|
||||
return `var(--colors-${name})`;
|
||||
};
|
||||
|
||||
export const border = (
|
||||
width = 1,
|
||||
style: BorderStyleProperty = 'solid',
|
||||
_color: ColorsStringLiteral = 'border'
|
||||
): string => `${width}px ${style} ${color(_color)}`;
|
||||
@@ -1,9 +1,11 @@
|
||||
import React, { useState, useContext } from 'react';
|
||||
import { LiveProvider, withLive, LiveError, LiveContext, LivePreview } from 'react-live';
|
||||
import { Box, CodeBlock as BaseCodeBlock } from '@blockstack/ui';
|
||||
import React, { useContext } from 'react';
|
||||
import { LiveProvider, LiveContext, LivePreview } from 'react-live';
|
||||
import { Box, CodeBlock as BaseCodeBlock, space, color } from '@blockstack/ui';
|
||||
import 'prismjs/components/prism-jsx';
|
||||
import { CodeEditor } from '@components/code-editor';
|
||||
import { Caption } from '@components/typography';
|
||||
import 'prismjs/components/prism-tsx';
|
||||
import { border } from '@common/utils';
|
||||
|
||||
const Error = (props: any) => {
|
||||
const { error } = useContext(LiveContext);
|
||||
@@ -32,28 +34,40 @@ export const liveErrorStyle = {
|
||||
};
|
||||
|
||||
export const LiveCodePreview = (props: any) => (
|
||||
<Box
|
||||
as={LivePreview}
|
||||
fontFamily="body"
|
||||
borderRadius="6px"
|
||||
p="base"
|
||||
border="1px solid var(--colors-border)"
|
||||
{...props}
|
||||
/>
|
||||
<Box fontFamily="body">
|
||||
<Box
|
||||
as={LivePreview}
|
||||
boxShadow="mid"
|
||||
border={border()}
|
||||
borderRadius="6px"
|
||||
p={space('base')}
|
||||
mb={space('base')}
|
||||
{...props}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
|
||||
export const JsxEditor = ({ liveProviderProps, editorCode, handleCodeChange, language }) => (
|
||||
export const JsxEditor = ({
|
||||
liveProviderProps,
|
||||
editorCode,
|
||||
handleCodeChange,
|
||||
language,
|
||||
...rest
|
||||
}) => (
|
||||
<LiveProvider {...liveProviderProps}>
|
||||
<Box mt="base" pl="base">
|
||||
<Caption fontFamily="body">Preview</Caption>
|
||||
<Box mb={space('tight')} mt={space('base')}>
|
||||
<Caption fontWeight={500} pl={space('tight')} fontFamily="body">
|
||||
Preview
|
||||
</Caption>
|
||||
</Box>
|
||||
<LiveCodePreview />
|
||||
<Box mt="base" tabIndex={-1} position="relative">
|
||||
<Box pl="base">
|
||||
<Caption fontFamily="body">Editable example</Caption>
|
||||
</Box>
|
||||
<CodeEditor value={editorCode} onChange={handleCodeChange} language={language} />
|
||||
|
||||
<Box mb={space('tight')}>
|
||||
<Caption fontWeight={500} pl={space('tight')} fontFamily="body">
|
||||
Editable example
|
||||
</Caption>
|
||||
</Box>
|
||||
<CodeEditor value={editorCode} onChange={handleCodeChange} language={language} />
|
||||
<Error />
|
||||
</LiveProvider>
|
||||
);
|
||||
@@ -68,7 +82,10 @@ export const Preview = ({ liveProviderProps }) => (
|
||||
|
||||
export const SimpleCodeBlock = ({ editorCode, language }) => (
|
||||
<BaseCodeBlock
|
||||
border="1px solid var(--colors-border)"
|
||||
borderTop={border()}
|
||||
borderBottom={border()}
|
||||
borderLeft={['none', border(), border()]}
|
||||
borderRight={['none', border(), border()]}
|
||||
code={editorCode}
|
||||
language={language}
|
||||
my="base"
|
||||
|
||||
@@ -70,7 +70,7 @@ export const CodeEditor = React.memo((props: CodeEditorProps) => {
|
||||
<Box
|
||||
className="code-editor"
|
||||
bg="ink"
|
||||
borderRadius="6px"
|
||||
borderRadius={['unset', 'unset', '6px', '6px']}
|
||||
py="base-tight"
|
||||
border="1px solid var(--colors-border)"
|
||||
overflowX="auto"
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import React, { forwardRef, Ref } from 'react';
|
||||
import { LinkProps } from '@components/typography';
|
||||
import { useColorMode } from '@blockstack/ui';
|
||||
import { DarkModeIcon } from '@components/icons/dark-mode';
|
||||
|
||||
import { useColorMode } from '@common/hooks/use-color-mode';
|
||||
import { LightModeIcon } from '@components/icons/light-mode';
|
||||
import { IconButton } from '@components/icon-button';
|
||||
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { createGlobalStyle } from 'styled-components';
|
||||
import { themeGet } from '@styled-system/theme-get';
|
||||
import { useMediaQuery } from '@common/hooks/use-media-query';
|
||||
import { Theme } from '@blockstack/ui';
|
||||
import { color } from '@common/utils';
|
||||
|
||||
export { color };
|
||||
|
||||
export const colorGet = (path: string, fallback?: string) => themeGet('colors.' + path, fallback);
|
||||
|
||||
enum Color {
|
||||
Accent = 'accent',
|
||||
Bg = 'bg',
|
||||
BgAlt = 'bg-alt',
|
||||
BgLight = 'bg-light',
|
||||
Invert = 'invert',
|
||||
TextHover = 'text-hover',
|
||||
TextTitle = 'text-title',
|
||||
TextCaption = 'text-caption',
|
||||
TextBody = 'text-body',
|
||||
InputPlaceholder = 'input-placeholder',
|
||||
Border = 'border',
|
||||
FeedbackAlert = 'feedback-alert',
|
||||
FeedbackError = 'feedback-error',
|
||||
FeedbackSuccess = 'feedback-success',
|
||||
}
|
||||
|
||||
export type ColorsStringLiteral =
|
||||
| 'accent'
|
||||
| 'bg'
|
||||
| 'bg-alt'
|
||||
| 'bg-light'
|
||||
| 'invert'
|
||||
| 'text-hover'
|
||||
| 'text-title'
|
||||
| 'text-caption'
|
||||
| 'text-body'
|
||||
| 'input-placeholder'
|
||||
| 'border'
|
||||
| 'feedback-alert'
|
||||
| 'feedback-error'
|
||||
| 'feedback-success';
|
||||
|
||||
type ColorModeTypes = {
|
||||
[key in ColorsStringLiteral]: string;
|
||||
};
|
||||
|
||||
interface ColorModesInterface {
|
||||
light: ColorModeTypes;
|
||||
dark: ColorModeTypes;
|
||||
}
|
||||
|
||||
const colors = (props: { theme: Theme }): ColorModesInterface => ({
|
||||
light: {
|
||||
[Color.Accent]: colorGet('blue')(props),
|
||||
[Color.Bg]: 'white',
|
||||
[Color.BgAlt]: colorGet('ink.50')(props),
|
||||
[Color.BgLight]: 'white',
|
||||
[Color.Invert]: colorGet('ink')(props),
|
||||
[Color.TextHover]: colorGet('blue')(props),
|
||||
[Color.TextTitle]: colorGet('ink')(props),
|
||||
[Color.TextCaption]: colorGet('ink.600')(props),
|
||||
[Color.TextBody]: colorGet('ink.900')(props),
|
||||
[Color.InputPlaceholder]: colorGet('ink.400')(props),
|
||||
[Color.Border]: 'rgb(229, 229, 236)',
|
||||
[Color.FeedbackAlert]: colorGet('orange')(props),
|
||||
[Color.FeedbackError]: colorGet('red')(props),
|
||||
[Color.FeedbackSuccess]: colorGet('green')(props),
|
||||
},
|
||||
dark: {
|
||||
[Color.Accent]: colorGet('blue.400')(props),
|
||||
[Color.Bg]: colorGet('ink')(props),
|
||||
[Color.BgAlt]: 'rgba(255,255,255,0.05)',
|
||||
[Color.BgLight]: 'rgba(255,255,255,0.08)',
|
||||
[Color.Invert]: 'white',
|
||||
[Color.TextHover]: colorGet('blue.300')(props),
|
||||
[Color.TextTitle]: 'white',
|
||||
[Color.TextCaption]: '#a7a7ad',
|
||||
[Color.TextBody]: colorGet('ink.300')(props),
|
||||
[Color.InputPlaceholder]: 'rgba(255,255,255,0.3)',
|
||||
[Color.Border]: 'rgb(39, 41, 46)',
|
||||
[Color.FeedbackAlert]: colorGet('orange')(props),
|
||||
[Color.FeedbackError]: colorGet('red')(props),
|
||||
[Color.FeedbackSuccess]: colorGet('green')(props),
|
||||
},
|
||||
});
|
||||
|
||||
const colorModeStyles = (props: { theme: Theme; colorMode: 'light' | 'dark' }) =>
|
||||
colors(props)[props.colorMode];
|
||||
|
||||
const colorMap = (props: { theme: Theme; colorMode: 'light' | 'dark' }) =>
|
||||
Object.keys(colors(props)[props.colorMode]);
|
||||
|
||||
export const ColorModes = createGlobalStyle`
|
||||
|
||||
:root{
|
||||
${({ colorMode = 'light', ...rest }: any) =>
|
||||
colorMap({ colorMode, ...rest }).map(key => {
|
||||
return `--colors-${key}: ${
|
||||
//@ts-ignore
|
||||
colorModeStyles({ colorMode, ...rest })[key as string]
|
||||
};`;
|
||||
})}
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
${({ colorMode = 'light', ...rest }: any) =>
|
||||
colorMap({ colorMode, ...rest }).map(key => {
|
||||
return `--colors-${key}: ${
|
||||
//@ts-ignore
|
||||
colorModeStyles({ colorMode, ...rest })[key as string]
|
||||
};`;
|
||||
})}
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
${({ colorMode = 'light', ...rest }: any) =>
|
||||
colorMap({ colorMode, ...rest }).map(key => {
|
||||
return `--colors-${key}: ${
|
||||
//@ts-ignore
|
||||
colorModeStyles({ colorMode, ...rest })[key as string]
|
||||
};`;
|
||||
})}
|
||||
}
|
||||
}
|
||||
|
||||
html, body, #__next {
|
||||
background: var(--colors-bg);
|
||||
border-color: var(--colors-border);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
`;
|
||||
|
||||
export const ColorModeContext = React.createContext<{ colorMode?: string; toggleColorMode?: any }>({
|
||||
colorMode: undefined,
|
||||
});
|
||||
|
||||
export const ColorModeProvider = ({
|
||||
colorMode,
|
||||
children,
|
||||
}: {
|
||||
colorMode?: string;
|
||||
children: any;
|
||||
}) => {
|
||||
const [mode, setMode] = React.useState(colorMode);
|
||||
const [darkmode] = useMediaQuery('(prefers-color-scheme: dark)');
|
||||
const [lightmode] = useMediaQuery('(prefers-color-scheme: light)');
|
||||
|
||||
const setColorMode = useCallback(
|
||||
(mode: 'light' | 'dark') => {
|
||||
setMode(mode);
|
||||
},
|
||||
[mode]
|
||||
);
|
||||
|
||||
const toggleColorMode = useCallback(() => {
|
||||
if (mode === 'light') {
|
||||
setColorMode('dark');
|
||||
return;
|
||||
}
|
||||
if (mode === 'dark') {
|
||||
setColorMode('light');
|
||||
return;
|
||||
}
|
||||
if (!colorMode && darkmode) {
|
||||
setColorMode('light');
|
||||
return;
|
||||
}
|
||||
if (!mode && lightmode) {
|
||||
setColorMode('dark');
|
||||
return;
|
||||
}
|
||||
}, [mode, lightmode, darkmode]);
|
||||
|
||||
return (
|
||||
<ColorModeContext.Provider value={{ colorMode: mode, toggleColorMode }}>
|
||||
<ColorModes colorMode={mode} />
|
||||
{children}
|
||||
</ColorModeContext.Provider>
|
||||
);
|
||||
};
|
||||
@@ -1,10 +1,9 @@
|
||||
import React from 'react';
|
||||
import { Box, Flex, useTheme } from '@blockstack/ui';
|
||||
import { Box, Flex, useTheme, space, colorGet, theme } from '@blockstack/ui';
|
||||
import { Text } from '@components/typography';
|
||||
import { space } from '@common/utils';
|
||||
import { InlineCode } from '@components/mdx';
|
||||
|
||||
export const ColorPalette = ({ color, isString = false, name, ...props }: any) => {
|
||||
const theme = useTheme();
|
||||
let colorCode = color;
|
||||
const [shade, hue] = color.split('.');
|
||||
|
||||
@@ -18,45 +17,26 @@ export const ColorPalette = ({ color, isString = false, name, ...props }: any) =
|
||||
|
||||
if (!colorCode) return null;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
flexWrap={['wrap', 'nowrap', 'nowrap']}
|
||||
p={space('base')}
|
||||
align="center"
|
||||
justify="center"
|
||||
flexDir="column"
|
||||
bg="white"
|
||||
borderRadius="12px"
|
||||
mb={space('base-loose')}
|
||||
boxShadow="mid"
|
||||
_hover={{
|
||||
boxShadow: 'high',
|
||||
cusor: 'pointer',
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<Box
|
||||
boxShadow="mid"
|
||||
flexShrink={0}
|
||||
borderRadius="100%"
|
||||
size={['32px', '32px', '64px']}
|
||||
bg={color}
|
||||
mb={space('tight')}
|
||||
/>
|
||||
const getColorCode = (col: string) => {
|
||||
if (col.includes('.')) {
|
||||
const key = col.split('.')[0];
|
||||
const number = col.split('.')[1];
|
||||
return theme.colors[key][number];
|
||||
}
|
||||
return theme.colors[col] && theme.colors[col].toString();
|
||||
};
|
||||
|
||||
<Flex flexDirection="column" justify="center" align="center" textAlign="center">
|
||||
return (
|
||||
<Box {...props}>
|
||||
<Flex align="center" justify="center" flexDirection="column" height="128px" bg={colorCode}>
|
||||
<Box>
|
||||
<Text color="ink" fontWeight={600} textTransform="capitalize">
|
||||
{name}
|
||||
</Text>
|
||||
<InlineCode>{color}</InlineCode>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text textTransform="uppercase" textStyle="caption" color="#767A85">
|
||||
{isString ? theme.colors[color] : colorCode}
|
||||
</Text>
|
||||
<InlineCode>{getColorCode(color)}</InlineCode>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -115,12 +95,5 @@ export const Colors = ({ colors = ['blue', 'ink', 'feedback', 'darken'], ...rest
|
||||
};
|
||||
|
||||
export const ColorWrapper = ({ isOdd, ...rest }: any) => (
|
||||
<Box
|
||||
flexShrink={0}
|
||||
mt={space('extra-loose')}
|
||||
pr={[isOdd ? space('extra-loose') : 0, space('base'), space('extra-loose')]}
|
||||
width={['50%', '25%', '25%']}
|
||||
minWidth="150px"
|
||||
{...rest}
|
||||
/>
|
||||
<Box flexShrink={0} mt={space('extra-loose')} width={'50%'} {...rest} />
|
||||
);
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import React from 'react';
|
||||
import { Flex, FlexProps } from '@blockstack/ui';
|
||||
import { space } from '@common/utils';
|
||||
import { Flex, FlexProps, space } from '@blockstack/ui';
|
||||
|
||||
const ContentWrapper: React.FC<FlexProps> = props => (
|
||||
<Flex
|
||||
width="100%"
|
||||
maxWidth="72ch"
|
||||
flexShrink={1}
|
||||
px={space('base')}
|
||||
pt={space(['base', 'base', 'extra-loose'])}
|
||||
mt={space('extra-loose')}
|
||||
pb={[4, 4, 6]}
|
||||
mx="auto"
|
||||
flexDirection="column"
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Flex } from '@blockstack/ui';
|
||||
import { Flex, Box, color, space } from '@blockstack/ui';
|
||||
import { SideNav } from './side-nav';
|
||||
import { Header } from './header';
|
||||
import { Main } from './main';
|
||||
@@ -8,8 +8,78 @@ import { useRouter } from 'next/router';
|
||||
import { WaffleHeader } from './waffle-header';
|
||||
import { ContentWrapper } from './content-wrapper';
|
||||
import NotFoundPage from '@pages/404';
|
||||
import { createGlobalStyle } from 'styled-components';
|
||||
import { slugify } from '@common/utils';
|
||||
import { Text } from '@components/typography';
|
||||
import { Link } from '@components/mdx';
|
||||
import { useActiveHeading } from '@common/hooks/use-active-heading';
|
||||
import { css } from '@styled-system/css';
|
||||
export const MdxOverrides = createGlobalStyle`
|
||||
|
||||
const DocsLayout: React.FC = ({ children }) => {
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
pre{
|
||||
display: inline-block;
|
||||
}
|
||||
p, ul, ol, table {
|
||||
color: ${color('text-body')};
|
||||
|
||||
a > pre {
|
||||
color: ${color('accent')} !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Item = ({ slug, label }) => {
|
||||
const [isActive, setActiveSlug] = useActiveHeading(slug);
|
||||
|
||||
return (
|
||||
<Box py={space('extra-tight')}>
|
||||
<Link
|
||||
href={`#${slug}`}
|
||||
fontSize="14px"
|
||||
color={isActive ? color('text-title') : color('text-caption')}
|
||||
fontWeight={isActive ? '600' : '400'}
|
||||
onClick={() => setActiveSlug(slug)}
|
||||
textDecoration="none"
|
||||
_hover={{
|
||||
textDecoration: 'underline',
|
||||
color: color('accent'),
|
||||
}}
|
||||
pointerEvents={isActive ? 'none' : 'unset'}
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const TableOfContents = ({ headings }: { headings?: string[] }) => {
|
||||
return (
|
||||
<Box position="relative">
|
||||
<Box
|
||||
mt="50px"
|
||||
flexShrink={0}
|
||||
display={['none', 'none', 'block', 'block']}
|
||||
minWidth={['100%', '200px', '200px']}
|
||||
position="sticky"
|
||||
top="118px"
|
||||
>
|
||||
<Box mb={space('extra-tight')}>
|
||||
<Text fontWeight="bold" fontSize="14px">
|
||||
On this page
|
||||
</Text>
|
||||
</Box>
|
||||
{headings.map((heading, index) => {
|
||||
return index > 0 ? <Item slug={slugify(heading)} label={heading} key={index} /> : null;
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const DocsLayout: React.FC<{ headings?: string[] }> = ({ children, headings }) => {
|
||||
const router = useRouter();
|
||||
let isErrorPage = false;
|
||||
|
||||
@@ -20,24 +90,65 @@ const DocsLayout: React.FC = ({ children }) => {
|
||||
}
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<Flex minHeight="100vh" flexDirection="column">
|
||||
<Header />
|
||||
<Flex minHeight="100vh">
|
||||
<Flex width="100%" flexGrow={1}>
|
||||
<SideNav display={['none', 'none', 'block']} />
|
||||
<Main
|
||||
maxWidth={['100%', '100%', 'calc(100% - 240px)']}
|
||||
width="100%"
|
||||
<Flex
|
||||
flexGrow={1}
|
||||
maxWidth={['100%', '100%', 'calc(100% - 200px)', 'calc(100% - 200px)']}
|
||||
mt={'50px'}
|
||||
flexDirection="column"
|
||||
>
|
||||
{router.pathname === '/getting-started' || router.pathname === '/' ? (
|
||||
<WaffleHeader />
|
||||
) : null}
|
||||
<ContentWrapper flexGrow={1}>{children}</ContentWrapper>
|
||||
<Main mx="unset" width={'100%'}>
|
||||
{router.pathname === '/getting-started' || router.pathname === '/' ? (
|
||||
<WaffleHeader />
|
||||
) : null}
|
||||
<Flex
|
||||
flexDirection={['column', 'column', 'row', 'row']}
|
||||
maxWidth="98ch"
|
||||
mx="auto"
|
||||
flexGrow={1}
|
||||
>
|
||||
<ContentWrapper
|
||||
width={
|
||||
headings?.length
|
||||
? ['100%', '100%', 'calc(100% - 200px)', 'calc(100% - 200px)']
|
||||
: '100%'
|
||||
}
|
||||
mx="unset"
|
||||
px="unset"
|
||||
pt="unset"
|
||||
css={css({
|
||||
'& > *:not(pre):not(ul):not(ol)': {
|
||||
px: space('extra-loose'),
|
||||
},
|
||||
'& > ul, & > ol': {
|
||||
pr: space('extra-loose'),
|
||||
pl: '64px ',
|
||||
},
|
||||
'& > pre > *:not(pre)': {
|
||||
border: 'none',
|
||||
px: space(['extra-loose', 'extra-loose', 'none', 'none']),
|
||||
},
|
||||
'& > pre': {
|
||||
px: space(['none', 'none', 'extra-loose', 'extra-loose']),
|
||||
border: 'none',
|
||||
boxShadow: 'none',
|
||||
},
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</ContentWrapper>
|
||||
{headings?.length && headings.length > 1 ? (
|
||||
<TableOfContents headings={headings} />
|
||||
) : null}
|
||||
</Flex>
|
||||
</Main>
|
||||
<Footer justifySelf="flex-end" />
|
||||
</Main>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,29 +2,29 @@ import { Box, Flex } from '@blockstack/ui';
|
||||
import { Text } from '@components/typography';
|
||||
import React from 'react';
|
||||
import { Pagination } from './pagination';
|
||||
import { Link } from './mdx-components';
|
||||
import { Link } from '@components//mdx';
|
||||
|
||||
const Footer = ({ hidePagination, ...rest }: any) => {
|
||||
return (
|
||||
<>
|
||||
{!hidePagination && <Pagination />}
|
||||
<Flex
|
||||
borderTop="1px solid"
|
||||
borderColor="var(--colors-border)"
|
||||
textStyle="body.small.medium"
|
||||
color="ink.400"
|
||||
p="base"
|
||||
{...rest}
|
||||
>
|
||||
<Box>
|
||||
<Text>Blockstack Design System</Text>
|
||||
</Box>
|
||||
<Box ml="auto">
|
||||
<Link as="a" href="https://blockstack.org">
|
||||
Blockstack PBC
|
||||
</Link>
|
||||
</Box>
|
||||
</Flex>
|
||||
{/*<Flex*/}
|
||||
{/* borderTop="1px solid"*/}
|
||||
{/* borderColor="var(--colors-border)"*/}
|
||||
{/* textStyle="body.small.medium"*/}
|
||||
{/* color="ink.400"*/}
|
||||
{/* p="base"*/}
|
||||
{/* {...rest}*/}
|
||||
{/*>*/}
|
||||
{/* <Box>*/}
|
||||
{/* <Text>Blockstack Design System</Text>*/}
|
||||
{/* </Box>*/}
|
||||
{/* <Box ml="auto">*/}
|
||||
{/* <Link as="a" href="https://blockstack.org">*/}
|
||||
{/* Blockstack PBC*/}
|
||||
{/* </Link>*/}
|
||||
{/* </Box>*/}
|
||||
{/*</Flex>*/}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Flex } from '@blockstack/ui';
|
||||
import { Flex, Box, BlockstackIcon, color, space } from '@blockstack/ui';
|
||||
import { Link, Text } from '@components/typography';
|
||||
import MenuIcon from 'mdi-react/MenuIcon';
|
||||
import CloseIcon from 'mdi-react/CloseIcon';
|
||||
@@ -8,7 +8,7 @@ import { useMobileMenuState } from '@common/hooks/use-mobile-menu';
|
||||
import { SideNav } from './side-nav';
|
||||
import GithubIcon from 'mdi-react/GithubIcon';
|
||||
import { IconButton } from '@components/icon-button';
|
||||
import { color, space } from '@common/utils';
|
||||
import { border } from '@common/utils';
|
||||
|
||||
const MenuButton = ({ ...rest }: any) => {
|
||||
const { isOpen, handleOpen, handleClose } = useMobileMenuState();
|
||||
@@ -26,17 +26,21 @@ const MenuButton = ({ ...rest }: any) => {
|
||||
);
|
||||
};
|
||||
|
||||
const GithubButton = ({ ...rest }: any) => {
|
||||
return (
|
||||
<IconButton
|
||||
as="a"
|
||||
href="https://github.com/blockstack/ux/tree/master/packages/ui#blockstack-ui"
|
||||
target="_blank"
|
||||
>
|
||||
<GithubIcon size="20px" />
|
||||
</IconButton>
|
||||
);
|
||||
};
|
||||
const GithubButton = () => (
|
||||
<IconButton
|
||||
as="a"
|
||||
href="https://github.com/blockstack/ux/tree/master/packages/ui#blockstack-ui"
|
||||
target="_blank"
|
||||
title="Find us on GitHub"
|
||||
position="relative"
|
||||
overflow="hidden"
|
||||
>
|
||||
<Text position="absolute" opacity={0} as="label">
|
||||
Find us on GitHub
|
||||
</Text>
|
||||
<GithubIcon size="20px" />
|
||||
</IconButton>
|
||||
);
|
||||
|
||||
const Header = ({ ...rest }: any) => {
|
||||
const { isOpen } = useMobileMenuState();
|
||||
@@ -45,28 +49,36 @@ const Header = ({ ...rest }: any) => {
|
||||
<>
|
||||
<Flex
|
||||
justifyContent="space-between"
|
||||
borderBottom="1px solid"
|
||||
borderColor="var(--colors-border)"
|
||||
borderBottom={border()}
|
||||
align="center"
|
||||
px="base"
|
||||
position="fixed"
|
||||
width="100%"
|
||||
bg="var(--colors-bg)"
|
||||
bg={color('bg')}
|
||||
zIndex={99}
|
||||
height="50px"
|
||||
boxShadow="mid"
|
||||
>
|
||||
<Text fontSize="14px">Blockstack Design System</Text>
|
||||
<Flex align="center">
|
||||
<Box color={color('invert')} mr={space('tight')}>
|
||||
<BlockstackIcon size="20px" />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text color={color('invert')} fontSize="14px" fontWeight={600}>
|
||||
Blockstack UI
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex align="center">
|
||||
<Link
|
||||
as="a"
|
||||
mr={space('base')}
|
||||
href="https://www.dropbox.com/work/Blockstack%20Branding"
|
||||
href="https://www.dropbox.com/sh/5uyhon1dxax4t6t/AABnh34kFRzD2TSck1wE9fmqa?dl=0"
|
||||
target="_blank"
|
||||
fontSize="12px"
|
||||
>
|
||||
Branding Assets
|
||||
</Link>
|
||||
<ColorModeButton />
|
||||
<GithubButton />
|
||||
<MenuButton />
|
||||
</Flex>
|
||||
@@ -79,6 +91,7 @@ const Header = ({ ...rest }: any) => {
|
||||
zIndex={99}
|
||||
bg={color('bg')}
|
||||
display={isOpen ? ['block', 'block', 'none'] : 'none'}
|
||||
border="unset"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { forwardRef, Ref } from 'react';
|
||||
import { Box } from '@blockstack/ui';
|
||||
import { color } from '@components/color-modes';
|
||||
import { Box, color } from '@blockstack/ui';
|
||||
import { LinkProps } from '@components/typography';
|
||||
|
||||
export const IconButton = forwardRef((props: LinkProps, ref: Ref<HTMLDivElement>) => (
|
||||
|
||||
22
packages/ui-docs/src/components/layouts/index.tsx
Normal file
22
packages/ui-docs/src/components/layouts/index.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import { DocsLayout } from '@components/docs-layout';
|
||||
import Head from 'next/head';
|
||||
export default function Layout(frontMatter) {
|
||||
const {
|
||||
title,
|
||||
description = 'The Blockstack design system, built with React and styled-system.',
|
||||
headings,
|
||||
} = frontMatter;
|
||||
|
||||
return ({ children }) => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{title} | Blockstack UI</title>
|
||||
<meta name="description" content={description} />
|
||||
</Head>
|
||||
<DocsLayout headings={headings}>{children}</DocsLayout>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Flex } from '@blockstack/ui';
|
||||
import { Box, BoxProps } from '@blockstack/ui';
|
||||
|
||||
const Main = (props: any) => (
|
||||
<Flex flexDirection="column" as="main" mx="auto" flexGrow={1} {...props} />
|
||||
);
|
||||
const Main = (props: BoxProps) => <Box mx="auto" as="main" flexGrow={1} {...props} />;
|
||||
|
||||
export { Main };
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
import { Box, Flex, FlexProps, BoxProps } from '@blockstack/ui';
|
||||
import NextLink from 'next/link';
|
||||
import React, { forwardRef, Ref } from 'react';
|
||||
import css from '@styled-system/css';
|
||||
import CodeBlock from './code-block';
|
||||
import LinkIcon from 'mdi-react/LinkVariantIcon';
|
||||
import HashtagIcon from 'mdi-react/HashtagIcon';
|
||||
import { useHover } from 'use-events';
|
||||
import Head from 'next/head';
|
||||
import { slugify } from '@common/utils';
|
||||
import { useActiveHeading } from '@common/hooks/use-active-heading';
|
||||
import { Text, Title, Pre } from '@components/typography';
|
||||
|
||||
const SmartLink = ({ href, ...rest }: { href: string }) => {
|
||||
const isExternal = href.includes('http');
|
||||
const link = <Link href={href} {...rest} />;
|
||||
|
||||
return isExternal ? (
|
||||
link
|
||||
) : (
|
||||
<NextLink href={href} passHref>
|
||||
{link}
|
||||
</NextLink>
|
||||
);
|
||||
};
|
||||
|
||||
const Table = (props: any) => (
|
||||
<Box
|
||||
color="var(--colors-text-body)"
|
||||
border="1px solic var(--colors-border)"
|
||||
as="table"
|
||||
textAlign="left"
|
||||
mt="32px"
|
||||
width="100%"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
const THead = (props: any) => {
|
||||
return (
|
||||
<Box
|
||||
as="th"
|
||||
color="var(--colors-text-caption)"
|
||||
bg="blue.50"
|
||||
p={2}
|
||||
textStyle={'body.small.medium'}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const TData = (props: any) => (
|
||||
<Box
|
||||
as="td"
|
||||
p={2}
|
||||
borderTopWidth="1px"
|
||||
borderColor="var(--colors-border)"
|
||||
textStyle="body.small"
|
||||
whiteSpace="normal"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const Link = forwardRef((props: { href: string } & BoxProps, ref: Ref<HTMLDivElement>) => (
|
||||
<Box
|
||||
as="a"
|
||||
ref={ref}
|
||||
color="var(--colors-accent)"
|
||||
cursor="pointer"
|
||||
textDecoration="underline"
|
||||
_hover={{ textDecoration: 'none' }}
|
||||
_focus={{ boxShadow: 'outline' }}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
const TextItem = (props: any) => (
|
||||
<Text
|
||||
mb="1em"
|
||||
mt="2em"
|
||||
css={{
|
||||
'&[id]': {
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
'&[id]:before': {
|
||||
display: 'block',
|
||||
height: ' 6rem',
|
||||
marginTop: '-6rem',
|
||||
visibility: 'hidden',
|
||||
content: `""`,
|
||||
},
|
||||
'&[id]:hover a': { opacity: 1 },
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<Box
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||
// @ts-ignore
|
||||
pointerEvents="auto"
|
||||
>
|
||||
{props.children}
|
||||
{props.id && (
|
||||
<Box
|
||||
aria-label="anchor"
|
||||
as="a"
|
||||
color="teal.500"
|
||||
fontWeight="normal"
|
||||
_focus={{ opacity: 1, boxShadow: 'outline' }}
|
||||
opacity={0}
|
||||
ml="0.375rem"
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||
// @ts-ignore
|
||||
href={`#${props.id}`}
|
||||
>
|
||||
#
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Text>
|
||||
);
|
||||
|
||||
const Heading = ({ as, children, id, ...rest }: FlexProps) => {
|
||||
// children should be a string, so we can get the slug of it to create anchors
|
||||
const slug = slugify(children?.toString());
|
||||
const [isActive, setActiveSlug] = useActiveHeading({ slug });
|
||||
const [hovered, bind] = useHover();
|
||||
return (
|
||||
<>
|
||||
<Flex key={slug} align="center" position="relative" {...bind} {...rest}>
|
||||
{isActive ? (
|
||||
<Box position="absolute" left="-20px" transform="translateY(1px)" color="blue.300">
|
||||
<HashtagIcon size="1rem" />
|
||||
</Box>
|
||||
) : null}
|
||||
<Box color={isActive ? 'blue' : 'ink'}>
|
||||
<Title as={as}>{children}</Title>
|
||||
</Box>
|
||||
<Link
|
||||
aria-label="anchor"
|
||||
_hover={{ cursor: 'pointer', opacity: 1 }}
|
||||
opacity={hovered ? 0.5 : 0}
|
||||
px={2}
|
||||
color="var(--colors-invert)"
|
||||
as="a"
|
||||
href={`#${slug}`}
|
||||
onClick={() => setActiveSlug(slug)}
|
||||
>
|
||||
<LinkIcon size="1rem" />
|
||||
</Link>
|
||||
<Box id={slug} transform="translateY(-82px)" />
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const H1Title = ({ children, ...rest }: any) => (
|
||||
<>
|
||||
<Heading width="100%" as="h1" {...{ ...rest, children }} />
|
||||
<Head>
|
||||
<title>{children} - Blockstack UI</title>
|
||||
</Head>
|
||||
</>
|
||||
);
|
||||
|
||||
const MDXComponents = {
|
||||
h1: (props: any) => <H1Title {...props} />,
|
||||
h2: (props: any) => <Heading width="100%" mt="extra-loose" as="h2" {...props} />,
|
||||
h3: (props: any) => <Heading width="100%" mt="extra-loose" as="h3" {...props} />,
|
||||
inlineCode: Pre,
|
||||
code: CodeBlock,
|
||||
pre: (props: any) => <Box as="pre" {...props} />,
|
||||
br: (props: any) => <Box height="24px" {...props} />,
|
||||
hr: (props: any) => (
|
||||
<Box
|
||||
as="hr"
|
||||
borderTopWidth="1px"
|
||||
borderColor="var(--colors-border)"
|
||||
my="extra-loose"
|
||||
c
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
table: Table,
|
||||
th: THead,
|
||||
td: TData,
|
||||
a: (props: any) => <SmartLink {...props} />,
|
||||
p: (props: any) => <Text as="p" mt="tight" display="block" lineHeight="24px" {...props} />,
|
||||
ul: (props: any) => <Text as="ul" pt="base" pl="base" {...props} />,
|
||||
ol: (props: any) => <Text as="ol" pt="base" pl="base" {...props} />,
|
||||
li: (props: any) => <Box as="li" color="currentColor" pb="base" {...props} />,
|
||||
blockquote: (props: any) => (
|
||||
<Box
|
||||
as="blockquote"
|
||||
display="block"
|
||||
my="base-loose"
|
||||
border="1px solid"
|
||||
borderColor="var(--colors-border)"
|
||||
borderRadius="6px"
|
||||
bg="var(--colors-bg-light)"
|
||||
px={3}
|
||||
py={3}
|
||||
>
|
||||
<Box
|
||||
css={css({
|
||||
'> *:first-of-type': {
|
||||
marginTop: 0,
|
||||
borderLeft: '4px solid',
|
||||
borderColor: 'var(--colors-accent)',
|
||||
pl: 2,
|
||||
},
|
||||
})}
|
||||
{...props}
|
||||
/>
|
||||
</Box>
|
||||
),
|
||||
};
|
||||
|
||||
export { MDXComponents };
|
||||
267
packages/ui-docs/src/components/mdx/components.tsx
Normal file
267
packages/ui-docs/src/components/mdx/components.tsx
Normal file
@@ -0,0 +1,267 @@
|
||||
import { Box, FlexProps, BoxProps, color, useClipboard, space } from '@blockstack/ui';
|
||||
import NextLink from 'next/link';
|
||||
import React, { forwardRef, Ref } from 'react';
|
||||
import LinkIcon from 'mdi-react/LinkVariantIcon';
|
||||
import HashtagIcon from 'mdi-react/HashtagIcon';
|
||||
import { useHover } from 'use-events';
|
||||
import { Tooltip } from '@components/tooltip';
|
||||
import { useActiveHeading } from '@common/hooks/use-active-heading';
|
||||
import { Text, Title } from '@components/typography';
|
||||
import { border } from '@common/utils';
|
||||
|
||||
const preProps = {
|
||||
display: 'inline-block',
|
||||
border: border(),
|
||||
borderRadius: '4px',
|
||||
transform: 'translateY(-1px)',
|
||||
fontSize: '12px',
|
||||
padding: '2px 6px',
|
||||
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.04)',
|
||||
bg: color('bg'),
|
||||
};
|
||||
export const InlineCode = (props: any) => <Text as="code" {...preProps} {...props} />;
|
||||
|
||||
export const Pre = (props: any) => <Text as="pre" {...props} />;
|
||||
|
||||
export const SmartLink = ({ href, ...rest }: { href: string }) => {
|
||||
const isExternal = href.includes('http') || href.includes('mailto');
|
||||
const link = <Link href={href} {...rest} />;
|
||||
|
||||
return isExternal ? (
|
||||
link
|
||||
) : (
|
||||
<NextLink href={href} passHref>
|
||||
{link}
|
||||
</NextLink>
|
||||
);
|
||||
};
|
||||
|
||||
export const Table = ({ children, ...rest }: any) => (
|
||||
<Box {...rest}>
|
||||
<Box
|
||||
color={color('text-body')}
|
||||
textAlign="left"
|
||||
my={space('extra-loose')}
|
||||
width="100%"
|
||||
as="table"
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
export const THead = (props: any) => {
|
||||
return (
|
||||
<Box
|
||||
as="th"
|
||||
color="var(--colors-text-caption)"
|
||||
bg="blue.50"
|
||||
p={2}
|
||||
textStyle={'body.small.medium'}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const TData = (props: any) => (
|
||||
<Box
|
||||
as="td"
|
||||
p={2}
|
||||
borderTopWidth="1px"
|
||||
borderColor="var(--colors-border)"
|
||||
textStyle="body.small"
|
||||
whiteSpace="normal"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const Link = forwardRef((props: { href: string } & BoxProps, ref: Ref<HTMLDivElement>) => (
|
||||
<Box
|
||||
as="a"
|
||||
ref={ref}
|
||||
color="var(--colors-accent)"
|
||||
cursor="pointer"
|
||||
textDecoration="underline"
|
||||
_hover={{ textDecoration: 'none' }}
|
||||
_focus={{ boxShadow: 'outline' }}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
export const TextItem = (props: any) => (
|
||||
<Text
|
||||
mb="1em"
|
||||
mt="2em"
|
||||
css={{
|
||||
'&[id]': {
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
'&[id]:before': {
|
||||
display: 'block',
|
||||
height: ' 6rem',
|
||||
marginTop: '-6rem',
|
||||
visibility: 'hidden',
|
||||
content: `""`,
|
||||
},
|
||||
'&[id]:hover a': { opacity: 1 },
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<Box
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||
// @ts-ignore
|
||||
pointerEvents="auto"
|
||||
>
|
||||
{props.children}
|
||||
{props.id && (
|
||||
<Box
|
||||
aria-label="anchor"
|
||||
as="a"
|
||||
color="teal.500"
|
||||
fontWeight="normal"
|
||||
_focus={{ opacity: 1, boxShadow: 'outline' }}
|
||||
opacity={0}
|
||||
ml="0.375rem"
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
||||
// @ts-ignore
|
||||
href={`#${props.id}`}
|
||||
>
|
||||
#
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Text>
|
||||
);
|
||||
|
||||
const baseStyles = {
|
||||
letterSpacing: '-0.01em',
|
||||
fontFeatureSettings: `'ss01' on`,
|
||||
};
|
||||
|
||||
const h1 = {
|
||||
fontSize: '36px',
|
||||
lineHeight: '52px',
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const h2 = {
|
||||
fontSize: '24px',
|
||||
lineHeight: '40px',
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
const h3 = {
|
||||
fontSize: '18px',
|
||||
lineHeight: '32px',
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const h4 = {
|
||||
fontSize: '18px',
|
||||
lineHeight: '32px',
|
||||
};
|
||||
const h5 = {
|
||||
fontSize: '16px',
|
||||
lineHeight: '28px',
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const h6 = {
|
||||
fontSize: '14px',
|
||||
lineHeight: '28px',
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const headings = {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
};
|
||||
|
||||
const getHeadingStyles = (as: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6') => {
|
||||
return {
|
||||
...baseStyles,
|
||||
...headings[as],
|
||||
};
|
||||
};
|
||||
|
||||
const LinkButton = React.memo(({ link, onClick, ...rest }: BoxProps & { link: string }) => {
|
||||
const { onCopy } = useClipboard(link);
|
||||
const label = 'Copy url';
|
||||
return (
|
||||
<Box
|
||||
as="span"
|
||||
display={['none', 'none', 'block', 'block']}
|
||||
onClick={e => {
|
||||
onClick && onClick(e);
|
||||
onCopy?.();
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
<Tooltip label={label} aria-label={label}>
|
||||
<Link
|
||||
opacity={0.5}
|
||||
_hover={{
|
||||
opacity: 1,
|
||||
}}
|
||||
color={color('text-title')}
|
||||
as="a"
|
||||
href={link}
|
||||
display="block"
|
||||
ml={space('tight')}
|
||||
>
|
||||
<LinkIcon size="1rem" />
|
||||
</Link>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
// this is to adjust the offset of where the page scrolls to when an anchor is present
|
||||
const AnchorOffset = ({ id }: BoxProps) => (
|
||||
<Box
|
||||
as="span"
|
||||
display="block"
|
||||
position="absolute"
|
||||
style={{ userSelect: 'none', pointerEvents: 'none' }}
|
||||
top="-120px"
|
||||
id={id}
|
||||
/>
|
||||
);
|
||||
|
||||
const Hashtag = () => (
|
||||
<Box position="absolute" as="span" left="10px" color={color('text-caption')}>
|
||||
<HashtagIcon size="1rem" />
|
||||
</Box>
|
||||
);
|
||||
|
||||
export const Heading = ({ as, children, id, ...rest }: FlexProps) => {
|
||||
const [isActive, setActiveSlug, url] = useActiveHeading(id);
|
||||
const [isHovered, bind] = useHover();
|
||||
|
||||
const link = `#${id}`;
|
||||
|
||||
const handleLinkClick = () => {
|
||||
setActiveSlug(id);
|
||||
};
|
||||
|
||||
return (
|
||||
<Title
|
||||
as={as}
|
||||
color={isActive ? color('accent') : color('text-title')}
|
||||
display="flex"
|
||||
style={{ alignItems: 'center' }}
|
||||
position="relative"
|
||||
{...bind}
|
||||
{...getHeadingStyles(as as any)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
<AnchorOffset id={id} />
|
||||
{isActive && <Hashtag />}
|
||||
<LinkButton opacity={isHovered ? 1 : 0} onClick={handleLinkClick} link={link} />
|
||||
</Title>
|
||||
);
|
||||
};
|
||||
2
packages/ui-docs/src/components/mdx/index.tsx
Normal file
2
packages/ui-docs/src/components/mdx/index.tsx
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './mdx-components';
|
||||
export * from './components';
|
||||
93
packages/ui-docs/src/components/mdx/mdx-components.tsx
Normal file
93
packages/ui-docs/src/components/mdx/mdx-components.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import React from 'react';
|
||||
import { Box, space, BoxProps, color } from '@blockstack/ui';
|
||||
import css from '@styled-system/css';
|
||||
import CodeBlock from '../code-block';
|
||||
import {
|
||||
Heading,
|
||||
Pre,
|
||||
THead,
|
||||
SmartLink,
|
||||
TData,
|
||||
Table,
|
||||
InlineCode,
|
||||
} from '@components/mdx/components';
|
||||
import { Text } from '@components/typography';
|
||||
import { border, onlyText, slugify } from '@common/utils';
|
||||
|
||||
const BaseHeading: React.FC<BoxProps> = React.memo(props => (
|
||||
<Heading width="100%" mt={space('base-loose')} mb={space('tight')} {...props} />
|
||||
));
|
||||
|
||||
const H1: React.FC<BoxProps> = props => <BaseHeading as="h1" mb={space('base-tight')} {...props} />;
|
||||
const H2: React.FC<BoxProps> = props => <BaseHeading as="h2" {...props} />;
|
||||
const H3: React.FC<BoxProps> = props => <BaseHeading as="h3" {...props} />;
|
||||
const H4: React.FC<BoxProps> = props => <BaseHeading as="h4" {...props} />;
|
||||
const H5: React.FC<BoxProps> = props => <BaseHeading as="h5" {...props} />;
|
||||
const H6: React.FC<BoxProps> = props => <BaseHeading as="h6" {...props} />;
|
||||
|
||||
const Br: React.FC<BoxProps> = props => <Box height="24px" {...props} />;
|
||||
const Hr: React.FC<BoxProps> = props => (
|
||||
<Box
|
||||
as="hr"
|
||||
borderTopWidth="1px"
|
||||
borderColor={color('border')}
|
||||
my={space('extra-loose')}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
const P: React.FC<BoxProps> = props => <Text display="block" as="p" {...props} />;
|
||||
const Ol: React.FC<BoxProps> = props => (
|
||||
<Box pt={space('base')} pl={space('base')} as="ol" {...props} />
|
||||
);
|
||||
const Ul: React.FC<BoxProps> = props => (
|
||||
<Box pt={space('base')} pl={space('base-loose')} mb={space('base')} as="ul" {...props} />
|
||||
);
|
||||
const Li: React.FC<BoxProps> = props => <Box as="li" pb={space('tight')} {...props} />;
|
||||
const BlockQuote: React.FC<BoxProps> = ({ children, ...rest }) => (
|
||||
<Box display="block" mt={space('base-tight')} mb={space('base-loose')} {...rest}>
|
||||
<Box
|
||||
as="blockquote"
|
||||
border="1px solid"
|
||||
css={css({
|
||||
border: border(),
|
||||
borderRadius: 'md',
|
||||
boxShadow: 'mid',
|
||||
py: space('base-tight'),
|
||||
px: space('base'),
|
||||
bg: color('bg-light'),
|
||||
'> *:first-of-type': {
|
||||
marginTop: 0,
|
||||
borderLeft: '4px solid',
|
||||
borderColor: color('accent'),
|
||||
pl: space('base'),
|
||||
},
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
export const MDXComponents = {
|
||||
h1: H1,
|
||||
h2: H2,
|
||||
h3: H3,
|
||||
h4: H4,
|
||||
h5: H5,
|
||||
h6: H6,
|
||||
inlineCode: InlineCode,
|
||||
code: CodeBlock,
|
||||
pre: Pre,
|
||||
br: Br,
|
||||
hr: Hr,
|
||||
table: Table,
|
||||
th: THead,
|
||||
td: TData,
|
||||
a: SmartLink,
|
||||
p: P,
|
||||
ul: Ul,
|
||||
ol: Ol,
|
||||
li: Li,
|
||||
blockquote: BlockQuote,
|
||||
};
|
||||
@@ -1,13 +1,12 @@
|
||||
import { Box, Flex } from '@blockstack/ui';
|
||||
import { Box, Flex, FlexProps, color, space, BoxProps } from '@blockstack/ui';
|
||||
import { Caption, Text } from '@components/typography';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
import { routes } from '@common/routes';
|
||||
import { slugify, space } from '@common/utils';
|
||||
import { routes, paginationRoutes } from '@common/routes';
|
||||
import { slugify } from '@common/utils';
|
||||
import Link from 'next/link';
|
||||
import { useHover } from 'use-events';
|
||||
import { ContentWrapper } from '@components/content-wrapper';
|
||||
import { color } from '@components/color-modes';
|
||||
|
||||
const transition = 'all 0.2s cubic-bezier(0.23, 1, 0.32, 1)';
|
||||
|
||||
@@ -29,7 +28,7 @@ const Previous = ({ isHovered }: { isHovered: boolean }) => {
|
||||
};
|
||||
const Next = ({ isHovered }: { isHovered: boolean }) => {
|
||||
return (
|
||||
<Flex>
|
||||
<Flex justifyContent="flex-end">
|
||||
<Box>
|
||||
<Caption>Next</Caption>
|
||||
</Box>
|
||||
@@ -44,13 +43,13 @@ const Next = ({ isHovered }: { isHovered: boolean }) => {
|
||||
);
|
||||
};
|
||||
|
||||
interface PaginationLinkProps {
|
||||
interface PaginationLinkProps extends BoxProps {
|
||||
slug: string;
|
||||
label: string;
|
||||
prev?: boolean;
|
||||
}
|
||||
|
||||
const PaginationLink = ({ slug, label, prev }: PaginationLinkProps) => {
|
||||
const PaginationLink = ({ slug, label, prev, ...rest }: PaginationLinkProps) => {
|
||||
const [isHovered, bindHover] = useHover();
|
||||
return (
|
||||
<Link href={`/${slug}`} passHref>
|
||||
@@ -60,57 +59,108 @@ const PaginationLink = ({ slug, label, prev }: PaginationLinkProps) => {
|
||||
color: 'var(--colors-accent)',
|
||||
}}
|
||||
as="a"
|
||||
textAlign="left"
|
||||
py={space('extra-loose')}
|
||||
display="block"
|
||||
flexGrow={1}
|
||||
{...bindHover}
|
||||
{...rest}
|
||||
>
|
||||
<Caption display="block">
|
||||
<Caption textAlign={prev ? 'left' : 'right'} display="block">
|
||||
{prev ? <Previous isHovered={isHovered} /> : <Next isHovered={isHovered} />}
|
||||
</Caption>
|
||||
<Text display="block" textStyle="display.large" color="currentColor">
|
||||
<Text
|
||||
textAlign={prev ? 'left' : 'right'}
|
||||
display="block"
|
||||
textStyle="display.large"
|
||||
color="currentColor"
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
</Box>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
const Pagination = () => {
|
||||
const router = useRouter();
|
||||
const routesAsSlugs = routes.map(r => slugify(r));
|
||||
const _route = router.asPath.replace('/', '');
|
||||
const section = _route.includes('/') ? _route.split('/')[0] : undefined;
|
||||
const __route = _route.includes('/') ? _route.split('/')[1] : _route;
|
||||
const route = __route === '' ? 'getting-started' : __route;
|
||||
const index = routesAsSlugs.indexOf(route);
|
||||
const previous = routes[index - 1];
|
||||
const previousSlug = section
|
||||
? section + '/' + routesAsSlugs[index - 1]
|
||||
: routesAsSlugs[index - 1];
|
||||
const next = routes[index + 1];
|
||||
const nextSlug = section ? section + '/' + routesAsSlugs[index + 1] : routesAsSlugs[index + 1];
|
||||
return (
|
||||
<ContentWrapper
|
||||
borderTop="1px solid"
|
||||
borderColor={color('border')}
|
||||
flexDirection="row"
|
||||
alignItems="baseline"
|
||||
justify="space-between"
|
||||
pt="unset"
|
||||
pb="unset"
|
||||
>
|
||||
{previous && (
|
||||
<Box textAlign="left">
|
||||
<PaginationLink slug={previousSlug} label={previous} prev />
|
||||
</Box>
|
||||
)}
|
||||
{next && (
|
||||
<Box textAlign="right" ml={!previous ? 'auto' : undefined}>
|
||||
<PaginationLink slug={nextSlug} label={next} />
|
||||
</Box>
|
||||
)}
|
||||
</ContentWrapper>
|
||||
);
|
||||
|
||||
const getRouteWithSection = (route: string) => {
|
||||
let section = '';
|
||||
const keys = Object.keys(paginationRoutes);
|
||||
keys.forEach(key => {
|
||||
const routes = paginationRoutes[key].map(r => slugify(r));
|
||||
if (routes.length && routes.find(r => r === route) && key !== 'top' && key !== 'bottom') {
|
||||
section = key + '/';
|
||||
}
|
||||
});
|
||||
return section + route;
|
||||
};
|
||||
|
||||
export { Pagination };
|
||||
const usePagination = () => {
|
||||
const router = useRouter();
|
||||
const [state, setState] = React.useState({
|
||||
previous: undefined,
|
||||
previousSlug: undefined,
|
||||
next: undefined,
|
||||
nextSlug: undefined,
|
||||
});
|
||||
React.useEffect(() => {
|
||||
const routesAsSlugs = routes.map(r => slugify(r));
|
||||
const _route = router.asPath.replace('/', '');
|
||||
const __route = _route.includes('/') ? _route.split('/')[1] : _route;
|
||||
const route = __route === '' ? 'getting-started' : __route;
|
||||
const index = routesAsSlugs.indexOf(route);
|
||||
const previous = routes[index - 1];
|
||||
const previousSlug = getRouteWithSection(routesAsSlugs[index - 1]);
|
||||
const next = routes[index + 1];
|
||||
const nextSlug = getRouteWithSection(routesAsSlugs[index + 1]);
|
||||
|
||||
setState({
|
||||
previous,
|
||||
previousSlug,
|
||||
next,
|
||||
nextSlug,
|
||||
});
|
||||
}, [router.asPath]);
|
||||
|
||||
const { previous, previousSlug, next, nextSlug } = state;
|
||||
|
||||
return [
|
||||
{ label: previous, path: previousSlug, condition: !!previous },
|
||||
{
|
||||
label: next,
|
||||
path: nextSlug,
|
||||
condition: !!next,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export const Pagination: React.FC<FlexProps> = props => {
|
||||
const buttons = usePagination();
|
||||
return (
|
||||
<Box maxWidth="100%" {...props}>
|
||||
<ContentWrapper
|
||||
borderTop="1px solid"
|
||||
borderColor={color('border')}
|
||||
flexDirection="row"
|
||||
alignItems="baseline"
|
||||
justify="space-between"
|
||||
pt="unset"
|
||||
pb="unset"
|
||||
width="100%"
|
||||
maxWidth="98ch"
|
||||
mx="auto"
|
||||
px={space('extra-loose')}
|
||||
>
|
||||
{buttons.map((button, index) =>
|
||||
button.condition ? (
|
||||
<PaginationLink
|
||||
textAlign={index === 0 ? 'left' : 'right'}
|
||||
slug={button.path}
|
||||
label={button.label}
|
||||
prev={index === 0}
|
||||
key={index}
|
||||
/>
|
||||
) : null
|
||||
)}
|
||||
</ContentWrapper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
85
packages/ui-docs/src/components/progress-bar.tsx
Normal file
85
packages/ui-docs/src/components/progress-bar.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import * as React from 'react';
|
||||
import Router from 'next/router';
|
||||
import NProgress from 'nprogress';
|
||||
import { createGlobalStyle, css } from 'styled-components';
|
||||
|
||||
const styles = css`
|
||||
/* Make clicks pass-through */
|
||||
#nprogress {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#nprogress .bar {
|
||||
background: var(--colors-invert);
|
||||
|
||||
position: fixed;
|
||||
z-index: 999999999;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
/* Fancy blur effect */
|
||||
#nprogress .peg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Remove these to get rid of the spinner */
|
||||
#nprogress .spinner {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nprogress-custom-parent {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nprogress-custom-parent #nprogress .spinner,
|
||||
.nprogress-custom-parent #nprogress .bar {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@-webkit-keyframes nprogress-spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes nprogress-spinner {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
`;
|
||||
const ProgressBarStyles = createGlobalStyle`${styles}`;
|
||||
|
||||
export const useProgressBar = () => {
|
||||
const { start, done } = NProgress;
|
||||
|
||||
return {
|
||||
start,
|
||||
done,
|
||||
};
|
||||
};
|
||||
|
||||
export const ProgressBar = () => {
|
||||
React.useEffect(() => {
|
||||
Router.events.on('routeChangeStart', url => {
|
||||
NProgress.start();
|
||||
});
|
||||
Router.events.on('routeChangeComplete', () => NProgress.done());
|
||||
Router.events.on('routeChangeError', () => NProgress.done());
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<ProgressBarStyles />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@blockstack/ui';
|
||||
import { slugify } from '@common/utils';
|
||||
import { Box, color, space } from '@blockstack/ui';
|
||||
import { border, slugify } from '@common/utils';
|
||||
import { Text, Caption } from '@components/typography';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
@@ -14,7 +14,7 @@ const sections = [
|
||||
{ links: bottomNavLinks },
|
||||
];
|
||||
|
||||
const Wrapper = ({ width = '240px', children, ...rest }: any) => (
|
||||
const Wrapper = ({ width = '200px', children, ...rest }: any) => (
|
||||
<Box
|
||||
position="relative"
|
||||
width={width}
|
||||
@@ -27,12 +27,11 @@ const Wrapper = ({ width = '240px', children, ...rest }: any) => (
|
||||
>
|
||||
<Box
|
||||
position="fixed"
|
||||
borderRight={['unset', '1px solid', '1px solid']}
|
||||
borderColor={['unset', 'var(--colors-border)', 'var(--colors-border)']}
|
||||
top={50}
|
||||
width={width}
|
||||
height="calc(100vh - 50px)"
|
||||
overflow="auto"
|
||||
borderRight={['none', border(), border()]}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
@@ -51,9 +50,10 @@ const LinkItem = React.forwardRef(({ isActive, ...rest }: any, ref) => (
|
||||
}
|
||||
: null
|
||||
}
|
||||
textStyle="body.small"
|
||||
color={isActive ? 'var(--colors-text-title)' : 'var(--colors-text-body)'}
|
||||
color={isActive ? color('accent') : color('text-body')}
|
||||
fontWeight={isActive ? 'semibold' : 'normal'}
|
||||
fontSize="14px"
|
||||
lineHeight="18px"
|
||||
as="a"
|
||||
{...rest}
|
||||
/>
|
||||
@@ -68,9 +68,9 @@ const Links = ({ links, prefix = '', ...rest }: any) => {
|
||||
const isActive =
|
||||
router.pathname.includes(slug) || (router.pathname === '/' && slug === 'getting-started');
|
||||
return (
|
||||
<Box px="base" py="extra-tight" key={linkKey} onClick={handleClose} {...rest}>
|
||||
<Link href={`/${prefix + slug}`}>
|
||||
<LinkItem isActive={isActive} href={`/${prefix + slug}`}>
|
||||
<Box width="100%" px="base" py="1px" key={linkKey} onClick={handleClose} {...rest}>
|
||||
<Link href={`/${prefix + slug}`} passHref>
|
||||
<LinkItem width="100%" isActive={isActive} href={`/${prefix + slug}`}>
|
||||
{link}
|
||||
</LinkItem>
|
||||
</Link>
|
||||
@@ -80,26 +80,15 @@ const Links = ({ links, prefix = '', ...rest }: any) => {
|
||||
};
|
||||
|
||||
const SectionTitle = ({ children, textStyles, ...rest }: any) => (
|
||||
<Box px={4} pb="tight" {...rest}>
|
||||
<Caption
|
||||
fontWeight="600"
|
||||
fontSize="10px"
|
||||
letterSpacing="1px"
|
||||
textTransform="uppercase"
|
||||
{...textStyles}
|
||||
>
|
||||
<Box px={space('base')} pb={space('extra-tight')} {...rest}>
|
||||
<Caption fontSize="14px" fontWeight="600" color={color('text-title')} {...textStyles}>
|
||||
{children}
|
||||
</Caption>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const Section = ({ section, isLast, ...rest }: any) => (
|
||||
<Box
|
||||
borderBottom="1px solid"
|
||||
borderColor={isLast ? 'transparent' : 'var(--colors-border)'}
|
||||
py="base"
|
||||
{...rest}
|
||||
>
|
||||
<Box width="100%" pt={space('base')} {...rest}>
|
||||
{section.title ? <SectionTitle>{section.title}</SectionTitle> : null}
|
||||
<Links prefix={section.prefix} links={section.links} />
|
||||
</Box>
|
||||
|
||||
41
packages/ui-docs/src/components/tooltip.tsx
Normal file
41
packages/ui-docs/src/components/tooltip.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import { color } from '@blockstack/ui';
|
||||
import { useTooltip, TooltipPopup } from '@reach/tooltip';
|
||||
|
||||
const centered = (triggerRect: any, tooltipRect: any) => {
|
||||
if (typeof window === 'undefined') return { left: 0, top: 0 };
|
||||
const triggerCenter = triggerRect.left + triggerRect.width / 2;
|
||||
const left = triggerCenter - tooltipRect.width / 2;
|
||||
const maxLeft = window.innerWidth - tooltipRect.width - 2;
|
||||
return {
|
||||
left: Math.min(Math.max(2, left), maxLeft) + window.scrollX,
|
||||
top: triggerRect.bottom + 8 + window.scrollY,
|
||||
};
|
||||
};
|
||||
|
||||
export const Tooltip = ({ children, label, 'aria-label': ariaLabel }: any) => {
|
||||
const [trigger, tooltip] = useTooltip();
|
||||
|
||||
const { onMouseDown, ...triggerProps } = trigger;
|
||||
return (
|
||||
<>
|
||||
{React.cloneElement(children, triggerProps)}
|
||||
<TooltipPopup
|
||||
{...tooltip}
|
||||
label={label}
|
||||
aria-label={ariaLabel}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
zIndex: 99999,
|
||||
background: color('invert'),
|
||||
color: color('bg'),
|
||||
border: 'none',
|
||||
borderRadius: '3px',
|
||||
padding: '0.5em 1em',
|
||||
fontSize: '12px',
|
||||
}}
|
||||
position={centered}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Text as BaseText, BoxProps } from '@blockstack/ui';
|
||||
import { color } from '@components/color-modes';
|
||||
import { Text as BaseText, BoxProps, color } from '@blockstack/ui';
|
||||
import { border } from '@common/utils';
|
||||
|
||||
export const Text = React.forwardRef((props: BoxProps, ref) => (
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import React from 'react';
|
||||
import { View, PropTypes } from 'react-view';
|
||||
import { Button } from '@blockstack/ui';
|
||||
|
||||
export const ButtonView = () => (
|
||||
<View
|
||||
componentName="Button"
|
||||
props={{
|
||||
children: {
|
||||
value: 'Hello world',
|
||||
type: PropTypes.ReactNode,
|
||||
description: 'Visible label.',
|
||||
},
|
||||
loadingText: {
|
||||
value: 'Loading...',
|
||||
type: PropTypes.String,
|
||||
description: 'The message to be shown when the button is loading.',
|
||||
},
|
||||
onClick: {
|
||||
value: '() => alert("click")',
|
||||
type: PropTypes.Function,
|
||||
description: 'Function called when button is clicked.',
|
||||
},
|
||||
isDisabled: {
|
||||
value: false,
|
||||
type: PropTypes.Boolean,
|
||||
description: 'Indicates that the button is disabled',
|
||||
},
|
||||
isLoading: {
|
||||
value: false,
|
||||
type: PropTypes.Boolean,
|
||||
description: 'Enables the loading state of the button.',
|
||||
},
|
||||
}}
|
||||
scope={{
|
||||
Button,
|
||||
}}
|
||||
imports={{
|
||||
'@blockstack/ui': {
|
||||
named: ['Button'],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -1 +0,0 @@
|
||||
export * from './button';
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Flex } from '@blockstack/ui';
|
||||
import { Flex, space } from '@blockstack/ui';
|
||||
import { Text } from '@components/typography';
|
||||
import { ContentWrapper } from './content-wrapper';
|
||||
import { useAppState } from '@common/hooks/use-app-state';
|
||||
@@ -13,9 +13,10 @@ export const WaffleHeader = () => {
|
||||
minHeight={['unset', 'unset', '300px']}
|
||||
bg="ink"
|
||||
borderBottom="1px solid var(--colors-border)"
|
||||
pb={space('extra-loose')}
|
||||
>
|
||||
<ContentWrapper>
|
||||
<Text color="white" as="h1" display="block" fontSize={[5, 5, 7]}>
|
||||
<ContentWrapper maxWidth="98ch" width="100%" px={space('extra-loose')}>
|
||||
<Text color="white" as="h1" display="block" fontSize="42px">
|
||||
Blockstack UI
|
||||
</Text>
|
||||
<Text pt={1} display="block" as="h2" fontSize={[3, 3, 4]} color="white">
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import { Flex, Box, Stack, FlexProps } from '@blockstack/ui';
|
||||
import { Flex, Box, Stack, FlexProps, color, space } from '@blockstack/ui';
|
||||
import { ContentWrapper } from '@components/content-wrapper';
|
||||
import { Text, Title, Link } from '@components/typography';
|
||||
import { color } from '@components/color-modes';
|
||||
import FileDocumentEditOutlineIcon from 'mdi-react/FileDocumentEditOutlineIcon';
|
||||
import { border, space } from '@common/utils';
|
||||
import { border } from '@common/utils';
|
||||
import { DocsLayout } from '@components/docs-layout';
|
||||
import Head from 'next/head';
|
||||
|
||||
const toPx = (number: number): string => `${number}px`;
|
||||
|
||||
@@ -44,25 +45,37 @@ const Graphic = (props: FlexProps) => {
|
||||
|
||||
const NotFoundPage = () => {
|
||||
return (
|
||||
<ContentWrapper align="center" justify="center" flexGrow={1}>
|
||||
<Stack spacing={space('loose')} pb={space('100px')}>
|
||||
<Box>
|
||||
<Graphic mb={space('base')} />
|
||||
<Box textAlign="center">
|
||||
<Title as="h1">We're still working on this</Title>
|
||||
<DocsLayout>
|
||||
<Head>
|
||||
<title>Page not found | Blockstack UI</title>
|
||||
</Head>
|
||||
<ContentWrapper align="center" justify="center" flexGrow={1}>
|
||||
<Stack spacing={space('loose')} pb={space('100px')}>
|
||||
<Box>
|
||||
<Graphic mb={space('base')} />
|
||||
<Box textAlign="center">
|
||||
<Title as="h1">We're still working on this</Title>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box mx="auto" maxWidth="40ch" textAlign="center">
|
||||
<Text>
|
||||
The docs for the Blockstack UI library are still pretty new, looks like there's nothing
|
||||
here yet.
|
||||
</Text>
|
||||
<Box mt={space('base')}>
|
||||
<Link color={color('accent')}>Want to contribute?</Link>
|
||||
<Box mx="auto" maxWidth="40ch" textAlign="center">
|
||||
<Text>
|
||||
The docs for the Blockstack UI library are still pretty new, looks like there's
|
||||
nothing here yet.
|
||||
</Text>
|
||||
<Box mt={space('base')}>
|
||||
<Link
|
||||
as="a"
|
||||
color={color('accent')}
|
||||
href="https://github.com/blockstack/ux"
|
||||
target="_blank"
|
||||
>
|
||||
Want to contribute?
|
||||
</Link>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack>
|
||||
</ContentWrapper>
|
||||
</Stack>
|
||||
</ContentWrapper>
|
||||
</DocsLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,34 +1,45 @@
|
||||
import React from 'react';
|
||||
import App, { AppContext } from 'next/app';
|
||||
import { CSSReset, ThemeProvider, theme } from '@blockstack/ui';
|
||||
import { CSSReset, ThemeProvider, theme, ColorModeProvider } from '@blockstack/ui';
|
||||
import { MDXProvider } from '@mdx-js/react';
|
||||
import { MDXComponents } from '@components/mdx-components';
|
||||
import { DocsLayout } from '@components/docs-layout';
|
||||
import { MDXComponents } from '@components/mdx';
|
||||
import { AppStateProvider } from '@components/app-state';
|
||||
import { ColorModeProvider } from '@components/color-modes';
|
||||
import { parseCookies } from 'nookies';
|
||||
import { MdxOverrides } from '@components/docs-layout';
|
||||
import { ProgressBar } from '@components/progress-bar';
|
||||
import engine from 'store/src/store-engine';
|
||||
import cookieStorage from 'store/storages/cookieStorage';
|
||||
import 'typeface-inter';
|
||||
import 'typeface-fira-code';
|
||||
|
||||
const AppWrapper = ({ children, version }: any) => (
|
||||
const COLOR_MODE_COOKIE = 'color_mode';
|
||||
|
||||
const cookieSetter = engine.createStore([cookieStorage]);
|
||||
|
||||
const handleColorModeChange = (mode: string) => cookieSetter.set(COLOR_MODE_COOKIE, mode);
|
||||
|
||||
const AppWrapper = ({ children, colorMode = 'light', version }: any) => (
|
||||
<ThemeProvider theme={theme}>
|
||||
<ColorModeProvider>
|
||||
<MdxOverrides />
|
||||
<ColorModeProvider onChange={handleColorModeChange} colorMode={colorMode}>
|
||||
<ProgressBar />
|
||||
<MDXProvider components={MDXComponents}>
|
||||
<AppStateProvider version={version}>
|
||||
<DocsLayout>
|
||||
<CSSReset />
|
||||
{children}
|
||||
</DocsLayout>
|
||||
<CSSReset />
|
||||
{children}
|
||||
</AppStateProvider>
|
||||
</MDXProvider>
|
||||
</ColorModeProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
const MyApp = ({ Component, pageProps, ...rest }: any) => {
|
||||
const MyApp = ({ Component, pageProps, colorMode, ...rest }: any) => {
|
||||
const [version, setVersion] = React.useState(pageProps?.version);
|
||||
if (!version && pageProps?.version) {
|
||||
setVersion(pageProps?.version);
|
||||
}
|
||||
return (
|
||||
<AppWrapper version={version}>
|
||||
<AppWrapper colorMode={colorMode} version={version}>
|
||||
<Component {...pageProps} />
|
||||
</AppWrapper>
|
||||
);
|
||||
@@ -36,6 +47,12 @@ const MyApp = ({ Component, pageProps, ...rest }: any) => {
|
||||
|
||||
MyApp.getInitialProps = async (appContext: AppContext) => {
|
||||
const appProps = await App.getInitialProps(appContext);
|
||||
const cookies = parseCookies(appContext.ctx);
|
||||
let colorMode = undefined;
|
||||
|
||||
if (cookies) {
|
||||
colorMode = cookies[COLOR_MODE_COOKIE] ? JSON.parse(cookies[COLOR_MODE_COOKIE]) : undefined;
|
||||
}
|
||||
if (appContext.ctx.res) {
|
||||
try {
|
||||
const res = await fetch('https://registry.npmjs.org/@blockstack/ui');
|
||||
@@ -47,13 +64,14 @@ MyApp.getInitialProps = async (appContext: AppContext) => {
|
||||
...appProps.pageProps,
|
||||
version,
|
||||
},
|
||||
colorMode,
|
||||
};
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
return appProps;
|
||||
return { ...appProps, colorMode };
|
||||
};
|
||||
|
||||
export default MyApp;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Document, { DocumentContext } from 'next/document';
|
||||
import Document, { DocumentContext, Html, Head, Main, NextScript } from 'next/document';
|
||||
|
||||
import { ServerStyleSheet } from 'styled-components';
|
||||
|
||||
@@ -27,4 +27,16 @@ export default class MyDocument extends Document<any> {
|
||||
sheet.seal();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
---
|
||||
title: 'Getting started'
|
||||
---
|
||||
|
||||
# Getting Started
|
||||
|
||||
First we need to install `@blockstack/ui` and its various dependencies.
|
||||
|
||||
```bash
|
||||
```
|
||||
yarn add @blockstack/ui styled-components babel-plugin-styled-components
|
||||
```
|
||||
|
||||
@@ -44,7 +48,7 @@ const App({ children }) => {
|
||||
}
|
||||
```
|
||||
|
||||
## Contributing
|
||||
### Contributing
|
||||
|
||||
Please see our [contribution guidelines](/contributing) to learn how you can
|
||||
contribute to this project.
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
---
|
||||
title: 'Box'
|
||||
---
|
||||
|
||||
# Box
|
||||
|
||||
Box is the base primitive component on top of which all other components
|
||||
are built. By default, it renders a `div` element. When building any new
|
||||
layout elements or components, you'll almost always go for a `Box` to
|
||||
start with. There are some other components that are lumped into the
|
||||
start with. There are some other components that are in the same
|
||||
category of "primitives": `Flex`, `Grid`, `Text`.
|
||||
|
||||
## Import
|
||||
@@ -15,9 +19,9 @@ import { Box } from '@blockstack/ui';
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
<Box w="100%" p={4} color="white" bg="salmon">
|
||||
<Box w="100%" p={space('base')} color="white" bg="salmon">
|
||||
Box is the base element all others are created from.{' '}
|
||||
<Box as="span" bg="white" color="ink.900">
|
||||
<Box as="span" bg="white" color={themeColor('ink.900')}>
|
||||
It can also be inline.
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -29,19 +33,25 @@ You can use the `as` prop to change which element is rendered. You can pass a st
|
||||
|
||||
```jsx
|
||||
<>
|
||||
<Box as="button" rounded="md" bg="salmon" color="white" px={4} h={8}>
|
||||
{/* Box as a button! */}
|
||||
<Box as="button" rounded="md" bg="salmon" color="white" px={space('base')} height={12}>
|
||||
Button
|
||||
</Box>
|
||||
{/* Box as Flex for recreating a button */}
|
||||
<Box
|
||||
mt={5}
|
||||
as={Flex}
|
||||
align="center"
|
||||
justify="center"
|
||||
rounded="md"
|
||||
bg="salmon"
|
||||
bg={themeColor('blue')}
|
||||
_hover={{
|
||||
bg: themeColor('blue.hover'),
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
color="white"
|
||||
px={4}
|
||||
h={8}
|
||||
px={space('base')}
|
||||
mt={space('base')}
|
||||
height="64px"
|
||||
as={Flex}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
Button
|
||||
</Box>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { ButtonView } from '../../components/views';
|
||||
---
|
||||
title: 'Button'
|
||||
---
|
||||
|
||||
# Button
|
||||
|
||||
@@ -22,7 +24,7 @@ import { Button } from '@blockstack/ui';
|
||||
Use the `size` prop to change the size of the button. You can set the value to `sm`, `md`, or `lg`. Default value is `md`.
|
||||
|
||||
```jsx
|
||||
<ButtonGroup spacing={4}>
|
||||
<ButtonGroup spacing={space('base')}>
|
||||
<Button size="sm">Button</Button>
|
||||
<Button size="md">Button</Button>
|
||||
<Button size="lg">Button</Button>
|
||||
@@ -35,7 +37,7 @@ Use the `mode` prop to change the visual style of the Button. You can set the
|
||||
value to `primary`, `secondary`, or `tertiary`.
|
||||
|
||||
```jsx
|
||||
<ButtonGroup spacing={4}>
|
||||
<ButtonGroup spacing={space('base')}>
|
||||
<Button mode="primary">Button</Button>
|
||||
<Button mode="secondary">Button</Button>
|
||||
<Button mode="tertiary">Button</Button>
|
||||
@@ -50,7 +52,7 @@ spinner and the loading text. Otherwise, the button will take the width of the
|
||||
text label and show only the spinner
|
||||
|
||||
```jsx
|
||||
<ButtonGroup spacing={4}>
|
||||
<ButtonGroup spacing={space('base')}>
|
||||
<Button isLoading variant="solid">
|
||||
Email
|
||||
</Button>
|
||||
@@ -67,15 +69,15 @@ text label and show only the spinner
|
||||
|
||||
## Composition
|
||||
|
||||
Button composes [PseudoBox](/pseudobox) and all props you pass (variant,
|
||||
Button composes [Box](/box) and all props you pass (mode,
|
||||
bg, color, etc.) are converted to style props. This means you can override
|
||||
any style of the Button via props.
|
||||
|
||||
```jsx
|
||||
// The size prop affects the height of the button
|
||||
// but I can still override it by passing a custom height
|
||||
<Button size="md" height="48px" width="200px" border="2px" borderColor="green">
|
||||
Button
|
||||
<Button size="md" height="200px" width="200px">
|
||||
Square Button
|
||||
</Button>
|
||||
```
|
||||
|
||||
@@ -117,10 +119,6 @@ style props to style the button.
|
||||
</Box>
|
||||
```
|
||||
|
||||
## Experiment
|
||||
|
||||
<ButtonView />
|
||||
|
||||
## Props
|
||||
|
||||
The Button composes the `Box` component so you can pass props for
|
||||
|
||||
117
packages/ui-docs/src/pages/components/color-modes.mdx
Normal file
117
packages/ui-docs/src/pages/components/color-modes.mdx
Normal file
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: 'Color modes'
|
||||
---
|
||||
|
||||
# Color modes
|
||||
|
||||
This component is used to enable applications to style our components in different modes: light and dark.
|
||||
|
||||
> Note: many of our components have yet to be converted to use these color names.
|
||||
|
||||
## ColorModeProvider
|
||||
|
||||
To use, import the `ColorModeProvider` into the root of your application (such as `_app.tsx` for next.js applications,
|
||||
or an App component for other react applications.) This component provides the context for our color mode to be
|
||||
consumed within the application.
|
||||
|
||||
```tsx live=false
|
||||
import { ColorModeProvider } from '@blockstack/ui';
|
||||
|
||||
// _app.tsx
|
||||
const AppWrapper = ({ children, colorMode = 'light' }: AppWrapperProps => (
|
||||
<ThemeProvider>
|
||||
<CSSReset />
|
||||
<ColorModeProvider onChange={handleColorModeChange} colorMode={colorMode}>
|
||||
{children}
|
||||
</ColorModeProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
```
|
||||
|
||||
### Provider Props
|
||||
|
||||
ColorModeProvider takes only a few props:
|
||||
|
||||
- `colorMode?: 'light' | 'dark'`
|
||||
- `onChange?: (mode: string) => void`
|
||||
|
||||
### colorMode
|
||||
|
||||
Useful for setting a default value, or a passing a persisted set value to default to.
|
||||
|
||||
### onChange
|
||||
|
||||
This method is called when the the color mode is toggled via the `toggleColorMode` function that you can access via the
|
||||
`useColorMode` hook. Here is an example to illustrate how one might persist the value to a cookie so that it can be
|
||||
used in a server side rendered environment.
|
||||
|
||||
```tsx live=false
|
||||
import { ColorModeProvider } from '@blockstack/ui';
|
||||
|
||||
import engine from 'store/src/store-engine';
|
||||
import cookieStorage from 'store/storages/cookieStorage';
|
||||
|
||||
// _app.tsx
|
||||
|
||||
const COLOR_MODE_COOKIE = 'color_mode';
|
||||
const cookieSetter = engine.createStore([cookieStorage]);
|
||||
const handleColorModeChange = (mode: string) => cookieSetter.set(COLOR_MODE_COOKIE, mode);
|
||||
|
||||
const AppWrapper = ({ children, colorMode = 'light' }: AppWrapperProps => (
|
||||
<ThemeProvider>
|
||||
<CSSReset />
|
||||
<ColorModeProvider onChange={handleColorModeChange} colorMode={colorMode}>
|
||||
{children}
|
||||
</ColorModeProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
```
|
||||
|
||||
## useColorMode
|
||||
|
||||
There is a color mode hook exposed that can be used to access the current `colorMode` value and a method to toggle the color mode.
|
||||
|
||||
```tsx live=false
|
||||
import { useColorMode } from '@blockstack/ui';
|
||||
|
||||
export const ColorModeButton = forwardRef((props: LinkProps, ref: Ref<HTMLDivElement>) => {
|
||||
const { colorMode, toggleColorMode } = useColorMode();
|
||||
return (
|
||||
<IconButton onClick={toggleColorMode} title="Toggle color mode" {...props} ref={ref}>
|
||||
{colorMode === 'dark' ? <DarkModeIcon /> : <LightModeIcon />}
|
||||
</IconButton>
|
||||
);
|
||||
});
|
||||
);
|
||||
```
|
||||
|
||||
## Colors
|
||||
|
||||
With the color modes component, we have a new way of naming our colors. Rather than them reflecting the name of each color, we now are using more semantically meaningful names. With this, we have exposed a helper function called `color` that allows you to pass in a name for one of the colors. This is useful because with typescript, it allows for autocomplete functionality and the ability to ensure strict typechecking on something like a color name.
|
||||
|
||||
```tsx live=false
|
||||
import { color } from '@blockstack/ui';
|
||||
|
||||
// some-component.tsx
|
||||
<Box background={color('bg-alt')} />;
|
||||
```
|
||||
|
||||
Here are all of the type literals:
|
||||
|
||||
```tsx live=false
|
||||
export type ColorsStringLiteral =
|
||||
| 'accent'
|
||||
| 'bg'
|
||||
| 'bg-alt'
|
||||
| 'bg-light'
|
||||
| 'invert'
|
||||
| 'text-hover'
|
||||
| 'text-title'
|
||||
| 'text-caption'
|
||||
| 'text-body'
|
||||
| 'input-placeholder'
|
||||
| 'border'
|
||||
| 'feedback-alert'
|
||||
| 'feedback-error'
|
||||
| 'feedback-success';
|
||||
```
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: 'Flex'
|
||||
---
|
||||
|
||||
# Flex
|
||||
|
||||
Flex is [Box](/box) with `display: flex` and comes with helpful style shorthand. It
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: 'Grid'
|
||||
---
|
||||
|
||||
# Grid
|
||||
|
||||
A primitive useful for grid layouts. Grid is `Box` with `display: grid` and
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: 'Input'
|
||||
---
|
||||
|
||||
# Input
|
||||
|
||||
Input component enables the user to interact with and input content and data.
|
||||
|
||||
@@ -1,315 +0,0 @@
|
||||
# PseudoBox
|
||||
|
||||
This component is inspired by
|
||||
[Tailwind CSS](https://tailwindcss.com/docs/pseudo-class-variants) Pseudo-Class
|
||||
variants and [Glamorous Pseudo](https://github.com/tkh44/glamorous-pseudo/).
|
||||
|
||||
PseudoBox composes [Box](/box) component and provides props to style common CSS pseudo
|
||||
selectors.
|
||||
|
||||
Styling elements on hover, focus, and more can be accomplished by prefixing `_`
|
||||
with the appropriate pseudo selector.
|
||||
|
||||
For example, to style `&:hover`, use the `_hover` prop and pass the style props.
|
||||
We use the underscore `_` notation to visually separate pseudo style props from
|
||||
regular style props.
|
||||
|
||||
## Import
|
||||
|
||||
```js
|
||||
import { PseudoBox } from '@blockstack/ui';
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
<Flex as="form">
|
||||
<PseudoBox
|
||||
as="input"
|
||||
placeholder="Your email"
|
||||
type="email"
|
||||
flex="1"
|
||||
py={2}
|
||||
px={4}
|
||||
rounded="md"
|
||||
bg="gray.100"
|
||||
borderWidth="1px"
|
||||
_hover={{ borderColor: 'gray.200', bg: 'gray.200' }}
|
||||
_focus={{
|
||||
outline: 'none',
|
||||
bg: 'white',
|
||||
boxShadow: 'outline',
|
||||
borderColor: 'gray.300',
|
||||
}}
|
||||
/>
|
||||
<PseudoBox
|
||||
as="button"
|
||||
bg="teal.500"
|
||||
py={2}
|
||||
px={4}
|
||||
ml={3}
|
||||
rounded="md"
|
||||
fontWeight="semibold"
|
||||
color="white"
|
||||
_hover={{ bg: 'teal.600' }}
|
||||
_focus={{ boxShadow: 'outline' }}
|
||||
>
|
||||
Sign Up
|
||||
</PseudoBox>
|
||||
</Flex>
|
||||
```
|
||||
|
||||
PseudoBox includes first-class support for styling elements on hover, focus,
|
||||
active, disabled, visited, first-child, last-child, odd-child, even-child,
|
||||
focus-within, and more.
|
||||
|
||||
It was created to help reduce the need to pass `css` prop or use `styled(...)`
|
||||
function to style common pseudo states.
|
||||
|
||||
### Hover
|
||||
|
||||
Add the `_hover` prop to only apply style props on hover.
|
||||
|
||||
```jsx
|
||||
<PseudoBox
|
||||
as="button"
|
||||
color="blue.700"
|
||||
fontWeight="semibold"
|
||||
py={2}
|
||||
px={4}
|
||||
borderWidth="1px"
|
||||
borderColor="blue"
|
||||
rounded="md"
|
||||
_hover={{ bg: 'blue', color: ' white' }}
|
||||
_focus={{ boxShadow: 'high' }}
|
||||
>
|
||||
Hover me
|
||||
</PseudoBox>
|
||||
```
|
||||
|
||||
### Focus
|
||||
|
||||
Add the `_focus` prop to only apply a styles on focus.
|
||||
|
||||
```jsx
|
||||
<PseudoBox
|
||||
as="input"
|
||||
placeholder="Focus me"
|
||||
py={2}
|
||||
px={4}
|
||||
bg="white"
|
||||
color="ink"
|
||||
borderColor="ink.100"
|
||||
borderWidth="2px"
|
||||
rounded="md"
|
||||
_focus={{ bg: 'white', borderColor: 'blue' }}
|
||||
/>
|
||||
```
|
||||
|
||||
### Active
|
||||
|
||||
Add the `_active` prop to only apply a styles on active.
|
||||
|
||||
```jsx
|
||||
<PseudoBox
|
||||
as="button"
|
||||
fontWeight="semibold"
|
||||
py={2}
|
||||
px={4}
|
||||
rounded="md"
|
||||
color="white"
|
||||
bg="blue"
|
||||
_active={{ bg: 'green' }}
|
||||
_focus={{ boxShadow: 'outline' }}
|
||||
>
|
||||
Click me
|
||||
</PseudoBox>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Add the `_disabled` prop to style an element when it is disabled. This style
|
||||
will apply when the `disabled` or `aria-disabled` attribute of an element is set
|
||||
to `true`
|
||||
|
||||
```jsx
|
||||
<Stack isInline>
|
||||
<PseudoBox
|
||||
as="button"
|
||||
fontWeight="semibold"
|
||||
py={2}
|
||||
px={4}
|
||||
rounded="md"
|
||||
color="white"
|
||||
bg="blue.500"
|
||||
_active={{ bg: 'blue.700' }}
|
||||
_focus={{ boxShadow: 'outline' }}
|
||||
>
|
||||
Click me
|
||||
</PseudoBox>
|
||||
|
||||
<PseudoBox
|
||||
as="button"
|
||||
disabled
|
||||
fontWeight="semibold"
|
||||
py={2}
|
||||
px={4}
|
||||
rounded="md"
|
||||
color="white"
|
||||
bg="blue.500"
|
||||
_active={{ bg: 'blue.700' }}
|
||||
_focus={{ boxShadow: 'outline' }}
|
||||
_disabled={{ opacity: 0.6 }}
|
||||
>
|
||||
Click me
|
||||
</PseudoBox>
|
||||
</Stack>
|
||||
```
|
||||
|
||||
### Visited
|
||||
|
||||
Add the `_visited` props to style a link that has been visited.
|
||||
|
||||
```jsx
|
||||
<Stack isInline>
|
||||
<PseudoBox as="a" href="/radio" color="blue.600" textDecoration="underline" fontWeight="semibold">
|
||||
Unvisited Link
|
||||
</PseudoBox>
|
||||
<PseudoBox
|
||||
as="a"
|
||||
href="/pseudobox"
|
||||
color="blue.600"
|
||||
textDecoration="underline"
|
||||
fontWeight="semibold"
|
||||
_visited={{ color: 'purple.600' }}
|
||||
>
|
||||
Visited Link
|
||||
</PseudoBox>
|
||||
</Stack>
|
||||
```
|
||||
|
||||
### First Child
|
||||
|
||||
Add the `_first` prefix to style an element when it is the first-child of its
|
||||
parent. This is mostly useful when elements are being generated in some kind of
|
||||
loop.
|
||||
|
||||
```jsx
|
||||
<Box borderWidth="1px" rounded="md">
|
||||
{['One', 'Two', 'Three'].map(item => (
|
||||
<PseudoBox key={item} px={4} py={2} borderTopWidth="1px" _first={{ borderTopWidth: 0 }}>
|
||||
{item}
|
||||
</PseudoBox>
|
||||
))}
|
||||
</Box>
|
||||
```
|
||||
|
||||
### Last Child
|
||||
|
||||
Add the `_last` prefix to style an element when it is the last-child of its
|
||||
parent. This is mostly useful when elements are being generated in some kind of
|
||||
loop.
|
||||
|
||||
```jsx
|
||||
<Box borderWidth="1px" rounded="md">
|
||||
{['One', 'Two', 'Three'].map(item => (
|
||||
<PseudoBox key={item} px={4} py={2} borderBottomWidth="1px" _last={{ borderBottomWidth: 0 }}>
|
||||
{item}
|
||||
</PseudoBox>
|
||||
))}
|
||||
</Box>
|
||||
```
|
||||
|
||||
### Odd Child
|
||||
|
||||
Add the `_odd` prop to style an element when it is the odd-child of its parent.
|
||||
This is mostly useful when elements are being generated in some kind of loop.
|
||||
|
||||
```jsx
|
||||
<Box borderWidth="1px" rounded="md" overflow="hidden">
|
||||
{['One', 'Two', 'Three'].map(item => (
|
||||
<PseudoBox key={item} px={4} py={2} bg="white" _odd={{ bg: 'gray.100' }}>
|
||||
{item}
|
||||
</PseudoBox>
|
||||
))}
|
||||
</Box>
|
||||
```
|
||||
|
||||
### Even Child
|
||||
|
||||
Add the `_even` prop to style an element when it is the even-child of its
|
||||
parent. This is mostly useful when elements are being generated in some kind of
|
||||
loop.
|
||||
|
||||
```jsx
|
||||
<Box borderWidth="1px" rounded="md" overflow="hidden">
|
||||
{['One', 'Two', 'Three'].map(item => (
|
||||
<PseudoBox key={item} px={4} py={2} bg="white" _even={{ bg: 'gray.100' }}>
|
||||
{item}
|
||||
</PseudoBox>
|
||||
))}
|
||||
</Box>
|
||||
```
|
||||
|
||||
### Group Hover
|
||||
|
||||
If you need to style a child element when hovering over a specific parent
|
||||
element, add the `role="group"` attribute to the parent element, then you can
|
||||
use `_groupHover` prop to style the child element.
|
||||
|
||||
```jsx
|
||||
<PseudoBox
|
||||
role="group"
|
||||
maxW="sm"
|
||||
overflow="hidden"
|
||||
rounded="md"
|
||||
p={5}
|
||||
cursor="pointer"
|
||||
bg="white"
|
||||
boxShadow="md"
|
||||
_hover={{ bg: 'blue.500' }}
|
||||
>
|
||||
<PseudoBox
|
||||
fontWeight="semibold"
|
||||
fontSize="lg"
|
||||
mb={1}
|
||||
color="gray.900"
|
||||
_groupHover={{ color: 'white' }}
|
||||
>
|
||||
New Project
|
||||
</PseudoBox>
|
||||
<PseudoBox color="gray.700" mb={2} _groupHover={{ color: 'white' }}>
|
||||
Create a new project from a variety of starting templates.
|
||||
</PseudoBox>
|
||||
</PseudoBox>
|
||||
```
|
||||
|
||||
## Selectors and Props
|
||||
|
||||
PseudoBox can be used to style any interactive component. You can apply styles
|
||||
to the following selectors. The selectors are also ARIA-friendly to help you
|
||||
naturally use `aria` attributes for better accessibility.
|
||||
|
||||
All PseudoBox props can use the style props.
|
||||
[Learn more about Style props](/style-props)
|
||||
|
||||
| Selector | Prop |
|
||||
| -------------------------------------- | -------------- |
|
||||
| `&:hover` | `_hover` |
|
||||
| `&:active` | `_active` |
|
||||
| `&:focus` | `_focus` |
|
||||
| `&:before` | `_before` |
|
||||
| `&:after` | `_after` |
|
||||
| `&::placeholder` | `_placeholder` |
|
||||
| `&:first-of-type` | `_first` |
|
||||
| `&:last-of-type` | `_last` |
|
||||
| `[role=group]:hover &` | `_groupHover` |
|
||||
| `&:disabled`, `[aria-disabled=true]` | `_disabled` |
|
||||
| `&[readonly]`, `&[aria-readonly=true]` | `_readonly` |
|
||||
| `&[aria-checked=true]` | `_checked` |
|
||||
| `&[aria-selected=true]` | `_selected` |
|
||||
| `&[aria-expanded=true]` | `_expanded` |
|
||||
| `&[aria-invalid=true]` | `_invalid` |
|
||||
| `&[aria-pressed=true]` | `_pressed` |
|
||||
| `&[aria-invalid=true]` | `_invalid` |
|
||||
| `&[aria-grabbed=true]` | `_grabbed` |
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: 'Stack'
|
||||
---
|
||||
|
||||
# Stack
|
||||
|
||||
Stack is a layout utility component that makes it easy to stack elements
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: 'Text'
|
||||
---
|
||||
|
||||
import { TextDisplay } from '@components/text-display';
|
||||
|
||||
# Text
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: 'Contributing'
|
||||
---
|
||||
|
||||
# Contributing to Blockstack UI
|
||||
|
||||
First of all: thank you for being interesting in helping the project out!
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: 'Further reading'
|
||||
---
|
||||
|
||||
# Further reading
|
||||
|
||||
As with most things, much of what we build is supported by the work of many other people. This page lists out some of the writing that has influenced the thought and ideas behind this design system.
|
||||
@@ -18,6 +22,6 @@ As with most things, much of what we build is supported by the work of many othe
|
||||
[What is a Design System?](https://varun.ca/what-is-a-design-system/)<br />
|
||||
[Tailwind CSS](https://tailwindcss.com/)<br />
|
||||
[Styled Components](https://styled-components.com/)<br />
|
||||
[Styled System](https://styled-system.com/)
|
||||
[Primer Components](https://primer.style/components)
|
||||
[Styled System](https://styled-system.com/)<br />
|
||||
[Primer Components](https://primer.style/components)<br />
|
||||
[Chakra UI](https://chakra-ui.com)
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: 'useTheme | Hooks'
|
||||
---
|
||||
|
||||
# useTheme
|
||||
|
||||
`useTheme` is a custom hook to get the theme object from context.
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
---
|
||||
title: 'Patterns and principles'
|
||||
---
|
||||
|
||||
# Patterns and principles
|
||||
|
||||
Blockstack UI is built with a few things in mind: consistency, composability, easy of use, and extensibility. These components aren't meant to be highly complex instances of specific UI elements; rather they are meant to be primitive components that you can use to build anything you want.
|
||||
Blockstack UI is built with a few things in mind: consistency, composability, easy of use, and extensibility.
|
||||
These components aren't meant to be highly complex instances of specific UI elements; rather they are meant to be
|
||||
primitive components that you can use to build anything you want.
|
||||
|
||||
## System props
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
# Responsive Styles
|
||||
---
|
||||
title: 'Responsive styles'
|
||||
---
|
||||
|
||||
# Responsive styles
|
||||
|
||||
Blockstack UI supports responsive styles out of the box because it is built with styled-system. Instead of manually adding
|
||||
`@media` queries and adding nested styles throughout your code, any component allows
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
---
|
||||
title: 'System props'
|
||||
---
|
||||
|
||||
# System props
|
||||
|
||||
All of the components in Blockstack UI are built with `styled-components` and implement `styled-system`. With this, you can pass css attributes to any component as props. Check out the page [further reading](/further-reading) to dig deeper.
|
||||
All of the components in Blockstack UI are built with `styled-components` and implement `styled-system`. With this,
|
||||
you can pass css attributes to any component as props. Check out the page [further reading](/further-reading) to dig
|
||||
deeper.
|
||||
|
||||
## System props reference
|
||||
|
||||
See below for the various props and aliases you can pass for styling components. You can see the full spec on the [Styled System docs](https://styled-system.com/api).
|
||||
See below for the various props and aliases you can pass for styling components. You can see the full spec on the
|
||||
[Styled System docs](https://styled-system.com/api).
|
||||
|
||||
### Margin & padding
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: 'Theme'
|
||||
---
|
||||
|
||||
import { Box, Flex, Grid, useTheme } from '@blockstack/ui';
|
||||
import { ColorPalette, ColorPalettes, ColorWrapper, Colors } from '@components/color-palette';
|
||||
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
"paths": {
|
||||
"@components/*": ["components/*"],
|
||||
"@pages/*": ["pages/*"],
|
||||
"@common/*": ["common/*"],
|
||||
"@blockstack/ui": ["../ui"],
|
||||
"@blockstack/ui/*": ["../ui/*"]
|
||||
"@common/*": ["common/*"]
|
||||
},
|
||||
"baseUrl": "src"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Theme } from '@blockstack/ui';
|
||||
import { Theme } from '../theme';
|
||||
import {
|
||||
ColorModesInterface,
|
||||
ColorsStringLiteral,
|
||||
|
||||
Reference in New Issue
Block a user