mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-01 10:52:46 +00:00
Merge branch 'master' into pr/2417
This commit is contained in:
@@ -15,7 +15,7 @@ module.exports = {
|
|||||||
rules : {
|
rules : {
|
||||||
/** Errors **/
|
/** Errors **/
|
||||||
'camelcase' : ['error', { properties: 'never' }],
|
'camelcase' : ['error', { properties: 'never' }],
|
||||||
'func-style' : ['error', 'expression', { allowArrowFunctions: true }],
|
//'func-style' : ['error', 'expression', { allowArrowFunctions: true }],
|
||||||
'no-array-constructor' : 'error',
|
'no-array-constructor' : 'error',
|
||||||
'no-iterator' : 'error',
|
'no-iterator' : 'error',
|
||||||
'no-nested-ternary' : 'error',
|
'no-nested-ternary' : 'error',
|
||||||
|
|||||||
@@ -185,6 +185,12 @@ const BrewRenderer = createClass({
|
|||||||
}, 100);
|
}, 100);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
emitClick : function(){
|
||||||
|
// console.log('iFrame clicked');
|
||||||
|
if(!window || !document) return;
|
||||||
|
document.dispatchEvent(new MouseEvent('click'));
|
||||||
|
},
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
//render in iFrame so broken code doesn't crash the site.
|
//render in iFrame so broken code doesn't crash the site.
|
||||||
//Also render dummy page while iframe is mounting.
|
//Also render dummy page while iframe is mounting.
|
||||||
@@ -203,7 +209,9 @@ const BrewRenderer = createClass({
|
|||||||
|
|
||||||
<Frame id='BrewRenderer' initialContent={this.state.initialContent}
|
<Frame id='BrewRenderer' initialContent={this.state.initialContent}
|
||||||
style={{ width: '100%', height: '100%', visibility: this.state.visibility }}
|
style={{ width: '100%', height: '100%', visibility: this.state.visibility }}
|
||||||
contentDidMount={this.frameDidMount}>
|
contentDidMount={this.frameDidMount}
|
||||||
|
onClick={()=>{this.emitClick();}}
|
||||||
|
>
|
||||||
<div className={'brewRenderer'}
|
<div className={'brewRenderer'}
|
||||||
onScroll={this.handleScroll}
|
onScroll={this.handleScroll}
|
||||||
style={{ height: this.state.height }}>
|
style={{ height: this.state.height }}>
|
||||||
|
|||||||
@@ -81,20 +81,70 @@
|
|||||||
color : pink;
|
color : pink;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.recent.navItem {
|
.recent.navDropdownContainer {
|
||||||
position : relative;
|
position : relative;
|
||||||
.dropdown {
|
.navDropdown .navItem {
|
||||||
position : absolute;
|
|
||||||
z-index : 10000;
|
|
||||||
top : 28px;
|
|
||||||
left : 0;
|
|
||||||
overflow : hidden auto;
|
overflow : hidden auto;
|
||||||
width : 100%;
|
|
||||||
max-height : ~"calc(100vh - 28px)";
|
max-height : ~"calc(100vh - 28px)";
|
||||||
scrollbar-color : #666 #333;
|
scrollbar-color : #666 #333;
|
||||||
scrollbar-width : thin;
|
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;
|
display : block;
|
||||||
box-sizing : border-box;
|
box-sizing : border-box;
|
||||||
padding : 5px 0;
|
padding : 5px 0;
|
||||||
@@ -109,62 +159,6 @@
|
|||||||
background-color : darken(@purple, 30%);
|
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 {
|
.metadata.navItem {
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ const RecentItems = createClass({
|
|||||||
|
|
||||||
removeItem : function(url, evt){
|
removeItem : function(url, evt){
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
evt.stopPropagation();
|
||||||
|
|
||||||
let edited = JSON.parse(localStorage.getItem(EDIT_KEY) || '[]');
|
let edited = JSON.parse(localStorage.getItem(EDIT_KEY) || '[]');
|
||||||
let viewed = JSON.parse(localStorage.getItem(VIEW_KEY) || '[]');
|
let viewed = JSON.parse(localStorage.getItem(VIEW_KEY) || '[]');
|
||||||
@@ -139,11 +140,11 @@ const RecentItems = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
renderDropdown : function(){
|
renderDropdown : function(){
|
||||||
if(!this.state.showDropdown) return null;
|
// if(!this.state.showDropdown) return null;
|
||||||
|
|
||||||
const makeItems = (brews)=>{
|
const makeItems = (brews)=>{
|
||||||
return _.map(brews, (brew, i)=>{
|
return _.map(brews, (brew, i)=>{
|
||||||
return <a href={brew.url} className='item' key={`${brew.id}-${i}`} target='_blank' rel='noopener noreferrer' title={brew.title || '[ no title ]'}>
|
return <a className='navItem' href={brew.url} key={`${brew.id}-${i}`} target='_blank' rel='noopener noreferrer' title={brew.title || '[ no title ]'}>
|
||||||
<span className='title'>{brew.title || '[ no title ]'}</span>
|
<span className='title'>{brew.title || '[ no title ]'}</span>
|
||||||
<span className='time'>{Moment(brew.ts).fromNow()}</span>
|
<span className='time'>{Moment(brew.ts).fromNow()}</span>
|
||||||
<div className='clear' title='Remove from Recents' onClick={(e)=>{this.removeItem(`${brew.url}`, e);}}><i className='fas fa-times'></i></div>
|
<div className='clear' title='Remove from Recents' onClick={(e)=>{this.removeItem(`${brew.url}`, e);}}><i className='fas fa-times'></i></div>
|
||||||
@@ -151,25 +152,25 @@ const RecentItems = createClass({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return <div className='dropdown'>
|
return <>
|
||||||
{(this.props.showEdit && this.props.showView) ?
|
{(this.props.showEdit && this.props.showView) ?
|
||||||
<h4>edited</h4> : null }
|
<Nav.item className='header'>edited</Nav.item> : null }
|
||||||
{this.props.showEdit ?
|
{this.props.showEdit ?
|
||||||
makeItems(this.state.edit) : null }
|
makeItems(this.state.edit) : null }
|
||||||
{(this.props.showEdit && this.props.showView) ?
|
{(this.props.showEdit && this.props.showView) ?
|
||||||
<h4>viewed</h4> : null }
|
<Nav.item className='header'>viewed</Nav.item> : null }
|
||||||
{this.props.showView ?
|
{this.props.showView ?
|
||||||
makeItems(this.state.view) : null }
|
makeItems(this.state.view) : null }
|
||||||
</div>;
|
</>;
|
||||||
},
|
},
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
return <Nav.item icon='fas fa-history' color='grey' className='recent'
|
return <Nav.dropdown className='recent'>
|
||||||
onMouseEnter={()=>this.handleDropdown(true)}
|
<Nav.item icon='fas fa-history' color='grey' >
|
||||||
onMouseLeave={()=>this.handleDropdown(false)}>
|
{this.props.text}
|
||||||
{this.props.text}
|
</Nav.item>
|
||||||
{this.renderDropdown()}
|
{this.renderDropdown()}
|
||||||
</Nav.item>;
|
</Nav.dropdown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
1336
package-lock.json
generated
1336
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -78,9 +78,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.22.5",
|
"@babel/core": "^7.22.8",
|
||||||
"@babel/plugin-transform-runtime": "^7.22.5",
|
"@babel/plugin-transform-runtime": "^7.22.7",
|
||||||
"@babel/preset-env": "^7.22.5",
|
"@babel/preset-env": "^7.22.7",
|
||||||
"@babel/preset-react": "^7.22.5",
|
"@babel/preset-react": "^7.22.5",
|
||||||
"@googleapis/drive": "^5.1.0",
|
"@googleapis/drive": "^5.1.0",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
@@ -103,10 +103,10 @@
|
|||||||
"marked-smartypants-lite": "^1.0.0",
|
"marked-smartypants-lite": "^1.0.0",
|
||||||
"markedLegacy": "npm:marked@^0.3.19",
|
"markedLegacy": "npm:marked@^0.3.19",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"mongoose": "^7.3.1",
|
"mongoose": "^7.3.2",
|
||||||
"nanoid": "3.3.4",
|
"nanoid": "3.3.4",
|
||||||
"nconf": "^0.12.0",
|
"nconf": "^0.12.0",
|
||||||
"npm": "^9.7.2",
|
"npm": "^9.8.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-frame-component": "^4.1.3",
|
"react-frame-component": "^4.1.3",
|
||||||
@@ -119,12 +119,12 @@
|
|||||||
"eslint": "^8.44.0",
|
"eslint": "^8.44.0",
|
||||||
"eslint-plugin-jest": "^27.2.2",
|
"eslint-plugin-jest": "^27.2.2",
|
||||||
"eslint-plugin-react": "^7.32.2",
|
"eslint-plugin-react": "^7.32.2",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.6.1",
|
||||||
"jest-expect-message": "^1.1.3",
|
"jest-expect-message": "^1.1.3",
|
||||||
"postcss-less": "^6.0.0",
|
"postcss-less": "^6.0.0",
|
||||||
"stylelint": "^15.9.0",
|
"stylelint": "^15.10.1",
|
||||||
"stylelint-config-recess-order": "^4.2.0",
|
"stylelint-config-recess-order": "^4.2.0",
|
||||||
"stylelint-config-recommended": "^12.0.0",
|
"stylelint-config-recommended": "^13.0.0",
|
||||||
"stylelint-stylistic": "^0.4.2",
|
"stylelint-stylistic": "^0.4.2",
|
||||||
"supertest": "^6.3.3"
|
"supertest": "^6.3.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,12 +135,12 @@ fs.emptyDirSync('./build');
|
|||||||
|
|
||||||
})().catch(console.error);
|
})().catch(console.error);
|
||||||
|
|
||||||
//In development set up a watch server and livereload
|
//In development, set up LiveReload (refreshes browser), and Nodemon (restarts server)
|
||||||
if(isDev){
|
if(isDev){
|
||||||
livereload('./build');
|
livereload('./build'); // Install the Chrome extension LiveReload to automatically refresh the browser
|
||||||
watchFile('./server.js', { // Rebuild when change detected to this file or any nested directory from here
|
watchFile('./server.js', { // Restart server when change detected to this file or any nested directory from here
|
||||||
ignore : ['./build'], // Ignore ./build or it will rebuild again
|
ignore : ['./build', './client', './themes'], // Ignore folders that are not running server code / avoids unneeded restarts
|
||||||
ext : 'less', // Other extensions to watch (only .js/.json/.jsx by default)
|
ext : 'js json' // Extensions to watch (only .js/.json by default)
|
||||||
//watch: ['./client', './server', './themes'], // Watch additional folders if you want
|
//watch : ['./server', './themes'], // Watch additional folders if needed
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -324,8 +324,8 @@ app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, r
|
|||||||
};
|
};
|
||||||
|
|
||||||
if(req.params.id.length > 12 && !brew._id) {
|
if(req.params.id.length > 12 && !brew._id) {
|
||||||
const googleId = req.params.id.slice(0, -12);
|
const googleId = brew.googleId;
|
||||||
const shareId = req.params.id.slice(-12);
|
const shareId = brew.shareId;
|
||||||
await GoogleActions.increaseView(googleId, shareId, 'share', brew)
|
await GoogleActions.increaseView(googleId, shareId, 'share', brew)
|
||||||
.catch((err)=>{next(err);});
|
.catch((err)=>{next(err);});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -243,9 +243,9 @@ const GoogleActions = {
|
|||||||
|
|
||||||
if(obj) {
|
if(obj) {
|
||||||
if(accessType == 'edit' && obj.data.properties.editId != accessId){
|
if(accessType == 'edit' && obj.data.properties.editId != accessId){
|
||||||
throw ('Edit ID does not match');
|
throw ({ message: 'Edit ID does not match' });
|
||||||
} else if(accessType == 'share' && obj.data.properties.shareId != accessId){
|
} else if(accessType == 'share' && obj.data.properties.shareId != accessId){
|
||||||
throw ('Share ID does not match');
|
throw ({ message: 'Share ID does not match' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const file = await drive.files.get({
|
const file = await drive.files.get({
|
||||||
|
|||||||
@@ -27,8 +27,13 @@ const api = {
|
|||||||
|
|
||||||
// If the id is longer than 12, then it's a google id + the edit id. This splits the longer id up.
|
// If the id is longer than 12, then it's a google id + the edit id. This splits the longer id up.
|
||||||
if(id.length > 12) {
|
if(id.length > 12) {
|
||||||
googleId = id.slice(0, -12);
|
if(id.length >= (33 + 12)) { // googleId is minimum 33 chars (may increase)
|
||||||
id = id.slice(-12);
|
googleId = id.slice(0, -12); // current editId is 12 chars
|
||||||
|
} else { // old editIds used to be 10 chars;
|
||||||
|
googleId = id.slice(0, -10); // if total string is too short, must be old brew
|
||||||
|
console.log('Old brew, using 10-char Id');
|
||||||
|
}
|
||||||
|
id = id.slice(googleId.length);
|
||||||
}
|
}
|
||||||
return { id, googleId };
|
return { id, googleId };
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -111,15 +111,26 @@ describe('Tests for api', ()=>{
|
|||||||
expect(googleId).toEqual('12345');
|
expect(googleId).toEqual('12345');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return id and google id from params', ()=>{
|
it('should return 12-char id and google id from params', ()=>{
|
||||||
const { id, googleId } = api.getId({
|
const { id, googleId } = api.getId({
|
||||||
params : {
|
params : {
|
||||||
id : '123456789012abcdefghijkl'
|
id : '123456789012345678901234567890123abcdefghijkl'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(googleId).toEqual('123456789012345678901234567890123');
|
||||||
expect(id).toEqual('abcdefghijkl');
|
expect(id).toEqual('abcdefghijkl');
|
||||||
expect(googleId).toEqual('123456789012');
|
});
|
||||||
|
|
||||||
|
it('should return 10-char id and google id from params', ()=>{
|
||||||
|
const { id, googleId } = api.getId({
|
||||||
|
params : {
|
||||||
|
id : '123456789012345678901234567890123abcdefghij'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(googleId).toEqual('123456789012345678901234567890123');
|
||||||
|
expect(id).toEqual('abcdefghij');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
require('./nav.less');
|
require('./nav.less');
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
|
const { useState, useRef, useEffect } = React;
|
||||||
const createClass = require('create-react-class');
|
const createClass = require('create-react-class');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames');
|
const cx = require('classnames');
|
||||||
@@ -71,64 +72,49 @@ const Nav = {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
dropdown : createClass({
|
dropdown : function dropdown(props) {
|
||||||
displayName : 'Nav.dropdown',
|
props = Object.assign({}, props, {
|
||||||
getDefaultProps : function() {
|
trigger : 'hover click'
|
||||||
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;
|
|
||||||
|
|
||||||
return (
|
const myRef = useRef(null);
|
||||||
<div className='navDropdown'>
|
const [showDropdown, setShowDropdown] = useState(false);
|
||||||
{dropdownChildren}
|
|
||||||
</div>
|
useEffect(()=>{
|
||||||
);
|
document.addEventListener('click', handleClickOutside);
|
||||||
},
|
return ()=>{
|
||||||
render : function () {
|
document.removeEventListener('click', handleClickOutside);
|
||||||
const dropdownChildren = React.Children.map(this.props.children, (child, i)=>{
|
};
|
||||||
// Ignore the first child
|
}, []);
|
||||||
if(i < 1) return;
|
|
||||||
return child;
|
function handleClickOutside(e) {
|
||||||
});
|
// Close dropdown when clicked outside
|
||||||
return (
|
if(!myRef.current?.contains(e.target)) {
|
||||||
<div className={`navDropdownContainer ${this.props.className}`}
|
handleDropdown(false);
|
||||||
ref='dropdown'
|
}
|
||||||
onMouseEnter={this.props.trigger == 'hover' ? ()=>{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)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
function handleDropdown(show) {
|
||||||
|
setShowDropdown(show ?? !showDropdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dropdownChildren = React.Children.map(props.children, (child, i)=>{
|
||||||
|
if(i < 1) return;
|
||||||
|
return child;
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`navDropdownContainer ${props.className}`}
|
||||||
|
ref={myRef}
|
||||||
|
onMouseEnter = { props.trigger.includes('hover') ? ()=>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 && <div className='navDropdown'>{dropdownChildren}</div>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ nav{
|
|||||||
left : 0px;
|
left : 0px;
|
||||||
z-index : 10000;
|
z-index : 10000;
|
||||||
width : 100%;
|
width : 100%;
|
||||||
|
overflow : hidden auto;
|
||||||
|
max-height : calc(100vh - 28px);
|
||||||
.navItem{
|
.navItem{
|
||||||
animation-name: glideDropDown;
|
animation-name: glideDropDown;
|
||||||
animation-duration: 0.4s;
|
animation-duration: 0.4s;
|
||||||
|
|||||||
Reference in New Issue
Block a user