Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a4ddf9b

Browse files
authoredJan 15, 2025··
Merge pull request #3279 from tespin/tespin/refactor-navbar-base
[Menubar] Base implementation of refactored NavBar
2 parents 9bd7c99 + de201ff commit a4ddf9b

File tree

11 files changed

+754
-647
lines changed

11 files changed

+754
-647
lines changed
 

‎client/components/Menubar/Menubar.jsx

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import PropTypes from 'prop-types';
2+
import React, { useCallback, useMemo, useRef, useState } from 'react';
3+
import useModalClose from '../../common/useModalClose';
4+
import { MenuOpenContext, MenubarContext } from './contexts';
5+
6+
function Menubar({ children, className }) {
7+
const [menuOpen, setMenuOpen] = useState('none');
8+
9+
const timerRef = useRef(null);
10+
11+
const handleClose = useCallback(() => {
12+
setMenuOpen('none');
13+
}, [setMenuOpen]);
14+
15+
const nodeRef = useModalClose(handleClose);
16+
17+
const clearHideTimeout = useCallback(() => {
18+
if (timerRef.current) {
19+
clearTimeout(timerRef.current);
20+
timerRef.current = null;
21+
}
22+
}, [timerRef]);
23+
24+
const handleBlur = useCallback(() => {
25+
timerRef.current = setTimeout(() => setMenuOpen('none'), 10);
26+
}, [timerRef, setMenuOpen]);
27+
28+
const toggleMenuOpen = useCallback(
29+
(menu) => {
30+
setMenuOpen((prevState) => (prevState === menu ? 'none' : menu));
31+
},
32+
[setMenuOpen]
33+
);
34+
35+
const contextValue = useMemo(
36+
() => ({
37+
createMenuHandlers: (menu) => ({
38+
onMouseOver: () => {
39+
setMenuOpen((prevState) => (prevState === 'none' ? 'none' : menu));
40+
},
41+
onClick: () => {
42+
toggleMenuOpen(menu);
43+
},
44+
onBlur: handleBlur,
45+
onFocus: clearHideTimeout
46+
}),
47+
createMenuItemHandlers: (menu) => ({
48+
onMouseUp: (e) => {
49+
if (e.button === 2) {
50+
return;
51+
}
52+
setMenuOpen('none');
53+
},
54+
onBlur: handleBlur,
55+
onFocus: () => {
56+
clearHideTimeout();
57+
setMenuOpen(menu);
58+
}
59+
}),
60+
toggleMenuOpen
61+
}),
62+
[setMenuOpen, toggleMenuOpen, clearHideTimeout, handleBlur]
63+
);
64+
65+
return (
66+
<MenubarContext.Provider value={contextValue}>
67+
<div className={className} ref={nodeRef}>
68+
<MenuOpenContext.Provider value={menuOpen}>
69+
{children}
70+
</MenuOpenContext.Provider>
71+
</div>
72+
</MenubarContext.Provider>
73+
);
74+
}
75+
76+
Menubar.propTypes = {
77+
children: PropTypes.node,
78+
className: PropTypes.string
79+
};
80+
81+
Menubar.defaultProps = {
82+
children: null,
83+
className: 'nav'
84+
};
85+
86+
export default Menubar;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import PropTypes from 'prop-types';
2+
import React, { useContext, useMemo } from 'react';
3+
import ButtonOrLink from '../../common/ButtonOrLink';
4+
import { MenubarContext, ParentMenuContext } from './contexts';
5+
6+
function MenubarItem({
7+
hideIf,
8+
className,
9+
role: customRole,
10+
selected,
11+
...rest
12+
}) {
13+
const parent = useContext(ParentMenuContext);
14+
15+
const { createMenuItemHandlers } = useContext(MenubarContext);
16+
17+
const handlers = useMemo(() => createMenuItemHandlers(parent), [
18+
createMenuItemHandlers,
19+
parent
20+
]);
21+
22+
if (hideIf) {
23+
return null;
24+
}
25+
26+
const role = customRole || 'menuitem';
27+
const ariaSelected = role === 'option' ? { 'aria-selected': selected } : {};
28+
29+
return (
30+
<li className={className}>
31+
<ButtonOrLink {...rest} {...handlers} {...ariaSelected} role={role} />
32+
</li>
33+
);
34+
}
35+
36+
MenubarItem.propTypes = {
37+
...ButtonOrLink.propTypes,
38+
onClick: PropTypes.func,
39+
value: PropTypes.string,
40+
/**
41+
* Provides a way to deal with optional items.
42+
*/
43+
hideIf: PropTypes.bool,
44+
className: PropTypes.string,
45+
role: PropTypes.oneOf(['menuitem', 'option']),
46+
selected: PropTypes.bool
47+
};
48+
49+
MenubarItem.defaultProps = {
50+
onClick: null,
51+
value: null,
52+
hideIf: false,
53+
className: 'nav__dropdown-item',
54+
role: 'menuitem',
55+
selected: false
56+
};
57+
58+
export default MenubarItem;
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// https://blog.logrocket.com/building-accessible-menubar-component-react
2+
3+
import classNames from 'classnames';
4+
import PropTypes from 'prop-types';
5+
import React, { useContext, useMemo } from 'react';
6+
import TriangleIcon from '../../images/down-filled-triangle.svg';
7+
import { MenuOpenContext, MenubarContext, ParentMenuContext } from './contexts';
8+
9+
export function useMenuProps(id) {
10+
const activeMenu = useContext(MenuOpenContext);
11+
12+
const isOpen = id === activeMenu;
13+
14+
const { createMenuHandlers } = useContext(MenubarContext);
15+
16+
const handlers = useMemo(() => createMenuHandlers(id), [
17+
createMenuHandlers,
18+
id
19+
]);
20+
21+
return { isOpen, handlers };
22+
}
23+
24+
/* -------------------------------------------------------------------------------------------------
25+
* MenubarTrigger
26+
* -----------------------------------------------------------------------------------------------*/
27+
28+
function MenubarTrigger({ id, title, role, hasPopup, ...props }) {
29+
const { isOpen, handlers } = useMenuProps(id);
30+
31+
return (
32+
<button
33+
{...handlers}
34+
{...props}
35+
role={role}
36+
aria-haspopup={hasPopup}
37+
aria-expanded={isOpen}
38+
>
39+
<span className="nav__item-header">{title}</span>
40+
<TriangleIcon
41+
className="nav__item-header-triangle"
42+
focusable="false"
43+
aria-hidden="true"
44+
/>
45+
</button>
46+
);
47+
}
48+
49+
MenubarTrigger.propTypes = {
50+
id: PropTypes.string.isRequired,
51+
title: PropTypes.node.isRequired,
52+
role: PropTypes.string,
53+
hasPopup: PropTypes.oneOf(['menu', 'listbox', 'true'])
54+
};
55+
56+
MenubarTrigger.defaultProps = {
57+
role: 'menuitem',
58+
hasPopup: 'menu'
59+
};
60+
61+
/* -------------------------------------------------------------------------------------------------
62+
* MenubarList
63+
* -----------------------------------------------------------------------------------------------*/
64+
65+
function MenubarList({ id, children, role, ...props }) {
66+
return (
67+
<ul className="nav__dropdown" role={role} {...props}>
68+
<ParentMenuContext.Provider value={id}>
69+
{children}
70+
</ParentMenuContext.Provider>
71+
</ul>
72+
);
73+
}
74+
75+
MenubarList.propTypes = {
76+
id: PropTypes.string.isRequired,
77+
children: PropTypes.node,
78+
role: PropTypes.oneOf(['menu', 'listbox'])
79+
};
80+
81+
MenubarList.defaultProps = {
82+
children: null,
83+
role: 'menu'
84+
};
85+
86+
/* -------------------------------------------------------------------------------------------------
87+
* MenubarSubmenu
88+
* -----------------------------------------------------------------------------------------------*/
89+
90+
function MenubarSubmenu({
91+
id,
92+
title,
93+
children,
94+
triggerRole: customTriggerRole,
95+
listRole: customListRole,
96+
...props
97+
}) {
98+
const { isOpen } = useMenuProps(id);
99+
100+
const triggerRole = customTriggerRole || 'menuitem';
101+
const listRole = customListRole || 'menu';
102+
103+
const hasPopup = listRole === 'listbox' ? 'listbox' : 'menu';
104+
105+
return (
106+
<li className={classNames('nav__item', isOpen && 'nav__item--open')}>
107+
<MenubarTrigger
108+
id={id}
109+
title={title}
110+
role={triggerRole}
111+
hasPopup={hasPopup}
112+
{...props}
113+
/>
114+
<MenubarList id={id} role={listRole}>
115+
{children}
116+
</MenubarList>
117+
</li>
118+
);
119+
}
120+
121+
MenubarSubmenu.propTypes = {
122+
id: PropTypes.string.isRequired,
123+
title: PropTypes.node.isRequired,
124+
children: PropTypes.node,
125+
triggerRole: PropTypes.string,
126+
listRole: PropTypes.string
127+
};
128+
129+
MenubarSubmenu.defaultProps = {
130+
children: null,
131+
triggerRole: 'menuitem',
132+
listRole: 'menu'
133+
};
134+
135+
export default MenubarSubmenu;

