Skip to content

Commit 6eda3b9

Browse files
committed
🔨 Switch Dashboard/Sidebar to use useOvermind
1 parent 7e4a905 commit 6eda3b9

File tree

16 files changed

+390
-357
lines changed

16 files changed

+390
-357
lines changed

‎packages/app/package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@
198198
"react-motion": "^0.5.0",
199199
"react-outside-click-handler": "^1.2.3",
200200
"react-refresh": "^0.7.2",
201-
"react-router-dom": "^5.0.1",
201+
"react-router-dom": "^5.1.2",
202202
"react-scrollbars-custom": "^4.0.20",
203203
"react-show": "^3.0.4",
204204
"react-split-pane": "^0.1.87",
@@ -265,7 +265,7 @@
265265
"@types/react-helmet": "^5.0.11",
266266
"@types/react-icons": "2.2.7",
267267
"@types/react-instantsearch": "^5.2.3",
268-
"@types/react-router-dom": "^4.3.1",
268+
"@types/react-router-dom": "^5.1.3",
269269
"@types/react-stripe-elements": "^1.3.2",
270270
"@types/resolve": "^0.0.8",
271271
"@types/semver": "6.2.0",
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { NavLink } from 'react-router-dom';
2+
import styled, { css } from 'styled-components';
3+
4+
export const Container = styled(NavLink)<{ active: boolean }>`
5+
${({ active, theme }) => css`
6+
transition: 0.3s ease all;
7+
display: flex;
8+
width: 100%;
9+
height: 2.5rem;
10+
user-select: none;
11+
12+
align-items: center;
13+
14+
padding: 0 0.5rem;
15+
box-sizing: border-box;
16+
17+
color: ${theme.placeholder};
18+
text-decoration: none;
19+
background-color: transparent;
20+
21+
cursor: pointer;
22+
position: relative;
23+
24+
&:hover {
25+
color: white;
26+
}
27+
28+
${active &&
29+
css`
30+
background-color: ${theme.secondary};
31+
color: white;
32+
`};
33+
`};
34+
`;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React, { ComponentProps, FunctionComponent } from 'react';
2+
3+
import { ContextMenu } from 'app/components/ContextMenu';
4+
5+
import { Container as ContainerBase } from './elements';
6+
7+
type ContainerBaseProps = ComponentProps<typeof ContainerBase>;
8+
type Props = {
9+
contextItems?: ComponentProps<typeof ContextMenu>['items'];
10+
} & Partial<Pick<ContainerBaseProps, 'onClick' | 'style'>> &
11+
Pick<ContainerBaseProps, 'active' | 'as' | 'exact' | 'to'>;
12+
export const Container: FunctionComponent<Props> = ({
13+
contextItems,
14+
...props
15+
}) => {
16+
if (!contextItems) {
17+
return <ContainerBase {...props} />;
18+
}
19+
20+
return (
21+
<ContextMenu items={contextItems}>
22+
<ContainerBase {...props} />
23+
</ContextMenu>
24+
);
25+
};

‎packages/app/src/app/pages/Dashboard/Sidebar/Item/elements.js‎

Lines changed: 0 additions & 52 deletions
This file was deleted.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import ChevronRight from 'react-icons/lib/md/chevron-right';
2+
import { Animate as AnimateBase } from 'react-show';
3+
import styled, { css } from 'styled-components';
4+
5+
export const Animate = styled(AnimateBase)`
6+
height: auto;
7+
overflow: hidden;
8+
`;
9+
10+
export const AnimatedChevron = styled(ChevronRight)<{ open: boolean }>`
11+
${({ open }) => css`
12+
transition: 0.25s ease transform;
13+
transform: rotate(${open ? 90 : 0}deg);
14+
margin-right: 0.25rem;
15+
width: 1rem;
16+
`};
17+
`;
18+
19+
export const ChevronPlaceholder = styled.div`
20+
width: 16px;
21+
height: 16px;
22+
margin-right: 0.25rem;
23+
`;
24+
25+
export const IconContainer = styled.div`
26+
display: flex;
27+
align-items: center;
28+
width: 2rem;
29+
font-size: 1.25rem;
30+
`;
31+
32+
export const ItemName = styled.div`
33+
font-size: 0.875rem;
34+
`;

‎packages/app/src/app/pages/Dashboard/Sidebar/Item/index.js‎

Lines changed: 0 additions & 116 deletions
This file was deleted.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import React, {
2+
ComponentProps,
3+
ComponentType,
4+
FunctionComponent,
5+
useEffect,
6+
useState,
7+
} from 'react';
8+
import { useRouteMatch } from 'react-router-dom';
9+
10+
import { Container } from './Container';
11+
import {
12+
Animate,
13+
AnimatedChevron,
14+
ChevronPlaceholder,
15+
IconContainer,
16+
ItemName,
17+
} from './elements';
18+
19+
type ContainerProps = ComponentProps<typeof Container>;
20+
type Props = {
21+
active?: boolean;
22+
Icon: ComponentType;
23+
name: string;
24+
openByDefault?: boolean;
25+
path: ContainerProps['to'];
26+
} & Omit<
27+
ComponentProps<typeof Container>,
28+
'active' | 'children' | 'exact' | 'to'
29+
>;
30+
export const Item: FunctionComponent<Props> = ({
31+
active = false,
32+
children,
33+
Icon,
34+
name,
35+
openByDefault,
36+
path,
37+
...props
38+
}) => {
39+
const match = useRouteMatch(path);
40+
const [open, setOpen] = useState(openByDefault);
41+
const isActive = match?.isExact || active;
42+
const isOpen = open || isActive;
43+
44+
useEffect(() => {
45+
if (openByDefault) {
46+
setOpen(true);
47+
}
48+
}, [openByDefault]);
49+
50+
useEffect(() => {
51+
if ((match || isActive) && open === undefined && children) {
52+
setOpen(true);
53+
}
54+
}, [children, isActive, match, open]);
55+
56+
const toggleOpen = event => {
57+
event.preventDefault();
58+
59+
setOpen(show => !show);
60+
};
61+
62+
return (
63+
<>
64+
<Container active={isActive} exact to={path} {...props}>
65+
{children ? (
66+
<AnimatedChevron onClick={toggleOpen} open={isOpen} />
67+
) : (
68+
<ChevronPlaceholder />
69+
)}
70+
71+
<IconContainer>
72+
<Icon />
73+
</IconContainer>
74+
75+
<ItemName>{name}</ItemName>
76+
</Container>
77+
78+
{children && (
79+
<Animate
80+
duration={250}
81+
show={isOpen}
82+
start={{
83+
height: 0, // The starting style for the component.
84+
// If the 'leave' prop isn't defined, 'start' is reused!
85+
}}
86+
stayMounted={false}
87+
transitionOnMount
88+
>
89+
{children}
90+
</Animate>
91+
)}
92+
</>
93+
);
94+
};

0 commit comments

Comments
 (0)