mirror of
https://github.com/zhigang1992/react.git
synced 2026-04-29 04:35:32 +08:00
Merge pull request #84 from unix/themes
docs: keep the theme perferences for visitors
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React, { useMemo, useRef, useState } from 'react'
|
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { NormalSizes } from '../utils/prop-types'
|
import { NormalSizes } from '../utils/prop-types'
|
||||||
import useClickAway from '../utils/use-click-away'
|
import useClickAway from '../utils/use-click-away'
|
||||||
import { pickChildByProps, pickChildrenFirst } from '../utils/collections'
|
import { pickChildByProps, pickChildrenFirst } from '../utils/collections'
|
||||||
@@ -12,6 +12,7 @@ import { getSizes } from './styles'
|
|||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
size?: NormalSizes
|
size?: NormalSizes
|
||||||
|
value?: string
|
||||||
initialValue?: string
|
initialValue?: string
|
||||||
placeholder?: React.ReactNode | string
|
placeholder?: React.ReactNode | string
|
||||||
icon?: React.ReactNode
|
icon?: React.ReactNode
|
||||||
@@ -32,8 +33,8 @@ type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
|
|||||||
export type SelectProps = Props & typeof defaultProps & NativeAttrs
|
export type SelectProps = Props & typeof defaultProps & NativeAttrs
|
||||||
|
|
||||||
const Select: React.FC<React.PropsWithChildren<SelectProps>> = ({
|
const Select: React.FC<React.PropsWithChildren<SelectProps>> = ({
|
||||||
children, size, disabled, initialValue: init, placeholder,
|
children, size, disabled, initialValue: init, value: customValue,
|
||||||
icon: Icon, onChange, className, pure, ...props
|
icon: Icon, onChange, className, pure, placeholder, ...props
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const ref = useRef<HTMLDivElement>(null)
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
@@ -63,6 +64,11 @@ const Select: React.FC<React.PropsWithChildren<SelectProps>> = ({
|
|||||||
|
|
||||||
useClickAway(ref, () => setVisible(false))
|
useClickAway(ref, () => setVisible(false))
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (customValue === undefined) return
|
||||||
|
setValue(customValue)
|
||||||
|
}, [customValue])
|
||||||
|
|
||||||
const selectedChild = useMemo(() => {
|
const selectedChild = useMemo(() => {
|
||||||
const [, optionChildren] = pickChildByProps(children, 'value', value)
|
const [, optionChildren] = pickChildByProps(children, 'value', value)
|
||||||
const child = pickChildrenFirst(optionChildren)
|
const child = pickChildrenFirst(optionChildren)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { MutableRefObject, useState } from 'react'
|
import React, { MutableRefObject, useEffect, useState } from 'react'
|
||||||
import { createPortal } from 'react-dom'
|
import { createPortal } from 'react-dom'
|
||||||
import usePortal from '../utils/use-portal'
|
import usePortal from '../utils/use-portal'
|
||||||
import useResize from '../utils/use-resize'
|
import useResize from '../utils/use-resize'
|
||||||
@@ -54,6 +54,14 @@ const Dropdown: React.FC<React.PropsWithChildren<Props>> = React.memo(({
|
|||||||
if (!shouldUpdatePosition) return
|
if (!shouldUpdatePosition) return
|
||||||
updateRect()
|
updateRect()
|
||||||
})
|
})
|
||||||
|
useEffect(() => {
|
||||||
|
if (!parent || !parent.current) return
|
||||||
|
parent.current.addEventListener('mouseenter', updateRect)
|
||||||
|
return () => {
|
||||||
|
if (!parent || !parent.current) return
|
||||||
|
parent.current.removeEventListener('mouseenter', updateRect)
|
||||||
|
}
|
||||||
|
}, [parent])
|
||||||
|
|
||||||
const clickHandler = (event: React.MouseEvent<HTMLDivElement>) => {
|
const clickHandler = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ const Controls: React.FC<{}> = React.memo(({
|
|||||||
|
|
||||||
const switchThemes = (type: 'dark' | 'light') => {
|
const switchThemes = (type: 'dark' | 'light') => {
|
||||||
updateCustomTheme({ type })
|
updateCustomTheme({ type })
|
||||||
|
if (typeof window === 'undefined' || !window.localStorage) return
|
||||||
|
window.localStorage.setItem('theme', type)
|
||||||
}
|
}
|
||||||
const switchLanguages = () => {
|
const switchLanguages = () => {
|
||||||
updateChineseState(!isChinese)
|
updateChineseState(!isChinese)
|
||||||
@@ -41,7 +43,7 @@ const Controls: React.FC<{}> = React.memo(({
|
|||||||
onClick={redirectGithub}
|
onClick={redirectGithub}
|
||||||
title={isChinese? '代码仓库' : 'Github Repository'}>{isChinese ? '代码仓库' : 'Github'}</Button>
|
title={isChinese? '代码仓库' : 'Github Repository'}>{isChinese ? '代码仓库' : 'Github'}</Button>
|
||||||
<Spacer x={.75} />
|
<Spacer x={.75} />
|
||||||
<Select size="small" pure onChange={switchThemes} initialValue={isDark ? 'dark' : 'light'}
|
<Select size="small" pure onChange={switchThemes} value={isDark ? 'dark' : 'light'}
|
||||||
title={isChinese ? '切换主题' : 'Switch Themes'}>
|
title={isChinese ? '切换主题' : 'Switch Themes'}>
|
||||||
<Select.Option value="light">
|
<Select.Option value="light">
|
||||||
<div className="select-content">
|
<div className="select-content">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useTheme } from 'components'
|
import { useTheme } from 'components'
|
||||||
import Sidebar from './sidebar'
|
import Sidebar from './sidebar'
|
||||||
import TabbarMobile from './sidebar/tabbar-mobile'
|
import TabbarMobile from './sidebar/tabbar-mobile'
|
||||||
@@ -16,6 +16,7 @@ export interface Props {
|
|||||||
|
|
||||||
export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ children }) => {
|
export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ children }) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const [showAfterRender, setShowAfterRender] = useState<boolean>(false)
|
||||||
const { tabbarFixed } = useConfigs()
|
const { tabbarFixed } = useConfigs()
|
||||||
const [, setBodyScroll] = useBodyScroll(null, { scrollLayer: true })
|
const [, setBodyScroll] = useBodyScroll(null, { scrollLayer: true })
|
||||||
const [expanded, setExpanded] = useState<boolean>(false)
|
const [expanded, setExpanded] = useState<boolean>(false)
|
||||||
@@ -24,6 +25,9 @@ export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ ch
|
|||||||
setBodyScroll(!expanded)
|
setBodyScroll(!expanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => setShowAfterRender(true), [])
|
||||||
|
|
||||||
|
if (!showAfterRender) return null
|
||||||
return (
|
return (
|
||||||
<div className="layout">
|
<div className="layout">
|
||||||
<TabbarMobile onClick={mobileTabbarClickHandler} />
|
<TabbarMobile onClick={mobileTabbarClickHandler} />
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import React from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import MenuLinks from './menu-links'
|
import MenuLinks from './menu-links'
|
||||||
import MenuSticker from './menu-sticker'
|
import MenuSticker from './menu-sticker'
|
||||||
|
|
||||||
const Menu = () => {
|
const Menu: React.FC<{}> = () => {
|
||||||
|
const [showAfterRender, setShowAfterRender] = useState<boolean>(false)
|
||||||
|
useEffect(() => setShowAfterRender(true), [])
|
||||||
|
|
||||||
|
if (!showAfterRender) return null
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<MenuLinks />
|
<MenuLinks />
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ const MenuSticker = () => {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
background-color: ${theme.palette.background};
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-fill.active {
|
.nav-fill.active {
|
||||||
|
|||||||
10
lib/use-dom-clean.ts
Normal file
10
lib/use-dom-clean.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
|
const useDomClean = (): void => {
|
||||||
|
useEffect(() => {
|
||||||
|
document.documentElement.removeAttribute('style')
|
||||||
|
document.body.removeAttribute('style')
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useDomClean
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
"eslint-plugin-react": "^7.19.0",
|
"eslint-plugin-react": "^7.19.0",
|
||||||
"extract-mdx-metadata": "^1.0.0",
|
"extract-mdx-metadata": "^1.0.0",
|
||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^8.1.0",
|
||||||
"next": "^9.3.2",
|
"next": "^9.3.4",
|
||||||
"react": "^16.13.0",
|
"react": "^16.13.0",
|
||||||
"react-color": "^2.18.0",
|
"react-color": "^2.18.0",
|
||||||
"react-dom": "^16.13.0",
|
"react-dom": "^16.13.0",
|
||||||
@@ -71,4 +71,4 @@
|
|||||||
"webpack-cli": "^3.3.11"
|
"webpack-cli": "^3.3.11"
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import { NextPage } from 'next'
|
import { NextPage } from 'next'
|
||||||
import { AppProps } from 'next/app'
|
import { AppProps } from 'next/app'
|
||||||
import { useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { CSSBaseline, ZEITUIProvider, useTheme, ZeitUIThemes } from 'components'
|
import { CSSBaseline, ZEITUIProvider, useTheme, ZeitUIThemes } from 'components'
|
||||||
import Menu from 'lib/components/menu'
|
import Menu from 'lib/components/menu'
|
||||||
import ConfigContext from 'lib/config-provider'
|
import ConfigContext from 'lib/config-provider'
|
||||||
|
import useDomClean from 'lib/use-dom-clean'
|
||||||
import { DeepPartial } from 'components/utils/types'
|
import { DeepPartial } from 'components/utils/types'
|
||||||
|
|
||||||
const Application: NextPage<AppProps> = ({ Component, pageProps }) => {
|
const Application: NextPage<AppProps<{}>> = ({ Component, pageProps }) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const [customTheme, setCustomTheme] = useState<DeepPartial<ZeitUIThemes>>({})
|
const [customTheme, setCustomTheme] = useState<DeepPartial<ZeitUIThemes>>({})
|
||||||
const themeChangeHandle = (theme: DeepPartial<ZeitUIThemes>) => {
|
const themeChangeHandle = (theme: DeepPartial<ZeitUIThemes>) => {
|
||||||
setCustomTheme(theme)
|
setCustomTheme(theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const theme = window.localStorage.getItem('theme')
|
||||||
|
if (theme !== 'dark') return
|
||||||
|
themeChangeHandle({ type: 'dark' })
|
||||||
|
}, [])
|
||||||
|
useDomClean()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -22,20 +22,29 @@ class MyDocument extends Document {
|
|||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<body>
|
<body>
|
||||||
<Main />
|
<script dangerouslySetInnerHTML={{ __html: `
|
||||||
<NextScript />
|
(function(){
|
||||||
<script async src={`https://www.googletagmanager.com/gtag/js?id=UA-110371817-12`} />
|
if (!window.localStorage) return;
|
||||||
<script
|
if (window.localStorage.getItem('theme') === 'dark') {
|
||||||
async
|
document.documentElement.style.background = '#000';
|
||||||
dangerouslySetInnerHTML={{
|
document.body.style.background = '#000';
|
||||||
__html: `
|
};
|
||||||
window.dataLayer = window.dataLayer || [];
|
})()
|
||||||
function gtag(){dataLayer.push(arguments);}
|
`}} />
|
||||||
gtag('js', new Date());
|
<Main />
|
||||||
gtag('config', 'UA-110371817-12');
|
<NextScript />
|
||||||
`
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-110371817-12" />
|
||||||
}}
|
<script
|
||||||
/>
|
async
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
gtag('config', 'UA-110371817-12');
|
||||||
|
`
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</body>
|
</body>
|
||||||
</Html>
|
</Html>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ Retrieve text input from a user.
|
|||||||
| Attribute | Description | Type | Accepted values | Default
|
| Attribute | Description | Type | Accepted values | Default
|
||||||
| ---------- | ---------- | ---- | -------------- | ------ |
|
| ---------- | ---------- | ---- | -------------- | ------ |
|
||||||
| **value** | input value | `string` | - | - |
|
| **value** | input value | `string` | - | - |
|
||||||
| **initialValue** | inital value | `string` | - | - |
|
| **initialValue** | initial value | `string` | - | - |
|
||||||
| **placeholder** | placeholder | `string` | - | - |
|
| **placeholder** | placeholder | `string` | - | - |
|
||||||
| **size** | input size | `NormalSizes` | `'mini', 'small', 'medium', 'large'` | `medium` |
|
| **size** | input size | `NormalSizes` | `'mini', 'small', 'medium', 'large'` | `medium` |
|
||||||
| **status** | current status | `NormalTypes` | `'default', 'secondary', 'success', 'warning', 'error'` | `default` |
|
| **status** | current status | `NormalTypes` | `'default', 'secondary', 'success', 'warning', 'error'` | `default` |
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ Display a dropdown list of items.
|
|||||||
|
|
||||||
| Attribute | Description | Type | Accepted values | Default
|
| Attribute | Description | Type | Accepted values | Default
|
||||||
| ---------- | ---------- | ---- | -------------- | ------ |
|
| ---------- | ---------- | ---- | -------------- | ------ |
|
||||||
| **initialValue** | selected value | `string` | - | - |
|
| **value** | selected value | `string` | - | - |
|
||||||
|
| **initialValue** | initial value | `string` | - | - |
|
||||||
| **placeholder** | placeholder string | `string` | - | - |
|
| **placeholder** | placeholder string | `string` | - | - |
|
||||||
| **size** | select component size | `NormalSizes` | `'mini', 'small', 'medium', 'large'` | `medium` |
|
| **size** | select component size | `NormalSizes` | `'mini', 'small', 'medium', 'large'` | `medium` |
|
||||||
| **icon** | icon component | `ReactNode` | - | `SVG Component` |
|
| **icon** | icon component | `ReactNode` | - | `SVG Component` |
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ export const meta = {
|
|||||||
|
|
||||||
| 属性 | 描述 | 类型 | 推荐值 | 默认
|
| 属性 | 描述 | 类型 | 推荐值 | 默认
|
||||||
| ---------- | ---------- | ---- | -------------- | ------ |
|
| ---------- | ---------- | ---- | -------------- | ------ |
|
||||||
|
| **value** | 手动设置选择器的值 | `string` | - | - |
|
||||||
| **initialValue** | 选择器初始值 | `string` | - | - |
|
| **initialValue** | 选择器初始值 | `string` | - | - |
|
||||||
| **placeholder** | 占位文本内容 | `string` | - | - |
|
| **placeholder** | 占位文本内容 | `string` | - | - |
|
||||||
| **size** | 选择器组件大小 | `NormalSizes` | `'mini', 'small', 'medium', 'large'` | `medium` |
|
| **size** | 选择器组件大小 | `NormalSizes` | `'mini', 'small', 'medium', 'large'` | `medium` |
|
||||||
|
|||||||
Reference in New Issue
Block a user