‎client/components/Nav/contexts.jsx renamed to ‎client/components/Menubar/contexts.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ export const ParentMenuContext = createContext('none');
44

55
export const MenuOpenContext = createContext('none');
66

7-
export const NavBarContext = createContext({
8-
createDropdownHandlers: () => ({}),
7+
export const MenubarContext = createContext({
8+
createMenuHandlers: () => ({}),
99
createMenuItemHandlers: () => ({}),
10-
toggleDropdownOpen: () => {}
10+
toggleMenuOpen: () => {}
1111
});

‎client/components/Nav/NavBar.jsx

Lines changed: 0 additions & 92 deletions
This file was deleted.

‎client/components/Nav/NavDropdownMenu.jsx

Lines changed: 0 additions & 59 deletions
This file was deleted.

‎client/components/Nav/NavMenuItem.jsx

Lines changed: 0 additions & 45 deletions
This file was deleted.

‎client/modules/IDE/components/Header/MobileNav.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { useTranslation } from 'react-i18next';
55
import { Link } from 'react-router-dom';
66
import { sortBy } from 'lodash';
77
import classNames from 'classnames';
8-
import { ParentMenuContext } from '../../../../components/Nav/contexts';
9-
import NavBar from '../../../../components/Nav/NavBar';
10-
import { useMenuProps } from '../../../../components/Nav/NavDropdownMenu';
11-
import NavMenuItem from '../../../../components/Nav/NavMenuItem';
8+
import { ParentMenuContext } from '../../../../components/Menubar/contexts';
9+
import Menubar from '../../../../components/Menubar/Menubar';
10+
import { useMenuProps } from '../../../../components/Menubar/MenubarSubmenu';
11+
import NavMenuItem from '../../../../components/Menubar/MenubarItem';
1212
import { prop, remSize } from '../../../../theme';
1313
import AsteriskIcon from '../../../../images/p5-asterisk.svg';
1414
import IconButton from '../../../../common/IconButton';
@@ -36,7 +36,7 @@ import Overlay from '../../../App/components/Overlay';
3636
import ProjectName from './ProjectName';
3737
import CollectionCreate from '../../../User/components/CollectionCreate';
3838

39-
const Nav = styled(NavBar)`
39+
const Nav = styled(Menubar)`
4040
background: ${prop('MobilePanel.default.background')};
4141
color: ${prop('primaryTextColor')};
4242
padding: ${remSize(8)} 0;

‎client/modules/IDE/components/Header/Nav.jsx

Lines changed: 87 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { sortBy } from 'lodash';
44
import { Link } from 'react-router-dom';
55
import PropTypes from 'prop-types';
66
import { useTranslation } from 'react-i18next';
7-
import NavDropdownMenu from '../../../../components/Nav/NavDropdownMenu';
8-
import NavMenuItem from '../../../../components/Nav/NavMenuItem';
7+
import MenubarSubmenu from '../../../../components/Menubar/MenubarSubmenu';
8+
import MenubarItem from '../../../../components/Menubar/MenubarItem';
99
import { availableLanguages, languageKeyToLabel } from '../../../../i18n';
1010
import getConfig from '../../../../utils/getConfig';
1111
import { showToast } from '../../actions/toast';
1212
import { setLanguage } from '../../actions/preferences';
13-
import NavBar from '../../../../components/Nav/NavBar';
13+
import Menubar from '../../../../components/Menubar/Menubar';
1414
import CaretLeftIcon from '../../../../images/left-arrow.svg';
1515
import LogoIcon from '../../../../images/p5js-logo-small.svg';
1616
import { selectRootFile } from '../../selectors/files';
@@ -37,10 +37,14 @@ const Nav = ({ layout }) => {
3737
return isMobile ? (
3838
<MobileNav />
3939
) : (
40-
<NavBar>
41-
<LeftLayout layout={layout} />
42-
<UserMenu />
43-
</NavBar>
40+
<>
41+
<header className="nav__header">
42+
<Menubar>
43+
<LeftLayout layout={layout} />
44+
<UserMenu />
45+
</Menubar>
46+
</header>
47+
</>
4448
);
4549
};
4650

@@ -159,36 +163,36 @@ const ProjectMenu = () => {
159163
</a>
160164
)}
161165
</li>
162-
<NavDropdownMenu id="file" title={t('Nav.File.Title')}>
163-
<NavMenuItem onClick={newSketch}>{t('Nav.File.New')}</NavMenuItem>
164-
<NavMenuItem
166+
<MenubarSubmenu id="file" title={t('Nav.File.Title')}>
167+
<MenubarItem onClick={newSketch}>{t('Nav.File.New')}</MenubarItem>
168+
<MenubarItem
165169
hideIf={
166170
!getConfig('LOGIN_ENABLED') || (project?.owner && !isUserOwner)
167171
}
168172
onClick={() => saveSketch(cmRef.current)}
169173
>
170174
{t('Common.Save')}
171175
<span className="nav__keyboard-shortcut">{metaKeyName}+S</span>
172-
</NavMenuItem>
173-
<NavMenuItem
176+
</MenubarItem>
177+
<MenubarItem
174178
hideIf={isUnsaved || !user.authenticated}
175179
onClick={() => dispatch(cloneProject())}
176180
>
177181
{t('Nav.File.Duplicate')}
178-
</NavMenuItem>
179-
<NavMenuItem hideIf={isUnsaved} onClick={shareSketch}>
182+
</MenubarItem>
183+
<MenubarItem hideIf={isUnsaved} onClick={shareSketch}>
180184
{t('Nav.File.Share')}
181-
</NavMenuItem>
182-
<NavMenuItem hideIf={isUnsaved} onClick={downloadSketch}>
185+
</MenubarItem>
186+
<MenubarItem hideIf={isUnsaved} onClick={downloadSketch}>
183187
{t('Nav.File.Download')}
184-
</NavMenuItem>
185-
<NavMenuItem
188+
</MenubarItem>
189+
<MenubarItem
186190
hideIf={!user.authenticated}
187191
href={`/${user.username}/sketches`}
188192
>
189193
{t('Nav.File.Open')}
190-
</NavMenuItem>
191-
<NavMenuItem
194+
</MenubarItem>
195+
<MenubarItem
192196
hideIf={
193197
!getConfig('UI_COLLECTIONS_ENABLED') ||
194198
!user.authenticated ||
@@ -197,56 +201,57 @@ const ProjectMenu = () => {
197201
href={`/${user.username}/sketches/${project?.id}/add-to-collection`}
198202
>
199203
{t('Nav.File.AddToCollection')}
200-
</NavMenuItem>
201-
<NavMenuItem
204+
</MenubarItem>
205+
<MenubarItem
202206
hideIf={!getConfig('EXAMPLES_ENABLED')}
203207
href="/p5/sketches"
204208
>
205209
{t('Nav.File.Examples')}
206-
</NavMenuItem>
207-
</NavDropdownMenu>
208-
<NavDropdownMenu id="edit" title={t('Nav.Edit.Title')}>
209-
<NavMenuItem onClick={cmRef.current?.tidyCode}>
210+
</MenubarItem>
211+
</MenubarSubmenu>
212+
<MenubarSubmenu id="edit" title={t('Nav.Edit.Title')}>
213+
<MenubarItem onClick={cmRef.current?.tidyCode}>
210214
{t('Nav.Edit.TidyCode')}
211215
<span className="nav__keyboard-shortcut">{metaKeyName}+Shift+F</span>
212-
</NavMenuItem>
213-
<NavMenuItem onClick={cmRef.current?.showFind}>
216+
</MenubarItem>
217+
<MenubarItem onClick={cmRef.current?.showFind}>
214218
{t('Nav.Edit.Find')}
215219
<span className="nav__keyboard-shortcut">{metaKeyName}+F</span>
216-
</NavMenuItem>
217-
<NavMenuItem onClick={cmRef.current?.showReplace}>
220+
</MenubarItem>
221+
<MenubarItem onClick={cmRef.current?.showReplace}>
218222
{t('Nav.Edit.Replace')}
219223
<span className="nav__keyboard-shortcut">{replaceCommand}</span>
220-
</NavMenuItem>
221-
</NavDropdownMenu>
222-
<NavDropdownMenu id="sketch" title={t('Nav.Sketch.Title')}>
223-
<NavMenuItem onClick={() => dispatch(newFile(rootFile.id))}>
224+
</MenubarItem>
225+
</MenubarSubmenu>
226+
<MenubarSubmenu id="sketch" title={t('Nav.Sketch.Title')}>
227+
<MenubarItem onClick={() => dispatch(newFile(rootFile.id))}>
224228
{t('Nav.Sketch.AddFile')}
225229
<span className="nav__keyboard-shortcut">{newFileCommand}</span>
226-
</NavMenuItem>
227-
<NavMenuItem onClick={() => dispatch(newFolder(rootFile.id))}>
230+
</MenubarItem>
231+
<MenubarItem onClick={() => dispatch(newFolder(rootFile.id))}>
228232
{t('Nav.Sketch.AddFolder')}
229-
</NavMenuItem>
230-
<NavMenuItem onClick={() => dispatch(startSketch())}>
233+
</MenubarItem>
234+
<MenubarItem onClick={() => dispatch(startSketch())}>
231235
{t('Nav.Sketch.Run')}
232236
<span className="nav__keyboard-shortcut">{metaKeyName}+Enter</span>
233-
</NavMenuItem>
234-
<NavMenuItem onClick={() => dispatch(stopSketch())}>
237+
</MenubarItem>
238+
<MenubarItem onClick={() => dispatch(stopSketch())}>
235239
{t('Nav.Sketch.Stop')}
236240
<span className="nav__keyboard-shortcut">
237241
Shift+{metaKeyName}+Enter
238242
</span>
239-
</NavMenuItem>
240-
</NavDropdownMenu>
241-
<NavDropdownMenu id="help" title={t('Nav.Help.Title')}>
242-
<NavMenuItem onClick={() => dispatch(showKeyboardShortcutModal())}>
243+
</MenubarItem>
244+
</MenubarSubmenu>
245+
<MenubarSubmenu id="help" title={t('Nav.Help.Title')}>
246+
<MenubarItem onClick={() => dispatch(showKeyboardShortcutModal())}>
243247
{t('Nav.Help.KeyboardShortcuts')}
244-
</NavMenuItem>
245-
<NavMenuItem href="https://p5js.org/reference/">
248+
</MenubarItem>
249+
<MenubarItem href="https://p5js.org/reference/">
246250
{t('Nav.Help.Reference')}
247-
</NavMenuItem>
248-
<NavMenuItem href="/about">{t('Nav.Help.About')}</NavMenuItem>
249-
</NavDropdownMenu>
251+
</MenubarItem>
252+
<MenubarItem href="/about">{t('Nav.Help.About')}</MenubarItem>
253+
</MenubarSubmenu>
254+
{getConfig('TRANSLATIONS_ENABLED') && <LanguageMenu />}
250255
</ul>
251256
);
252257
};
@@ -261,32 +266,44 @@ const LanguageMenu = () => {
261266
}
262267

263268
return (
264-
<NavDropdownMenu id="lang" title={languageKeyToLabel(language)}>
269+
<MenubarSubmenu
270+
id="lang"
271+
title={languageKeyToLabel(language)}
272+
triggerRole="button"
273+
listRole="listbox"
274+
>
265275
{sortBy(availableLanguages).map((key) => (
266276
// eslint-disable-next-line react/jsx-no-bind
267-
<NavMenuItem key={key} value={key} onClick={handleLangSelection}>
277+
<MenubarItem
278+
key={key}
279+
value={key}
280+
onClick={handleLangSelection}
281+
role="option"
282+
selected={key === language}
283+
>
268284
{languageKeyToLabel(key)}
269-
</NavMenuItem>
285+
</MenubarItem>
270286
))}
271-
</NavDropdownMenu>
287+
</MenubarSubmenu>
272288
);
273289
};
274290

