mirror of
https://github.com/zhigang1992/react.git
synced 2026-03-26 06:55:07 +08:00
style(prettier): format code style
This commit is contained in:
@@ -2,9 +2,17 @@ import React from 'react'
|
||||
|
||||
const AnchorIcon = () => {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" width="100%" height="100%" stroke="currentColor" strokeWidth="1.5"
|
||||
strokeLinecap="round" strokeLinejoin="round" fill="none"
|
||||
shapeRendering="geometricPrecision" style={{ color: 'currentColor' }}>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
width="100%"
|
||||
height="100%"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
shapeRendering="geometricPrecision"
|
||||
style={{ color: 'currentColor' }}>
|
||||
<path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71" />
|
||||
<path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71" />
|
||||
</svg>
|
||||
|
||||
@@ -11,9 +11,7 @@ export const virtualAnchorEncode = (text?: string) => {
|
||||
return text.toLowerCase().replace(/ /g, '-')
|
||||
}
|
||||
|
||||
const VirtualAnchor: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
children, pure,
|
||||
}) => {
|
||||
const VirtualAnchor: React.FC<React.PropsWithChildren<Props>> = ({ children, pure }) => {
|
||||
const theme = useTheme()
|
||||
const ref = useRef<HTMLAnchorElement>(null)
|
||||
const [id, setId] = useState<string | undefined>()
|
||||
@@ -22,22 +20,28 @@ const VirtualAnchor: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
if (!ref.current) return
|
||||
setId(virtualAnchorEncode(ref.current.textContent || undefined))
|
||||
}, [ref.current])
|
||||
|
||||
|
||||
return (
|
||||
<span className="parent" ref={ref}>
|
||||
<Link pure href={`#${id}`}>{children}</Link>
|
||||
<Link pure href={`#${id}`}>
|
||||
{children}
|
||||
</Link>
|
||||
<span className="virtual" id={id} />
|
||||
{!pure && <span className="icon"><AnchorIcon /></span>}
|
||||
{!pure && (
|
||||
<span className="icon">
|
||||
<AnchorIcon />
|
||||
</span>
|
||||
)}
|
||||
<style jsx>{`
|
||||
.parent {
|
||||
position: relative;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
.parent :global(a) {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
.virtual {
|
||||
position: absolute;
|
||||
top: -65px;
|
||||
@@ -46,7 +50,7 @@ const VirtualAnchor: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
.icon {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
@@ -59,12 +63,12 @@ const VirtualAnchor: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
font-size: inherit;
|
||||
width: .8em;
|
||||
height: .8em;
|
||||
width: 0.8em;
|
||||
height: 0.8em;
|
||||
margin-top: 1px;
|
||||
color: ${theme.palette.accents_5};
|
||||
}
|
||||
|
||||
|
||||
.parent:hover > .icon {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
|
||||
@@ -7,52 +7,58 @@ export interface AttributesTitleProps {
|
||||
alias?: string
|
||||
}
|
||||
|
||||
const getAlias = (isChinese: boolean, alias?: string, ) => {
|
||||
const getAlias = (isChinese: boolean, alias?: string) => {
|
||||
if (!alias) return null
|
||||
return (
|
||||
<small><span>[</span>{isChinese ? '别名' : 'alias'}: <Code>{alias}</Code><span>]</span></small>
|
||||
<small>
|
||||
<span>[</span>
|
||||
{isChinese ? '别名' : 'alias'}: <Code>{alias}</Code>
|
||||
<span>]</span>
|
||||
</small>
|
||||
)
|
||||
}
|
||||
|
||||
const AttributesTitle: React.FC<React.PropsWithChildren<AttributesTitleProps>> = React.memo(({
|
||||
children, alias,
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const { isChinese } = useConfigs()
|
||||
const AttributesTitle: React.FC<React.PropsWithChildren<AttributesTitleProps>> = React.memo(
|
||||
({ children, alias }) => {
|
||||
const theme = useTheme()
|
||||
const { isChinese } = useConfigs()
|
||||
|
||||
return (
|
||||
<>
|
||||
<h4 className="title">
|
||||
<Code><VirtualAnchor pure>{children}</VirtualAnchor></Code>
|
||||
{getAlias(!!isChinese, alias)}
|
||||
</h4>
|
||||
<Spacer y={.6} />
|
||||
|
||||
<style jsx>{`
|
||||
h4 {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 2rem;
|
||||
padding-left: ${theme.layout.gapQuarter};
|
||||
padding-right: ${theme.layout.gapHalf};
|
||||
background-color: ${theme.palette.accents_1};
|
||||
border-radius: ${theme.layout.radius};
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<h4 className="title">
|
||||
<Code>
|
||||
<VirtualAnchor pure>{children}</VirtualAnchor>
|
||||
</Code>
|
||||
{getAlias(!!isChinese, alias)}
|
||||
</h4>
|
||||
<Spacer y={0.6} />
|
||||
|
||||
h4 :global(small) {
|
||||
font-size: .65em;
|
||||
padding-left: .65rem;
|
||||
color: ${theme.palette.accents_4};
|
||||
align-self: flex-end;
|
||||
line-height: 1.6rem;
|
||||
}
|
||||
|
||||
h4 :global(span) {
|
||||
color: ${theme.palette.accents_6};
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
)
|
||||
})
|
||||
<style jsx>{`
|
||||
h4 {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 2rem;
|
||||
padding-left: ${theme.layout.gapQuarter};
|
||||
padding-right: ${theme.layout.gapHalf};
|
||||
background-color: ${theme.palette.accents_1};
|
||||
border-radius: ${theme.layout.radius};
|
||||
}
|
||||
|
||||
h4 :global(small) {
|
||||
font-size: 0.65em;
|
||||
padding-left: 0.65rem;
|
||||
color: ${theme.palette.accents_4};
|
||||
align-self: flex-end;
|
||||
line-height: 1.6rem;
|
||||
}
|
||||
|
||||
h4 :global(span) {
|
||||
color: ${theme.palette.accents_6};
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
export default AttributesTitle
|
||||
|
||||
@@ -9,116 +9,118 @@ export interface AttributesProps {
|
||||
edit: string
|
||||
}
|
||||
|
||||
const Attributes: React.FC<React.PropsWithChildren<AttributesProps>> = React.memo(({
|
||||
edit, children,
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const { isChinese } = useConfigs()
|
||||
const path = edit.replace('/pages', 'pages')
|
||||
|
||||
return (
|
||||
<>
|
||||
<Spacer y={5} />
|
||||
<h3><VirtualAnchor>APIs</VirtualAnchor>{isChinese && ' / 接口文档'}</h3>
|
||||
<Card className="attr">
|
||||
{children}
|
||||
</Card>
|
||||
<Spacer y={3} />
|
||||
<h4 className="contributor-title">{isChinese ? '文档贡献者' : 'Contributors'}</h4>
|
||||
<Contributors path={path} />
|
||||
<style global jsx>{`
|
||||
.attr table {
|
||||
margin-right: ${theme.layout.gap};
|
||||
}
|
||||
const Attributes: React.FC<React.PropsWithChildren<AttributesProps>> = React.memo(
|
||||
({ edit, children }) => {
|
||||
const theme = useTheme()
|
||||
const { isChinese } = useConfigs()
|
||||
const path = edit.replace('/pages', 'pages')
|
||||
|
||||
.attr pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.attr h4.title {
|
||||
margin-top: calc(${theme.layout.gap} * 2.2);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Spacer y={5} />
|
||||
<h3>
|
||||
<VirtualAnchor>APIs</VirtualAnchor>
|
||||
{isChinese && ' / 接口文档'}
|
||||
</h3>
|
||||
<Card className="attr">{children}</Card>
|
||||
<Spacer y={3} />
|
||||
<h4 className="contributor-title">{isChinese ? '文档贡献者' : 'Contributors'}</h4>
|
||||
<Contributors path={path} />
|
||||
<style global jsx>{`
|
||||
.attr table {
|
||||
margin-right: ${theme.layout.gap};
|
||||
}
|
||||
|
||||
.attr h4.title:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.attr table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.attr thead th td {
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.attr tbody tr td {
|
||||
height: 3.333rem;
|
||||
}
|
||||
|
||||
.attr th, .attr td {
|
||||
padding: 0 0.625rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.attr th {
|
||||
height: 2.5rem;
|
||||
color: ${theme.palette.accents_5};;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
background: ${theme.palette.accents_1};
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
border-top: 1px solid ${theme.palette.border};
|
||||
}
|
||||
|
||||
.attr th:nth-child(1) {
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
border-left: 1px solid ${theme.palette.border};
|
||||
border-radius: 4px 0 0 4px;
|
||||
border-top: 1px solid ${theme.palette.border};
|
||||
}
|
||||
|
||||
.attr th:last-child {
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
border-radius: 0 4px 4px 0;
|
||||
border-right: 1px solid ${theme.palette.border};
|
||||
border-top: 1px solid ${theme.palette.border};
|
||||
}
|
||||
|
||||
.attr tr td {
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
color: ${theme.palette.accents_6};
|
||||
font-size: 0.875rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.attr td:nth-child(1) {
|
||||
border-left: 1px solid transparent;
|
||||
}
|
||||
|
||||
.contributor-title {
|
||||
text-transform: uppercase;
|
||||
font-size: 1rem;
|
||||
letter-spacing: 1.5px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
|
||||
.attr {
|
||||
overflow-x: scroll;
|
||||
.attr pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.attr::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
|
||||
.attr h4.title {
|
||||
margin-top: calc(${theme.layout.gap} * 2.2);
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
.attr h4.title:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.attr table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.attr thead th td {
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.attr tbody tr td {
|
||||
height: 3.333rem;
|
||||
}
|
||||
|
||||
.attr th,
|
||||
.attr td {
|
||||
padding: 0 0.625rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.attr th {
|
||||
height: 2.5rem;
|
||||
color: ${theme.palette.accents_5};
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
background: ${theme.palette.accents_1};
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
border-top: 1px solid ${theme.palette.border};
|
||||
}
|
||||
|
||||
.attr th:nth-child(1) {
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
border-left: 1px solid ${theme.palette.border};
|
||||
border-radius: 4px 0 0 4px;
|
||||
border-top: 1px solid ${theme.palette.border};
|
||||
}
|
||||
|
||||
.attr th:last-child {
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
border-radius: 0 4px 4px 0;
|
||||
border-right: 1px solid ${theme.palette.border};
|
||||
border-top: 1px solid ${theme.palette.border};
|
||||
}
|
||||
|
||||
.attr tr td {
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
color: ${theme.palette.accents_6};
|
||||
font-size: 0.875rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.attr td:nth-child(1) {
|
||||
border-left: 1px solid transparent;
|
||||
}
|
||||
|
||||
.contributor-title {
|
||||
text-transform: uppercase;
|
||||
font-size: 1rem;
|
||||
letter-spacing: 1.5px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
|
||||
.attr {
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
.attr::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
type AttributesComponent<P = {}> = React.FC<P> & {
|
||||
Title: typeof AttributesTitle
|
||||
|
||||
@@ -29,7 +29,7 @@ const Contributors: React.FC<Props> = ({ path }) => {
|
||||
const { isChinese } = useConfigs()
|
||||
const [users, setUsers] = useState<Array<Contributor>>([])
|
||||
const link = useMemo(() => `${GithubURL}/${path || '/pages'}`, [])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
let unmount = false
|
||||
;(async () => {
|
||||
@@ -41,7 +41,7 @@ const Contributors: React.FC<Props> = ({ path }) => {
|
||||
unmount = true
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
||||
return (
|
||||
<div className="contributors">
|
||||
{users.map((user, index) => (
|
||||
@@ -65,7 +65,7 @@ const Contributors: React.FC<Props> = ({ path }) => {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
|
||||
.contributors :global(.tooltip) {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@ import Router, { useRouter } from 'next/router'
|
||||
import MoonIcon from '@zeit-ui/react-icons/moon'
|
||||
import SunIcon from '@zeit-ui/react-icons/sun'
|
||||
|
||||
const Controls: React.FC<{}> = React.memo(({
|
||||
}) => {
|
||||
const Controls: React.FC<{}> = React.memo(({}) => {
|
||||
const theme = useTheme()
|
||||
const { updateCustomTheme, updateChineseState } = useConfigs()
|
||||
const { pathname } = useRouter()
|
||||
@@ -37,13 +36,24 @@ const Controls: React.FC<{}> = React.memo(({
|
||||
return (
|
||||
<div className="controls">
|
||||
<div className="tools">
|
||||
<Button auto type="abort" size="small" onClick={switchLanguages}>{isChinese ? 'English' : '中文文档'}</Button>
|
||||
<Spacer x={.25} />
|
||||
<Button auto type="abort" size="small"
|
||||
<Button auto type="abort" size="small" onClick={switchLanguages}>
|
||||
{isChinese ? 'English' : '中文文档'}
|
||||
</Button>
|
||||
<Spacer x={0.25} />
|
||||
<Button
|
||||
auto
|
||||
type="abort"
|
||||
size="small"
|
||||
onClick={redirectGithub}
|
||||
title={isChinese? '代码仓库' : 'Github Repository'}>{isChinese ? '代码仓库' : 'Github'}</Button>
|
||||
<Spacer x={.75} />
|
||||
<Select size="small" pure onChange={switchThemes} value={isDark ? 'dark' : 'light'}
|
||||
title={isChinese ? '代码仓库' : 'Github Repository'}>
|
||||
{isChinese ? '代码仓库' : 'Github'}
|
||||
</Button>
|
||||
<Spacer x={0.75} />
|
||||
<Select
|
||||
size="small"
|
||||
pure
|
||||
onChange={switchThemes}
|
||||
value={isDark ? 'dark' : 'light'}
|
||||
title={isChinese ? '切换主题' : 'Switch Themes'}>
|
||||
<Select.Option value="light">
|
||||
<div className="select-content">
|
||||
@@ -64,30 +74,30 @@ const Controls: React.FC<{}> = React.memo(({
|
||||
margin: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.controls :global(.select) {
|
||||
width: min-content;
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
|
||||
.select-content {
|
||||
width: auto;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.select-content :global(svg) {
|
||||
margin-right: .5rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
.tools {
|
||||
display: flex;
|
||||
height: 2.5rem;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
|
||||
.controls {
|
||||
display: none;
|
||||
|
||||
@@ -8,15 +8,15 @@ import useClipboard from 'components/utils/use-clipboard'
|
||||
import CopyIcon from 'components/snippet/snippet-icon'
|
||||
import { useConfigs } from 'lib/config-context'
|
||||
|
||||
export const getDeepDifferents = <T extends MergeObject,>(source: T, target: T): T => {
|
||||
export const getDeepDifferents = <T extends MergeObject>(source: T, target: T): T => {
|
||||
if (!isObject(target) || !isObject(source)) return target
|
||||
|
||||
|
||||
const sourceKeys = Object.keys(source) as Array<keyof T>
|
||||
let result = {} as T
|
||||
for (const key of sourceKeys) {
|
||||
const sourceValue = source[key]
|
||||
const targetValue = target[key]
|
||||
|
||||
|
||||
if (isObject(sourceValue) && isObject(targetValue)) {
|
||||
const childrenDiff = getDeepDifferents(sourceValue, { ...targetValue })
|
||||
if (Object.keys(childrenDiff).length !== 0) {
|
||||
@@ -36,10 +36,10 @@ const CustomizationCodes = () => {
|
||||
const { copy } = useClipboard()
|
||||
const [, setToast] = useToasts()
|
||||
|
||||
const deepDifferents = useMemo(
|
||||
() => getDeepDifferents(DefaultTheme, theme),
|
||||
[DefaultTheme, theme],
|
||||
)
|
||||
const deepDifferents = useMemo(() => getDeepDifferents(DefaultTheme, theme), [
|
||||
DefaultTheme,
|
||||
theme,
|
||||
])
|
||||
const userCodes = useMemo(() => {
|
||||
return `const myTheme = ${JSON.stringify(deepDifferents, null, 2)}
|
||||
|
||||
@@ -55,7 +55,7 @@ const CustomizationCodes = () => {
|
||||
* }
|
||||
**/`
|
||||
}, [deepDifferents])
|
||||
|
||||
|
||||
const copyCode = () => {
|
||||
copy(userCodes)
|
||||
setToast({ text: 'Theme code copied.' })
|
||||
@@ -66,13 +66,19 @@ const CustomizationCodes = () => {
|
||||
<h3 className="title">{isChinese ? '主题代码' : 'Theme Codes'}</h3>
|
||||
<Spacer y={1} />
|
||||
{isChinese ? (
|
||||
<Text>这里是你所有的变更,点击 <Code>copy</Code> 按钮即可使用在你自己的项目中。</Text>
|
||||
<Text>
|
||||
这里是你所有的变更,点击 <Code>copy</Code> 按钮即可使用在你自己的项目中。
|
||||
</Text>
|
||||
) : (
|
||||
<Text>This is all your changes, click <Code>copy</Code> to use it in your own project.</Text>
|
||||
<Text>
|
||||
This is all your changes, click <Code>copy</Code> to use it in your own project.
|
||||
</Text>
|
||||
)}
|
||||
<Spacer y={2} />
|
||||
<div className="codes">
|
||||
<div className="copy" onClick={copyCode}><CopyIcon /></div>
|
||||
<div className="copy" onClick={copyCode}>
|
||||
<CopyIcon />
|
||||
</div>
|
||||
<LiveProvider code={userCodes} disabled theme={codeTheme}>
|
||||
<LiveEditor />
|
||||
</LiveProvider>
|
||||
@@ -86,7 +92,7 @@ const CustomizationCodes = () => {
|
||||
margin: 3rem auto 2.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
width: 80%;
|
||||
@@ -100,17 +106,17 @@ const CustomizationCodes = () => {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1.5px;
|
||||
}
|
||||
|
||||
|
||||
.codes {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
border: 1px solid ${theme.palette.border};
|
||||
border-radius: ${theme.layout.radius};
|
||||
overflow: hidden;
|
||||
padding: calc(.6 * ${theme.layout.gap}) ${theme.layout.gap};
|
||||
padding: calc(0.6 * ${theme.layout.gap}) ${theme.layout.gap};
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.copy {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
@@ -121,13 +127,14 @@ const CustomizationCodes = () => {
|
||||
user-select: none;
|
||||
transition: color 200ms ease;
|
||||
}
|
||||
|
||||
|
||||
.copy:hover {
|
||||
color: ${theme.palette.accents_6};
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
|
||||
.title, .codes {
|
||||
.title,
|
||||
.codes {
|
||||
width: 90vw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,22 @@ import React from 'react'
|
||||
import { Card, useTheme } from 'components'
|
||||
import { CardTypes } from 'components/utils/prop-types'
|
||||
|
||||
const types = ['secondary', 'success', 'warning', 'error',
|
||||
'dark', 'alert', 'purple', 'violet', 'cyan', 'lite']
|
||||
const types = [
|
||||
'secondary',
|
||||
'success',
|
||||
'warning',
|
||||
'error',
|
||||
'dark',
|
||||
'alert',
|
||||
'purple',
|
||||
'violet',
|
||||
'cyan',
|
||||
'lite',
|
||||
]
|
||||
|
||||
const Colors: React.FC<React.PropsWithChildren<{}>> = () => {
|
||||
const theme = useTheme()
|
||||
|
||||
|
||||
return (
|
||||
<div className="colors">
|
||||
{types.map((type, index) => {
|
||||
@@ -22,7 +32,7 @@ const Colors: React.FC<React.PropsWithChildren<{}>> = () => {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
|
||||
.color-card {
|
||||
display: flex;
|
||||
width: 9rem;
|
||||
|
||||
@@ -6,42 +6,59 @@ import { useConfigs } from 'lib/config-context'
|
||||
const Demo: React.FC<React.PropsWithChildren<{}>> = () => {
|
||||
const theme = useTheme()
|
||||
const { isChinese } = useConfigs()
|
||||
|
||||
|
||||
return (
|
||||
<div className="demo">
|
||||
<div className="content">
|
||||
{isChinese ? (
|
||||
<>
|
||||
<Text h3>预览</Text>
|
||||
<Text>这里是你变更主题后的即时预览。此外,当你每次更新主题变量时,整个文档站点也会随之变化。</Text>
|
||||
<Text>
|
||||
这里是你变更主题后的即时预览。此外,当你每次更新主题变量时,整个文档站点也会随之变化。
|
||||
</Text>
|
||||
<Text>你可以拷贝自动生成的代码,或是与任何人分享你自定义的主题样式。</Text>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Text h3>Preview</Text>
|
||||
<Text>Here's a preview of your changes to the Theme. When you set the changes,
|
||||
the entire document site will change with the theme.</Text>
|
||||
<Text>You can copy automatically generated codes or share your custom theme with anyone.</Text>
|
||||
<Text>
|
||||
Here's a preview of your changes to the Theme. When you set the changes, the
|
||||
entire document site will change with the theme.
|
||||
</Text>
|
||||
<Text>
|
||||
You can copy automatically generated codes or share your custom theme with anyone.
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
<Spacer y={1.7} />
|
||||
<Text h4>{isChinese ? '色彩' : 'Colors'}</Text>
|
||||
<Colors />
|
||||
|
||||
|
||||
<Spacer y={1.7} />
|
||||
<Text h4>{isChinese ? '排版' : 'Typography'}</Text>
|
||||
<Text><Code>inline codes</Code></Text>
|
||||
<Text><a>Hyperlink Text</a> </Text>
|
||||
<Text><Link href="#" color>Link Component</Link></Text>
|
||||
<Text>Our mission is to make cloud computing accessible to everyone. We build products for developers and designers. And those who aspire to become one.</Text>
|
||||
<Text>
|
||||
<Code>inline codes</Code>
|
||||
</Text>
|
||||
<Text>
|
||||
<a>Hyperlink Text</a>{' '}
|
||||
</Text>
|
||||
<Text>
|
||||
<Link href="#" color>
|
||||
Link Component
|
||||
</Link>
|
||||
</Text>
|
||||
<Text>
|
||||
Our mission is to make cloud computing accessible to everyone. We build products for
|
||||
developers and designers. And those who aspire to become one.
|
||||
</Text>
|
||||
<Text h6>Heading</Text>
|
||||
<Text h5>Heading</Text>
|
||||
<Text h4>Heading</Text>
|
||||
<Text h3>Heading</Text>
|
||||
<Text h2>Heading</Text>
|
||||
<Text h1>Heading</Text>
|
||||
|
||||
|
||||
<Spacer y={1.7} />
|
||||
<Text h4>{isChinese ? '基础组件' : 'Basic Components'}</Text>
|
||||
<Select placeholder="Choose one" initialValue="1">
|
||||
@@ -49,12 +66,18 @@ const Demo: React.FC<React.PropsWithChildren<{}>> = () => {
|
||||
<Select.Option value="2">Option 2</Select.Option>
|
||||
</Select>
|
||||
<Spacer y={1} />
|
||||
<Button disabled auto size="small">Action</Button>
|
||||
<Spacer inline x={.5} />
|
||||
<Button auto size="small">Action</Button>
|
||||
<Spacer inline x={.5} />
|
||||
<Button auto type="secondary" size="small">Action</Button>
|
||||
<Spacer y={.5} />
|
||||
<Button disabled auto size="small">
|
||||
Action
|
||||
</Button>
|
||||
<Spacer inline x={0.5} />
|
||||
<Button auto size="small">
|
||||
Action
|
||||
</Button>
|
||||
<Spacer inline x={0.5} />
|
||||
<Button auto type="secondary" size="small">
|
||||
Action
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button>Action</Button>
|
||||
</div>
|
||||
<style jsx>{`
|
||||
@@ -68,11 +91,11 @@ const Demo: React.FC<React.PropsWithChildren<{}>> = () => {
|
||||
height: 100%;
|
||||
transition: width 200ms ease;
|
||||
}
|
||||
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
|
||||
.demo {
|
||||
display: none;
|
||||
|
||||
@@ -10,17 +10,16 @@ interface Props {
|
||||
}
|
||||
|
||||
const getRandomColor = () => {
|
||||
const hex = `00000${(Math.random() * 0x1000000 << 0).toString(16)}`
|
||||
const hex = `00000${((Math.random() * 0x1000000) << 0).toString(16)}`
|
||||
return `#${hex.substr(-6)}`
|
||||
}
|
||||
|
||||
const getRandomColors = () => {
|
||||
const kyes = Object.keys(DefaultTheme.palette) as Array<keyof ZeitUIThemesPalette>
|
||||
const basicColors = new Array(5).fill('')
|
||||
.map(() => {
|
||||
const index = Math.round(Math.random() * (kyes.length)) + kyes.length
|
||||
return DefaultTheme.palette[kyes[index]]
|
||||
})
|
||||
const basicColors = new Array(5).fill('').map(() => {
|
||||
const index = Math.round(Math.random() * kyes.length) + kyes.length
|
||||
return DefaultTheme.palette[kyes[index]]
|
||||
})
|
||||
const deduplicatedColors = [...new Set(...basicColors)]
|
||||
const randomColors = new Array(10 - deduplicatedColors.length)
|
||||
.fill('')
|
||||
@@ -28,9 +27,7 @@ const getRandomColors = () => {
|
||||
return deduplicatedColors.concat(randomColors)
|
||||
}
|
||||
|
||||
const EditorColorItem: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
keyName,
|
||||
}) => {
|
||||
const EditorColorItem: React.FC<React.PropsWithChildren<Props>> = ({ keyName }) => {
|
||||
const theme = useTheme()
|
||||
const { updateCustomTheme } = useConfigs()
|
||||
const label = `${keyName}`
|
||||
@@ -38,14 +35,17 @@ const EditorColorItem: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
const randomColors = useMemo(() => getRandomColors(), [])
|
||||
const colorChangeHandler = ({ hex }: ColorResult) => {
|
||||
updateCustomTheme({
|
||||
palette: { [keyName]: hex }
|
||||
palette: { [keyName]: hex },
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const popoverContent = (color: string) => (
|
||||
<TwitterPicker triangle="hide" color={color}
|
||||
<TwitterPicker
|
||||
triangle="hide"
|
||||
color={color}
|
||||
onChangeComplete={colorChangeHandler}
|
||||
colors={randomColors} />
|
||||
colors={randomColors}
|
||||
/>
|
||||
)
|
||||
return (
|
||||
<Popover content={() => popoverContent(mainColor)} portalClassName="editor-popover" offset={3}>
|
||||
@@ -65,48 +65,49 @@ const EditorColorItem: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
border: 1px solid ${theme.palette.border};
|
||||
border-radius: ${theme.layout.radius};
|
||||
color: ${theme.palette.accents_5};
|
||||
margin-right: .75rem;
|
||||
margin-bottom: .5rem;
|
||||
margin-right: 0.75rem;
|
||||
margin-bottom: 0.5rem;
|
||||
cursor: pointer;
|
||||
transition: color 200ms ease;
|
||||
}
|
||||
|
||||
|
||||
:global(.editor-popover .inner) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
:global(.editor-popover .twitter-picker) {
|
||||
box-shadow: none !important;
|
||||
border: 0 !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
|
||||
.editor-item:hover {
|
||||
color: ${theme.palette.accents_8};
|
||||
}
|
||||
|
||||
|
||||
.editor-item:hover .dot {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.dot-box, .dot {
|
||||
|
||||
.dot-box,
|
||||
.dot {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.dot-box {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
margin-right: .75rem;
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
.dot {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background-color: ${mainColor};
|
||||
transform: scale(.8);
|
||||
transform: scale(0.8);
|
||||
transition: transform 200ms ease;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
@@ -8,9 +8,7 @@ type Props = {
|
||||
keyName: string
|
||||
}
|
||||
|
||||
const EditorInputItem: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
groupName, keyName
|
||||
}) => {
|
||||
const EditorInputItem: React.FC<React.PropsWithChildren<Props>> = ({ groupName, keyName }) => {
|
||||
const theme = useTheme()
|
||||
const { updateCustomTheme } = useConfigs()
|
||||
const currentVal = useMemo(() => {
|
||||
@@ -18,19 +16,22 @@ const EditorInputItem: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
const key = keyName as keyof typeof group
|
||||
return theme[groupName][key]
|
||||
}, [theme.expressiveness, keyName])
|
||||
const width = useMemo(() => `${currentVal}`.length > 15 ? '350px' : 'auto', [])
|
||||
|
||||
const width = useMemo(() => (`${currentVal}`.length > 15 ? '350px' : 'auto'), [])
|
||||
|
||||
const changeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updateCustomTheme({
|
||||
[groupName]: { [keyName]: event.target.value },
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="editor-item">
|
||||
<Input value={currentVal as string} label={keyName}
|
||||
<Input
|
||||
value={currentVal as string}
|
||||
label={keyName}
|
||||
onChange={changeHandler}
|
||||
className="editor-input" />
|
||||
className="editor-input"
|
||||
/>
|
||||
<style jsx>{`
|
||||
.editor-item {
|
||||
background-color: transparent;
|
||||
@@ -40,12 +41,12 @@ const EditorInputItem: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: ${theme.palette.accents_5};
|
||||
margin-right: .75rem;
|
||||
margin-bottom: .5rem;
|
||||
margin-right: 0.75rem;
|
||||
margin-bottom: 0.5rem;
|
||||
cursor: pointer;
|
||||
transition: color 200ms ease;
|
||||
}
|
||||
|
||||
|
||||
.editor-item :global(.editor-input) {
|
||||
width: ${width};
|
||||
}
|
||||
|
||||
@@ -1,46 +1,91 @@
|
||||
import React from 'react'
|
||||
import { Text, Button, useTheme, ZeitUIThemesPalette, ZeitUIThemesExpressiveness, ZeitUIThemesLayout } from 'components'
|
||||
import {
|
||||
Text,
|
||||
Button,
|
||||
useTheme,
|
||||
ZeitUIThemesPalette,
|
||||
ZeitUIThemesExpressiveness,
|
||||
ZeitUIThemesLayout,
|
||||
} from 'components'
|
||||
import EditorColorItem from './editor-color-item'
|
||||
import EditorInputItem from './editor-input-item'
|
||||
import DefaultTheme from 'components/styles/themes/default'
|
||||
import { useConfigs } from 'lib/config-context'
|
||||
|
||||
const basicColors: Array<keyof ZeitUIThemesPalette> = [
|
||||
'accents_1', 'accents_2', 'accents_3', 'accents_4', 'accents_5', 'accents_6',
|
||||
'accents_7', 'accents_8', 'foreground', 'background',
|
||||
'accents_1',
|
||||
'accents_2',
|
||||
'accents_3',
|
||||
'accents_4',
|
||||
'accents_5',
|
||||
'accents_6',
|
||||
'accents_7',
|
||||
'accents_8',
|
||||
'foreground',
|
||||
'background',
|
||||
]
|
||||
const statusColors: Array<keyof ZeitUIThemesPalette> = [
|
||||
'success', 'successLight', 'successDark', 'error', 'errorLight', 'errorDark',
|
||||
'warning', 'warningLight', 'warningDark',
|
||||
'success',
|
||||
'successLight',
|
||||
'successDark',
|
||||
'error',
|
||||
'errorLight',
|
||||
'errorDark',
|
||||
'warning',
|
||||
'warningLight',
|
||||
'warningDark',
|
||||
]
|
||||
const otherColors: Array<keyof ZeitUIThemesPalette> = [
|
||||
'selection', 'secondary', 'link', 'border', 'code', 'cyan', 'purple', 'alert', 'violet'
|
||||
'selection',
|
||||
'secondary',
|
||||
'link',
|
||||
'border',
|
||||
'code',
|
||||
'cyan',
|
||||
'purple',
|
||||
'alert',
|
||||
'violet',
|
||||
]
|
||||
const expressiveness: Array<keyof ZeitUIThemesExpressiveness> = [
|
||||
'linkStyle', 'linkHoverStyle', 'dropdownBoxShadow', 'shadowSmall',
|
||||
'shadowMedium', 'shadowLarge',
|
||||
'linkStyle',
|
||||
'linkHoverStyle',
|
||||
'dropdownBoxShadow',
|
||||
'shadowSmall',
|
||||
'shadowMedium',
|
||||
'shadowLarge',
|
||||
]
|
||||
const pageLayout: Array<keyof ZeitUIThemesLayout> = [
|
||||
'pageWidth', 'pageWidthWithMargin', 'pageMargin', 'radius',
|
||||
'pageWidth',
|
||||
'pageWidthWithMargin',
|
||||
'pageMargin',
|
||||
'radius',
|
||||
]
|
||||
const gapLayout: Array<keyof ZeitUIThemesLayout> = [
|
||||
'gap', 'gapNegative', 'gapHalf', 'gapHalfNegative', 'gapQuarter', 'gapQuarterNegative',
|
||||
'gap',
|
||||
'gapNegative',
|
||||
'gapHalf',
|
||||
'gapHalfNegative',
|
||||
'gapQuarter',
|
||||
'gapQuarterNegative',
|
||||
]
|
||||
|
||||
const Editor = () => {
|
||||
const theme = useTheme()
|
||||
const { updateCustomTheme, isChinese } = useConfigs()
|
||||
|
||||
|
||||
const resetLayout = () => updateCustomTheme({ layout: DefaultTheme.layout })
|
||||
const restColors = () => updateCustomTheme({ palette: DefaultTheme.palette })
|
||||
const resetExpressiveness = () => {
|
||||
updateCustomTheme({ expressiveness: DefaultTheme.expressiveness })
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="editor">
|
||||
<Text h3>{isChinese ? '色彩' : 'Colors'}
|
||||
<Button type="abort" auto size="mini" onClick={restColors}>{isChinese ? '重置' : 'Reset'}</Button>
|
||||
<Text h3>
|
||||
{isChinese ? '色彩' : 'Colors'}
|
||||
<Button type="abort" auto size="mini" onClick={restColors}>
|
||||
{isChinese ? '重置' : 'Reset'}
|
||||
</Button>
|
||||
</Text>
|
||||
<p className="subtitle">{isChinese ? '基础' : 'basic'}</p>
|
||||
<div className="content">
|
||||
@@ -60,9 +105,12 @@ const Editor = () => {
|
||||
<EditorColorItem key={`${item}-${index}`} keyName={item} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Text h3>{isChinese ? '表现力' : 'Expressiveness'}
|
||||
<Button type="abort" auto size="mini" onClick={resetExpressiveness}>{isChinese ? '重置' : 'Reset'}</Button>
|
||||
|
||||
<Text h3>
|
||||
{isChinese ? '表现力' : 'Expressiveness'}
|
||||
<Button type="abort" auto size="mini" onClick={resetExpressiveness}>
|
||||
{isChinese ? '重置' : 'Reset'}
|
||||
</Button>
|
||||
</Text>
|
||||
<p className="subtitle">{isChinese ? '基础' : 'basic'}</p>
|
||||
<div className="content">
|
||||
@@ -70,14 +118,20 @@ const Editor = () => {
|
||||
<EditorInputItem key={`${item}-${index}`} groupName="expressiveness" keyName={item} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Text h3>{isChinese ? '布局' : 'Layout'}
|
||||
<Button type="abort" auto size="mini" onClick={resetLayout}>{isChinese ? '重置' : 'Reset'}</Button>
|
||||
|
||||
<Text h3>
|
||||
{isChinese ? '布局' : 'Layout'}
|
||||
<Button type="abort" auto size="mini" onClick={resetLayout}>
|
||||
{isChinese ? '重置' : 'Reset'}
|
||||
</Button>
|
||||
</Text>
|
||||
{isChinese ? (
|
||||
<p>大多数的布局间距都依赖这些变量,不合理的更改可能会导致布局失衡。</p>
|
||||
) : (
|
||||
<p>Most layout spacing depends on these variables, unreasonable changes may cause layout imbalance.</p>
|
||||
<p>
|
||||
Most layout spacing depends on these variables, unreasonable changes may cause layout
|
||||
imbalance.
|
||||
</p>
|
||||
)}
|
||||
<p className="subtitle">{isChinese ? '基础' : 'basic'}</p>
|
||||
<div className="content">
|
||||
@@ -101,15 +155,15 @@ const Editor = () => {
|
||||
margin: 0 auto;
|
||||
padding-left: ${theme.layout.gapQuarter};
|
||||
}
|
||||
|
||||
|
||||
.editor :global(h3) {
|
||||
margin: 2rem 0 1rem 0;
|
||||
}
|
||||
|
||||
|
||||
.subtitle {
|
||||
color: ${theme.palette.accents_4};
|
||||
text-transform: uppercase;
|
||||
font-size: .75rem;
|
||||
font-size: 0.75rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
@@ -3,9 +3,7 @@ import { useTheme, Row } from 'components'
|
||||
import CustomizationCodes from './codes'
|
||||
import Demo from './demo'
|
||||
|
||||
const CustomizationLayout: React.FC<React.PropsWithChildren<{}>> = ({
|
||||
children,
|
||||
}) => {
|
||||
const CustomizationLayout: React.FC<React.PropsWithChildren<{}>> = ({ children }) => {
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
@@ -17,7 +15,7 @@ const CustomizationLayout: React.FC<React.PropsWithChildren<{}>> = ({
|
||||
<Row>
|
||||
<CustomizationCodes />
|
||||
</Row>
|
||||
|
||||
|
||||
<style jsx>{`
|
||||
.layout {
|
||||
min-height: calc(100vh - 108px);
|
||||
@@ -28,7 +26,7 @@ const CustomizationLayout: React.FC<React.PropsWithChildren<{}>> = ({
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -54,19 +54,23 @@ const colorsData: { [key: string]: ColorEnum } = {
|
||||
|
||||
export const getColorData = (type: string): ColorEnum => {
|
||||
const data = colorsData[type]
|
||||
return data || colorsData.normal as ColorEnum
|
||||
return data || (colorsData.normal as ColorEnum)
|
||||
}
|
||||
|
||||
export const getCurrentColor = (palette: ZeitUIThemesPalette, type: string, index: number): string => {
|
||||
export const getCurrentColor = (
|
||||
palette: ZeitUIThemesPalette,
|
||||
type: string,
|
||||
index: number,
|
||||
): string => {
|
||||
if (type === 'normal') {
|
||||
if (index >= 5) return palette.background
|
||||
return palette.foreground
|
||||
}
|
||||
|
||||
|
||||
if (type === 'highlight') {
|
||||
if (index < 3) return 'white'
|
||||
return 'black'
|
||||
}
|
||||
|
||||
|
||||
return palette.background
|
||||
}
|
||||
|
||||
@@ -11,14 +11,16 @@ const getColorItem = (type: string, palette: ZeitUIThemesPalette, copy: Function
|
||||
const data = getColorData(type)
|
||||
const getColor = (index: number) => getCurrentColor(palette, type, index)
|
||||
const keys = Object.keys(data)
|
||||
|
||||
|
||||
return (keys as Array<keyof ZeitUIThemesPalette>).map((key, index) => (
|
||||
<div className="color" key={`color-item-${index}`}>
|
||||
<h4>{data[key]}</h4>
|
||||
<span className="usage"
|
||||
onClick={() => copy(`theme.palette.${key}`)}>theme.palette.{key}</span>
|
||||
<span className="value"
|
||||
onClick={() => copy(palette[key])}>{palette[key]}</span>
|
||||
<span className="usage" onClick={() => copy(`theme.palette.${key}`)}>
|
||||
theme.palette.{key}
|
||||
</span>
|
||||
<span className="value" onClick={() => copy(palette[key])}>
|
||||
{palette[key]}
|
||||
</span>
|
||||
<style jsx>{`
|
||||
.color {
|
||||
background-color: ${palette[key]};
|
||||
@@ -29,21 +31,25 @@ const getColorItem = (type: string, palette: ZeitUIThemesPalette, copy: Function
|
||||
))
|
||||
}
|
||||
|
||||
const Colors: React.FC<Props> = ({
|
||||
type,
|
||||
}) => {
|
||||
const Colors: React.FC<Props> = ({ type }) => {
|
||||
const theme = useTheme()
|
||||
const { copy } = useClipboard()
|
||||
const [, setToast] = useToasts()
|
||||
const copyText = (text: string) => {
|
||||
copy(text)
|
||||
setToast(({ text: <span>Copied <Code>{text}</Code></span> }))
|
||||
setToast({
|
||||
text: (
|
||||
<span>
|
||||
Copied <Code>{text}</Code>
|
||||
</span>
|
||||
),
|
||||
})
|
||||
}
|
||||
const colorItems = useMemo(
|
||||
() => getColorItem(type, theme.palette, copyText),
|
||||
[type, theme.palette],
|
||||
)
|
||||
|
||||
const colorItems = useMemo(() => getColorItem(type, theme.palette, copyText), [
|
||||
type,
|
||||
theme.palette,
|
||||
])
|
||||
|
||||
return (
|
||||
<div className="colors">
|
||||
{colorItems}
|
||||
@@ -53,7 +59,7 @@ const Colors: React.FC<Props> = ({
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.colors :global(.color) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -64,32 +70,32 @@ const Colors: React.FC<Props> = ({
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
||||
.colors :global(.color:first-child) {
|
||||
border-top-left-radius: ${theme.layout.radius};
|
||||
border-top-right-radius: ${theme.layout.radius};
|
||||
}
|
||||
|
||||
|
||||
.colors :global(.color:last-child) {
|
||||
border-bottom-left-radius: ${theme.layout.radius};
|
||||
border-bottom-right-radius: ${theme.layout.radius};
|
||||
}
|
||||
|
||||
|
||||
.colors :global(.color h4) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
.colors :global(.usage) {
|
||||
font-size: .875rem;
|
||||
font-size: 0.875rem;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
|
||||
.colors :global(.value) {
|
||||
font-size: .875rem;
|
||||
font-size: 0.875rem;
|
||||
text-transform: uppercase;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react'
|
||||
import { Text, useTheme } from 'components'
|
||||
|
||||
export const getFileName = (name: string): string => {
|
||||
return name.replace(/^(.)/, g => g.toLowerCase())
|
||||
return name.replace(/^(.)/, (g) => g.toLowerCase())
|
||||
}
|
||||
|
||||
export const getImportString = (name: string) => {
|
||||
@@ -10,7 +10,8 @@ export const getImportString = (name: string) => {
|
||||
const single = `import ${name} from '@zeit-ui/react-icons/${fileName}'`
|
||||
const normal = `import { ${name} } from '@zeit-ui/react-icons'`
|
||||
return {
|
||||
single, normal,
|
||||
single,
|
||||
normal,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +21,14 @@ interface Props {
|
||||
onClick: (name: string) => void
|
||||
}
|
||||
|
||||
const IconsCell: React.FC<Props> = ({
|
||||
component: Component, name, onClick
|
||||
}) => {
|
||||
const IconsCell: React.FC<Props> = ({ component: Component, name, onClick }) => {
|
||||
const theme = useTheme()
|
||||
return (
|
||||
<div className="icon-item" key={name} onClick={() => onClick(name)}>
|
||||
<Component />
|
||||
<Text type="secondary" small>{name}</Text>
|
||||
<Text type="secondary" small>
|
||||
{name}
|
||||
</Text>
|
||||
<style jsx>{`
|
||||
.icon-item {
|
||||
display: flex;
|
||||
@@ -45,7 +46,7 @@ const IconsCell: React.FC<Props> = ({
|
||||
user-select: none;
|
||||
transition: all 150ms ease-in-out;
|
||||
}
|
||||
|
||||
|
||||
.icon-item > :global(small) {
|
||||
display: inline-block;
|
||||
width: 90%;
|
||||
@@ -53,11 +54,11 @@ const IconsCell: React.FC<Props> = ({
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
.icon-item:hover {
|
||||
box-shadow: ${theme.expressiveness.shadowMedium};
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
|
||||
.icon-item {
|
||||
flex-basis: 30%;
|
||||
|
||||
@@ -23,7 +23,7 @@ const Icons: React.FC = () => {
|
||||
const { state: query, bindings } = useInput('')
|
||||
const [importStr, setImportStr] = useState({ title: '', single: '', normal: '' })
|
||||
const icons = Object.entries(Icon).filter(
|
||||
([name]) => !query || name.toLowerCase().includes(query.toLowerCase())
|
||||
([name]) => !query || name.toLowerCase().includes(query.toLowerCase()),
|
||||
)
|
||||
const onCellClick = (name: string) => {
|
||||
const { single, normal } = getImportString(name)
|
||||
@@ -35,11 +35,20 @@ const Icons: React.FC = () => {
|
||||
<>
|
||||
<h3 className="title">{isChinese ? '图标画廊' : 'Icons Gallery'}</h3>
|
||||
<Card>
|
||||
<Input width="100%" icon={<Icon.Search />} placeholder={isChinese ? '搜索' : 'Search'} {...bindings} />
|
||||
<Input
|
||||
width="100%"
|
||||
icon={<Icon.Search />}
|
||||
placeholder={isChinese ? '搜索' : 'Search'}
|
||||
{...bindings}
|
||||
/>
|
||||
<div className="icons-grid">
|
||||
{icons.map(([name, component], index) => (
|
||||
<IconsCell name={name} component={component} key={`${name}-${index}`}
|
||||
onClick={onCellClick} />
|
||||
<IconsCell
|
||||
name={name}
|
||||
component={component}
|
||||
key={`${name}-${index}`}
|
||||
onClick={onCellClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<Modal {...modalBindings}>
|
||||
|
||||
@@ -15,7 +15,7 @@ export type ExampleBlockProps = Props & typeof defaultProps
|
||||
|
||||
const getBackground = (theme: ZeitUIThemes, plain: number | boolean) => {
|
||||
if (typeof plain !== 'number') return theme.palette.success
|
||||
|
||||
|
||||
const colors = [
|
||||
theme.palette.accents_1,
|
||||
theme.palette.accents_2,
|
||||
@@ -27,27 +27,27 @@ const getBackground = (theme: ZeitUIThemes, plain: number | boolean) => {
|
||||
return colors[plain - 1] || theme.palette.success
|
||||
}
|
||||
|
||||
const ExampleBlock: React.FC<React.PropsWithChildren<ExampleBlockProps>> = React.memo(({
|
||||
plain, children, ...props
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const bg = useMemo(() => getBackground(theme, plain), [theme, plain])
|
||||
|
||||
return (
|
||||
<div className="block" {...props}>
|
||||
{children}
|
||||
<style jsx>{`
|
||||
.block {
|
||||
width: 100%;
|
||||
background: ${bg};
|
||||
padding: ${theme.layout.gapHalf};
|
||||
border-radius: ${theme.layout.radius};
|
||||
color: ${theme.palette.background};
|
||||
font-size: .75rem;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
const ExampleBlock: React.FC<React.PropsWithChildren<ExampleBlockProps>> = React.memo(
|
||||
({ plain, children, ...props }) => {
|
||||
const theme = useTheme()
|
||||
const bg = useMemo(() => getBackground(theme, plain), [theme, plain])
|
||||
|
||||
return (
|
||||
<div className="block" {...props}>
|
||||
{children}
|
||||
<style jsx>{`
|
||||
.block {
|
||||
width: 100%;
|
||||
background: ${bg};
|
||||
padding: ${theme.layout.gapHalf};
|
||||
border-radius: ${theme.layout.radius};
|
||||
color: ${theme.palette.background};
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
export default withDefaults(ExampleBlock, defaultProps)
|
||||
|
||||
@@ -6,14 +6,10 @@ export const LogoIcon: React.FC<React.SVGAttributes<any>> = ({ ...props }) => {
|
||||
return (
|
||||
<svg width="25" viewBox="0 0 114 100" fill="none" {...props}>
|
||||
<g fill={theme.palette.foreground}>
|
||||
<path
|
||||
d="M62.7991 21.1559L67.9119 30.1784L65.6224 31.4758L60.5096 22.4533L62.7991 21.1559ZM42.6148 30.1784L47.7276 21.1559L50.0172 22.4533L44.9044 31.4758L42.6148 30.1784ZM71.7465 36.9453L76.8593 45.9679L74.5697 47.2653L69.457 38.2427L71.7465 36.9453ZM33.6675 45.9679L38.7803 36.9453L41.0698 38.2427L35.957 47.2653L33.6675 45.9679ZM24.7201 61.7574L29.8329 52.7348L32.1224 54.0322L27.0096 63.0548L24.7201 61.7574ZM80.6939 52.7348L85.8066 61.7574L83.5171 63.0548L78.4043 54.0322L80.6939 52.7348ZM15.7727 77.5468L20.8855 68.5243L23.1751 69.8217L18.0623 78.8442L15.7727 77.5468ZM89.6412 68.5243L94.754 77.5468L92.4645 78.8442L87.3517 69.8217L89.6412 68.5243ZM33.534 90.7895H23.3085V88.1579H33.534V90.7895ZM51.4288 90.7895H41.2032V88.1579H51.4288V90.7895ZM69.3235 90.7895H59.098V88.1579H69.3235V90.7895ZM87.2183 90.7895H76.9927V88.1579H87.2183V90.7895Z" />
|
||||
<path
|
||||
d="M55.2636 2.63158C50.9035 2.63158 47.3689 6.16617 47.3689 10.5263C47.3689 14.8865 50.9035 18.4211 55.2636 18.4211C59.6238 18.4211 63.1584 14.8865 63.1584 10.5263C63.1584 6.16617 59.6238 2.63158 55.2636 2.63158ZM44.7373 10.5263C44.7373 4.71279 49.4501 0 55.2636 0C61.0771 0 65.7899 4.71279 65.7899 10.5263C65.7899 16.3398 61.0771 21.0526 55.2636 21.0526C49.4501 21.0526 44.7373 16.3398 44.7373 10.5263Z" />
|
||||
<path
|
||||
d="M102.632 81.579C98.2716 81.579 94.737 85.1136 94.737 89.4737C94.737 93.8338 98.2716 97.3684 102.632 97.3684C106.992 97.3684 110.527 93.8338 110.527 89.4737C110.527 85.1136 106.992 81.579 102.632 81.579ZM92.1055 89.4737C92.1055 83.6602 96.8183 78.9474 102.632 78.9474C108.445 78.9474 113.158 83.6602 113.158 89.4737C113.158 95.2872 108.445 100 102.632 100C96.8183 100 92.1055 95.2872 92.1055 89.4737Z" />
|
||||
<path
|
||||
d="M10.5263 81.579C6.16617 81.579 2.63158 85.1136 2.63158 89.4737C2.63158 93.8338 6.16617 97.3684 10.5263 97.3684C14.8865 97.3684 18.4211 93.8338 18.4211 89.4737C18.4211 85.1136 14.8865 81.579 10.5263 81.579ZM0 89.4737C0 83.6602 4.71279 78.9474 10.5263 78.9474C16.3398 78.9474 21.0526 83.6602 21.0526 89.4737C21.0526 95.2872 16.3398 100 10.5263 100C4.71279 100 0 95.2872 0 89.4737Z" />
|
||||
<path d="M62.7991 21.1559L67.9119 30.1784L65.6224 31.4758L60.5096 22.4533L62.7991 21.1559ZM42.6148 30.1784L47.7276 21.1559L50.0172 22.4533L44.9044 31.4758L42.6148 30.1784ZM71.7465 36.9453L76.8593 45.9679L74.5697 47.2653L69.457 38.2427L71.7465 36.9453ZM33.6675 45.9679L38.7803 36.9453L41.0698 38.2427L35.957 47.2653L33.6675 45.9679ZM24.7201 61.7574L29.8329 52.7348L32.1224 54.0322L27.0096 63.0548L24.7201 61.7574ZM80.6939 52.7348L85.8066 61.7574L83.5171 63.0548L78.4043 54.0322L80.6939 52.7348ZM15.7727 77.5468L20.8855 68.5243L23.1751 69.8217L18.0623 78.8442L15.7727 77.5468ZM89.6412 68.5243L94.754 77.5468L92.4645 78.8442L87.3517 69.8217L89.6412 68.5243ZM33.534 90.7895H23.3085V88.1579H33.534V90.7895ZM51.4288 90.7895H41.2032V88.1579H51.4288V90.7895ZM69.3235 90.7895H59.098V88.1579H69.3235V90.7895ZM87.2183 90.7895H76.9927V88.1579H87.2183V90.7895Z" />
|
||||
<path d="M55.2636 2.63158C50.9035 2.63158 47.3689 6.16617 47.3689 10.5263C47.3689 14.8865 50.9035 18.4211 55.2636 18.4211C59.6238 18.4211 63.1584 14.8865 63.1584 10.5263C63.1584 6.16617 59.6238 2.63158 55.2636 2.63158ZM44.7373 10.5263C44.7373 4.71279 49.4501 0 55.2636 0C61.0771 0 65.7899 4.71279 65.7899 10.5263C65.7899 16.3398 61.0771 21.0526 55.2636 21.0526C49.4501 21.0526 44.7373 16.3398 44.7373 10.5263Z" />
|
||||
<path d="M102.632 81.579C98.2716 81.579 94.737 85.1136 94.737 89.4737C94.737 93.8338 98.2716 97.3684 102.632 97.3684C106.992 97.3684 110.527 93.8338 110.527 89.4737C110.527 85.1136 106.992 81.579 102.632 81.579ZM92.1055 89.4737C92.1055 83.6602 96.8183 78.9474 102.632 78.9474C108.445 78.9474 113.158 83.6602 113.158 89.4737C113.158 95.2872 108.445 100 102.632 100C96.8183 100 92.1055 95.2872 92.1055 89.4737Z" />
|
||||
<path d="M10.5263 81.579C6.16617 81.579 2.63158 85.1136 2.63158 89.4737C2.63158 93.8338 6.16617 97.3684 10.5263 97.3684C14.8865 97.3684 18.4211 93.8338 18.4211 89.4737C18.4211 85.1136 14.8865 81.579 10.5263 81.579ZM0 89.4737C0 83.6602 4.71279 78.9474 10.5263 78.9474C16.3398 78.9474 21.0526 83.6602 21.0526 89.4737C21.0526 95.2872 16.3398 100 10.5263 100C4.71279 100 0 95.2872 0 89.4737Z" />
|
||||
</g>
|
||||
<style jsx>{`
|
||||
svg {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
|
||||
export { default as Layout } from './layout'
|
||||
export { default as Layout } from './layout'
|
||||
export { default as ActiveLink } from 'lib/components/sidebar/active-link'
|
||||
export { default as ActiveCatalog } from 'lib/components/sidebar/active-catalog'
|
||||
export { default as Sidebar } from './sidebar'
|
||||
export { default as Playground } from './playground'
|
||||
export { default as ExampleBlock } from './example-block'
|
||||
export { default as Attributes } from './attributes'
|
||||
|
||||
export { default as Sidebar } from './sidebar'
|
||||
export { default as Playground } from './playground'
|
||||
export { default as ExampleBlock } from './example-block'
|
||||
export { default as Attributes } from './attributes'
|
||||
|
||||
@@ -24,20 +24,21 @@ export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ ch
|
||||
setExpanded(!expanded)
|
||||
setBodyScroll(!expanded)
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => setShowAfterRender(true), [])
|
||||
|
||||
if (!showAfterRender) return (
|
||||
<section>
|
||||
{children}
|
||||
<style jsx>{`
|
||||
section {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
}
|
||||
`}</style>
|
||||
</section>
|
||||
)
|
||||
|
||||
if (!showAfterRender)
|
||||
return (
|
||||
<section>
|
||||
{children}
|
||||
<style jsx>{`
|
||||
section {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
}
|
||||
`}</style>
|
||||
</section>
|
||||
)
|
||||
return (
|
||||
<div className="layout">
|
||||
<TabbarMobile onClick={mobileTabbarClickHandler} />
|
||||
@@ -57,7 +58,7 @@ export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ ch
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
.sidebar {
|
||||
width: 200px;
|
||||
margin-right: 20px;
|
||||
@@ -77,7 +78,7 @@ export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ ch
|
||||
flex-shrink: 0;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
max-width: calc(100% - 220px);
|
||||
@@ -87,7 +88,7 @@ export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ ch
|
||||
flex: 0 0 100%;
|
||||
padding-bottom: 150px;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
|
||||
.layout {
|
||||
max-width: 100%;
|
||||
@@ -108,13 +109,13 @@ export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ ch
|
||||
overflow: hidden;
|
||||
transition: height 250ms ease;
|
||||
}
|
||||
|
||||
|
||||
.main {
|
||||
width: 90vw;
|
||||
max-width: 90vw;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
.side-shadow {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
|
||||
@@ -11,24 +11,20 @@ const Menu: React.FC<{}> = () => {
|
||||
useEffect(() => setShowAfterRender(true), [])
|
||||
useEffect(() => {
|
||||
const prefetch = async () => {
|
||||
const urls = isChinese ? [
|
||||
'/zh-cn/guide/introduction',
|
||||
'/zh-cn/components/text',
|
||||
'/zh-cn/customization',
|
||||
] : [
|
||||
'/en-us/guide/introduction',
|
||||
'/en-us/components/text',
|
||||
'/en-us/customization',
|
||||
]
|
||||
await Promise.all(urls.map(async (url) => {
|
||||
await router.prefetch(url)
|
||||
}))
|
||||
const urls = isChinese
|
||||
? ['/zh-cn/guide/introduction', '/zh-cn/components/text', '/zh-cn/customization']
|
||||
: ['/en-us/guide/introduction', '/en-us/components/text', '/en-us/customization']
|
||||
await Promise.all(
|
||||
urls.map(async (url) => {
|
||||
await router.prefetch(url)
|
||||
}),
|
||||
)
|
||||
}
|
||||
prefetch()
|
||||
.then()
|
||||
.catch(err => console.log(err))
|
||||
.catch((err) => console.log(err))
|
||||
}, [isChinese])
|
||||
|
||||
|
||||
if (!showAfterRender) return null
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -5,7 +5,6 @@ import Controls from 'lib/components/controls'
|
||||
import LogoIcon from 'lib/components/icons/logo'
|
||||
import { useConfigs } from '../../config-context'
|
||||
|
||||
|
||||
const MenuLinks = () => {
|
||||
const theme = useTheme()
|
||||
const { isChinese } = useConfigs()
|
||||
@@ -36,7 +35,7 @@ const MenuLinks = () => {
|
||||
padding: 0 ${theme.layout.gap};
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
|
||||
.site-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -40,12 +40,16 @@ const MenuSticker = () => {
|
||||
<nav className={fixed ? 'fixed' : ''}>
|
||||
<div className="sticker">
|
||||
<div className="inner">
|
||||
<Tabs value={tabValue} onChange={val => setTabValue(val)}>
|
||||
{tabbarData ? tabbarData.map((tab, index) => (
|
||||
<Tabs.Item label={tab.localeName || tab.name}
|
||||
value={tab.name}
|
||||
key={`${tab.localeName || tab.name}-${index}`} />
|
||||
)) : null}
|
||||
<Tabs value={tabValue} onChange={(val) => setTabValue(val)}>
|
||||
{tabbarData
|
||||
? tabbarData.map((tab, index) => (
|
||||
<Tabs.Item
|
||||
label={tab.localeName || tab.name}
|
||||
value={tab.name}
|
||||
key={`${tab.localeName || tab.name}-${index}`}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,7 +63,7 @@ const MenuSticker = () => {
|
||||
pointer-events: none;
|
||||
background-color: ${theme.palette.background};
|
||||
}
|
||||
|
||||
|
||||
.nav-fill.active {
|
||||
height: 48px;
|
||||
visibility: visible;
|
||||
@@ -71,7 +75,7 @@ const MenuSticker = () => {
|
||||
height: 48px;
|
||||
background-color: ${theme.palette.background};
|
||||
}
|
||||
|
||||
|
||||
nav.fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@@ -87,7 +91,7 @@ const MenuSticker = () => {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.sticker:before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
@@ -97,7 +101,7 @@ const MenuSticker = () => {
|
||||
bottom: 0;
|
||||
background-color: ${theme.palette.border};
|
||||
}
|
||||
|
||||
|
||||
.inner {
|
||||
max-width: ${theme.layout.pageWidth};
|
||||
padding: 0 ${theme.layout.gap};
|
||||
@@ -109,28 +113,29 @@ const MenuSticker = () => {
|
||||
z-index: 900;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
.inner :global(.content) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.inner :global(.tabs), .inner :global(header) {
|
||||
|
||||
.inner :global(.tabs),
|
||||
.inner :global(header) {
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
.inner :global(.tab) {
|
||||
height: calc(100% - 2px);
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
color: ${theme.palette.accents_5};
|
||||
font-size: .875rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
|
||||
.inner :global(.tab):hover {
|
||||
color: ${theme.palette.foreground};
|
||||
}
|
||||
|
||||
|
||||
.inner :global(.active) {
|
||||
color: ${theme.palette.foreground};
|
||||
}
|
||||
|
||||
@@ -13,100 +13,100 @@ const makeCodeTheme = (theme: ZeitUIThemes): PrismTheme => ({
|
||||
},
|
||||
styles: [
|
||||
{
|
||||
types: ["comment", "prolog", "doctype", "cdata", "punctuation"],
|
||||
types: ['comment', 'prolog', 'doctype', 'cdata', 'punctuation'],
|
||||
style: {
|
||||
color: 'theme.palette.accents_3',
|
||||
opacity: .5,
|
||||
}
|
||||
opacity: 0.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["namespace"],
|
||||
types: ['namespace'],
|
||||
style: {
|
||||
opacity: 1
|
||||
}
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["tag", "operator", "number"],
|
||||
types: ['tag', 'operator', 'number'],
|
||||
style: {
|
||||
color: theme.palette.accents_6,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["property", "function"],
|
||||
types: ['property', 'function'],
|
||||
style: {
|
||||
color: theme.palette.success,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["tag-id", "selector", "atrule-id"],
|
||||
types: ['tag-id', 'selector', 'atrule-id'],
|
||||
style: {
|
||||
color: "#eeebff"
|
||||
}
|
||||
color: '#eeebff',
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["attr-name"],
|
||||
types: ['attr-name'],
|
||||
style: {
|
||||
color: theme.palette.warning,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
types: [
|
||||
"boolean",
|
||||
"string",
|
||||
"entity",
|
||||
"url",
|
||||
"attr-value",
|
||||
"keyword",
|
||||
"control",
|
||||
"directive",
|
||||
"unit",
|
||||
"statement",
|
||||
"regex",
|
||||
"at-rule",
|
||||
"placeholder",
|
||||
"variable"
|
||||
'boolean',
|
||||
'string',
|
||||
'entity',
|
||||
'url',
|
||||
'attr-value',
|
||||
'keyword',
|
||||
'control',
|
||||
'directive',
|
||||
'unit',
|
||||
'statement',
|
||||
'regex',
|
||||
'at-rule',
|
||||
'placeholder',
|
||||
'variable',
|
||||
],
|
||||
style: {
|
||||
color: theme.palette.purple,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["deleted"],
|
||||
types: ['deleted'],
|
||||
style: {
|
||||
textDecorationLine: "line-through"
|
||||
}
|
||||
textDecorationLine: 'line-through',
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ['language-javascript', 'script'],
|
||||
style: {
|
||||
color: theme.palette.success
|
||||
color: theme.palette.success,
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["inserted"],
|
||||
types: ['inserted'],
|
||||
style: {
|
||||
textDecorationLine: "underline"
|
||||
}
|
||||
textDecorationLine: 'underline',
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["italic"],
|
||||
types: ['italic'],
|
||||
style: {
|
||||
fontStyle: "italic"
|
||||
}
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["important", "bold"],
|
||||
types: ['important', 'bold'],
|
||||
style: {
|
||||
fontWeight: "bold"
|
||||
}
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["important"],
|
||||
types: ['important'],
|
||||
style: {
|
||||
color: "#c4b9fe"
|
||||
}
|
||||
}
|
||||
]
|
||||
color: '#c4b9fe',
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
export default makeCodeTheme
|
||||
|
||||
@@ -21,48 +21,55 @@ const Editor: React.FC<Props> = ({ code }) => {
|
||||
event.preventDefault()
|
||||
setVisible(!visible)
|
||||
}
|
||||
|
||||
|
||||
const copyHandler = (event: React.MouseEvent) => {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
copy(code)
|
||||
setToast({ text: isChinese ? '代码已拷贝至剪切板。' : 'code copied.' })
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="editor">
|
||||
<details open={visible}>
|
||||
<summary onClick={clickHandler}>
|
||||
<Row justify="space-between" align="middle" style={{ height: '100%', width: '100%' }}>
|
||||
<Col className="action">
|
||||
<span className="arrow"><RightIcon size={16} /></span>
|
||||
<span className="arrow">
|
||||
<RightIcon size={16} />
|
||||
</span>
|
||||
<span>{isChinese ? '编辑代码' : 'Code Editor'}</span>
|
||||
</Col>
|
||||
<Col className="action">
|
||||
{visible && (
|
||||
<span className="copy" onClick={copyHandler} title={isChinese ? '拷贝代码' : 'Copy Code'}>
|
||||
<span
|
||||
className="copy"
|
||||
onClick={copyHandler}
|
||||
title={isChinese ? '拷贝代码' : 'Copy Code'}>
|
||||
<CopyIcon size={18} />
|
||||
</span>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</summary>
|
||||
<div className="area"><LiveEditor /></div>
|
||||
<div className="area">
|
||||
<LiveEditor />
|
||||
</div>
|
||||
</details>
|
||||
|
||||
|
||||
<style jsx>{`
|
||||
.editor {
|
||||
border-bottom-left-radius: ${theme.layout.radius};
|
||||
border-bottom-right-radius: ${theme.layout.radius};
|
||||
}
|
||||
|
||||
|
||||
details {
|
||||
transition: all 0.2s ease;
|
||||
overflow: hidden;
|
||||
border-bottom-left-radius: ${theme.layout.radius};
|
||||
border-bottom-right-radius: ${theme.layout.radius};
|
||||
}
|
||||
|
||||
|
||||
summary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -75,18 +82,18 @@ const Editor: React.FC<Props> = ({ code }) => {
|
||||
user-select: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
summary :global(svg) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
summary :global(.action) {
|
||||
width: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: .8rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
|
||||
.area {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
@@ -99,24 +106,24 @@ const Editor: React.FC<Props> = ({ code }) => {
|
||||
border-top: 1px solid ${theme.palette.accents_2};
|
||||
padding: ${theme.layout.gapHalf};
|
||||
}
|
||||
|
||||
|
||||
.arrow {
|
||||
transition: all .2s ease;
|
||||
transition: all 0.2s ease;
|
||||
transform: rotate(${visible ? 90 : 0}deg);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
margin-right: .5rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
.copy {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: ${theme.palette.accents_4};
|
||||
transition: color .2s ease;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
|
||||
.copy:hover {
|
||||
color: ${theme.palette.accents_6};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
const DynamicPlaygroundWithNoSSR = dynamic(
|
||||
() => import('./playground'),
|
||||
{ ssr: false }
|
||||
)
|
||||
const DynamicPlaygroundWithNoSSR = dynamic(() => import('./playground'), { ssr: false })
|
||||
|
||||
export default DynamicPlaygroundWithNoSSR
|
||||
|
||||
@@ -24,45 +24,45 @@ const defaultProps = {
|
||||
|
||||
export type PlaygroundProps = Props & typeof defaultProps
|
||||
|
||||
const Playground: React.FC<PlaygroundProps> = React.memo(({
|
||||
title: inputTitle, code: inputCode, desc, scope,
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const { isChinese } = useConfigs()
|
||||
const codeTheme = makeCodeTheme(theme)
|
||||
const code = inputCode.trim()
|
||||
const title = inputTitle || (isChinese ? '基础的' : 'Default')
|
||||
const Playground: React.FC<PlaygroundProps> = React.memo(
|
||||
({ title: inputTitle, code: inputCode, desc, scope }) => {
|
||||
const theme = useTheme()
|
||||
const { isChinese } = useConfigs()
|
||||
const codeTheme = makeCodeTheme(theme)
|
||||
const code = inputCode.trim()
|
||||
const title = inputTitle || (isChinese ? '基础的' : 'Default')
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title title={title} desc={desc} />
|
||||
<div className="playground">
|
||||
<LiveProvider code={code} scope={scope} theme={codeTheme}>
|
||||
<div className="wrapper">
|
||||
<LivePreview />
|
||||
<LiveError />
|
||||
</div>
|
||||
<Editor code={code} />
|
||||
</LiveProvider>
|
||||
|
||||
<style jsx>{`
|
||||
.playground {
|
||||
width: 100%;
|
||||
border-radius: ${theme.layout.radius};
|
||||
border: 1px solid ${theme.palette.accents_2};
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
padding: ${theme.layout.pageMargin};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
})
|
||||
return (
|
||||
<>
|
||||
<Title title={title} desc={desc} />
|
||||
<div className="playground">
|
||||
<LiveProvider code={code} scope={scope} theme={codeTheme}>
|
||||
<div className="wrapper">
|
||||
<LivePreview />
|
||||
<LiveError />
|
||||
</div>
|
||||
<Editor code={code} />
|
||||
</LiveProvider>
|
||||
|
||||
<style jsx>{`
|
||||
.playground {
|
||||
width: 100%;
|
||||
border-radius: ${theme.layout.radius};
|
||||
border: 1px solid ${theme.palette.accents_2};
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
padding: ${theme.layout.pageMargin};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
export default withDefaults(Playground, defaultProps)
|
||||
|
||||
@@ -18,22 +18,19 @@ const replaceCode = (desc: string) => {
|
||||
let count = 0
|
||||
return desc.replace(/`/g, () => {
|
||||
const val = count % 2 === 0 ? '<code>' : '</code>'
|
||||
count ++
|
||||
count++
|
||||
return val
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const Title: React.FC<TitleProps> = React.memo(({
|
||||
title, desc,
|
||||
}) => {
|
||||
const Title: React.FC<TitleProps> = React.memo(({ title, desc }) => {
|
||||
return (
|
||||
<>
|
||||
<h3>
|
||||
<VirtualAnchor>{title}</VirtualAnchor>
|
||||
</h3>
|
||||
{desc && <p dangerouslySetInnerHTML={{ __html: replaceCode(desc) }} />}
|
||||
|
||||
|
||||
<style jsx>{`
|
||||
h3 {
|
||||
margin-bottom: ${desc ? 0 : '30px'};
|
||||
@@ -43,12 +40,13 @@ const Title: React.FC<TitleProps> = React.memo(({
|
||||
text-transform: capitalize;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
h3 > p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h3 > :global(code), h3 > :global(pre) {
|
||||
|
||||
h3 > :global(code),
|
||||
h3 > :global(pre) {
|
||||
text-transform: none;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
@@ -7,25 +7,23 @@ export interface Props {
|
||||
localeName?: string
|
||||
}
|
||||
|
||||
const ActiveCatalog: React.FC<Props> = React.memo(({
|
||||
name, localeName, ...props
|
||||
}) => {
|
||||
const ActiveCatalog: React.FC<Props> = React.memo(({ name, localeName, ...props }) => {
|
||||
const theme = useTheme()
|
||||
const { pathname } = useRouter()
|
||||
const isActive = pathname.includes(`/${name}/`)
|
||||
|
||||
|
||||
return (
|
||||
<span {...props} className={isActive ? 'active' : ''}>
|
||||
{localeName || name}
|
||||
<style jsx>{`
|
||||
span {
|
||||
font-size: .8125rem;
|
||||
transition: all .2s ease;
|
||||
font-size: 0.8125rem;
|
||||
transition: all 0.2s ease;
|
||||
color: ${theme.palette.accents_4};
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1.3px;
|
||||
}
|
||||
|
||||
|
||||
.active {
|
||||
color: ${theme.palette.foreground};
|
||||
}
|
||||
|
||||
@@ -9,18 +9,13 @@ export interface Props {
|
||||
text: string
|
||||
}
|
||||
|
||||
const ActiveLink: React.FC<Props> = React.memo(({
|
||||
href, text,
|
||||
}) => {
|
||||
const ActiveLink: React.FC<Props> = React.memo(({ href, text }) => {
|
||||
const theme = useTheme()
|
||||
const { pathname } = useRouter()
|
||||
const [title, subtitle] = useMemo(() => {
|
||||
if (!/[\u4E00-\u9FA5]/.test(text)) return [text, null]
|
||||
if (/zeit|ui|ZEIT|UI/.test(text)) return [text, null]
|
||||
return [
|
||||
text.replace(/[^\u4E00-\u9FA5]/g, ''),
|
||||
text.replace(/[^a-zA-Z]/g, ''),
|
||||
]
|
||||
return [text.replace(/[^\u4E00-\u9FA5]/g, ''), text.replace(/[^a-zA-Z]/g, '')]
|
||||
}, [text])
|
||||
const isActive = pathname === href
|
||||
|
||||
@@ -28,7 +23,8 @@ const ActiveLink: React.FC<Props> = React.memo(({
|
||||
<div className="link">
|
||||
<Link href={href}>
|
||||
<a className={isActive ? 'active' : ''}>
|
||||
{title}{subtitle && <span> {subtitle}</span>}
|
||||
{title}
|
||||
{subtitle && <span> {subtitle}</span>}
|
||||
</a>
|
||||
</Link>
|
||||
<style jsx>{`
|
||||
@@ -42,7 +38,7 @@ const ActiveLink: React.FC<Props> = React.memo(({
|
||||
cursor: pointer;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
|
||||
a {
|
||||
color: ${theme.palette.accents_7};
|
||||
font-size: 1rem;
|
||||
@@ -51,18 +47,18 @@ const ActiveLink: React.FC<Props> = React.memo(({
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
|
||||
a.active {
|
||||
color: ${theme.palette.success};
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
a.active span {
|
||||
color: ${theme.palette.successLight};
|
||||
}
|
||||
|
||||
|
||||
span {
|
||||
font-size: .75rem;
|
||||
font-size: 0.75rem;
|
||||
color: ${theme.palette.accents_4};
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
@@ -6,15 +6,18 @@ import useLocale from 'lib/use-locale'
|
||||
import { useConfigs } from 'lib/config-context'
|
||||
import Metadatas from 'lib/data'
|
||||
|
||||
export interface Props {
|
||||
}
|
||||
export interface Props {}
|
||||
|
||||
export type SideChildren = Sides | Array<Sides>
|
||||
|
||||
export const SideGroup: React.FC<{ sides?: SideChildren }> = React.memo(({ sides }) => {
|
||||
if (!sides) return null
|
||||
sides = Array.isArray(sides) ? sides : [sides]
|
||||
return <SideItem sides={sides} ><SideGroup /></SideItem>
|
||||
return (
|
||||
<SideItem sides={sides}>
|
||||
<SideGroup />
|
||||
</SideItem>
|
||||
)
|
||||
})
|
||||
|
||||
export const Sidebar: React.FC<Props> = React.memo(() => {
|
||||
@@ -25,7 +28,7 @@ export const Sidebar: React.FC<Props> = React.memo(() => {
|
||||
|
||||
const tabbarData = useMemo(() => {
|
||||
const allSides = Metadatas[locale]
|
||||
const currentSide = allSides.filter(side => side.name === tabbar)[0]
|
||||
const currentSide = allSides.filter((side) => side.name === tabbar)[0]
|
||||
return (currentSide.children || []) as Array<Sides>
|
||||
}, [locale, tabbar])
|
||||
|
||||
@@ -52,7 +55,7 @@ export const Sidebar: React.FC<Props> = React.memo(() => {
|
||||
width: 100%;
|
||||
padding-bottom: ${theme.layout.gap};
|
||||
}
|
||||
|
||||
|
||||
.box {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
@@ -61,16 +64,16 @@ export const Sidebar: React.FC<Props> = React.memo(() => {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.box::-webkit-scrollbar {
|
||||
width: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.box>:global(.item) {
|
||||
|
||||
.box > :global(.item) {
|
||||
margin-bottom: ${theme.layout.gap};
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
|
||||
.box {
|
||||
padding: calc(3.5 * ${theme.layout.gap}) 15vw;
|
||||
|
||||
@@ -14,56 +14,58 @@ export interface SideItemProps {
|
||||
sides: Array<Sides>
|
||||
}
|
||||
|
||||
const SideItem: React.FC<React.PropsWithChildren<SideItemProps>> = React.memo(({
|
||||
children, sides,
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const SideItem: React.FC<React.PropsWithChildren<SideItemProps>> = React.memo(
|
||||
({ children, sides }) => {
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<>
|
||||
{sides.map((side, index) => {
|
||||
const showChildren = side.children && children
|
||||
return (
|
||||
<div key={`${side.localeName || side.name}-${index}`} className="item">
|
||||
{!side.url && <ActiveCatalog name={side.name} localeName={side.localeName} />}
|
||||
{side.url && <ActiveLink href={side.url} text={side.name} />}
|
||||
|
||||
{showChildren && <div className="children">
|
||||
{React.cloneElement(children as ReactElement, {
|
||||
sides: side.children,
|
||||
})}
|
||||
</div>}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<style jsx>{`
|
||||
.item {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.children {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
transition: all .2s ease-in-out;
|
||||
position: relative;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.active-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
|
||||
.link {
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
height: 3.5rem;
|
||||
return (
|
||||
<>
|
||||
{sides.map((side, index) => {
|
||||
const showChildren = side.children && children
|
||||
return (
|
||||
<div key={`${side.localeName || side.name}-${index}`} className="item">
|
||||
{!side.url && <ActiveCatalog name={side.name} localeName={side.localeName} />}
|
||||
{side.url && <ActiveLink href={side.url} text={side.name} />}
|
||||
|
||||
{showChildren && (
|
||||
<div className="children">
|
||||
{React.cloneElement(children as ReactElement, {
|
||||
sides: side.children,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<style jsx>{`
|
||||
.item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
.children {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
transition: all 0.2s ease-in-out;
|
||||
position: relative;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.active-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
|
||||
.link {
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
height: 3.5rem;
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
export default SideItem
|
||||
|
||||
@@ -6,7 +6,7 @@ interface Props {
|
||||
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void
|
||||
}
|
||||
|
||||
const TabbarMobile:React.FC<Props> = ({ onClick }) => {
|
||||
const TabbarMobile: React.FC<Props> = ({ onClick }) => {
|
||||
const theme = useTheme()
|
||||
const handler = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
onClick && onClick(event)
|
||||
@@ -34,7 +34,7 @@ const TabbarMobile:React.FC<Props> = ({ onClick }) => {
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid ${theme.palette.border};
|
||||
}
|
||||
|
||||
|
||||
.tabbar :global(.toggle) {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
@@ -44,14 +44,14 @@ const TabbarMobile:React.FC<Props> = ({ onClick }) => {
|
||||
align-items: center;
|
||||
color: ${theme.palette.accents_6};
|
||||
}
|
||||
|
||||
|
||||
span {
|
||||
color: ${theme.palette.accents_7};
|
||||
font-size: .75rem;
|
||||
font-size: 0.75rem;
|
||||
display: inline-flex;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (min-width: ${theme.layout.breakpointMobile}) {
|
||||
.tabbar {
|
||||
display: none;
|
||||
|
||||
Reference in New Issue
Block a user