import React from 'react' ; import { FormattedMessage , injectIntl } from 'react-intl' ; import { Link } from 'gatsby' ; import { AppstoreAddOutlined , HomeOutlined , MenuOutlined , NotificationOutlined , PlayCircleOutlined , ReadOutlined , SearchOutlined , ZhihuOutlined , TwitterOutlined , YuqueOutlined } from '@ant-design/icons' ; import { Row , Col , Select , Input , Menu , Popover , Button } from 'antd' ; import * as utils from '../utils' ; import { version } from '../../../siteconfig.json' ; import { Icon } from './Icon' ; const { Option } = Select ; const LOGO_URL = 'https://gw.alipayobjects.com/mdn/rms_d27172/afts/img/A*w3sZQpMix18AAAAAAAAAAAAAARQnAQ' ; let docSearch ; if ( typeof window !== 'undefined' ) { docSearch = require ( 'docsearch.js' ) ; } function initDocSearch ( ) { if ( ! docSearch ) { return ; } docSearch ( { apiKey : '6cea501a58304e81c8e9d028a1d995e9' , indexName : 'oasisengine' , inputSelector : '#search-box input' , algoliaOptions : { facetFilters : [ `version:${ version }` ] } , transformData ( hits ) { hits . forEach ( ( hit ) => { hit . url = hit . url . replace ( 'oasisengine.cn' , window . location . host ) ; hit . url = hit . url . replace ( 'https:' , window . location . protocol ) ; } ) ; return hits ; } , debug : false , } ) ; } interface HeaderProps { isMobile : boolean ; intl : any ; location : { pathname : string ; } ; showVersion ? : boolean ; } interface HeaderState { inputValue ? : string ; menuVisible : boolean ; menuMode ? : 'vertical' | 'vertical-left' | 'vertical-right' | 'horizontal' | 'inline' ; searchOption ? : any [ ] ; searching ? : boolean ; versions ? : string [ ] ; } class Header extends React . Component < HeaderProps , HeaderState > { searchInput : Input | null | undefined ; timer : number ; constructor ( props ) { super ( props ) ; this . state = { menuVisible : false , menuMode : props . isMobile ? 'inline' : 'horizontal' , versions : [ ] } ; } async componentDidMount ( ) { const { searchInput } = this ; const { intl : { locale } } = this . props ; this . redirect ( ) ; document . addEventListener ( 'keyup' , ( event ) => { if ( event . keyCode === 83 && event . target === document . body ) { if ( searchInput ) { searchInput . focus ( ) ; } } } ) ; initDocSearch ( locale === 'zh-CN' ? 'cn' : 'en' ) ; const versionConfig = 'https://render.alipay.com/p/h5data/oasis-version_site-doc-versions-h5data.json' ; const versions = await fetch ( versionConfig ) . then ( ( e ) => e . json ( ) ) ; if ( versions ) { this . setState ( { versions : versions . map ( ( v ) => v . version ) } ) ; } } componentDidUpdate ( preProps ) { const { isMobile } = this . props ; if ( isMobile !== preProps . isMobile ) { this . setMenuMode ( isMobile ) ; } } redirect ( ) { const { pathname } = window . location ; const isPathNameZhCN = /-cn\/?$/ . test ( pathname ) ; const isZhCN = utils . isZhCN ( ) ; if ( this . isNotMarkdownPage ( pathname ) ) { return ; } if ( isZhCN !== isPathNameZhCN ) { this . replacePathName ( pathname , isZhCN ) ; } } setMenuMode = ( isMobile ) => { this . setState ( { menuMode : isMobile ? 'inline' : 'horizontal' } ) ; } ; handleHideMenu = ( ) => { this . setState ( { menuVisible : false , } ) ; } ; handleShowMenu = ( ) => { this . setState ( { menuVisible : true , } ) ; } ; onMenuVisibleChange = ( visible ) => { this . setState ( { menuVisible : visible , } ) ; } ; handleSelect = ( value ) => { window . location . href = value ; } ; replacePathName = ( pathname , isZhCN ) => { const currentProtocol = `${ window . location . protocol }//` ; const currentHref = window . location . href . substr ( currentProtocol . length ) ; window . location . href = currentProtocol + currentHref . replace ( window . location . pathname , utils . getLocalizedPathname ( pathname , isZhCN ) ) ; } ; isNotMarkdownPage ( pathname ) { return pathname === '/' || /api/ . test ( pathname ) || /gltf-viewer/ . test ( pathname ) || /examples/ . test ( pathname ) ; } handleLangChange = ( ) => { const { location : { pathname } , } = this . props ; const isPathNameZhCN = /-cn\/?$/ . test ( pathname ) ; const isZhCN = utils . isZhCN ( ) ; window . localStorage . setItem ( 'locale' , isZhCN ? 'en-US' : 'zh-CN' ) ; if ( this . isNotMarkdownPage ( pathname ) ) { window . location . reload ( ) ; return ; } if ( isZhCN && isPathNameZhCN ) { this . replacePathName ( pathname , false ) ; return ; } if ( ! isZhCN && ! isPathNameZhCN ) { this . replacePathName ( pathname , true ) ; } } ; onVersionChange = ( value ) => { const versionReg = /\/(\d+[.]\d+[^/]*)\// ; const matchedResult = window . location . href . match ( versionReg ) ; if ( matchedResult && matchedResult [ 1 ] ) { window . location . href = window . location . href . replace ( matchedResult [ 1 ] , value ) ; } } ; render ( ) { const { menuMode , menuVisible } = this . state ; const { location , intl } = this . props ; const path = location . pathname ; const { formatMessage } = intl ; const module = location . pathname . replace ( /(^\/|\/$)/g , '' ) . split ( '/' ) . slice ( 0 , - 1 ) . join ( '/' ) ; let activeMenuItem = module || 'home' ; if ( /docs/ . test ( path ) ) { if ( /docs\/editor[-]/ . test ( path ) ) { activeMenuItem = 'editor-docs' ; } else if ( /docs\/artist[-]/ . test ( path ) ) { activeMenuItem = 'artist-docs' ; } else { activeMenuItem = 'engine-docs' ; } } else if ( /api/ . test ( path ) ) { activeMenuItem = 'api' ; } else if ( /examples/ . test ( path ) ) { activeMenuItem = 'examples' ; } else if ( /gltf-viewer/ . test ( path ) ) { activeMenuItem = 'gltfviewer' ; } else if ( path === '/' ) { activeMenuItem = 'home' ; } const isZhCN = intl . locale === 'zh-CN' ; const menu = [ < Menu mode = { menuMode } selectedKeys = { [ activeMenuItem ] } id = "nav" key = "nav" > < Menu . Item key = "home" icon = { < HomeOutlined / > } > < Link to = "/" > < FormattedMessage id = "app.header.menu.home" / > < /Link> < /Menu.Item> < Menu . SubMenu key = "docs" icon = { < ReadOutlined / > } title = { formatMessage ( { id : "app.header.menu.docs" } ) } > < Menu . ItemGroup title = { formatMessage ( { id : "app.header.menu.engine" } ) } > < Menu . Item key = "engine-docs" > < Link to = { utils . getLocalizedPathname ( `${ version }/docs/install` , isZhCN ) } > { formatMessage ( { id : "app.header.menu.engine.docs" } ) } < /Link> < /Menu.Item> < Menu . Item key = "api" > < Link to = { `/${ version }/api/core/index` } > API < /Link> < /Menu.Item> < /Menu.ItemGroup> < Menu . ItemGroup title = { formatMessage ( { id : "app.header.menu.artist" } ) } > < Menu . Item key = "artist-docs" > < Link to = { utils . getLocalizedPathname ( `/${ version }/docs/artist-bake` , isZhCN ) } > { formatMessage ( { id : "app.header.menu.artist.docs" } ) } < /Link> < /Menu.Item> < /Menu.ItemGroup> { isZhCN && < Menu . ItemGroup title = { formatMessage ( { id : "app.header.menu.editor" } ) } > < Menu . Item key = "editor-docs" > < Link to = { utils . getLocalizedPathname ( `/${ version }/docs/editor` , isZhCN ) } > { formatMessage ( { id : "app.header.menu.editor.docs" } ) } < /Link> < /Menu.Item> < /Menu.ItemGroup>} < /Menu.SubMenu> < Menu . Item key = "examples" icon = { < PlayCircleOutlined / > } > < Link to = { `/${ version }/examples` } > < FormattedMessage id = "app.header.menu.engine.examples" / > < /Link> < /Menu.Item> < Menu . SubMenu key = "ecosystem" icon = { < AppstoreAddOutlined / > } title = { formatMessage ( { id : "app.header.menu.ecosystem" } ) } > < Menu . ItemGroup title = { formatMessage ( { id : "app.header.menu.ecosystem.tool" } ) } > < Menu . Item key = "miniprogram" > < Link to = { utils . getLocalizedPathname ( `/${ version }/docs/miniprogram` , isZhCN ) } > { formatMessage ( { id : "app.header.menu.ecosystem.miniprogram" } ) } < /Link> < /Menu.Item> < Menu . Item key = "gltfviewer" > < Link to = { `/gltf-viewer` } > { formatMessage ( { id : "app.header.menu.ecosystem.gltfviewer" } ) } < /Link> < /Menu.Item> < Menu . Item key = "createapp" > < Link to = "https://github.com/oasis-engine/create-oasis-app" target = "_blank" > { formatMessage ( { id : "app.header.menu.ecosystem.createapp" } ) } < /Link> < /Menu.Item> { isZhCN && < Menu . Item key = "editor" > < Link to = "https://oasis.alipay.com/editor" target = "_blank" > { formatMessage ( { id : "app.header.menu.ecosystem.editor" } ) } < /Link> < /Menu.Item>} < /Menu.ItemGroup> < Menu . ItemGroup title = { formatMessage ( { id : "app.header.menu.ecosystem.animation" } ) } > < Menu . Item key = "spine" > < Link to = { utils . getLocalizedPathname ( `/${ version }/docs/spine` , isZhCN ) } > Spine < /Link> < /Menu.Item> < Menu . Item key = "lottie" > < Link to = { utils . getLocalizedPathname ( `/${ version }/docs/lottie` , isZhCN ) } > Lottie < /Link> < /Menu.Item> < /Menu.ItemGroup> < /Menu.SubMenu> < Menu . SubMenu key = "community" icon = { < NotificationOutlined / > } title = { formatMessage ( { id : "app.header.menu.community" } ) } > < Menu . Item key = "zhihu" icon = { < ZhihuOutlined / > } > < a target = "_blank" rel = "noopener noreferrer" href = "https://www.zhihu.com/column/c_1369047387231592448" > < FormattedMessage id = "app.community.zhihu" / > < /a> < /Menu.Item> < Menu . Item key = "juejin" icon = { < Icon type = "icon-juejin" / > } > < a target = "_blank" rel = "noopener noreferrer" href = "https://juejin.cn/team/6930507995474313230/posts" > < FormattedMessage id = "app.community.juejin" / > < /a> < /Menu.Item> < Menu . Item key = "yuque" icon = { < YuqueOutlined / > } > < a target = "_blank" rel = "noopener noreferrer" href = "https://www.yuque.com/oasis-engine/blog" > < FormattedMessage id = "app.community.yuque" / > < /a> < /Menu.Item> < Menu . Item key = "twitter" icon = { < TwitterOutlined / > } > < a target = "_blank" rel = "noopener noreferrer" href = "https://twitter.com/OasisEngine" > < FormattedMessage id = "app.community.twitter" / > < /a> < /Menu.Item> < /Menu.SubMenu> < /Menu> ] ; return ( < div > < div id = "header" className = "header" > { menuMode === 'inline' ? ( < Popover overlayClassName = "popover-menu" placement = "bottomRight" content = { menu } trigger = "click" visible = { menuVisible } arrowPointAtCenter onVisibleChange = { this . onMenuVisibleChange } > < MenuOutlined className = "nav-phone-icon" onClick = { this . handleShowMenu } / > < /Popover>) : null} < Row > < Col xxl = { 4 } xl = { 5 } lg = { 8 } md = { 8 } sm = { 24 } xs = { 24 } > < Link id = "logo" to = "/" > < img src = { LOGO_URL } alt = "Oasis Engine" / > < /Link> < /Col> < Col xxl = { 20 } xl = { 19 } lg = { 16 } md = { 16 } sm = { 0 } xs = { 0 } > < div id = "search-box" > < SearchOutlined /> < Input ref = { ( ref ) => { this . searchInput = ref ; } } placeholder = { intl . formatMessage ( { id : 'app.header.search' } ) } / > < /div> < div className = "header-meta" > < div className = "right-header" > < div id = "lang" > < Button onClick = { this . handleLangChange } size = "small" > < FormattedMessage id = "app.header.lang" / > < /Button> < /div> { ( this . state . versions . length && this . props . showVersion ) ? < Select size = "small" onChange = { this . onVersionChange } value = { version } > { this . state . versions . map ( ( v ) => { return < Option value = { v } key = { v } > { `v${ v }` } < /Option>; } ) } < /Select> : null} < /div> { menuMode === 'horizontal' ? < div id = "menu" > { menu } < /div> : null} < /div> < /Col> < /Row> < /div> < /div>); } } export default injectIntl ( Header ) ;