275291
const UnauthenticatedUserMenu = () => {
276292
const { t } = useTranslation();
277293
return (
278-
<ul className="nav__items-right" title="user-menu" role="navigation">
279-
{getConfig('TRANSLATIONS_ENABLED') && <LanguageMenu />}
294+
<ul className="nav__items-right" title="user-menu">
280295
<li className="nav__item">
281-
<Link to="/login" className="nav__auth-button" role="menuitem">
296+
<Link to="/login" className="nav__auth-button">
282297
<span className="nav__item-header" title="Login">
283298
{t('Nav.Login')}
284299
</span>
285300
</Link>
286301
</li>
287-
<li className="nav__item-or">{t('Nav.LoginOr')}</li>
302+
<li className="nav__item-or" role="presentation">
303+
{t('Nav.LoginOr')}
304+
</li>
288305
<li className="nav__item">
289-
<Link to="/signup" className="nav__auth-button" role="menuitem">
306+
<Link to="/signup" className="nav__auth-button">
290307
<span className="nav__item-header" title="SignUp">
291308
{t('Nav.SignUp')}
292309
</span>
@@ -303,33 +320,32 @@ const AuthenticatedUserMenu = () => {
303320
const dispatch = useDispatch();
304321

305322
return (
306-
<ul className="nav__items-right" title="user-menu" role="navigation">
307-
{getConfig('TRANSLATIONS_ENABLED') && <LanguageMenu />}
308-
<NavDropdownMenu
323+
<ul className="nav__items-right" title="user-menu">
324+
<MenubarSubmenu
309325
id="account"
310326
title={
311327
<span>
312328
{t('Nav.Auth.Hello')}, {username}!
313329
</span>
314330
}
315331
>
316-
<NavMenuItem href={`/${username}/sketches`}>
332+
<MenubarItem href={`/${username}/sketches`}>
317333
{t('Nav.Auth.MySketches')}
318-
</NavMenuItem>
319-
<NavMenuItem
334+
</MenubarItem>
335+
<MenubarItem
320336
href={`/${username}/collections`}
321337
hideIf={!getConfig('UI_COLLECTIONS_ENABLED')}
322338
>
323339
{t('Nav.Auth.MyCollections')}
324-
</NavMenuItem>
325-
<NavMenuItem href={`/${username}/assets`}>
340+
</MenubarItem>
341+
<MenubarItem href={`/${username}/assets`}>
326342
{t('Nav.Auth.MyAssets')}
327-
</NavMenuItem>
328-
<NavMenuItem href="/account">{t('Preferences.Settings')}</NavMenuItem>
329-
<NavMenuItem onClick={() => dispatch(logoutUser())}>
343+
</MenubarItem>
344+
<MenubarItem href="/account">{t('Preferences.Settings')}</MenubarItem>
345+
<MenubarItem onClick={() => dispatch(logoutUser())}>
330346
{t('Nav.Auth.LogOut')}
331-
</NavMenuItem>
332-
</NavDropdownMenu>
347+
</MenubarItem>
348+
</MenubarSubmenu>
333349
</ul>
334350
);
335351
};

‎client/modules/IDE/components/Header/__snapshots__/Nav.unit.test.jsx.snap

Lines changed: 366 additions & 366 deletions
Large diffs are not rendered by default.

‎client/styles/components/_nav.scss

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,34 @@
33
.nav {
44
height: #{math.div(42, $base-font-size)}rem;
55
display: flex;
6+
width: 100%;
67
flex-direction: row;
78
justify-content: space-between;
89

9-
@include themify() {
10-
border-bottom: 1px dashed map-get($theme-map, 'nav-border-color');
11-
}
12-
1310
& button {
1411
padding: 0;
1512
}
1613
}
1714

15+
.nav__header {
16+
display: flex;
17+
flex-direction: row;
18+
justify-content: space-between;
19+
align-items: center;
20+
21+
@include themify() {
22+
border-bottom: 1px dashed map-get($theme-map, 'nav-border-color');
23+
}
24+
// padding-left: #{math.div(20, $base-font-size)}rem;
25+
}
26+
1827
.nav__items-left,
1928
.nav__items-right {
2029
list-style: none;
2130
display: flex;
2231
flex-direction: row;
23-
justify-content: flex-end;
24-
height: 100%;
2532
align-items: center;
33+
height: 100%;
2634
}
2735

2836
.preview-nav__editor-svg {

0 commit comments

Comments
 (0)
Please sign in to comment.