diff --git a/.changeset/late-seals-report.md b/.changeset/late-seals-report.md new file mode 100644 index 00000000000..7e528c31d83 --- /dev/null +++ b/.changeset/late-seals-report.md @@ -0,0 +1,6 @@ +--- +'@arch-ui/navbar': patch +'@keystonejs/app-admin-ui': minor +--- + +Revamped sidebar design. diff --git a/packages/app-admin-ui/client/components/Nav/NavIcons.js b/packages/app-admin-ui/client/components/Nav/NavIcons.js deleted file mode 100644 index ec52ee4952e..00000000000 --- a/packages/app-admin-ui/client/components/Nav/NavIcons.js +++ /dev/null @@ -1,38 +0,0 @@ -/* global ENABLE_DEV_FEATURES */ -/** @jsx jsx */ - -import { Fragment } from 'react'; -import { jsx } from '@emotion/core'; - -import { TerminalIcon, MarkGithubIcon, SignOutIcon } from '@arch-ui/icons'; -import { NavIcon, NavGroupIcons } from '@arch-ui/navbar'; -import { A11yText } from '@arch-ui/typography'; -import { useAdminMeta } from '../../providers/AdminMeta'; - -const GITHUB_PROJECT = 'https://github.com/keystonejs/keystone'; - -export function NavIcons() { - let { graphiqlPath, signoutPath, authStrategy } = useAdminMeta(); - return ENABLE_DEV_FEATURES || authStrategy ? ( - - {authStrategy ? ( - - - Sign Out - - ) : null} - {ENABLE_DEV_FEATURES ? ( - - - - GitHub - - - - Graphiql Console - - - ) : null} - - ) : null; -} diff --git a/packages/app-admin-ui/client/components/Nav/index.js b/packages/app-admin-ui/client/components/Nav/index.js index bb5ccfe245a..0747cc72236 100644 --- a/packages/app-admin-ui/client/components/Nav/index.js +++ b/packages/app-admin-ui/client/components/Nav/index.js @@ -1,6 +1,7 @@ +/* global ENABLE_DEV_FEATURES */ /** @jsx jsx */ -import React, { useState } from 'react'; // eslint-disable-line no-unused-vars +import React, { useState, useMemo } from 'react'; // eslint-disable-line no-unused-vars import { Link, useRouteMatch } from 'react-router-dom'; import PropToggle from 'react-prop-toggle'; import { uid } from 'react-uid'; @@ -19,11 +20,10 @@ import { import { Title, Truncate } from '@arch-ui/typography'; import Tooltip from '@arch-ui/tooltip'; import { FlexGroup } from '@arch-ui/layout'; -import { PersonIcon } from '@arch-ui/icons'; +import { PersonIcon, SignOutIcon, TerminalIcon, MarkGithubIcon } from '@arch-ui/icons'; import { useAdminMeta } from '../../providers/AdminMeta'; import ResizeHandler, { KEYBOARD_SHORTCUT } from './ResizeHandler'; -import { NavIcons } from './NavIcons'; import ScrollQuery from '../ScrollQuery'; import { useQuery } from '@apollo/react-hooks'; @@ -36,30 +36,36 @@ function camelToKebab(string) { return string.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); } -const Col = styled.div({ - alignItems: 'flex-start', - display: 'flex', - flex: 1, - flexDirection: 'column', - justifyContent: 'flex-start', - overflow: 'hidden', - width: '100%', -}); -const Inner = styled(Col)({ - height: ' 100vh', -}); -const Page = styled.div({ - flex: 1, - minHeight: '100vh', - position: 'relative', -}); -const PageWrapper = styled.div({ - display: 'flex', -}); -const Relative = styled(Col)({ - height: ' 100%', - position: 'relative', -}); +const Col = styled.div` + align-items: flex-start; + display: flex; + flex: 1; + flex-direction: column; + justify-content: flex-start; + overflow: hidden; + width: 100%; +`; + +const Inner = styled(Col)` + height: 100vh; + align-items: stretch; +`; + +const Page = styled.div` + flex: 1; + min-height: 100vh; + position: relative; +`; + +const PageWrapper = styled.div` + display: flex; +`; + +const Relative = styled(Col)` + height: 100%; + position: relative; +`; + const GrabHandle = styled.div(({ isActive }) => ({ backgroundColor: alpha(colors.text, 0.06), height: isActive ? '100%' : 0, @@ -88,6 +94,7 @@ const GrabHandle = styled.div(({ isActive }) => ({ top: -gridSize, }, })); + const CollapseExpand = styled.button(({ isCollapsed, mouseIsOverNav }) => { const size = 32; const offsetTop = 20; @@ -293,9 +300,8 @@ function PrimaryNavItems({ } const UserInfoContainer = styled.div` - align-self: stretch; - padding: ${PRIMARY_NAV_GUTTER}px 0; - margin: 0 ${PRIMARY_NAV_GUTTER}px; + padding-bottom: ${PRIMARY_NAV_GUTTER}px; + margin: ${PRIMARY_NAV_GUTTER}px; border-bottom: 2px solid ${colors.N10}; display: flex; align-items: center; @@ -358,6 +364,65 @@ const UserInfo = ({ authListKey, authListPath }) => { ); }; +const GITHUB_PROJECT = 'https://github.com/keystonejs/keystone'; + +const ActionItems = ({ mouseIsOverNav }) => { + const { signoutPath, graphiqlPath, authStrategy } = useAdminMeta(); + + const entries = useMemo( + () => [ + ...(authStrategy + ? [ + { + label: 'Sign out', + to: signoutPath, + icon: SignOutIcon, + }, + ] + : []), + ...(ENABLE_DEV_FEATURES + ? [ + { + label: 'GraphiQL Playground', + to: graphiqlPath, + icon: TerminalIcon, + target: '_blank', + }, + { + label: 'Keystone on GitHub', + to: GITHUB_PROJECT, + icon: MarkGithubIcon, + target: '_blank', + }, + ] + : []), + ], + [] // The admin meta never changes between server restarts + ); + + // No items to show + if (!entries.length) { + return null; + } + + return ( +
+ {entries.map(({ label, to, icon: ActionIcon, target }) => ( + + + {label} + + ))} +
+ ); +}; + const PrimaryNavContent = ({ mouseIsOverNav }) => { const { adminPath, @@ -375,15 +440,22 @@ const PrimaryNavContent = ({ mouseIsOverNav }) => { margin="both" crop css={{ + fontSize: '1.6em', color: colors.N90, textDecoration: 'none', - alignSelf: 'stretch', marginLeft: PRIMARY_NAV_GUTTER, marginRight: PRIMARY_NAV_GUTTER, }} > {name} + {authListKey && ( + + )} + { pages={pages} mouseIsOverNav={mouseIsOverNav} /> - {authListKey && ( - - )} - ); }; diff --git a/packages/arch/packages/navbar/src/PrimaryNav.js b/packages/arch/packages/navbar/src/PrimaryNav.js index 08db2428dac..02b9d42b3fe 100644 --- a/packages/arch/packages/navbar/src/PrimaryNav.js +++ b/packages/arch/packages/navbar/src/PrimaryNav.js @@ -13,6 +13,7 @@ export const NavGroupIcons = styled.div({ }); export const PrimaryNav = styled.nav({ + backgroundColor: colors.page, boxSizing: 'border-box', display: 'flex', flexDirection: 'column', @@ -20,6 +21,7 @@ export const PrimaryNav = styled.nav({ position: 'fixed', zIndex: 2, }); + export const PrimaryNavScrollArea = styled.div(({ hasScroll, isBottom, isScrollable }) => { const divider = { backgroundColor: 'rgba(9, 30, 66, 0.1)', @@ -71,7 +73,7 @@ export const PrimaryNavItem = styled(ItemElement)(({ depth, isSelected, mouseIsO display: 'block', marginBottom: 2, overflow: 'hidden', - padding: PRIMARY_NAV_GUTTER, + padding: `${gridSize * 1.5}px`, paddingLeft: depth ? PRIMARY_NAV_GUTTER * depth : PRIMARY_NAV_GUTTER, position: 'relative', textDecoration: 'none', diff --git a/test-projects/basic/cypress/integration/nav-bar_spec.js b/test-projects/basic/cypress/integration/nav-bar_spec.js index 7f88040ab67..bb909cbe35e 100644 --- a/test-projects/basic/cypress/integration/nav-bar_spec.js +++ b/test-projects/basic/cypress/integration/nav-bar_spec.js @@ -10,11 +10,11 @@ describe('Nav Bar', () => { { text: 'Posts', target: '/admin/posts' }, { text: 'Post Categories', target: '/admin/post-categories' }, { - text: 'GitHub', + text: 'Keystone on GitHub', target: 'https://github.com/keystonejs/keystone', newTab: true, }, - { text: 'Graphiql', target: '/admin/graphiql', newTab: true }, + { text: 'GraphiQL Playground', target: '/admin/graphiql', newTab: true }, ].forEach(({ text, target, newTab = false }) => { it(`${newTab ? 'Check' : 'Click'} ${text}`, () => { cy.visit('/admin');