diff --git a/.eslintrc.js b/.eslintrc.js index dd4bcd0d3..74e7bb660 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,7 +15,7 @@ module.exports = { rules : { /** Errors **/ 'camelcase' : ['error', { properties: 'never' }], - 'func-style' : ['error', 'expression', { allowArrowFunctions: true }], + //'func-style' : ['error', 'expression', { allowArrowFunctions: true }], 'no-array-constructor' : 'error', 'no-iterator' : 'error', 'no-nested-ternary' : 'error', diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 27fef7e16..5dd6dd3a7 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -185,6 +185,12 @@ const BrewRenderer = createClass({ }, 100); }, + emitClick : function(){ + // console.log('iFrame clicked'); + if(!window || !document) return; + document.dispatchEvent(new MouseEvent('click')); + }, + render : function(){ //render in iFrame so broken code doesn't crash the site. //Also render dummy page while iframe is mounting. @@ -203,7 +209,9 @@ const BrewRenderer = createClass({ + contentDidMount={this.frameDidMount} + onClick={()=>{this.emitClick();}} + >
diff --git a/client/homebrew/navbar/navbar.less b/client/homebrew/navbar/navbar.less index f23034dd8..036f52cf4 100644 --- a/client/homebrew/navbar/navbar.less +++ b/client/homebrew/navbar/navbar.less @@ -81,20 +81,70 @@ color : pink; } } - .recent.navItem { + .recent.navDropdownContainer { position : relative; - .dropdown { - position : absolute; - z-index : 10000; - top : 28px; - left : 0; + .navDropdown .navItem { overflow : hidden auto; - width : 100%; max-height : ~"calc(100vh - 28px)"; scrollbar-color : #666 #333; scrollbar-width : thin; - h4 { - font-size : 0.8em; + + + #backgroundColorsHover; + .animate(background-color); + position : relative; + display : block; + overflow : clip; + box-sizing : border-box; + padding : 8px 5px 13px; + text-decoration : none; + color : white; + border-top : 1px solid #888; + background-color : #333; + .clear { + position : absolute; + top : 50%; + right : 0; + display : none; + width : 20px; + height : 100%; + transform : translateY(-50%); + opacity : 70%; + border-radius : 3px; + background-color : #333; + &:hover { + opacity : 100%; + } + i { + font-size : 10px; + width : 100%; + height : 100%; + margin : 0; + text-align : center; + } + } + &:hover { + background-color : @blue; + .clear { + display : grid; + place-content : center; + } + } + .title { + display : inline-block; + overflow : hidden; + width : 100%; + white-space : nowrap; + text-overflow : ellipsis; + } + .time { + font-size : 0.7em; + position : absolute; + right : 2px; + bottom : 2px; + color : #888; + } + &.header { display : block; box-sizing : border-box; padding : 5px 0; @@ -109,62 +159,6 @@ background-color : darken(@purple, 30%); } } - .item { - #backgroundColorsHover; - .animate(background-color); - position : relative; - display : block; - overflow : clip; - box-sizing : border-box; - padding : 8px 5px 13px; - text-decoration : none; - color : white; - border-top : 1px solid #888; - background-color : #333; - .clear { - position : absolute; - top : 50%; - right : 0; - display : none; - width : 20px; - height : 100%; - transform : translateY(-50%); - opacity : 70%; - border-radius : 3px; - background-color : #333; - &:hover { - opacity : 100%; - } - i { - font-size : 10px; - width : 100%; - height : 100%; - margin : 0; - text-align : center; - } - } - &:hover { - background-color : @blue; - .clear { - display : grid; - place-content : center; - } - } - .title { - display : inline-block; - overflow : hidden; - width : 100%; - white-space : nowrap; - text-overflow : ellipsis; - } - .time { - font-size : 0.7em; - position : absolute; - right : 2px; - bottom : 2px; - color : #888; - } - } } } .metadata.navItem { diff --git a/client/homebrew/navbar/recent.navitem.jsx b/client/homebrew/navbar/recent.navitem.jsx index 169c46a0e..431bdd8df 100644 --- a/client/homebrew/navbar/recent.navitem.jsx +++ b/client/homebrew/navbar/recent.navitem.jsx @@ -121,6 +121,7 @@ const RecentItems = createClass({ removeItem : function(url, evt){ evt.preventDefault(); + evt.stopPropagation(); let edited = JSON.parse(localStorage.getItem(EDIT_KEY) || '[]'); let viewed = JSON.parse(localStorage.getItem(VIEW_KEY) || '[]'); @@ -139,11 +140,11 @@ const RecentItems = createClass({ }, renderDropdown : function(){ - if(!this.state.showDropdown) return null; + // if(!this.state.showDropdown) return null; const makeItems = (brews)=>{ return _.map(brews, (brew, i)=>{ - return + return {brew.title || '[ no title ]'} {Moment(brew.ts).fromNow()}
{this.removeItem(`${brew.url}`, e);}}>
@@ -151,25 +152,25 @@ const RecentItems = createClass({ }); }; - return
+ return <> {(this.props.showEdit && this.props.showView) ? -

edited

: null } + edited : null } {this.props.showEdit ? makeItems(this.state.edit) : null } {(this.props.showEdit && this.props.showView) ? -

viewed

: null } + viewed : null } {this.props.showView ? makeItems(this.state.view) : null } -
; + ; }, render : function(){ - return this.handleDropdown(true)} - onMouseLeave={()=>this.handleDropdown(false)}> - {this.props.text} + return + + {this.props.text} + {this.renderDropdown()} - ; + ; } }); diff --git a/shared/naturalcrit/nav/nav.jsx b/shared/naturalcrit/nav/nav.jsx index 5d5aacd78..3c7fd7c5e 100644 --- a/shared/naturalcrit/nav/nav.jsx +++ b/shared/naturalcrit/nav/nav.jsx @@ -1,5 +1,6 @@ require('./nav.less'); const React = require('react'); +const { useState, useRef, useEffect } = React; const createClass = require('create-react-class'); const _ = require('lodash'); const cx = require('classnames'); @@ -71,64 +72,49 @@ const Nav = { } }), - dropdown : createClass({ - displayName : 'Nav.dropdown', - getDefaultProps : function() { - return { - trigger : 'hover' - }; - }, - getInitialState : function() { - return { - showDropdown : false - }; - }, - componentDidMount : function() { - if(this.props.trigger == 'click') - document.addEventListener('click', this.handleClickOutside); - }, - componentWillUnmount : function() { - if(this.props.trigger == 'click') - document.removeEventListener('click', this.handleClickOutside); - }, - handleClickOutside : function(e){ - // Close dropdown when clicked outside - if(this.refs.dropdown && !this.refs.dropdown.contains(e.target)) { - this.handleDropdown(false); - } - }, - handleDropdown : function(show){ - this.setState({ - showDropdown : show - }); - }, - renderDropdown : function(dropdownChildren){ - if(!this.state.showDropdown) return null; + dropdown : function dropdown(props) { + props = Object.assign({}, props, { + trigger : 'hover click' + }); - return ( -
- {dropdownChildren} -
- ); - }, - render : function () { - const dropdownChildren = React.Children.map(this.props.children, (child, i)=>{ - // Ignore the first child - if(i < 1) return; - return child; - }); - return ( -
{this.handleDropdown(true);} : undefined} - onClick= {this.props.trigger == 'click' ? ()=>{this.handleDropdown(true);} : undefined} - onMouseLeave={this.props.trigger == 'hover' ? ()=>{this.handleDropdown(false);} : undefined}> - {this.props.children[0] || this.props.children /*children is not an array when only one child*/} - {this.renderDropdown(dropdownChildren)} -
- ); + const myRef = useRef(null); + const [showDropdown, setShowDropdown] = useState(false); + + useEffect(()=>{ + document.addEventListener('click', handleClickOutside); + return ()=>{ + document.removeEventListener('click', handleClickOutside); + }; + }, []); + + function handleClickOutside(e) { + // Close dropdown when clicked outside + if(!myRef.current?.contains(e.target)) { + handleDropdown(false); + } } - }) + + function handleDropdown(show) { + setShowDropdown(show ?? !showDropdown); + } + + const dropdownChildren = React.Children.map(props.children, (child, i)=>{ + if(i < 1) return; + return child; + }); + + return ( +
handleDropdown(true) : undefined } + onMouseLeave = { props.trigger.includes('hover') ? ()=>handleDropdown(false) : undefined } + onClick = { props.trigger.includes('click') ? ()=>handleDropdown(true) : undefined } + > + {props.children[0] || props.children /*children is not an array when only one child*/} + {showDropdown &&
{dropdownChildren}
} +
+ ); + } }; diff --git a/shared/naturalcrit/nav/nav.less b/shared/naturalcrit/nav/nav.less index e01715a95..e3a58a33a 100644 --- a/shared/naturalcrit/nav/nav.less +++ b/shared/naturalcrit/nav/nav.less @@ -79,6 +79,8 @@ nav{ left : 0px; z-index : 10000; width : 100%; + overflow : hidden auto; + max-height : calc(100vh - 28px); .navItem{ animation-name: glideDropDown; animation-duration: 0.4s;