Browse Source

feat(dashboard): Redesign Explore Menu (#11820)

Redesign explore menu with chrissys design.

Still needs some shadows work...
![image](https://user-images.githubusercontent.com/79684/52024453-ba03c300-24b5-11e9-9eb7-4b7ff21e46fe.png)
Billy Vong 6 years ago
parent
commit
ece3ff3079

+ 80 - 32
src/sentry/static/sentry/app/views/organizationDashboard/exploreWidget.jsx

@@ -1,22 +1,16 @@
 import React from 'react';
-import styled, {css} from 'react-emotion';
+import styled from 'react-emotion';
 
 import {getDiscoverUrlPathFromDiscoverQuery} from 'app/views/organizationDashboard/utils/getDiscoverUrlPathFromDiscoverQuery';
 import {getEventsUrlPathFromDiscoverQuery} from 'app/views/organizationDashboard/utils/getEventsUrlPathFromDiscoverQuery';
 import {t} from 'app/locale';
 import Button from 'app/components/button';
-import DropdownLink from 'app/components/dropdownLink';
+import DropdownMenu from 'app/components/dropdownMenu';
 import InlineSvg from 'app/components/inlineSvg';
 import SentryTypes from 'app/sentryTypes';
 import space from 'app/styles/space';
 import withOrganization from 'app/utils/withOrganization';
 
-const exploreMenuCss = css`
-  font-weight: normal;
-  text-transform: none;
-  white-space: nowrap;
-`;
-
 class ExploreWidget extends React.Component {
   static propTypes = {
     widget: SentryTypes.Widget,
@@ -47,42 +41,96 @@ class ExploreWidget extends React.Component {
     const discoverQueries = widget.queries.discover;
 
     return (
-      <DropdownLink
-        anchorRight={true}
-        title={t('Explore')}
-        topLevelClasses={exploreMenuCss}
-      >
-        {discoverQueries.map(query => (
-          <ExploreRow key={query.name}>
-            <QueryName>{query.name}</QueryName>
-
-            <ExploreActions>
-              <Button borderless size="zero" to={this.getExportToDiscover(query)}>
-                <InlineSvg src="icon-discover" />
-              </Button>
-              <Button borderless size="zero" to={this.getExportToEvents(query)}>
-                <InlineSvg src="icon-stack" />
-              </Button>
-            </ExploreActions>
-          </ExploreRow>
-        ))}
-      </DropdownLink>
+      <DropdownMenu>
+        {({isOpen, getRootProps, getActorProps, getMenuProps}) => {
+          return (
+            <ExploreRoot {...getRootProps()}>
+              <div {...getActorProps()}>
+                <ExploreButton isOpen={isOpen}>
+                  {t('Explore Data')}
+                  <Chevron isOpen={isOpen} src="icon-chevron-right" />
+                </ExploreButton>
+              </div>
+              <ExploreMenu {...getMenuProps({isStyled: true, isOpen})}>
+                {discoverQueries.map(query => (
+                  <ExploreRow key={query.name}>
+                    <QueryName>{query.name}</QueryName>
+
+                    <ExploreAction to={this.getExportToDiscover(query)}>
+                      <InlineSvg src="icon-discover" />
+                    </ExploreAction>
+                    <ExploreAction to={this.getExportToEvents(query)}>
+                      <InlineSvg src="icon-stack" />
+                    </ExploreAction>
+                  </ExploreRow>
+                ))}
+              </ExploreMenu>
+            </ExploreRoot>
+          );
+        }}
+      </DropdownMenu>
     );
   }
 }
 export default withOrganization(ExploreWidget);
 
+const ExploreRoot = styled('div')`
+  border-left: 1px solid ${p => p.theme.borderLight};
+  position: relative;
+`;
+
+const UnstyledButton = props => <Button borderless size="zero" {...props} />;
+
+const ExploreButton = styled(({isOpen, ...props}) => <UnstyledButton {...props} />)`
+  position: relative;
+  color: ${p => (p.isOpen ? p.theme.purple : p.theme.gray2)};
+  padding: ${space(1)} ${space(2)};
+  border-radius: 0 0 ${p => p.theme.borderRadius} 0;
+  ${p => p.isOpen && `z-index: ${p.theme.zIndex.dropdownAutocomplete.actor}`};
+  ${p => p.isOpen && `box-shadow: ${p.theme.dropShadowHeavy}`};
+  &:hover {
+    color: ${p => p.theme.purple};
+  }
+  transition: box-shadow 0.25s;
+`;
+
+const ExploreMenu = styled('div')`
+  display: ${p => (p.isOpen ? 'flex' : 'none')};
+  flex-direction: column;
+
+  position: absolute;
+  right: -1px;
+  bottom: calc(100% - 1px);
+  z-index: ${p => p.theme.zIndex.dropdownAutocomplete.menu};
+
+  background-color: white;
+  border: 1px solid ${p => p.theme.borderLight};
+  box-shadow: ${p => p.theme.dropShadowHeavy};
+`;
+
 const ExploreRow = styled('li')`
   display: flex;
-  justify-content: space-between;
   align-items: center;
   padding: 0 ${space(0.5)};
 `;
 
-const ExploreActions = styled('div')`
-  display: flex;
+const ExploreAction = styled(UnstyledButton)`
+  padding: ${space(1)};
+  color: ${p => p.theme.purple};
+  &:hover {
+    color: ${p => p.theme.purpleDark};
+  }
 `;
 
 const QueryName = styled('span')`
-  margin-right: ${space(1)};
+  flex-grow: 1;
+  white-space: nowrap;
+  font-size: 0.9em;
+  margin: ${space(1)};
+  margin-right: ${space(2)};
+`;
+
+const Chevron = styled(InlineSvg)`
+  ${p => (p.isOpen ? `transform: rotate(-90deg);` : '')};
+  transition: transform 0.25s;
 `;

+ 10 - 4
src/sentry/static/sentry/app/views/organizationDashboard/widget.jsx

@@ -58,13 +58,14 @@ class Widget extends React.Component {
               <WidgetWrapperForMask>
                 {reloading && <ReloadingMask />}
                 <StyledPanel>
-                  <WidgetHeader>
-                    {title}
-                    <ExploreWidget {...{widget, queries, router, selection}} />
-                  </WidgetHeader>
+                  <WidgetHeader>{title}</WidgetHeader>
                   <StyledPanelBody>
                     <WidgetChart {...widgetChartProps} />
                   </StyledPanelBody>
+                  <WidgetFooter>
+                    <div />
+                    <ExploreWidget {...{widget, queries, router, selection}} />
+                  </WidgetFooter>
                 </StyledPanel>
               </WidgetWrapperForMask>
             );
@@ -108,6 +109,7 @@ const ErrorCard = styled(Placeholder)`
   border: 1px solid ${p => p.theme.alert.error.border};
   color: ${p => p.theme.alert.error.textLight};
   border-radius: ${p => p.theme.borderRadius};
+  margin-bottom: ${space(2)};
 `;
 
 const WidgetHeader = styled('div')`
@@ -116,3 +118,7 @@ const WidgetHeader = styled('div')`
   align-items: center;
   padding: ${space(1)} ${space(2)};
 `;
+const WidgetFooter = styled(WidgetHeader)`
+  border-top: 1px solid ${p => p.theme.borderLight};
+  padding: 0;
+`;