@mongodb-js/mongodb-ui-components
Version:
A collection of frequently used functional UI components found on mongodb properties
241 lines (218 loc) • 7.54 kB
JavaScript
import {h, Component} from 'preact'
import {loginIcon, mongodbLogo} from './icons'
import {Panel} from './panel'
import {Dropdown} from './dropdown'
import {Search} from './search'
export class DesktopNav extends Component {
constructor (props) {
super(props)
this.state = {
isPanOpen: false,
isDdOpen: false,
panelIndex: -1,
ddIndex: -1,
searching: false,
compressed: false
}
this.topRightEls = []
}
componentDidMount () {
document.addEventListener('scroll', () => {
const {compressed} = this.state
const shouldCompress = window.pageYOffset > 100
if (compressed && !shouldCompress) {
this.setState({compressed: false})
} else if (!compressed && shouldCompress) {
this.setState({compressed: true})
}
})
}
togglePanSection (i) {
this.setState({panelIndex: i, isDdOpen: false})
setTimeout(() => this.setState({isPanOpen: true}))
}
toggleDdSection (i) {
if (this.state.searching) return
this.setState({ddIndex: i, isPanOpen: false})
setTimeout(() => this.setState({isDdOpen: true}))
}
renderItem (item, i, left, active, activeIndex) {
if (item.href) {
return (
<a
class='reset p-0 m-r-35'
onMouseEnter={(e) => {
this.setState({isPanOpen: false, isDdOpen: false}, () => {
e.currentTarget.style.color = '#13AA52'
e.currentTarget.children[0].style.color = ''
})
}}
onMouseLeave={(e) => {
e.currentTarget.style.color = ''
e.currentTarget.children[0].style.color = left ? '' : '#798186'
}}
href={item.href}>
<p style={{
color: left ? '' : '#798186',
fontSize: left ? '16px' : '14px'
}}>{item.text}</p>
</a>
)
}
return (
<button
ref={left === false ? (el) => { this.topRightEls.push(el) } : null}
style={{outline: '0'}}
class='reset p-0 m-r-35'
data-opens={item.opens}
onClick={() =>
this.setState(left
? {isPanOpen: !this.state.isPanOpen}
: {isDdOpen: !this.state.isDdOpen}
)}
onMouseEnter={() => left
? this.togglePanSection(i)
: this.toggleDdSection(i)}>
<p style={{
color: active && activeIndex === i ? '#13AA52' : (left ? '' : '#798186'),
fontSize: left ? '16px' : '14px'
}}>
{item.text}
</p>
</button>
)
}
ddTransform (el) {
if (el === undefined) return ''
const width = el.offsetWidth
const left = el.offsetLeft
return `translate(${left + (width / 2) - 110}px, 0px)`
}
onNavMouseLeave () {
this.setState({
isPanOpen: false,
isDdOpen: false
})
}
render (
{logoHref, top, panels, dropdowns},
{isPanOpen, isDdOpen, panelIndex, ddIndex, searching, compressed}
) {
return (
<nav
onMouseLeave={() => this.onNavMouseLeave()}
style={{zIndex: 1000000}}
class='m-nav-desktop fixed top left w-full'>
<div
style={{
zIndex: 1,
borderBottom: '1px solid rgba(179,187,193,0.5)',
transition: '200ms',
height: compressed ? '50px' : '70px'
}}
class='relative fl fl-justify-between bg-white'>
<div class='fl fl-center m-h-20'>
<a href={logoHref} class='m-r-15'>
{mongodbLogo}
</a>
{top.left.map((item, i) =>
this.renderItem(item, i, true, isPanOpen, panelIndex))}
</div>
<div class='fl fl-center m-h-20'>
<div class='fl fl-center' style={{
transition: searching ? 'none' : '150ms cubic-bezier(0.230, 1.000, 0.320, 1.000)',
width: searching ? '0px' : '',
opacity: searching ? '0' : '1'
}}>
{top.right.map((item, i) =>
this.renderItem(item, i, false, isDdOpen, ddIndex)
)}
</div>
<div class='relative'>
<Search onSearchClick={(newVal) => this.setState({searching: newVal})} />
</div>
<a
href='https://cloud.mongodb.com/user'
onMouseEnter={function (e) {
const svg = e.target.querySelector('svg')
svg.style.transition = '200ms'
svg.style.transform = 'translate(-2px, 0) scale(1.4)'
}}
onMouseLeave={function (e) {
const svg = e.target.querySelector('svg')
svg.style.transform = 'translate(0, 0) scale(1)'
}}>
<button class='reset p-0 m-r-35'>
<p class='fl fl-center' style={{fontSize: '14px', cursor: 'pointer'}}>
<strong clasxss='m-l-5'>Sign In</strong> {loginIcon}
</p>
</button>
</a>
<a href='/download-center'>
<button class='btn-green'>
Try Free
</button>
</a>
</div>
</div>
<div style={{pointerEvents: isPanOpen ? '' : 'none'}}>
<div
style={{
boxShadow: '0 4px 7px 0 rgba(0,0,0,0.2)',
transition: 'opacity 100ms, transform 200ms cubic-bezier(0.175, 0.885, 0.320, 1.275)',
transform: isPanOpen ? 'translate(0, -10px)' : 'translate(0, -30px)',
opacity: isPanOpen ? '1' : '0'
}}
class='relative bg-white'>
<div
class='relative m-auto'
style={{
transition: isPanOpen ? '' : 'height 1ms 210ms',
height: isPanOpen ? `${panels[panelIndex].height + 10}px` : '0px'
}}>
{panels.map((panel, i) =>
<Panel
width={panel.width}
position={i > panelIndex ? 1 : -1}
isOpen={isPanOpen}
isActive={panelIndex === i}
sections={panel.sections}
callout={panel.callout} />
)}
</div>
</div>
</div>
<div
class='absolute top left'
style={{
zIndex: 10,
pointerEvents: isDdOpen ? '' : 'none',
transition: isDdOpen ? 'opacity 150ms, transform 250ms cubic-bezier(0.175, 0.885, 0.320, 1.275)' : '',
opacity: isDdOpen ? '1' : '0',
transform: this.ddTransform(this.topRightEls[ddIndex])
}}>
<div
style={{
border: '1px solid rgba(179,187,193,0.25)',
borderRadius: '4px',
boxShadow: '0 2px 4px 0 rgba(0,0,0,0.1)',
transition: 'transform 250ms cubic-bezier(0.175, 0.885, 0.320, 1.275), height 100ms',
transform: isDdOpen
? `translate(0, ${compressed ? '43px' : '60px'})`
: `translate(0, ${compressed ? '38px' : '55px'})`,
opacity: isDdOpen ? '1' : '0',
height: isDdOpen ? `${dropdowns[ddIndex].height}px` : ''
}}
class='absolute w-220 bg-white'>
{dropdowns.map((dropdown, i) =>
<Dropdown
isOpen={isDdOpen}
isActive={ddIndex === i}
items={dropdown.items} />
)}
</div>
</div>
</nav>
)
}
}