mirror of
https://github.com/zhigang1992/react.git
synced 2026-03-26 22:42:51 +08:00
docs: optimize the experience of switch of language and tabbar
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { Button, useTheme, Select, Spacer } from 'components'
|
||||
import { useConfigs } from 'lib/config-context'
|
||||
import useLocale from 'lib/use-locale'
|
||||
import Router, { useRouter } from 'next/router'
|
||||
import MoonIcon from './icons/moon'
|
||||
import SunIcon from './icons/sun'
|
||||
@@ -10,19 +11,22 @@ const Controls: React.FC<{}> = React.memo(({
|
||||
const theme = useTheme()
|
||||
const { onChange, updateChineseState } = useConfigs()
|
||||
const { pathname } = useRouter()
|
||||
const isChinese = useMemo(() => pathname.toLowerCase().includes('zh-cn'), [pathname])
|
||||
const { locale } = useLocale()
|
||||
const isChinese = useMemo(() => locale === 'zh-cn', [locale])
|
||||
const isDark = useMemo(() => theme.type === 'dark', [theme.type])
|
||||
const nextLocalePath = useMemo(() => {
|
||||
const nextLocale = isChinese ? 'en-us' : 'zh-cn'
|
||||
return pathname.replace(locale, nextLocale)
|
||||
}, [locale, pathname])
|
||||
|
||||
const switchThemes = (val: string) => {
|
||||
const isDark = val === 'dark'
|
||||
onChange && onChange(isDark)
|
||||
}
|
||||
|
||||
const switchLanguages = () => {
|
||||
const nextPath = `/${isChinese ? 'en-us' : 'zh-cn'}`
|
||||
updateChineseState(!isChinese)
|
||||
Router.push(nextPath)
|
||||
Router.push(nextLocalePath)
|
||||
}
|
||||
|
||||
const redirectGithub = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
window.open('https://github.com/zeit-ui/react')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useTheme } from 'components'
|
||||
import Sidebar from './sidebar'
|
||||
import { Sides } from './sidebar/side-item'
|
||||
import TabbarMobile from './sidebar/tabbar-mobile'
|
||||
import useBodyScroll from 'components/utils/use-body-scroll'
|
||||
import { useConfigs } from '../config-context'
|
||||
@@ -15,31 +14,26 @@ export interface Props {
|
||||
getStaticProps?: any
|
||||
}
|
||||
|
||||
export interface MultilLocaleMetaInformation {
|
||||
[key: string]: Sides[]
|
||||
}
|
||||
|
||||
export const Layout: React.FC<React.PropsWithChildren<Props>> = React.memo(({ children }) => {
|
||||
const theme = useTheme()
|
||||
const { sides, tabbarFixed } = useConfigs()
|
||||
const { tabbarFixed } = useConfigs()
|
||||
const [, setBodyScroll] = useBodyScroll(null, { scrollLayer: true })
|
||||
const [expanded, setExpanded] = useState<boolean>(false)
|
||||
const mobileTabbarClickHandler = () => {
|
||||
setExpanded(!expanded)
|
||||
setBodyScroll(!expanded)
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="layout">
|
||||
<TabbarMobile onClick={mobileTabbarClickHandler} />
|
||||
<aside className="sidebar">
|
||||
<Sidebar sides={sides}/>
|
||||
<Sidebar />
|
||||
</aside>
|
||||
<div className="side-shadow" />
|
||||
<main className="main">
|
||||
<div>{children}</div>
|
||||
</main>
|
||||
|
||||
<style jsx>{`
|
||||
.layout {
|
||||
min-height: calc(100vh - 108px);
|
||||
|
||||
@@ -1,37 +1,22 @@
|
||||
import React, { useEffect, useMemo } from 'react'
|
||||
import { Tabs, useTheme } from 'components'
|
||||
import useCurrentState from 'components/utils/use-current-state'
|
||||
import sides from 'lib/data/metadata.json'
|
||||
import { Sides } from 'lib/components/sidebar/side-item'
|
||||
import Router, { useRouter } from 'next/router'
|
||||
import { useConfigs } from '../../config-context'
|
||||
|
||||
export interface MultilLocaleMetaInformation {
|
||||
[key: string]: Sides[]
|
||||
}
|
||||
import Router from 'next/router'
|
||||
import Metadatas from 'lib/data'
|
||||
import useLocale from 'lib/use-locale'
|
||||
import { useConfigs } from 'lib/config-context'
|
||||
|
||||
const MenuSticker = () => {
|
||||
const theme = useTheme()
|
||||
const { pathname } = useRouter()
|
||||
const { updateSides, updateTabbarFixed } = useConfigs()
|
||||
const { updateTabbarFixed } = useConfigs()
|
||||
const { tabbar: currentUrlTabValue, locale } = useLocale()
|
||||
const [tabValue, setTabValue, tabValueRef] = useCurrentState<string>('')
|
||||
const [fixed, setFixed, fixedRef] = useCurrentState<boolean>(false)
|
||||
|
||||
const currentUrlTabValue = useMemo(() => {
|
||||
return pathname.split('/').filter(r => !!r)[1]
|
||||
}, [pathname])
|
||||
|
||||
const tabbarData = useMemo(() => {
|
||||
const language = pathname
|
||||
.split('/')
|
||||
.filter(r => !!r)
|
||||
const locale: string = language[0] || 'en-us'
|
||||
return (sides as MultilLocaleMetaInformation)[locale]
|
||||
}, [pathname])
|
||||
|
||||
const tabbarData = useMemo(() => Metadatas[locale], [locale])
|
||||
|
||||
useEffect(() => updateTabbarFixed(fixed), [fixed])
|
||||
useEffect(() => setTabValue(currentUrlTabValue), [currentUrlTabValue])
|
||||
|
||||
useEffect(() => {
|
||||
const scrollHandler = () => {
|
||||
const shouldFixed = document.documentElement.scrollTop > 60
|
||||
@@ -43,22 +28,11 @@ const MenuSticker = () => {
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const currentTab = tabbarData.find(tab => tab.name === tabValueRef.current)
|
||||
if (!currentTab || !Array.isArray(currentTab.children)) return
|
||||
|
||||
let firstChildren = currentTab.children
|
||||
if (Array.isArray(firstChildren[0].children)) {
|
||||
firstChildren = firstChildren[0].children
|
||||
}
|
||||
|
||||
const defaultPath = firstChildren[0].url
|
||||
if (!defaultPath) return
|
||||
updateSides(currentTab.children)
|
||||
|
||||
const shouldRedirectDefaultPage = currentUrlTabValue !== tabValueRef.current
|
||||
if (!shouldRedirectDefaultPage) return
|
||||
const defaultPath = `/${locale}/${tabValueRef.current}`
|
||||
Router.push(defaultPath)
|
||||
}, [tabValue, tabbarData, currentUrlTabValue])
|
||||
}, [tabValue, currentUrlTabValue])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,27 +1,34 @@
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import React, { useEffect, useMemo, useRef } from 'react'
|
||||
import Router from 'next/router'
|
||||
import { useTheme, Spacer } from 'components'
|
||||
import SideItem, { SideItemProps, Sides } from './side-item'
|
||||
import SideItem, { Sides } from './side-item'
|
||||
import useLocale from 'lib/use-locale'
|
||||
import { useConfigs } from 'lib/config-context'
|
||||
import Metadatas from 'lib/data'
|
||||
|
||||
export interface Props {
|
||||
}
|
||||
|
||||
export type SideGroupProps = Props & SideItemProps
|
||||
|
||||
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} />
|
||||
return <SideItem sides={sides} ><SideGroup /></SideItem>
|
||||
})
|
||||
|
||||
export const Sidebar: React.FC<SideGroupProps> = React.memo(({ sides }) => {
|
||||
export const Sidebar: React.FC<Props> = React.memo(() => {
|
||||
const theme = useTheme()
|
||||
const boxRef = useRef<HTMLDivElement>(null)
|
||||
const { sidebarScrollHeight, updateSidebarScrollHeight } = useConfigs()
|
||||
|
||||
const { locale, tabbar } = useLocale()
|
||||
|
||||
const tabbarData = useMemo(() => {
|
||||
const allSides = Metadatas[locale]
|
||||
const currentSide = allSides.filter(side => side.name === tabbar)[0]
|
||||
return (currentSide.children || []) as Array<Sides>
|
||||
}, [locale, tabbar])
|
||||
|
||||
useEffect(() => {
|
||||
Router.events.on('routeChangeStart', () => {
|
||||
if (!boxRef.current) return
|
||||
@@ -36,7 +43,7 @@ export const Sidebar: React.FC<SideGroupProps> = React.memo(({ sides }) => {
|
||||
|
||||
return (
|
||||
<div ref={boxRef} className="sides box">
|
||||
<SideItem sides={sides}>
|
||||
<SideItem sides={tabbarData}>
|
||||
<SideGroup />
|
||||
</SideItem>
|
||||
<Spacer />
|
||||
|
||||
@@ -22,12 +22,13 @@ const SideItem: React.FC<React.PropsWithChildren<SideItemProps>> = React.memo(({
|
||||
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} />}
|
||||
|
||||
{side.children && <div className="children">
|
||||
{showChildren && <div className="children">
|
||||
{React.cloneElement(children as ReactElement, {
|
||||
sides: side.children,
|
||||
})}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react'
|
||||
import { Sides } from 'lib/components/sidebar/side-item'
|
||||
|
||||
export interface Configs {
|
||||
onChange?: Function
|
||||
@@ -8,9 +7,6 @@ export interface Configs {
|
||||
sidebarScrollHeight: number
|
||||
updateSidebarScrollHeight: Function
|
||||
|
||||
sides: Sides[]
|
||||
updateSides: Function
|
||||
|
||||
tabbarFixed: boolean
|
||||
updateTabbarFixed: Function
|
||||
}
|
||||
@@ -19,9 +15,6 @@ export const defaultConfigs: Configs = {
|
||||
sidebarScrollHeight: 0,
|
||||
updateSidebarScrollHeight: () => {},
|
||||
updateChineseState: () => {},
|
||||
|
||||
sides: [],
|
||||
updateSides: () => {},
|
||||
|
||||
tabbarFixed: false,
|
||||
updateTabbarFixed: () => {},
|
||||
|
||||
@@ -2,7 +2,6 @@ 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 { Sides } from 'lib/components/sidebar/side-item'
|
||||
|
||||
interface Props {
|
||||
onChange?: Function
|
||||
@@ -19,21 +18,18 @@ const ConfigProvider: React.FC<React.PropsWithChildren<ConfigProviderProps>> = R
|
||||
const { pathname } = useRouter()
|
||||
const [isChinese, setIsChinese] = useState<boolean>(() => pathname.includes('zh-cn'))
|
||||
const [scrollHeight, setScrollHeight] = useState<number>(0)
|
||||
const [sides, setSides] = useState<Sides[]>([] as Sides[])
|
||||
const [tabbarFixed, setTabbarFixed] = useState<boolean>(false)
|
||||
const updateSidebarScrollHeight = (height: number) => setScrollHeight(height)
|
||||
const updateChineseState = (state: boolean) => setIsChinese(state)
|
||||
const updateSides = (sides: Sides[]) => setSides(sides)
|
||||
const updateTabbarFixed = (state: boolean) => setTabbarFixed(state)
|
||||
|
||||
const initialValue = useMemo<Configs>(() => ({
|
||||
onChange, sides, isChinese, tabbarFixed,
|
||||
updateSides,
|
||||
onChange, isChinese, tabbarFixed,
|
||||
updateTabbarFixed,
|
||||
updateChineseState,
|
||||
sidebarScrollHeight: scrollHeight,
|
||||
updateSidebarScrollHeight,
|
||||
}), [onChange, scrollHeight, sides, tabbarFixed, isChinese])
|
||||
}), [onChange, scrollHeight, tabbarFixed, isChinese])
|
||||
|
||||
return (
|
||||
<ConfigContext.Provider value={initialValue}>
|
||||
|
||||
3
pages/en-us/components/index.js
Normal file
3
pages/en-us/components/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import redirect from 'lib/redirect'
|
||||
|
||||
export default redirect('/en-us/components/button')
|
||||
3
pages/en-us/guide/index.js
Normal file
3
pages/en-us/guide/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import redirect from 'lib/redirect'
|
||||
|
||||
export default redirect('/en-us/guide/introduction')
|
||||
3
pages/zh-cn/components/index.js
Normal file
3
pages/zh-cn/components/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import redirect from 'lib/redirect'
|
||||
|
||||
export default redirect('/zh-cn/components/button')
|
||||
3
pages/zh-cn/guide/index.js
Normal file
3
pages/zh-cn/guide/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import redirect from 'lib/redirect'
|
||||
|
||||
export default redirect('/zh-cn/guide/introduction')
|
||||
Reference in New Issue
Block a user