-
-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Animate the expanding/collapsing of sub-items in navigation #10
Comments
I've now made use of JavaScript animations. This is the complete /* modified */
/* eslint-disable no-sequences */
import React, {useContext} from 'react';
import {Link} from 'gatsby';
import styled from '@emotion/styled';
import {GlobalDispatchContext, GlobalStateContext} from '../../context/GlobalContextProvider';
import ButtonCollapse from '../ButtonCollapse';
const NavItem = ({item}) =>
{
const state = useContext(GlobalStateContext);
const dispatch = useContext(GlobalDispatchContext);
const isCollapsed = state.collapsed[item.url];
const hasChildren = item.items && item.items.length > 0;
function expandList ()
{
var elem1 = document.getElementById("navChild");
var pos1 = -100;
var id1 = setInterval(frame1, 1);
function frame1()
{
if (pos1 === 0)
{
clearInterval(id1);
} else
{
pos1++;
elem1.style.top = pos1 + 'px';
}
}
}
function collapseList ()
{
var elem2 = document.getElementById("navChild");
var pos2 = 0;
var id2 = setInterval(frame2, 1);
function frame2()
{
if (pos2 === -100)
{
clearInterval(id2);
} else
{
pos2--;
elem2.style.top = pos2 + 'px';
}
}
}
return (
<StyledNavItem>
<NavItemLink to = {item.url} activeClassName = "is-active">
{item.title}
</NavItemLink>
{
hasChildren && (
<ButtonCollapse isCollapsed = {isCollapsed} onClick =
{
() => isCollapsed ? (
<>
{
expandList(),
dispatch({type: 'TOGGLE_NAV_COLLAPSED', url: item.url})
}
</>) : (
<>
{
collapseList(),
setTimeout(() =>
{
dispatch({type: 'TOGGLE_NAV_COLLAPSED', url: item.url})
}, 250)
}
</>)
}/>)
}
<div style = {{overflowY: "hidden"}}>
{
hasChildren && (
<NavItemChild id = "navChild">
{
item.items.map(child => (
<StyledNavItem key = {child.url}>
<NavItemLink to = {child.url} activeClassName = "is-active">
{child.title}
</NavItemLink>
</StyledNavItem>))
}
</NavItemChild>)
}
</div>
</StyledNavItem>);
};
const StyledNavItem = styled.li `position: relative; display: block; padding: 0; margin: 0.2rem 0; width: 100%; list-style: none`;
const NavItemLink = styled(Link) `display: block; padding: 0.5rem 1.8rem 0.5rem 1.2rem; width: 100%; color: ${p => p.theme.colors.text}; font-weight: 600; text-decoration: none; transition: color ${p => p.theme.transition}; &:hover, &:focus, &.is-active {color: ${p => p.theme.colors.primary}}`;
const NavItemChild = styled.ul `margin: 0.5rem 0 0.5rem 1.2rem; padding: 0; border-left: 1px solid ${p => p.theme.colors.text}; list-style: none; & > li {margin: 0}; position: relative`;
export default React.memo(NavItem); This is definitely not the best way to do it, but, at my skill level, even this took my entire day and a lot of efforts. All suggestions to make it better even slighter are welcome, but, till then, I'm using it like this. |
I didn't consider the use case of adding more items to the list and now that I try with that, it doesn't work. The subsequent items don't move. |
After a lot of reading, I have reached till here: /* modified */
/* eslint-disable no-sequences */
import React from 'react';
import {Link} from 'gatsby';
import styled from '@emotion/styled';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
import {faCaretRight} from '@fortawesome/free-solid-svg-icons'
const NavItem = ({item}) =>
{
var isCollapsed = false
const hasChildren = item.items && item.items.length > 0;
let buttonRef = React.createRef();
let listRef = React.createRef();
function expandList ()
{
listRef.current.style.display = 'block';
var pos1 = -100;
var rot1 = 90;
var id1a = setInterval(frame1a, 1);
var id1b = setInterval(frame1b, 1);
function frame1a()
{
if (pos1 === 0)
{
clearInterval(id1a);
} else
{
pos1++;
listRef.current.style.top = pos1 + 'px';
}
}
function frame1b()
{
if (rot1 === -90)
{
clearInterval(id1b);
} else
{
rot1--;
buttonRef.current.style.transform = 'rotate(' + rot1 + 'deg)';
}
}
}
function collapseList ()
{
var pos2 = 0;
var rot2 = -90;
var id2a = setInterval(frame2a, 1);
var id2b = setInterval(frame2b, 1)
function frame2a()
{
if (pos2 === -100)
{
clearInterval(id2a);
listRef.current.style.display = 'none';
} else
{
pos2--;
listRef.current.style.top = pos2 + 'px';
}
}
function frame2b()
{
if (rot2 === 90)
{
clearInterval(id2b);
} else
{
rot2++;
buttonRef.current.style.transform = 'rotate(' + rot2 + 'deg)';
}
}
}
return (
<StyledNavItem>
<NavItemLink to = {item.url} activeClassName = "is-active">
{item.title}
</NavItemLink>
{
hasChildren && (
<StyledButton ref = {buttonRef}>
<FontAwesomeIcon icon = {faCaretRight} size = "1.75x" fixedWidth onClick =
{
() => isCollapsed ? (
<>
{
expandList(),
isCollapsed = false
}
</>) : (
<>
{
collapseList(),
isCollapsed = true
}
</>)
}/>
</StyledButton>)
}
<div style = {{overflowY: "hidden"}}>
{
hasChildren && (
<NavItemChild ref = {listRef}>
{
item.items.map(child => (
<StyledNavItem key = {child.url}>
<NavItemLink to = {child.url} activeClassName = "is-active">
{child.title}
</NavItemLink>
</StyledNavItem>))
}
</NavItemChild>)
}
</div>
</StyledNavItem>);
};
const StyledNavItem = styled.li `position: relative; display: block; padding: 0; margin: 0.2rem 0; width: 100%; list-style: none`;
const NavItemLink = styled(Link) `display: block; padding: 0.5rem 1.8rem 0.5rem 1.2rem; width: 100%; color: ${p => p.theme.colors.text}; font-weight: 600; text-decoration: none; transition: color ${p => p.theme.transition}; &:hover, &:focus, &.is-active {color: ${p => p.theme.colors.primary}}`;
const StyledButton = styled.button `position: absolute; top: 0; right: 0; padding: 0 0.8rem; height: 37px; background: none; border: 0; color: ${p => p.theme.colors.text}; cursor: pointer; font-size: 1rem; outline: none; transform: rotate(-90deg)`;
const NavItemChild = styled.ul `margin: 0.5rem 0 0.5rem 1.2rem; padding: 0; border-left: 1px solid ${p => p.theme.colors.text}; list-style: none; & > li {margin: 0}; position: relative`;
export default React.memo(NavItem); I've got rid of the The last things left to fix in this is the animation sync of the rotation of arrow and position of the list 'jump' that's caused when the next navChild move up or down. Here's a screen-recording of my progress: |
The above code doesn't save the state when navigating in pages. I'm now giving up on this as it was the end of my skill level, unless some skilled and kind soul decides to help. |
Hello.
I've been trying to animate the opening/closing of sub-items in the navigation. I've got successful in animating the expand, but, I don't know how I should animate the collapse.
Here's what I did to animate the expand:
src\gatsby-theme-document\components\LeftSidebar\NavItem.js
, I wrapped the sub-items inside a<div>
withoverflow-y: hidden
like this:NavItemChild
(theconst
in the end of the file):src\gatsby-theme-document\styles\global.js
, I added the animation:So, yeah, this works perfectly while expanding, but, the collapsing is still instant. How can I animate that too?
Here's the demo of what I've done:
The text was updated successfully, but these errors were encountered: