docs: add customization page

This commit is contained in:
unix
2020-04-10 18:19:33 +08:00
parent e089e1c04b
commit bf689b76d1
18 changed files with 605 additions and 32 deletions

View File

@@ -9,7 +9,7 @@ import SunIcon from './icons/sun'
const Controls: React.FC<{}> = React.memo(({
}) => {
const theme = useTheme()
const { onChange, updateChineseState } = useConfigs()
const { updateCustomTheme, updateChineseState } = useConfigs()
const { pathname } = useRouter()
const { locale } = useLocale()
const isChinese = useMemo(() => locale === 'zh-cn', [locale])
@@ -19,9 +19,8 @@ const Controls: React.FC<{}> = React.memo(({
return pathname.replace(locale, nextLocale)
}, [locale, pathname])
const switchThemes = (val: string) => {
const isDark = val === 'dark'
onChange && onChange(isDark)
const switchThemes = (type: 'dark' | 'light') => {
updateCustomTheme({ type })
}
const switchLanguages = () => {
updateChineseState(!isChinese)

View File

@@ -0,0 +1,37 @@
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 Colors: React.FC<React.PropsWithChildren<{}>> = () => {
const theme = useTheme()
return (
<div className="colors">
{types.map((type, index) => {
return (
<div key={`${type}-${index}`} className="color-card">
<Card type={type as CardTypes}>{type}</Card>
</div>
)
})}
<style jsx>{`
.colors {
display: flex;
flex-wrap: wrap;
}
.color-card {
display: flex;
width: 9rem;
margin-right: ${theme.layout.gapHalf};
margin-bottom: ${theme.layout.gapHalf};
}
`}</style>
</div>
)
}
export default Colors

View File

@@ -0,0 +1,110 @@
import React, { useState } from 'react'
import FullScreenIcon from 'lib/components/icons/full-screen'
import FullScreenCloseIcon from 'lib/components/icons/full-screen-close'
import Colors from './colors'
import { useTheme, Button, Text, Code, Spacer, Link, Select, Checkbox } from 'components'
const Demo: React.FC<React.PropsWithChildren<{}>> = () => {
const theme = useTheme()
const [fullScreen, setFullScreen] = useState<boolean>(false)
const showMoreOrLess = () => {
setFullScreen(last => !last)
}
return (
<div className="demo">
<div className="action" onClick={showMoreOrLess}>
<Button type="abort" auto>
{fullScreen ? <FullScreenIcon /> : <FullScreenCloseIcon />}
</Button>
</div>
<div className="content">
<Text h3>Preview</Text>
<Text>Here&#39;s a preview of your changes to the Theme. When you save the changes,
the entire document site will change with the theme.</Text>
<Text>You can download automatically generated code or share your custom theme with anyone.</Text>
<Spacer y={1.7} />
<Text h4>Colors</Text>
<Colors />
<Spacer y={1.7} />
<Text h4>Typography</Text>
<Text><Code>inline codes</Code>, <Link href="#" color>Hyperlink</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>Basic Components</Text>
<Select placeholder="Choose one" initialValue="1">
<Select.Option value="1">Option 1</Select.Option>
<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>Action</Button>
<Spacer y={1} />
<Checkbox.Group value={['sydney']}>
<Checkbox value="sydney">Sydney</Checkbox>
<Checkbox value="beijing">Bei Jing</Checkbox>
</Checkbox.Group>
<Spacer y={4} />
</div>
<style jsx>{`
.demo {
width: ${fullScreen ? '100%' : '35%'};
margin-top: calc(${theme.layout.gap} * 2);
margin-right: 20px;
position: relative;
border-right: 1px solid ${theme.palette.border};
height: 100%;
transition: width 200ms ease;
}
.action {
position: absolute;
right: .5rem;
top: 0;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: color 200ms ease-out;
color: ${theme.palette.accents_3};
}
.action:hover {
color: ${theme.palette.accents_6};
}
.action :global(button) {
width: 2rem;
height: 2rem;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
color: inherit;
}
.content {
width: 100%;
}
`}</style>
</div>
)
}
export default Demo

View File

@@ -0,0 +1,95 @@
import React, { useMemo } from 'react'
import { useTheme, ZeitUIThemesPalette, Popover } from 'components'
import { ColorResult, TwitterPicker } from 'react-color'
import { useConfigs } from 'lib/config-context'
interface Props {
value?: string
keyName: keyof ZeitUIThemesPalette
}
const EditorColorItem: React.FC<React.PropsWithChildren<Props>> = ({
keyName,
}) => {
const theme = useTheme()
const { updateCustomTheme } = useConfigs()
const label = `${keyName}`
const mainColor = useMemo(() => theme.palette[keyName], [theme.palette, keyName])
const colorChangeHandler = ({ hex }: ColorResult) => {
updateCustomTheme({
palette: { [keyName]: hex }
})
}
const popoverContent = (color: string) => (
<TwitterPicker triangle="hide" color={color} onChangeComplete={colorChangeHandler} />
)
return (
<Popover content={() => popoverContent(mainColor)} portalClassName="editor-popover" offset={3}>
<div className="editor-item">
<div className="dot-box">
<span className="dot" />
</div>
{label}
<style jsx>{`
.editor-item {
background-color: transparent;
width: auto;
padding: 0 ${theme.layout.gapHalf};
line-height: 2rem;
display: inline-flex;
align-items: center;
border: 1px solid ${theme.palette.border};
border-radius: ${theme.layout.radius};
color: ${theme.palette.accents_5};
margin-right: .75rem;
margin-bottom: .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 {
display: inline-flex;
justify-content: center;
align-items: center;
}
.dot-box {
width: 1rem;
height: 1rem;
margin-right: .75rem;
}
.dot {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: ${mainColor};
transform: scale(.8);
transition: transform 200ms ease;
}
`}</style>
</div>
</Popover>
)
}
export default EditorColorItem

View File

@@ -0,0 +1,55 @@
import React, { useMemo } from 'react'
import { useTheme, Input, ZeitUIThemes } from 'components'
import { useConfigs } from 'lib/config-context'
type Props = {
value?: string
groupName: keyof ZeitUIThemes
keyName: string
}
const EditorInputItem: React.FC<React.PropsWithChildren<Props>> = ({
groupName, keyName
}) => {
const theme = useTheme()
const { updateCustomTheme } = useConfigs()
const currentVal = useMemo(() => {
const group = theme[groupName]
const key = keyName as keyof typeof group
return theme[groupName][key]
}, [theme.expressiveness, keyName])
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} onChange={changeHandler} className="editor-input" />
<style jsx>{`
.editor-item {
background-color: transparent;
width: auto;
padding: 0 ${theme.layout.gapHalf};
line-height: 2rem;
display: inline-flex;
align-items: center;
color: ${theme.palette.accents_5};
margin-right: .75rem;
margin-bottom: .5rem;
cursor: pointer;
transition: color 200ms ease;
}
.editor-item :global(.editor-input) {
width: ${width};
}
`}</style>
</div>
)
}
export default EditorInputItem

View File

@@ -0,0 +1,108 @@
import React from 'react'
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',
]
const statusColors: Array<keyof ZeitUIThemesPalette> = [
'success', 'successLight', 'successDark', 'error', 'errorLight', 'errorDark',
'warning', 'warningLight', 'warningDark',
]
const otherColors: Array<keyof ZeitUIThemesPalette> = [
'selection', 'secondary', 'border', 'code', 'cyan', 'purple', 'alert', 'violet'
]
const expressiveness: Array<keyof ZeitUIThemesExpressiveness> = [
'linkStyle', 'linkHoverStyle', 'dropdownBoxShadow', 'shadowSmall',
'shadowMedium', 'shadowLarge',
]
const pageLayout: Array<keyof ZeitUIThemesLayout> = [
'pageWidth', 'pageWidthWithMargin', 'pageMargin', 'radius',
]
const gapLayout: Array<keyof ZeitUIThemesLayout> = [
'gap', 'gapNegative', 'gapHalf', 'gapHalfNegative', 'gapQuarter', 'gapQuarterNegative',
]
const Editor = () => {
const theme = useTheme()
const { updateCustomTheme } = 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>Colors <Button type="abort" auto size="mini" onClick={restColors}>Reset</Button></Text>
<p className="subtitle">basic</p>
<div className="content">
{basicColors.map((item, index) => (
<EditorColorItem key={`${item}-${index}`} keyName={item} />
))}
</div>
<p className="subtitle">status</p>
<div className="content">
{statusColors.map((item, index) => (
<EditorColorItem key={`${item}-${index}`} keyName={item} />
))}
</div>
<p className="subtitle">others</p>
<div className="content">
{otherColors.map((item, index) => (
<EditorColorItem key={`${item}-${index}`} keyName={item} />
))}
</div>
<Text h3>Expressiveness <Button type="abort" auto size="mini" onClick={resetExpressiveness}>Reset</Button></Text>
<p className="subtitle">basic</p>
<div className="content">
{expressiveness.map((item, index) => (
<EditorInputItem key={`${item}-${index}`} groupName="expressiveness" keyName={item} />
))}
</div>
<Text h3>Layout <Button type="abort" auto size="mini" onClick={resetLayout}>Reset</Button></Text>
<p className="subtitle">basic</p>
<div className="content">
{pageLayout.map((item, index) => (
<EditorInputItem key={`${item}-${index}`} groupName="layout" keyName={item} />
))}
</div>
<p className="subtitle">gaps</p>
<div className="content">
{gapLayout.map((item, index) => (
<EditorInputItem key={`${item}-${index}`} groupName="layout" keyName={item} />
))}
</div>
<style jsx>{`
.content {
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: wrap;
width: auto;
margin: 0 auto;
}
.editor :global(h3) {
margin: 2rem 0 1rem 0;
}
.subtitle {
color: ${theme.palette.accents_4};
text-transform: uppercase;
font-size: .75rem;
margin-top: 2rem;
}
`}</style>
</div>
)
}
export default Editor

View File

@@ -0,0 +1,38 @@
import React from 'react'
import { useTheme } from 'components'
import Demo from './demo'
const CustomizationLayout: React.FC<React.PropsWithChildren<{}>> = ({
children,
}) => {
const theme = useTheme()
return (
<div className="layout">
<Demo />
<div className="content">
{children}
</div>
<style jsx>{`
.layout {
min-height: calc(100vh - 108px);
max-width: 1000px;
margin: 0 auto;
padding: 0 ${theme.layout.gap};
display: flex;
box-sizing: border-box;
}
.content {
flex: 1;
}
.demo {
}
`}</style>
</div>
)
}
export default CustomizationLayout

View File

@@ -0,0 +1,28 @@
import React from 'react'
import withDefaults from 'components/utils/with-defaults'
interface Props {
width: number
height: number
}
const defaultProps = {
width: 20,
height: 20,
}
export type FullScreenCloseIconProps = Props & typeof defaultProps & React.SVGAttributes<any>
const FullScreenCloseIcon: React.FC<React.PropsWithChildren<FullScreenCloseIconProps>> = ({
width, height, ...props
}) => {
return (
<svg viewBox="0 0 24 24" width={width} height={height} {...props} stroke="currentColor" strokeWidth="1.5"
strokeLinecap="round" strokeLinejoin="round" fill="none" shapeRendering="geometricPrecision"
style={{ color: 'currentColor' }}>
<path d="M4 14h6m0 0v6m0-6l-7 7m17-11h-6m0 0V4m0 6l7-7m-7 17v-6m0 0h6m-6 0l7 7M10 4v6m0 0H4m6 0L3 3"/>
</svg>
)
}
export default withDefaults(FullScreenCloseIcon, defaultProps)

View File

@@ -0,0 +1,27 @@
import React from 'react'
import withDefaults from 'components/utils/with-defaults'
interface Props {
width: number
height: number
}
const defaultProps = {
width: 20,
height: 20,
}
export type FullScreenIconProps = Props & typeof defaultProps & React.SVGAttributes<any>
const FullScreenIcon: React.FC<React.PropsWithChildren<FullScreenIconProps>> = ({
width, height, ...props
}) => {
return (
<svg viewBox="0 0 24 24" width={width} height={height} {...props} stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"
strokeLinejoin="round" fill="none" shapeRendering="geometricPrecision" style={{ color: 'currentColor' }}>
<path d="M15 3h6m0 0v6m0-6l-7 7M9 21H3m0 0v-6m0 6l7-7M3 9V3m0 0h6M3 3l7 7m11 5v6m0 0h-6m6 0l-7-7"/>
</svg>
)
}
export default withDefaults(FullScreenIcon, defaultProps)

View File

@@ -1,7 +1,9 @@
import React from 'react'
import { ZeitUIThemes } from 'components/styles/themes'
import { DeepPartial } from 'components/utils/types'
export interface Configs {
onChange?: Function
onThemeChange?: Function
isChinese?: boolean
updateChineseState: Function
sidebarScrollHeight: number
@@ -9,6 +11,9 @@ export interface Configs {
tabbarFixed: boolean
updateTabbarFixed: Function
customTheme: DeepPartial<ZeitUIThemes>
updateCustomTheme: (theme: DeepPartial<ZeitUIThemes>) => void
}
export const defaultConfigs: Configs = {
@@ -18,6 +23,10 @@ export const defaultConfigs: Configs = {
tabbarFixed: false,
updateTabbarFixed: () => {},
customTheme: {},
updateCustomTheme: () => {},
onThemeChange: () => {},
}
export const ConfigContext = React.createContext<Configs>(defaultConfigs)

View File

@@ -2,9 +2,14 @@ import React, { useMemo, useState } from 'react'
import withDefaults from 'components/utils/with-defaults'
import { ConfigContext, Configs } from 'lib/config-context'
import { useRouter } from 'next/router'
import { DeepPartial } from 'components/utils/types'
import { ZeitUIThemes } from 'components/styles/themes'
import { deepMergeObject } from 'components/styles/theme-provider/theme-provider'
import useCurrentState from 'components/utils/use-current-state'
import { useTheme } from 'components'
interface Props {
onChange?: Function
onThemeChange?: Function
}
const defaultProps = {
@@ -13,23 +18,33 @@ const defaultProps = {
export type ConfigProviderProps = Props & typeof defaultProps
const ConfigProvider: React.FC<React.PropsWithChildren<ConfigProviderProps>> = React.memo(({
onChange, children,
onThemeChange, children,
}) => {
const theme = useTheme()
const { pathname } = useRouter()
const [isChinese, setIsChinese] = useState<boolean>(() => pathname.includes('zh-cn'))
const [scrollHeight, setScrollHeight] = useState<number>(0)
const [tabbarFixed, setTabbarFixed] = useState<boolean>(false)
const [customTheme, setCustomTheme, customThemeRef] = useCurrentState<DeepPartial<ZeitUIThemes>>(theme)
const updateSidebarScrollHeight = (height: number) => setScrollHeight(height)
const updateChineseState = (state: boolean) => setIsChinese(state)
const updateTabbarFixed = (state: boolean) => setTabbarFixed(state)
const updateCustomTheme = (nextTheme: DeepPartial<ZeitUIThemes>) => {
const mergedTheme = deepMergeObject(customThemeRef.current, nextTheme)
setCustomTheme(mergedTheme)
onThemeChange && onThemeChange(mergedTheme)
}
const initialValue = useMemo<Configs>(() => ({
onChange, isChinese, tabbarFixed,
onThemeChange, isChinese, tabbarFixed,
customTheme,
updateCustomTheme,
updateTabbarFixed,
updateChineseState,
sidebarScrollHeight: scrollHeight,
updateSidebarScrollHeight,
}), [onChange, scrollHeight, tabbarFixed, isChinese])
}), [onThemeChange, scrollHeight, tabbarFixed, isChinese])
return (
<ConfigContext.Provider value={initialValue}>

View File

@@ -1 +1 @@
[{"name":"guide","children":[{"name":"getting-started","children":[{"name":"introduction","url":"/en-us/guide/introduction","index":5,"group":"getting-started"},{"name":"installation","url":"/en-us/guide/installation","index":10,"group":"getting-started"},{"name":"Server Render","url":"/en-us/guide/server-render","index":15,"group":"getting-started"}]},{"name":"customization","children":[{"name":"Colors","url":"/en-us/guide/colors","index":100,"group":"customization"},{"name":"Themes","url":"/en-us/guide/themes","index":100,"group":"customization"}]}]},{"name":"components","children":[{"name":"General","children":[{"name":"button","url":"/en-us/components/button","index":100,"group":"General"},{"name":"Code","url":"/en-us/components/code","index":100,"group":"General"},{"name":"Spacer","url":"/en-us/components/spacer","index":100,"group":"General"},{"name":"text","url":"/en-us/components/text","index":100,"group":"General"}]},{"name":"layout","children":[{"name":"layout","url":"/en-us/components/layout","index":100,"group":"layout"}]},{"name":"Surfaces","children":[{"name":"card","url":"/en-us/components/card","index":100,"group":"Surfaces"},{"name":"collapse","url":"/en-us/components/collapse","index":100,"group":"Surfaces"},{"name":"fieldset","url":"/en-us/components/fieldset","index":100,"group":"Surfaces"}]},{"name":"Data Entry","children":[{"name":"Auto-Complete","url":"/en-us/components/auto-complete","index":100,"group":"Data Entry"},{"name":"checkbox","url":"/en-us/components/checkbox","index":100,"group":"Data Entry"},{"name":"Input","url":"/en-us/components/input","index":100,"group":"Data Entry"},{"name":"radio","url":"/en-us/components/radio","index":100,"group":"Data Entry"},{"name":"select","url":"/en-us/components/select","index":100,"group":"Data Entry"},{"name":"textarea","url":"/en-us/components/textarea","index":100,"group":"Data Entry"},{"name":"Toggle","url":"/en-us/components/toggle","index":100,"group":"Data Entry"}]},{"name":"Data Display","children":[{"name":"avatar","url":"/en-us/components/avatar","index":100,"group":"Data Display"},{"name":"Badge","url":"/en-us/components/badge","index":100,"group":"Data Display"},{"name":"Capacity","url":"/en-us/components/capacity","index":100,"group":"Data Display"},{"name":"Description","url":"/en-us/components/description","index":100,"group":"Data Display"},{"name":"Display","url":"/en-us/components/display","index":100,"group":"Data Display"},{"name":"Dot","url":"/en-us/components/dot","index":100,"group":"Data Display"},{"name":"File-Tree","url":"/en-us/components/file-tree","index":100,"group":"Data Display"},{"name":"Image","url":"/en-us/components/image","index":100,"group":"Data Display"},{"name":"keyboard","url":"/en-us/components/keyboard","index":100,"group":"Data Display"},{"name":"Popover","url":"/en-us/components/popover","index":100,"group":"Data Display"},{"name":"Table","url":"/en-us/components/table","index":100,"group":"Data Display"},{"name":"Tag","url":"/en-us/components/tag","index":100,"group":"Data Display"},{"name":"Tooltip","url":"/en-us/components/tooltip","index":100,"group":"Data Display"}]},{"name":"Feedback","children":[{"name":"Loading","url":"/en-us/components/loading","index":100,"group":"Feedback"},{"name":"modal","url":"/en-us/components/modal","index":100,"group":"Feedback"},{"name":"note","url":"/en-us/components/note","index":100,"group":"Feedback"},{"name":"Progress","url":"/en-us/components/progress","index":100,"group":"Feedback"},{"name":"Spinner","url":"/en-us/components/spinner","index":100,"group":"Feedback"},{"name":"toast","url":"/en-us/components/toast","index":100,"group":"Feedback"}]},{"name":"Navigation","children":[{"name":"link","url":"/en-us/components/link","index":100,"group":"Navigation"},{"name":"tabs","url":"/en-us/components/tabs","index":100,"group":"Navigation"},{"name":"button-dropdown","url":"/en-us/components/button-dropdown","index":101,"group":"Navigation"}]},{"name":"Others","children":[{"name":"Snippet","url":"/en-us/components/snippet","index":100,"group":"Others"}]}]}]
[{"name":"guide","children":[{"name":"getting-started","children":[{"name":"introduction","url":"/en-us/guide/introduction","index":5,"group":"getting-started"},{"name":"installation","url":"/en-us/guide/installation","index":10,"group":"getting-started"},{"name":"Server Render","url":"/en-us/guide/server-render","index":15,"group":"getting-started"}]},{"name":"customization","children":[{"name":"Colors","url":"/en-us/guide/colors","index":100,"group":"customization"},{"name":"Themes","url":"/en-us/guide/themes","index":100,"group":"customization"}]}]},{"name":"components","children":[{"name":"General","children":[{"name":"button","url":"/en-us/components/button","index":100,"group":"General"},{"name":"Code","url":"/en-us/components/code","index":100,"group":"General"},{"name":"Spacer","url":"/en-us/components/spacer","index":100,"group":"General"},{"name":"text","url":"/en-us/components/text","index":100,"group":"General"}]},{"name":"layout","children":[{"name":"layout","url":"/en-us/components/layout","index":100,"group":"layout"}]},{"name":"Surfaces","children":[{"name":"card","url":"/en-us/components/card","index":100,"group":"Surfaces"},{"name":"collapse","url":"/en-us/components/collapse","index":100,"group":"Surfaces"},{"name":"fieldset","url":"/en-us/components/fieldset","index":100,"group":"Surfaces"}]},{"name":"Data Entry","children":[{"name":"Auto-Complete","url":"/en-us/components/auto-complete","index":100,"group":"Data Entry"},{"name":"checkbox","url":"/en-us/components/checkbox","index":100,"group":"Data Entry"},{"name":"Input","url":"/en-us/components/input","index":100,"group":"Data Entry"},{"name":"radio","url":"/en-us/components/radio","index":100,"group":"Data Entry"},{"name":"select","url":"/en-us/components/select","index":100,"group":"Data Entry"},{"name":"textarea","url":"/en-us/components/textarea","index":100,"group":"Data Entry"},{"name":"Toggle","url":"/en-us/components/toggle","index":100,"group":"Data Entry"}]},{"name":"Data Display","children":[{"name":"avatar","url":"/en-us/components/avatar","index":100,"group":"Data Display"},{"name":"Badge","url":"/en-us/components/badge","index":100,"group":"Data Display"},{"name":"Capacity","url":"/en-us/components/capacity","index":100,"group":"Data Display"},{"name":"Description","url":"/en-us/components/description","index":100,"group":"Data Display"},{"name":"Display","url":"/en-us/components/display","index":100,"group":"Data Display"},{"name":"Dot","url":"/en-us/components/dot","index":100,"group":"Data Display"},{"name":"File-Tree","url":"/en-us/components/file-tree","index":100,"group":"Data Display"},{"name":"Image","url":"/en-us/components/image","index":100,"group":"Data Display"},{"name":"keyboard","url":"/en-us/components/keyboard","index":100,"group":"Data Display"},{"name":"Popover","url":"/en-us/components/popover","index":100,"group":"Data Display"},{"name":"Table","url":"/en-us/components/table","index":100,"group":"Data Display"},{"name":"Tag","url":"/en-us/components/tag","index":100,"group":"Data Display"},{"name":"Tooltip","url":"/en-us/components/tooltip","index":100,"group":"Data Display"}]},{"name":"Feedback","children":[{"name":"Loading","url":"/en-us/components/loading","index":100,"group":"Feedback"},{"name":"modal","url":"/en-us/components/modal","index":100,"group":"Feedback"},{"name":"note","url":"/en-us/components/note","index":100,"group":"Feedback"},{"name":"Progress","url":"/en-us/components/progress","index":100,"group":"Feedback"},{"name":"Spinner","url":"/en-us/components/spinner","index":100,"group":"Feedback"},{"name":"toast","url":"/en-us/components/toast","index":100,"group":"Feedback"}]},{"name":"Navigation","children":[{"name":"link","url":"/en-us/components/link","index":100,"group":"Navigation"},{"name":"tabs","url":"/en-us/components/tabs","index":100,"group":"Navigation"},{"name":"button-dropdown","url":"/en-us/components/button-dropdown","index":101,"group":"Navigation"}]},{"name":"Others","children":[{"name":"Snippet","url":"/en-us/components/snippet","index":100,"group":"Others"}]}]},{"name":"customization","children":[]}]

View File

@@ -39,21 +39,11 @@ const nextConfig = {
permanent: true,
destination: '/en-us/guide/:path*'
},
{
source: '/en-us/customization/:path*',
permanent: true,
destination: '/en-us/guide/:path*'
},
{
source: '/zh-cn/getting-started/:path*',
permanent: true,
destination: '/zh-cn/guide/:path*'
},
{
source: '/zh-cn/customization/:path*',
permanent: true,
destination: '/zh-cn/guide/:path*'
},
{
source: '/zh-cn/',
permanent: true,

View File

@@ -49,6 +49,7 @@
"@mdx-js/loader": "^1.5.7",
"@next/mdx": "^9.2.2",
"@types/react": "^16.9.22",
"@types/react-color": "^3.0.1",
"@types/react-dom": "^16.9.5",
"@types/styled-jsx": "^2.2.8",
"@typescript-eslint/eslint-plugin": "^2.24.0",
@@ -61,6 +62,7 @@
"fs-extra": "^8.1.0",
"next": "^9.3.2",
"react": "^16.13.0",
"react-color": "^2.18.0",
"react-dom": "^16.13.0",
"react-live": "^2.2.2",
"styled-jsx": "^3.2.4",
@@ -69,4 +71,4 @@
"webpack-cli": "^3.3.11"
},
"dependencies": {}
}
}

View File

@@ -1,17 +1,18 @@
import Head from 'next/head'
import { NextPage } from 'next'
import { AppProps } from 'next/app'
import { useCallback, useState } from 'react'
import { CSSBaseline, ZEITUIProvider, useTheme } from 'components'
import { useState } from 'react'
import { CSSBaseline, ZEITUIProvider, useTheme, ZeitUIThemes } from 'components'
import Menu from 'lib/components/menu'
import ConfigContext from 'lib/config-provider'
import { DeepPartial } from 'components/utils/types'
const Application: NextPage<AppProps> = ({ Component, pageProps }) => {
const theme = useTheme()
const [themeType, setThemeType] = useState<typeof theme.type>(theme.type)
const changeHandle = useCallback((isDark: boolean) => {
setThemeType(isDark ? 'dark' : 'light')
}, [])
const [customTheme, setCustomTheme] = useState<DeepPartial<ZeitUIThemes>>({})
const themeChangeHandle = (theme: DeepPartial<ZeitUIThemes>) => {
setCustomTheme(theme)
}
return (
<>
@@ -32,9 +33,9 @@ const Application: NextPage<AppProps> = ({ Component, pageProps }) => {
<meta property="twitter:image" content="https://user-images.githubusercontent.com/11304944/76085431-fd036480-5fec-11ea-8412-9e581425344a.png" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, viewport-fit=cover" />
</Head>
<ZEITUIProvider theme={{ type: themeType }}>
<ZEITUIProvider theme={customTheme}>
<CSSBaseline />
<ConfigContext onChange={changeHandle}>
<ConfigContext onThemeChange={themeChangeHandle}>
<Menu />
<Component {...pageProps} />
</ConfigContext>

View File

@@ -0,0 +1,18 @@
import React from 'react'
import { Text, Spacer } from 'components'
import CustomizationLayout from 'lib/components/customization/layout'
import CustomizationEditor from 'lib/components/customization/editor'
const Customization = () => {
return (
<CustomizationLayout>
<Spacer y={1.2} />
<Text h2>Customization</Text>
<Text>Custom themes is a very simple thing in ZEIT UI, click change, download or share.</Text>
<CustomizationEditor />
<Spacer y={3.2} />
</CustomizationLayout>
)
}
export default Customization

View File

@@ -11,8 +11,8 @@ const weights = {
'guide': 1,
'docs': 2,
'getting-started': 3,
'customization': 4,
'components': 5,
'customization': 10,
}
const groupWeights = {
'快速上手': 1,

View File

@@ -1020,6 +1020,11 @@
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==
"@icons/material@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==
"@mapbox/rehype-prism@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@mapbox/rehype-prism/-/rehype-prism-0.4.0.tgz#58714b345ec01256aa74c24762a341f6a771494e"
@@ -1125,6 +1130,13 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/react-color@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/react-color/-/react-color-3.0.1.tgz#5433e2f503ea0e0831cbc6fd0c20f8157d93add0"
integrity sha512-J6mYm43Sid9y+OjZ7NDfJ2VVkeeuTPNVImNFITgQNXodHteKfl/t/5pAR5Z9buodZ2tCctsZjgiMlQOpfntakw==
dependencies:
"@types/react" "*"
"@types/react-dom@^16.9.5":
version "16.9.5"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.5.tgz#5de610b04a35d07ffd8f44edad93a71032d9aaa7"
@@ -4728,7 +4740,7 @@ lodash.uniq@4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4:
lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@@ -4824,6 +4836,11 @@ markdown-escapes@^1.0.0:
resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535"
integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==
material-colors@^1.2.1:
version "1.2.6"
resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -6239,7 +6256,7 @@ prop-types-exact@1.2.0:
object.assign "^4.1.0"
reflect.ownkeys "^0.2.0"
prop-types@15.7.2, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@15.7.2, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -6360,6 +6377,18 @@ raw-body@2.4.0:
iconv-lite "0.4.24"
unpipe "1.0.0"
react-color@^2.18.0:
version "2.18.0"
resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.18.0.tgz#34956f0bac394f6c3bc01692fd695644cc775ffd"
integrity sha512-FyVeU1kQiSokWc8NPz22azl1ezLpJdUyTbWL0LPUpcuuYDrZ/Y1veOk9rRK5B3pMlyDGvTk4f4KJhlkIQNRjEA==
dependencies:
"@icons/material" "^0.2.4"
lodash "^4.17.11"
material-colors "^1.2.1"
prop-types "^15.5.10"
reactcss "^1.2.0"
tinycolor2 "^1.4.1"
react-dom@^16.13.0:
version "16.13.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.0.tgz#cdde54b48eb9e8a0ca1b3dc9943d9bb409b81866"
@@ -6413,6 +6442,13 @@ react@^16.13.0:
object-assign "^4.1.1"
prop-types "^15.6.2"
reactcss@^1.2.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==
dependencies:
lodash "^4.0.1"
read-pkg@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
@@ -7443,6 +7479,11 @@ tiny-emitter@^2.0.0:
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
tinycolor2@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=
title-case@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa"