+ {topContent}
{sections.map(({
name,
icon,
@@ -84,7 +140,7 @@ const Sidebar = ({
return (
- {active ? _subMenu(subsections) : null}
+ {!collapsed && active ? _subMenu(subsections) : null}
);
})}
@@ -101,16 +157,39 @@ const Sidebar = ({
)
}
- return
-
- {sidebarContent}
-
-
Open Source Hub
-
GitHub
-
Docs
-
+ return (
+
setCollapsed(false)
+ : undefined
+ }
+ onMouseLeave={
+ !collapsed && !fixed
+ ? (e => {
+ if (!isInsidePopover(e.relatedTarget)) {
+ setAppsMenuOpen(false);
+ setCollapsed(true);
+ }
+ })
+ : undefined
+ }
+ >
+
+ {sidebarContent}
+
-
+ );
}
Sidebar.contextTypes = {
diff --git a/src/components/Sidebar/Sidebar.scss b/src/components/Sidebar/Sidebar.scss
index 5ca30c99a0..65e9bfe414 100644
--- a/src/components/Sidebar/Sidebar.scss
+++ b/src/components/Sidebar/Sidebar.scss
@@ -20,38 +20,18 @@ $footerHeight: 36px;
bottom: 0;
background: #0c5582;
color: #fff;
- transition: left 0.5s ease-in;
-}
-
-.toggle {
- position: fixed;
- border-radius: 5px;
- width: 28px;
- height: 28px;
- top: 10px;
- left: 310px;
- opacity: 0;
- transition: left 0.5s ease-in, opacity 0.5s 0.5s ease-in;
-}
+ z-index: 100;
-@media (max-width: 980px) {
- .sidebar {
+ &.collapsed {
left: 0;
- }
-
- .toggle {
- left: 310px;
- top: 10px;
- opacity: 1;
- }
+ width: 54px;
- body:global(.expanded) {
- .sidebar {
- left: -300px;
+ .section_header > svg {
+ margin: 0;
}
- .toggle {
- left: 10px;
+ .pinContainer > svg {
+ fill: white;
}
}
}
@@ -128,10 +108,10 @@ $footerHeight: 36px;
font-size: 18px;
font-weight: 700;
line-height: 30px;
- cursor: pointer;
}
.menuRow {
+ cursor: pointer;
border-bottom: 1px solid #0c5582;
> *:first-child {
@@ -149,31 +129,40 @@ $footerHeight: 36px;
.currentApp {
position: relative;
- overflow: hidden;
- text-overflow: ellipsis;
- padding-right: 40px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .appNameContainer {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+
+ .currentAppName {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 215px;
+ }
- &:hover{
+ &:after {
+ @include arrow('down', 10px, 7px, #132B39);
+ content: '';
+ margin-left: 10px;
+ }
+
+ &:hover {
&:after {
border-top-color: white;
}
- }
-
- &:after {
- @include arrow('down', 10px, 7px, #132B39);
- position: absolute;
- content: '';
- top: 20px;
- right: 15px;
+ }
}
}
-.appsMenu .currentApp:after {
- @include arrow('up', 10px, 7px, #ffffff);
- position: absolute;
- content: '';
- top: 20px;
- right: 15px;
+.sidebarPin {
+ cursor: pointer;
+ height: 30px;
+ width: 30px;
+ padding: 6px;
}
.appsMenu {
@@ -185,6 +174,20 @@ $footerHeight: 36px;
background: #0c5582;
}
+ .currentApp {
+ .currentAppName {
+ &:after {
+ @include arrow('up', 10px, 7px, #132B39);
+ }
+
+ &:hover {
+ &:after {
+ border-bottom-color: white;
+ }
+ }
+ }
+ }
+
.appListContainer {
overflow-y: auto;
height: calc(100vh - #{$headerHeight} - #{$menuSectionHeight} - #{$sidebarMenuItemHeight} - #{$footerHeight});
@@ -392,3 +395,23 @@ a.subitem {
}
}
}
+
+.pinContainer {
+ height: 48px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: #094162;
+
+ svg {
+ cursor: pointer;
+ height: 40px;
+ width: 40px;
+ padding: 10px 10px 10px 10px;
+ fill: #132B39;
+
+ &:hover {
+ fill: white;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/components/Sidebar/SidebarHeader.react.js b/src/components/Sidebar/SidebarHeader.react.js
index 67de9c4cad..bab045fe4f 100644
--- a/src/components/Sidebar/SidebarHeader.react.js
+++ b/src/components/Sidebar/SidebarHeader.react.js
@@ -24,21 +24,33 @@ export default class SidebarHeader extends React.Component {
});
}
render() {
- return (
-
-
+ const { isCollapsed = false } = this.props;
+ const headerContent = isCollapsed
+ ? (
+
-
-
-
-
- Parse Dashboard {version}
+
+ )
+ : (
+ <>
+
+
+
+
+
- {this.state.dashboardUser}
+ Parse Dashboard {version}
+
+ {this.state.dashboardUser}
+
-
-
+
+ >
+ )
+ return (
+
+ {headerContent}
);
}
diff --git a/src/components/Sidebar/SidebarSection.react.js b/src/components/Sidebar/SidebarSection.react.js
index a8ff39f833..fb86c00c60 100644
--- a/src/components/Sidebar/SidebarSection.react.js
+++ b/src/components/Sidebar/SidebarSection.react.js
@@ -10,7 +10,7 @@ import { Link } from 'react-router-dom';
import React from 'react';
import styles from 'components/Sidebar/Sidebar.scss';
-let SidebarSection = ({ active, children, name, link, icon, style, primaryBackgroundColor, secondaryBackgroundColor }) => {
+let SidebarSection = ({ active, children, name, link, icon, style, primaryBackgroundColor, secondaryBackgroundColor, isCollapsed }) => {
let classes = [styles.section];
if (active) {
classes.push(styles.active);
@@ -19,6 +19,16 @@ let SidebarSection = ({ active, children, name, link, icon, style, primaryBackgr
if (icon) {
iconContent =
;
}
+ if (isCollapsed) {
+ classes.push(styles.collapsed);
+ return (
+
+ );
+ }
return (
{active ?
diff --git a/src/components/Sidebar/SidebarToggle.react.js b/src/components/Sidebar/SidebarToggle.react.js
deleted file mode 100644
index d1fb02660b..0000000000
--- a/src/components/Sidebar/SidebarToggle.react.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2016-present, Parse, LLC
- * All rights reserved.
- *
- * This source code is licensed under the license found in the LICENSE file in
- * the root directory of this source tree.
- */
-import React from 'react';
-import styles from 'components/Sidebar/Sidebar.scss';
-import Icon from 'components/Icon/Icon.react';
-
-function toggleSidebarExpansion() {
- if (document.body.className.indexOf(' expanded') > -1) {
- document.body.className = document.body.className.replace(' expanded', '');
- } else {
- document.body.className += ' expanded';
- }
-}
-
-let SidebarToggle = () =>
;
-
-export default SidebarToggle;
diff --git a/src/components/Toolbar/Toolbar.scss b/src/components/Toolbar/Toolbar.scss
index 7deaf77159..847333f017 100644
--- a/src/components/Toolbar/Toolbar.scss
+++ b/src/components/Toolbar/Toolbar.scss
@@ -15,13 +15,12 @@
background: #353446;
height: 96px;
color: white;
- transition: left 0.5s ease-in;
z-index: 5;
}
-@media (max-width: 980px) {
+body:global(.expanded) {
.toolbar {
- left: 0;
+ left: $sidebarCollapsedWidth;
}
}
diff --git a/src/dashboard/AccountView.react.js b/src/dashboard/AccountView.react.js
index 4c467c8e1a..1a44591f63 100644
--- a/src/dashboard/AccountView.react.js
+++ b/src/dashboard/AccountView.react.js
@@ -7,7 +7,6 @@
*/
import React from 'react';
import { buildAccountSidebar } from './SidebarBuilder';
-import SidebarToggle from 'components/Sidebar/SidebarToggle.react';
import styles from 'dashboard/Dashboard.scss';
export default class AccountView extends React.Component {
@@ -23,7 +22,6 @@ export default class AccountView extends React.Component {
{this.props.children}
{sidebar}
-
);
}
diff --git a/src/dashboard/Dashboard.scss b/src/dashboard/Dashboard.scss
index b517ad6708..140c11b2bd 100644
--- a/src/dashboard/Dashboard.scss
+++ b/src/dashboard/Dashboard.scss
@@ -5,15 +5,16 @@
* This source code is licensed under the license found in the LICENSE file in
* the root directory of this source tree.
*/
+@import 'stylesheets/globals.scss';
+
.content {
margin-left: 300px;
- transition: margin-left 0.5s ease-in;
overflow: auto;
max-height: 100vh;
}
-@media (max-width: 980px) {
+body:global(.expanded) {
.content {
- margin-left: 0;
+ margin-left: $sidebarCollapsedWidth;
}
-}
+}
\ No newline at end of file
diff --git a/src/dashboard/DashboardView.react.js b/src/dashboard/DashboardView.react.js
index 849d823a1b..c1d53a6e0e 100644
--- a/src/dashboard/DashboardView.react.js
+++ b/src/dashboard/DashboardView.react.js
@@ -9,7 +9,6 @@ import PropTypes from 'lib/PropTypes';
import ParseApp from 'lib/ParseApp';
import React from 'react';
import Sidebar from 'components/Sidebar/Sidebar.react';
-import SidebarToggle from 'components/Sidebar/SidebarToggle.react';
import styles from 'dashboard/Dashboard.scss';
export default class DashboardView extends React.Component {
@@ -255,7 +254,6 @@ export default class DashboardView extends React.Component {
{this.renderContent()}
{sidebar}
-
);
}
diff --git a/src/dashboard/Data/Browser/Browser.scss b/src/dashboard/Data/Browser/Browser.scss
index b6acada937..970c84cf60 100644
--- a/src/dashboard/Data/Browser/Browser.scss
+++ b/src/dashboard/Data/Browser/Browser.scss
@@ -15,7 +15,6 @@
bottom: 0;
overflow: auto;
padding-top: 30px;
- transition: left 0.5s ease-in;
// fix for safari scrolling issue:
// https://css-tricks.com/forums/topic/safari-for-ios-z-index-ordering-bug-while-scrolling-a-page-with-a-fixed-element/
// only applying to safari as a side effect of this is emptystate component centering is off
@@ -24,9 +23,9 @@
}
}
-@media (max-width: 980px) {
+body:global(.expanded) {
.browser {
- left: 0;
+ left: $sidebarCollapsedWidth;
}
}
diff --git a/src/dashboard/TableView.scss b/src/dashboard/TableView.scss
index fab0e39da2..5027e6a89f 100644
--- a/src/dashboard/TableView.scss
+++ b/src/dashboard/TableView.scss
@@ -14,13 +14,12 @@
right: 0;
background: #66637A;
height: 30px;
- transition: left 0.5s ease-in;
white-space: nowrap;
}
-@media (max-width: 980px) {
+body:global(.expanded) {
.headers {
- left: 0;
+ left: $sidebarCollapsedWidth;
}
}
diff --git a/src/icons/pin.svg b/src/icons/pin.svg
new file mode 100644
index 0000000000..31a74cab87
--- /dev/null
+++ b/src/icons/pin.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/lib/isInsidePopover.js b/src/lib/isInsidePopover.js
new file mode 100644
index 0000000000..a5d7457980
--- /dev/null
+++ b/src/lib/isInsidePopover.js
@@ -0,0 +1,12 @@
+export default function isInsidePopover(node) {
+ let cur = node.parentNode;
+ while (cur && cur.nodeType === 1) {
+ // If id starts with "fixed_wrapper", we consider it as the
+ // root element of the Popover component
+ if (/^fixed_wrapper/g.test(cur.id)) {
+ return true;
+ }
+ cur = cur.parentNode;
+ }
+ return false;
+}
\ No newline at end of file
diff --git a/src/stylesheets/globals.scss b/src/stylesheets/globals.scss
index 98ae89247a..e70066e8b8 100644
--- a/src/stylesheets/globals.scss
+++ b/src/stylesheets/globals.scss
@@ -51,6 +51,8 @@ $pushDetailsContent: #66637A;
$darkPurple: #8D11BA;
$blueGreen: #11A4BA;
+$sidebarCollapsedWidth: 54px;
+
@mixin NotoSansFont {
font-family: 'Noto Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}