docs: show and copy the theme codes of user changes

This commit is contained in:
unix
2020-04-11 09:26:36 +08:00
parent 7452fe1279
commit 156b39ded8
14 changed files with 178 additions and 65 deletions

View File

@@ -105,7 +105,7 @@ const Attributes: React.FC<React.PropsWithChildren<AttributesProps>> = React.mem
border-left: 1px solid transparent;
}
@media only screen and (max-width: 767px) {
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
.attr {
overflow-x: scroll;
}

View File

@@ -86,7 +86,7 @@ const Controls: React.FC<{}> = React.memo(({
align-items: center;
}
@media only screen and (max-width: 767px) {
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
.controls {
display: none;
pointer-events: none;

View File

@@ -0,0 +1,132 @@
import React, { useMemo } from 'react'
import { Text, Spacer, useTheme, Code, useToasts } from 'components'
import DefaultTheme from 'components/styles/themes/default'
import { isObject, MergeObject } from 'components/styles/theme-provider/theme-provider'
import { LiveEditor, LiveProvider } from 'react-live'
import makeCodeTheme from 'lib/components/playground/code-theme'
import useClipboard from 'components/utils/use-clipboard'
import CopyIcon from 'components/snippet/snippet-icon'
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) {
result[key] = childrenDiff
}
} else if (sourceValue !== targetValue) {
result[key] = targetValue
}
}
return result
}
const CustomizationCodes = () => {
const theme = useTheme()
const codeTheme = makeCodeTheme(theme)
const { copy } = useClipboard()
const [, setToast] = useToasts()
const deepDifferents = useMemo(
() => getDeepDifferents(DefaultTheme, theme),
[DefaultTheme, theme],
)
const userCodes = useMemo(() => {
return `const myTheme = ${JSON.stringify(deepDifferents, null, 2)}
/***
* Usage::
* export const App = () => {
* return (
* <ZEITUIProvider theme={myTheme}>
* <CSSBaseline />
* <YourComponent />
* </ZEITUIProvider>
* )
* }
**/`
}, [deepDifferents])
const copyCode = () => {
copy(userCodes)
setToast({ text: 'Theme code copied.' })
}
return (
<div className="custom-codes">
<h3 className="title">Theme Codes</h3>
<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>
<LiveProvider code={userCodes} disabled theme={codeTheme}>
<LiveEditor />
</LiveProvider>
</div>
<Spacer y={5} />
<style jsx>{`
.custom-codes {
display: flex;
flex-direction: column;
flex: 1;
margin: 2.5rem auto;
text-align: center;
}
.title {
text-align: center;
width: 80%;
margin: 0 auto;
display: inline-block;
background: ${theme.palette.foreground};
color: ${theme.palette.background};
font-size: 1rem;
line-height: 1rem;
padding: ${theme.layout.gap} 0;
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};
position: relative;
}
.copy {
position: absolute;
right: 1rem;
top: 1rem;
z-index: 2000;
color: ${theme.palette.accents_3};
cursor: pointer;
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 {
width: 90vw;
}
}
`}</style>
</div>
)
}
export default CustomizationCodes

View File

@@ -1,30 +1,18 @@
import React, { useState } from 'react'
import FullScreenIcon from 'lib/components/icons/full-screen'
import FullScreenCloseIcon from 'lib/components/icons/full-screen-close'
import React from 'react'
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,
<Text>Here&#39;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 download automatically generated code or share your custom theme with anyone.</Text>
<Text>You can copy automatically generated codes or share your custom theme with anyone.</Text>
<Spacer y={1.7} />
<Text h4>Colors</Text>
@@ -32,7 +20,9 @@ const Demo: React.FC<React.PropsWithChildren<{}>> = () => {
<Spacer y={1.7} />
<Text h4>Typography</Text>
<Text><Code>inline codes</Code>, <Link href="#" color>Hyperlink</Link></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>
@@ -60,48 +50,28 @@ const Demo: React.FC<React.PropsWithChildren<{}>> = () => {
<Checkbox value="sydney">Sydney</Checkbox>
<Checkbox value="beijing">Bei Jing</Checkbox>
</Checkbox.Group>
<Spacer y={4} />
</div>
<style jsx>{`
.demo {
width: ${fullScreen ? '100%' : '35%'};
width: 34%;
margin-top: calc(${theme.layout.gap} * 2);
margin-right: 20px;
padding-right: ${theme.layout.gapQuarter};
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%;
}
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
.demo {
display: none;
}
}
`}</style>
</div>
)

View File

@@ -19,6 +19,7 @@ const EditorInputItem: React.FC<React.PropsWithChildren<Props>> = ({
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 },
@@ -27,7 +28,9 @@ const EditorInputItem: React.FC<React.PropsWithChildren<Props>> = ({
return (
<div className="editor-item">
<Input value={currentVal as string} label={keyName} onChange={changeHandler} className="editor-input" />
<Input value={currentVal as string} label={keyName}
onChange={changeHandler}
className="editor-input" />
<style jsx>{`
.editor-item {
background-color: transparent;
@@ -46,7 +49,6 @@ const EditorInputItem: React.FC<React.PropsWithChildren<Props>> = ({
.editor-item :global(.editor-input) {
width: ${width};
}
`}</style>
</div>
)

View File

@@ -14,7 +14,7 @@ const statusColors: Array<keyof ZeitUIThemesPalette> = [
'warning', 'warningLight', 'warningDark',
]
const otherColors: Array<keyof ZeitUIThemesPalette> = [
'selection', 'secondary', 'border', 'code', 'cyan', 'purple', 'alert', 'violet'
'selection', 'secondary', 'link', 'border', 'code', 'cyan', 'purple', 'alert', 'violet'
]
const expressiveness: Array<keyof ZeitUIThemesExpressiveness> = [
'linkStyle', 'linkHoverStyle', 'dropdownBoxShadow', 'shadowSmall',

View File

@@ -1,5 +1,6 @@
import React from 'react'
import { useTheme } from 'components'
import { useTheme, Row } from 'components'
import CustomizationCodes from './codes'
import Demo from './demo'
const CustomizationLayout: React.FC<React.PropsWithChildren<{}>> = ({
@@ -9,22 +10,30 @@ const CustomizationLayout: React.FC<React.PropsWithChildren<{}>> = ({
return (
<div className="layout">
<Demo />
<div className="content">
{children}
</div>
<Row>
<Demo />
<div className="content">
{children}
</div>
</Row>
<Row>
<CustomizationCodes />
</Row>
<style jsx>{`
.layout {
min-height: calc(100vh - 108px);
max-width: 1000px;
max-width: ${theme.layout.pageWidthWithMargin};
margin: 0 auto;
padding: 0 ${theme.layout.gap};
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.content {
flex: 1;
overflow: hidden;
}
.demo {

View File

@@ -37,7 +37,7 @@ export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ ch
<style jsx>{`
.layout {
min-height: calc(100vh - 108px);
max-width: 1000px;
max-width: ${theme.layout.pageWidthWithMargin};
margin: 0 auto;
padding: 0 ${theme.layout.gap};
display: flex;
@@ -74,7 +74,7 @@ export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ ch
padding-bottom: 150px;
}
@media only screen and (max-width: 767px) {
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
.layout {
max-width: 100%;
width: 100%;

View File

@@ -98,7 +98,7 @@ const MenuSticker = () => {
}
.inner {
max-width: 1000px;
max-width: ${theme.layout.pageWidth};
padding: 0 ${theme.layout.gap};
width: 100%;
display: flex;

View File

@@ -71,7 +71,7 @@ export const Sidebar: React.FC<Props> = React.memo(() => {
margin-bottom: ${theme.layout.gap};
}
@media only screen and (max-width: 767px) {
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
.box {
padding: calc(3.5 * ${theme.layout.gap}) 15vw;
width: 100vw;

View File

@@ -55,7 +55,7 @@ const SideItem: React.FC<React.PropsWithChildren<SideItemProps>> = React.memo(({
font-weight: bold;
}
@media only screen and (max-width: 767px) {
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
.link {
border-bottom: 1px solid ${theme.palette.border};
height: 3.5rem;

View File

@@ -51,7 +51,7 @@ const TabbarMobile:React.FC<Props> = ({ onClick }) => {
text-transform: capitalize;
}
@media only screen and (min-width: 767px) {
@media only screen and (min-width: ${theme.layout.breakpointMobile}) {
.tabbar {
display: none;
visibility: hidden;