From eb8cc044e281f69057441035e49716d13b7d230f Mon Sep 17 00:00:00 2001 From: Siarhei Iukou Date: Tue, 4 Jun 2024 08:02:03 +0300 Subject: [PATCH 1/8] EPMRPP-90965 || Sidebar structure reorganization --- .../componentLibrary/sidebar/navbar/index.js | 17 --- .../sidebar/navbar/navbar.jsx | 107 -------------- .../sidebar/navbar/navbar.scss | 82 ----------- app/src/componentLibrary/sidebar/sidebar.jsx | 134 +++++------------- app/src/componentLibrary/sidebar/sidebar.scss | 68 ++++++--- .../sidebar/sidebarButton/sidebarButton.jsx | 40 +++--- .../sidebar/sidebarButton/sidebarButton.scss | 80 ++++++++++- .../organizationsBlock/index.js | 17 --- .../organizationsBlock/organizationsBlock.jsx | 51 ------- .../organizationsBlock.scss | 43 ------ .../organizationsControl.jsx | 58 ++++---- .../organizationsControl.scss | 62 ++++++-- .../organizationsPopover.jsx | 6 +- .../projectSidebar/projectSidebar.jsx | 66 ++------- .../layouts/common/appSidebar/appSidebar.jsx | 127 +++++------------ .../layouts/common/appSidebar/appSidebar.scss | 99 +++---------- .../helpAndService/FAQcontent/FAQContent.jsx | 8 +- .../helpAndService/previewPopover.jsx | 30 ++-- .../helpAndService/previewPopover.scss | 90 +++++++++--- .../servicesContent/servicesContent.jsx | 8 +- .../appSidebar/img/open-outside-inline.svg | 3 + .../common/appSidebar/userAvatar/index.js | 17 --- .../appSidebar/userAvatar/userAvatar.jsx | 52 ------- .../appSidebar/userAvatar/userAvatar.scss | 38 ----- .../userControl/profileMenu/profileMenu.jsx | 6 +- .../appSidebar/userControl/userControl.jsx | 49 +++++-- .../appSidebar/userControl/userControl.scss | 51 ++++++- 27 files changed, 500 insertions(+), 909 deletions(-) delete mode 100644 app/src/componentLibrary/sidebar/navbar/index.js delete mode 100644 app/src/componentLibrary/sidebar/navbar/navbar.jsx delete mode 100644 app/src/componentLibrary/sidebar/navbar/navbar.scss delete mode 100644 app/src/layouts/appLayout/projectSidebar/organizationsBlock/index.js delete mode 100644 app/src/layouts/appLayout/projectSidebar/organizationsBlock/organizationsBlock.jsx delete mode 100644 app/src/layouts/appLayout/projectSidebar/organizationsBlock/organizationsBlock.scss create mode 100644 app/src/layouts/common/appSidebar/img/open-outside-inline.svg delete mode 100644 app/src/layouts/common/appSidebar/userAvatar/index.js delete mode 100644 app/src/layouts/common/appSidebar/userAvatar/userAvatar.jsx delete mode 100644 app/src/layouts/common/appSidebar/userAvatar/userAvatar.scss diff --git a/app/src/componentLibrary/sidebar/navbar/index.js b/app/src/componentLibrary/sidebar/navbar/index.js deleted file mode 100644 index 2c22c1b917..0000000000 --- a/app/src/componentLibrary/sidebar/navbar/index.js +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2024 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { Navbar } from './navbar'; diff --git a/app/src/componentLibrary/sidebar/navbar/navbar.jsx b/app/src/componentLibrary/sidebar/navbar/navbar.jsx deleted file mode 100644 index 534dc8acb4..0000000000 --- a/app/src/componentLibrary/sidebar/navbar/navbar.jsx +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2024 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import PropTypes from 'prop-types'; -import classNames from 'classnames/bind'; -import Parser from 'html-react-parser'; -import { SidebarButton } from '../sidebarButton'; -import styles from './navbar.scss'; - -const cx = classNames.bind(styles); - -export const Navbar = ({ - active, - onCloseNavbar, - logoControlIcon, - createMainControlBlock, - topSidebarControlItems, - bottomSidebarControlItems, - createFooterControlBlock, - getClassName, - setHoverType, - clearActionButton, - setActiveType, -}) => ( -
- {logoControlIcon && ( -
- {Parser(logoControlIcon)} -
- )} -
{createMainControlBlock(onCloseNavbar)}
- {topSidebarControlItems.length > 0 && ( -
- {topSidebarControlItems.map(({ sidebarBlockItem, key, onClick }) => ( - { - onClick(); - onCloseNavbar(); - }} - onMouseEnter={() => setHoverType(key)} - onMouseLeave={clearActionButton} - onMouseDown={() => setActiveType(key)} - > - {sidebarBlockItem} - - ))} -
- )} - {bottomSidebarControlItems.length > 0 && ( -
- {bottomSidebarControlItems.map(({ bottomSidebarItem, key, onClick }) => ( - { - onClick(); - onCloseNavbar(); - }} - onMouseEnter={() => setHoverType(key)} - onMouseLeave={clearActionButton} - onMouseDown={() => setActiveType(key)} - > - {bottomSidebarItem} - - ))} -
- )} -
{createFooterControlBlock(onCloseNavbar)}
-
-); - -Navbar.propTypes = { - active: PropTypes.bool, - topSidebarControlItems: PropTypes.array, - bottomSidebarControlItems: PropTypes.array, - onCloseNavbar: PropTypes.func.isRequired, - logoControlIcon: PropTypes.element, - createMainControlBlock: PropTypes.func, - createFooterControlBlock: PropTypes.func, - getClassName: PropTypes.object.isRequired, - setHoverType: PropTypes.func.isRequired, - clearActionButton: PropTypes.func.isRequired, - setActiveType: PropTypes.func.isRequired, -}; - -Navbar.defaultProps = { - active: false, - topSidebarControlItems: [], - bottomSidebarControlItems: [], - createMainControlBlock: () => {}, - createFooterControlBlock: () => {}, -}; diff --git a/app/src/componentLibrary/sidebar/navbar/navbar.scss b/app/src/componentLibrary/sidebar/navbar/navbar.scss deleted file mode 100644 index 13249a8949..0000000000 --- a/app/src/componentLibrary/sidebar/navbar/navbar.scss +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2024 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -.navbar { - position: absolute; - width: 280px; - height: calc(100% - 40px); - left: 48px; - top: 0; - z-index: 2; - padding-top: 16px; - padding-bottom: 24px; - background-color: $COLOR--darkmode-gray-450; - transform: translateX(-100%); - transition: transform 0.3s ease-out; - transition-delay: 0.5s; - display: flex; - flex-direction: column; - gap: 32px; - - &:not(.active) { - transition-delay: 0s; - } -} - -.active { - transform: translateX(0); -} - -.logo-wrapper { - height: 48px; - min-height: 48px; - display: flex; - align-items: center; - padding-left: 16px; -} - -.logo { - width: 102px; - height: 24px; -} - -.navbar-btn { - height: 40px; - display: flex; - align-items: center; - - & > div { - background-color: $COLOR--darkmode-gray-450; - padding: 0 8px; - } - - a { - text-align: start; - font-family: $FONT-ROBOTO-MEDIUM; - font-size: 13px; - line-height: 20px; - padding: 10px 8px; - } -} - -.bottom-block { - display: flex; - flex-direction: column; - align-items: center; - justify-content: end; - flex-grow: 1; - gap: 8px; -} diff --git a/app/src/componentLibrary/sidebar/sidebar.jsx b/app/src/componentLibrary/sidebar/sidebar.jsx index 1f45f69658..2972cdcc47 100644 --- a/app/src/componentLibrary/sidebar/sidebar.jsx +++ b/app/src/componentLibrary/sidebar/sidebar.jsx @@ -19,154 +19,96 @@ import PropTypes from 'prop-types'; import Parser from 'html-react-parser'; import classNames from 'classnames/bind'; import { useOnClickOutside } from 'common/hooks'; -import { Navbar } from './navbar'; import { SidebarButton } from './sidebarButton'; import styles from './sidebar.scss'; const cx = classNames.bind(styles); -const HOVER = 'hover'; -const ACTIVE = 'active'; export const Sidebar = ({ - logoBlockIcon, + logoLeftIcon, + logoRightIcon, createMainBlock, topSidebarItems, - bottomSidebarItems, createFooterBlock, shouldBeCollapsedOnLeave, - ...navbarProps }) => { - const [isOpenNavbar, setIsOpenNavbar] = useState(false); - - const [actionButtonKey, setActionButtonKey] = useState(null); - const [actionButtonType, setActionButtonType] = useState(null); + const [isOpenSidebar, setIsOpenSidebar] = useState(false); const sidebarRef = useRef(null); - const onCloseNavbar = () => { - setIsOpenNavbar(false); + const onCloseSidebar = () => { + setIsOpenSidebar(false); }; const handleClickOutside = useCallback(() => { - if (isOpenNavbar) { - onCloseNavbar(); + if (isOpenSidebar) { + onCloseSidebar(); } - }, [isOpenNavbar]); + }, [isOpenSidebar]); useOnClickOutside(sidebarRef, handleClickOutside); - const onOpenNavbar = () => { - setIsOpenNavbar(true); + const onOpenSidebar = () => { + setIsOpenSidebar(true); }; - const onLeaveNavbar = () => { + const onLeaveSidebar = () => { if (shouldBeCollapsedOnLeave) { - onCloseNavbar(); + onCloseSidebar(); } }; - const onButtonClick = (onClick) => { - onClick(); - onCloseNavbar(); - }; - - const setHoverType = (key) => { - setActionButtonKey(key); - setActionButtonType(HOVER); - }; - - const setActiveType = (key) => { - setActionButtonKey(key); - setActionButtonType(ACTIVE); - }; - - const clearActionButton = () => { - setActionButtonKey(null); - setActionButtonType(null); - }; - - const getClassName = (key) => { - const isAction = actionButtonKey === key; - - return cx({ - hover: isAction && actionButtonType === HOVER, - active: isAction && actionButtonType === ACTIVE, - }); - }; - return (
-
); }; Sidebar.propTypes = { topSidebarItems: PropTypes.array, - bottomSidebarItems: PropTypes.array, - logoBlockIcon: PropTypes.element, + logoLeftIcon: PropTypes.element, + logoRightIcon: PropTypes.element, createMainBlock: PropTypes.element, createFooterBlock: PropTypes.func, shouldBeCollapsedOnLeave: PropTypes.bool, }; Sidebar.defaultProps = { - logoBlockIcon: null, + logoLeftIcon: null, + logoRightIcon: null, createMainBlock: null, topSidebarItems: [], - bottomSidebarItems: [], shouldBeCollapsedOnLeave: false, createFooterBlock: () => {}, }; diff --git a/app/src/componentLibrary/sidebar/sidebar.scss b/app/src/componentLibrary/sidebar/sidebar.scss index 406f3a20ac..9c993481e6 100644 --- a/app/src/componentLibrary/sidebar/sidebar.scss +++ b/app/src/componentLibrary/sidebar/sidebar.scss @@ -17,24 +17,61 @@ .sidebar-container { height: 100%; font-family: $FONT-ROBOTO-REGULAR; + width: 48px; + transition: width 0.3s ease-out; + transition-delay: 0.5s; + position: relative; + z-index: 1; + overflow: hidden; } .sidebar { + position: absolute; + left: 0; + top: 0; display: flex; flex-direction: column; align-items: center; - position: relative; padding: 16px 0px 24px 0; - width: 48px; height: calc(100% - 40px); gap: 32px; - background-color: $COLOR--darkmode-gray-500; + background-image: + linear-gradient(to right, $COLOR--darkmode-gray-500 0 48px,$COLOR--darkmode-gray-450 48px 100%); z-index: 3; + + width: 328px; + align-items: start; } -.logo { - width: 48px; +.open { + width: 328px; + animation-name: delay-overflow; + animation-delay: 0.8s; + animation-duration: 99999s; +} + +@keyframes delay-overflow { + from { overflow: visible; } +} + +.logo-wrapper { + width: 100%; height: 48px; + display: flex; + align-items: center; +} + +.logo-left { + svg { + width: 48px; + height: 48px; + } +} + +.logo-right { + width: 102px; + height: 24px; + margin-left: 16px; } .top-block { @@ -43,7 +80,7 @@ flex-direction: column; } -.main-block { +.main-block-wrapper { height: 60px; @media (max-width: $SCREEN_XS_MAX) { @@ -72,22 +109,6 @@ } } -.active { - path, - rect, - polygon { - fill: $COLOR--darkmode-topaz-pressed; - } - - & > div { - background-color: $COLOR--darkmode-gray-500; - - a { - color: $COLOR--darkmode-topaz-pressed; - } - } -} - .bottom-block { display: flex; flex-direction: column; @@ -111,8 +132,9 @@ .footer-block { display: flex; flex-direction: column; - align-items: center; + align-items: start; justify-content: end; flex-grow: 1; gap: 8px; + width: 100%; } diff --git a/app/src/componentLibrary/sidebar/sidebarButton/sidebarButton.jsx b/app/src/componentLibrary/sidebar/sidebarButton/sidebarButton.jsx index 657440aaa0..dc9b9bacf5 100644 --- a/app/src/componentLibrary/sidebar/sidebarButton/sidebarButton.jsx +++ b/app/src/componentLibrary/sidebar/sidebarButton/sidebarButton.jsx @@ -16,35 +16,31 @@ import { PropTypes } from 'prop-types'; import classNames from 'classnames/bind'; +import { NavLink } from 'components/main/navLink'; +import Parser from 'html-react-parser'; import styles from './sidebarButton.scss'; const cx = classNames.bind(styles); -export const SidebarButton = ({ - className, - onClick, - onMouseEnter, - onMouseLeave, - onMouseDown, - children, -}) => ( - + {Parser(icon)} + {message} + ); SidebarButton.propTypes = { - className: PropTypes.string.isRequired, + icon: PropTypes.element.isRequired, onClick: PropTypes.func.isRequired, - children: PropTypes.element.isRequired, - onMouseEnter: PropTypes.func.isRequired, - onMouseLeave: PropTypes.func.isRequired, - onMouseDown: PropTypes.func.isRequired, + message: PropTypes.string.isRequired, + onLeaveSidebar: PropTypes.func.isRequired, + link: PropTypes.string.isRequired, }; diff --git a/app/src/componentLibrary/sidebar/sidebarButton/sidebarButton.scss b/app/src/componentLibrary/sidebar/sidebarButton/sidebarButton.scss index 7528cae16e..50d9186537 100644 --- a/app/src/componentLibrary/sidebar/sidebarButton/sidebarButton.scss +++ b/app/src/componentLibrary/sidebar/sidebarButton/sidebarButton.scss @@ -14,10 +14,82 @@ * limitations under the License. */ + .btn-icon { + width: 48px; + height: 40px; + + svg { + width: 48px; + height: 40px; + } +} + +.title { + width: 280px; + display: flex; + align-items: center; + padding: 8px 16px; + line-height: 20px; + font-size: 13px; + font-family: $FONT-ROBOTO-MEDIUM; +} + +.active { + path, + rect, + polygon { + fill: $COLOR--darkmode-topaz-pressed; + } + + & > div { + background-color: $COLOR--darkmode-gray-500; + + a { + color: $COLOR--darkmode-topaz-pressed; + } + } +} + .sidebar-button { - padding: 0; - border: none; - background-color: transparent; - cursor: pointer; + display: flex; + align-items: center; width: 100%; + height: 100%; + box-sizing: border-box; + color: $COLOR--darkmode-gray-100; + text-decoration: none; + text-align: center; + border-radius: 4px; + + &:hover { + background-color: $COLOR--darkmode-gray-500; + color: $COLOR--white-two; + + svg path { + fill: $COLOR--white-two; + } + } + + &:active { + background-color: $COLOR--darkmode-gray-500; + color: $COLOR--darkmode-topaz-pressed; + + svg path { + fill: $COLOR--darkmode-topaz-pressed; + } + } + + &.active { + svg { + path, + rect, + polygon { + fill: $COLOR--darkmode-topaz-text; + } + } + + span { + color: $COLOR--darkmode-topaz-text; + } + } } diff --git a/app/src/layouts/appLayout/projectSidebar/organizationsBlock/index.js b/app/src/layouts/appLayout/projectSidebar/organizationsBlock/index.js deleted file mode 100644 index 0b013e9e34..0000000000 --- a/app/src/layouts/appLayout/projectSidebar/organizationsBlock/index.js +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2024 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { OrganizationsBlock } from './organizationsBlock'; diff --git a/app/src/layouts/appLayout/projectSidebar/organizationsBlock/organizationsBlock.jsx b/app/src/layouts/appLayout/projectSidebar/organizationsBlock/organizationsBlock.jsx deleted file mode 100644 index 3c42422ffc..0000000000 --- a/app/src/layouts/appLayout/projectSidebar/organizationsBlock/organizationsBlock.jsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2024 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import PropTypes from 'prop-types'; -import classNames from 'classnames/bind'; -import { useSelector } from 'react-redux'; -import { organizationNameSelector } from 'controllers/project'; -import styles from './organizationsBlock.scss'; - -const cx = classNames.bind(styles); - -export const OrganizationsBlock = ({ - onHoverOrganization, - onClearOrganization, - isHoveredOrganization, - onClick, -}) => { - const organizationName = useSelector(organizationNameSelector); - const title = `${organizationName[0]}${organizationName[organizationName.length - 1]}`; - - return ( - - ); -}; - -OrganizationsBlock.propTypes = { - onHoverOrganization: PropTypes.func.isRequired, - onClearOrganization: PropTypes.func.isRequired, - isHoveredOrganization: PropTypes.bool.isRequired, - onClick: PropTypes.func.isRequired, -}; diff --git a/app/src/layouts/appLayout/projectSidebar/organizationsBlock/organizationsBlock.scss b/app/src/layouts/appLayout/projectSidebar/organizationsBlock/organizationsBlock.scss deleted file mode 100644 index 0aa1bd4780..0000000000 --- a/app/src/layouts/appLayout/projectSidebar/organizationsBlock/organizationsBlock.scss +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2024 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -.organization-block { - display: flex; - align-items: center; - justify-content: center; - width: 40px; - height: 60px; - background-color: $COLOR--darkmode-gray-300; - border-radius: 8px; - cursor: pointer; - color: $COLOR--darkmode-gray-100; - text-transform: uppercase; - text-align: center; - font-size: 13px; - line-height: 20px; - font-family: $FONT-ROBOTO-BOLD; - border: none; - - &:focus-visible { - outline: none; - border: 2px solid $COLOR--topaz-focused; - } -} - -.hover { - color: $COLOR--white-two; - background-color: $COLOR--darkmode-gray-350; -} diff --git a/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsControl.jsx b/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsControl.jsx index 1e934acd8a..4d8f46af5a 100644 --- a/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsControl.jsx +++ b/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsControl.jsx @@ -35,48 +35,42 @@ const messages = defineMessages({ }, }); -export const OrganizationsControl = ({ - isPopoverOpen, - onHoverOrganization, - onClearOrganization, - isHoveredOrganization, -}) => { +export const OrganizationsControl = ({ isPopoverOpen, onClick }) => { const { formatMessage } = useIntl(); const organizationName = useSelector(organizationNameSelector); const projectName = useSelector(projectNameSelector); + const title = `${organizationName[0]}${organizationName[organizationName.length - 1]}`; return ( - -
{projectName}
- - - {Parser(OpenPopoverIcon)} - - +
+ + +
{projectName}
+
+ + {Parser(OpenPopoverIcon)} + + + ); }; OrganizationsControl.propTypes = { isPopoverOpen: PropTypes.bool.isRequired, - onHoverOrganization: PropTypes.func.isRequired, - onClearOrganization: PropTypes.func.isRequired, - isHoveredOrganization: PropTypes.bool.isRequired, + onClick: PropTypes.func.isRequired, }; export const OrganizationsControlWithPopover = withPopover({ diff --git a/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsControl.scss b/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsControl.scss index aef1c35df6..980e7c8800 100644 --- a/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsControl.scss +++ b/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsControl.scss @@ -21,25 +21,50 @@ max-width: $maxSize; } +.organizations-control-wrapper { + display: flex; + width: 324px; + + &:hover { + .organization-block { + color: $COLOR--white-two; + background-color: $COLOR--darkmode-gray-350; + } + + .organizations-control { + background-color: $COLOR--darkmode-gray-350; + } + + .project-name { + color: $COLOR--white-two; + } + + .open-popover path { + fill: $COLOR--white-two; + } + } +} + .organizations-control { - width: 264px; + width: 280px; height: 60px; background-color: $COLOR--darkmode-gray-300; border-radius: 8px; cursor: pointer; box-sizing: border-box; - padding: 10px 12px; + padding: 0px 12px; display: flex; align-items: center; justify-content: space-between; background-clip: padding-box; - border: 2px solid $COLOR--darkmode-gray-300; + border: none; outline: none; + margin-left: 12px; + margin-right: 4px; } .hover { background-color: $COLOR--darkmode-gray-350; - border: 2px solid $COLOR--darkmode-gray-350; .project-name { color: $COLOR--white-two; @@ -93,7 +118,6 @@ .popover { max-height: calc(100% - 112px); - margin-left: 4px; padding: 8px 0; &::after { @@ -102,7 +126,6 @@ } .popover-control { - margin-left: 8px; background-color: transparent; height: 60px; outline: none; @@ -111,9 +134,30 @@ &:focus-visible { box-shadow: 0px 0px 0px 2px $COLOR--topaz-focused inset; + } +} - .organizations-control { - border: 2px solid transparent; - } +.organization-block { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + min-width: 40px; + height: 60px; + background-color: $COLOR--darkmode-gray-300; + border-radius: 8px; + cursor: pointer; + color: $COLOR--darkmode-gray-100; + text-transform: uppercase; + text-align: center; + font-size: 13px; + line-height: 20px; + font-family: $FONT-ROBOTO-BOLD; + border: none; + margin-left: 4px; + + &:focus-visible { + outline: none; + border: 2px solid $COLOR--topaz-focused; } } diff --git a/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsPopover/organizationsPopover.jsx b/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsPopover/organizationsPopover.jsx index 40762bcf42..3e521c3a75 100644 --- a/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsPopover/organizationsPopover.jsx +++ b/app/src/layouts/appLayout/projectSidebar/organizationsControl/organizationsPopover/organizationsPopover.jsx @@ -36,7 +36,7 @@ const messages = defineMessages({ }, }); -export const OrganizationsPopover = ({ closePopover, closeNavbar }) => { +export const OrganizationsPopover = ({ closePopover, closeSidebar }) => { const { formatMessage } = useIntl(); const availableProjects = useSelector(availableProjectsSelector); const { organizationSlug: currentOrganization, projectSlug } = useSelector( @@ -45,7 +45,7 @@ export const OrganizationsPopover = ({ closePopover, closeNavbar }) => { const maxHeightPopover = window.innerHeight - MARGIN_TOP_AND_MARGIN_BOTTOM; const onClose = () => { - closeNavbar(); + closeSidebar(); closePopover(); }; @@ -89,6 +89,6 @@ export const OrganizationsPopover = ({ closePopover, closeNavbar }) => { }; OrganizationsPopover.propTypes = { - closeNavbar: PropTypes.func.isRequired, + closeSidebar: PropTypes.func.isRequired, closePopover: PropTypes.func.isRequired, }; diff --git a/app/src/layouts/appLayout/projectSidebar/projectSidebar.jsx b/app/src/layouts/appLayout/projectSidebar/projectSidebar.jsx index 46fbdfc044..7a90c2ff0b 100644 --- a/app/src/layouts/appLayout/projectSidebar/projectSidebar.jsx +++ b/app/src/layouts/appLayout/projectSidebar/projectSidebar.jsx @@ -40,13 +40,11 @@ import { AppSidebar } from 'layouts/common/appSidebar'; import { ExtensionLoader } from 'components/extensionLoader'; import { urlOrganizationAndProjectSelector } from 'controllers/pages'; import FiltersIcon from 'common/img/filters-icon-inline.svg'; -import { SidebarButton } from 'components/buttons/sidebarButton/sidebarButton'; import DashboardIcon from './img/dashboard-icon-inline.svg'; import LaunchesIcon from './img/launches-icon-inline.svg'; import DebugIcon from './img/debug-icon-inline.svg'; import MembersIcon from './img/members-icon-inline.svg'; import SettingsIcon from './img/settings-icon-inline.svg'; -import { OrganizationsBlock } from './organizationsBlock'; import { OrganizationsControlWithPopover } from './organizationsControl'; export const ProjectSidebar = ({ onClickNavBtn }) => { @@ -56,21 +54,12 @@ export const ProjectSidebar = ({ onClickNavBtn }) => { const projectPageExtensions = useSelector(uiExtensionProjectPagesSelector); const { organizationSlug, projectSlug } = useSelector(urlOrganizationAndProjectSelector); const [isOpenOrganizationPopover, setIsOpenOrganizationPopover] = useState(false); - const [isHoveredOrganization, setIsHoveredOrganization] = useState(false); const onClickButton = (eventInfo) => { onClickNavBtn(); trackEvent(eventInfo); }; - const onHoverOrganization = () => { - setIsHoveredOrganization(true); - }; - - const onClearOrganization = () => { - setIsHoveredOrganization(false); - }; - const getSidebarItems = () => { const topItems = [ { @@ -149,64 +138,25 @@ export const ProjectSidebar = ({ onClickNavBtn }) => { }), ); - const topSidebarItems = topItems.map(({ link, icon, message, name, component, onClick }) => ({ - key: component ? name : link.type, - onClick, - topSidebarItem: ( - <> - {component || ( - - {message} - - )} - - ), - })); - - const topSidebarControlItems = topItems.map(({ component, name, link, onClick, message }) => ({ - key: component ? name : link.type, - onClick, - sidebarBlockItem: component || ( - - {message} - - ), - })); - - return { topSidebarItems, topSidebarControlItems }; + return topItems; }; - const { topSidebarItems, topSidebarControlItems } = getSidebarItems(); - - const createMainBlock = (openNavbar) => ( - { - openNavbar(); - setIsOpenOrganizationPopover(!isOpenOrganizationPopover); - }} - /> - ); - - const createMainControlBlock = (closeNavbar) => ( + const createMainBlock = (openSidebar, closeSidebar) => ( { + openSidebar(); + setIsOpenOrganizationPopover(!isOpenOrganizationPopover); + }} /> ); return ( ); diff --git a/app/src/layouts/common/appSidebar/appSidebar.jsx b/app/src/layouts/common/appSidebar/appSidebar.jsx index 4af2b3b202..7708d408aa 100644 --- a/app/src/layouts/common/appSidebar/appSidebar.jsx +++ b/app/src/layouts/common/appSidebar/appSidebar.jsx @@ -22,121 +22,68 @@ import { useIntl } from 'react-intl'; import Parser from 'html-react-parser'; import { useSelector } from 'react-redux'; import { Sidebar } from 'componentLibrary/sidebar'; -import HelpIcon from 'common/img/help-inline.svg'; import { userIdSelector } from 'controllers/user'; import { getFAQOpenStatus } from './utils'; import { ServiceWithPopover } from './helpAndService'; -import LogoBlockIcon from './img/logo-icon-inline.svg'; -import LogoControlIcon from './img/logo-text-icon-inline.svg'; -import { UserAvatar } from './userAvatar'; +import LogoLeftIcon from './img/logo-icon-inline.svg'; +import LogoRightIcon from './img/logo-text-icon-inline.svg'; +import OpenOutsideIcon from './img/open-outside-inline.svg'; import { UserControlWithPopover } from './userControl'; -import styles from './appSidebar.scss'; import { messages } from './messages'; +import styles from './appSidebar.scss'; const cx = classNames.bind(styles); -export const AppSidebar = ({ - createMainBlock, - createMainControlBlock, - topSidebarItems, - bottomSidebarItems, - topSidebarControlItems, - bottomSidebarControlItems, - isOpenOrganizationPopover, -}) => { +export const AppSidebar = ({ createMainBlock, topSidebarItems, isOpenOrganizationPopover }) => { const userId = useSelector(userIdSelector); const [isFaqTouched, setIsFaqTouched] = useState(!!getFAQOpenStatus(userId)); const { formatMessage } = useIntl(); const [isOpenAvatarPopover, setIsOpenAvatarPopover] = useState(false); const [isOpenSupportPopover, setIsOpenSupportPopover] = useState(false); - const [isHoveredUser, setIsHoveredUser] = useState(false); - const [isHoveredService, setIsHoveredService] = useState(false); - - const onHoverUser = () => { - setIsHoveredUser(true); - }; - - const onClearUser = () => { - setIsHoveredUser(false); - }; - const onHoverService = () => { - setIsHoveredService(true); - }; - - const onClearService = () => { - setIsHoveredService(false); - }; - const createFooterBlock = (openNavbar) => ( + const createFooterBlock = (openSidebar, closeSidebar) => ( <> -
-
+ { - openNavbar(); + openSidebar(); setIsOpenSupportPopover(!isOpenSupportPopover); }} - onMouseEnter={onHoverService} - onMouseLeave={onClearService} - > - {Parser(HelpIcon)} - - + { - openNavbar(); + openSidebar(); setIsOpenAvatarPopover(!isOpenAvatarPopover); }} - onHoverUser={onHoverUser} - onClearUser={onClearUser} - isHoveredUser={isHoveredUser} /> ); - const createFooterControlBlock = (onCloseNavbar) => ( - <> - - -
- -
- - ); - return ( {}, createMainBlock: () => {}, }; diff --git a/app/src/layouts/common/appSidebar/appSidebar.scss b/app/src/layouts/common/appSidebar/appSidebar.scss index ad8d2d8340..7ff140c0f1 100644 --- a/app/src/layouts/common/appSidebar/appSidebar.scss +++ b/app/src/layouts/common/appSidebar/appSidebar.scss @@ -75,107 +75,40 @@ } .policy-block { - height: 36px; -} - -.policy-control { font-size: 11px; line-height: 16px; + height: 36px; width: 100%; box-sizing: border-box; - padding: 0 8px; + padding-left: 48px; cursor: pointer; &:hover { background-color: $COLOR--darkmode-gray-500; - a { - color: $COLOR--white-two; - } - } - - a { - text-decoration: none; - color: $COLOR--darkmode-gray-100; - padding: 10px 8px; - display: inline-block; - width: 100%; - box-sizing: border-box; - border-radius: 4px; - - &:focus-visible { - outline: none; - box-shadow: 0px 0px 0px 2px $COLOR--topaz-focused inset; - } - - &:active { - color: $COLOR--darkmode-topaz-pressed; - } - } -} - -.hover { - background-color: $COLOR--darkmode-gray-500; - - button { - div { + .policy-block-link { color: $COLOR--white-two; - } - path { - fill: $COLOR--white-two; + svg path { + fill: $COLOR--white-two; + } } } } -.user-control { - width: 100%; - box-sizing: border-box; - padding: 0 8px; - cursor: pointer; - - &:hover { - @extend .hover; - } -} - -.service-control { - border: none; - background-color: transparent; - width: 280px; - padding: 0; -} - -.service-block { - position: relative; - width: 40px; - height: 48px; +.policy-block-link { + text-decoration: none; + color: $COLOR--darkmode-gray-100; + padding: 10px 0px 10px 16px; display: flex; align-items: center; - justify-content: center; - cursor: pointer; - background-color: transparent; - border: none; + width: 100%; +} +.policy-block-icon { svg { - width: 20px; - height: 20px; - } - - i { - display: flex; - align-items: center; - } - - &.untouched::after { - content: ''; - position: absolute; - width: 8px; - height: 8px; - background-color: $COLOR--system-notification-marker; - border-radius: 50%; - border: 2px solid $COLOR--darkmode-gray-500; - right: 20%; - top: 20%; + width: 16px; + height: 16px; } + margin-left: 4px; } diff --git a/app/src/layouts/common/appSidebar/helpAndService/FAQcontent/FAQContent.jsx b/app/src/layouts/common/appSidebar/helpAndService/FAQcontent/FAQContent.jsx index 13a130b0c2..ec14bd698b 100644 --- a/app/src/layouts/common/appSidebar/helpAndService/FAQcontent/FAQContent.jsx +++ b/app/src/layouts/common/appSidebar/helpAndService/FAQcontent/FAQContent.jsx @@ -33,7 +33,7 @@ import styles from './FAQContent.scss'; const cx = classNames.bind(styles); -export const FAQContent = ({ onOpen, closeNavbar, closePopover }) => { +export const FAQContent = ({ onOpen, closeSidebar, closePopover }) => { const { formatMessage } = useIntl(); const dispatch = useDispatch(); const userId = useSelector(userIdSelector); @@ -76,7 +76,7 @@ export const FAQContent = ({ onOpen, closeNavbar, closePopover }) => { ]; const openModal = () => { closePopover(); - closeNavbar(); + closeSidebar(); dispatch( showModalAction({ id: 'requestSupportModal', @@ -112,7 +112,7 @@ export const FAQContent = ({ onOpen, closeNavbar, closePopover }) => { className={cx('menu-item')} onClick={() => { closePopover(); - closeNavbar(); + closeSidebar(); }} key={contentItem.linkTo} /> @@ -132,6 +132,6 @@ export const FAQContent = ({ onOpen, closeNavbar, closePopover }) => { FAQContent.propTypes = { onOpen: PropTypes.func.isRequired, - closeNavbar: PropTypes.func.isRequired, + closeSidebar: PropTypes.func.isRequired, closePopover: PropTypes.func.isRequired, }; diff --git a/app/src/layouts/common/appSidebar/helpAndService/previewPopover.jsx b/app/src/layouts/common/appSidebar/helpAndService/previewPopover.jsx index 85c50f676a..7100268165 100644 --- a/app/src/layouts/common/appSidebar/helpAndService/previewPopover.jsx +++ b/app/src/layouts/common/appSidebar/helpAndService/previewPopover.jsx @@ -20,29 +20,39 @@ import { withPopover } from 'componentLibrary/popover'; import PropTypes from 'prop-types'; import React from 'react'; import { FAQContent } from 'layouts/common/appSidebar/helpAndService/FAQcontent'; +import HelpIcon from 'common/img/help-inline.svg'; import { ServicesContent } from './servicesContent'; import ArrowRightIcon from '../img/arrow-right-inline.svg'; import styles from './previewPopover.scss'; const cx = classNames.bind(styles); -const PreviewPopover = ({ title, isFaqTouched, isHovered }) => { + +const PreviewPopover = ({ title, isFaqTouched, onClick }) => { return ( -
-
- {title} -
- {Parser(ArrowRightIcon)} +
+ +
+
); }; PreviewPopover.propTypes = { - isFaqTouched: PropTypes.bool, - isHovered: PropTypes.bool, - title: PropTypes.string, + isFaqTouched: PropTypes.bool.isRequired, + title: PropTypes.string.isRequired, + onClick: PropTypes.func.isRequired, }; + export const ServiceWithPopover = withPopover({ ContentComponent: ServicesContent, side: 'right', diff --git a/app/src/layouts/common/appSidebar/helpAndService/previewPopover.scss b/app/src/layouts/common/appSidebar/helpAndService/previewPopover.scss index 0fc2dd7fc6..a10eb37c15 100644 --- a/app/src/layouts/common/appSidebar/helpAndService/previewPopover.scss +++ b/app/src/layouts/common/appSidebar/helpAndService/previewPopover.scss @@ -25,8 +25,7 @@ position: relative; display: flex; color: $COLOR--darkmode-gray-100; - width: 100%; - height: 48px; + height: 40px; align-items: center; padding: 0 16px; @@ -38,12 +37,13 @@ .service-popover { padding: 8px 0px; margin-left: -4px; + margin-top: 4px; transform: translateY(-100%); } .service-popover-control { - height: 48px; - width: 280px; + height: 40px; + width: 328px; display: flex; align-items: center; @@ -67,22 +67,6 @@ width: 16px; height: 16px; } - - &:hover { - @extend .hovered; - } -} - -.hovered { - background-color: $COLOR--darkmode-gray-500; - - .title { - color: $COLOR--white-two; - } - - path { - fill: $COLOR--white-two; - } } .title { @@ -101,6 +85,10 @@ min-width: 270px; display: flex; align-items: center; + + .service-block { + display: none; + } } .arrow-icon { @@ -116,3 +104,65 @@ margin-right: 8px; } } + +.service-wrapper { + display: flex; + + &:hover { + background-color: $COLOR--darkmode-gray-500; + + .title, + .service-block { + color: $COLOR--white-two; + } + + .service-block, + .arrow-icon { + path { + fill: $COLOR--white-two; + } + } + } +} + +.service-control { + border: none; + background-color: transparent; + width: 280px; + padding: 0; + cursor: pointer; +} + +.service-block { + position: relative; + width: 48px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + background-color: transparent; + border: none; + + svg { + width: 20px; + height: 20px; + } + + i { + display: flex; + align-items: center; + } + + &.untouched::after { + content: ''; + position: absolute; + width: 8px; + height: 8px; + background-color: $COLOR--system-notification-marker; + border-radius: 50%; + border: 2px solid $COLOR--darkmode-gray-500; + right: 20%; + top: 20%; + } +} diff --git a/app/src/layouts/common/appSidebar/helpAndService/servicesContent/servicesContent.jsx b/app/src/layouts/common/appSidebar/helpAndService/servicesContent/servicesContent.jsx index 676fe1e7cd..1a674522de 100644 --- a/app/src/layouts/common/appSidebar/helpAndService/servicesContent/servicesContent.jsx +++ b/app/src/layouts/common/appSidebar/helpAndService/servicesContent/servicesContent.jsx @@ -27,7 +27,7 @@ import { messages } from '../../messages'; const cx = classNames.bind(styles); -export const ServicesContent = ({ closePopover, closeNavbar, isFaqTouched, onOpen }) => { +export const ServicesContent = ({ closePopover, closeSidebar, isFaqTouched, onOpen }) => { const [isHovered, setIsHovered] = useState(false); const { formatMessage } = useIntl(); @@ -77,7 +77,7 @@ export const ServicesContent = ({ closePopover, closeNavbar, isFaqTouched, onOpe onMouseEnter={onSetHover} > { closePopover(); - closeNavbar(); + closeSidebar(); }} className={cx('menu-item')} isInternal={contentItem.isInternal} @@ -108,7 +108,7 @@ export const ServicesContent = ({ closePopover, closeNavbar, isFaqTouched, onOpe ServicesContent.propTypes = { closePopover: PropTypes.func.isRequired, - closeNavbar: PropTypes.func.isRequired, + closeSidebar: PropTypes.func.isRequired, isFaqTouched: PropTypes.bool.isRequired, onOpen: PropTypes.func.isRequired, }; diff --git a/app/src/layouts/common/appSidebar/img/open-outside-inline.svg b/app/src/layouts/common/appSidebar/img/open-outside-inline.svg new file mode 100644 index 0000000000..d6b2aeb31a --- /dev/null +++ b/app/src/layouts/common/appSidebar/img/open-outside-inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/src/layouts/common/appSidebar/userAvatar/index.js b/app/src/layouts/common/appSidebar/userAvatar/index.js deleted file mode 100644 index cdcad3337d..0000000000 --- a/app/src/layouts/common/appSidebar/userAvatar/index.js +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2024 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { UserAvatar } from './userAvatar'; diff --git a/app/src/layouts/common/appSidebar/userAvatar/userAvatar.jsx b/app/src/layouts/common/appSidebar/userAvatar/userAvatar.jsx deleted file mode 100644 index 4e744f6686..0000000000 --- a/app/src/layouts/common/appSidebar/userAvatar/userAvatar.jsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2024 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import PropTypes from 'prop-types'; -import classNames from 'classnames/bind'; -import { Image } from 'components/main/image'; -import DefaultUserImage from 'common/img/default-user-avatar.png'; -import { photoTimeStampSelector } from 'controllers/user'; -import { URLS } from 'common/urls'; -import { useSelector } from 'react-redux'; -import styles from './userAvatar.scss'; - -const cx = classNames.bind(styles); - -export const UserAvatar = ({ onClick, onHoverUser, onClearUser }) => { - const photoTimeStamp = useSelector(photoTimeStampSelector); - - return ( - - ); -}; - -UserAvatar.propTypes = { - onClick: PropTypes.func.isRequired, - onHoverUser: PropTypes.func.isRequired, - onClearUser: PropTypes.func.isRequired, -}; diff --git a/app/src/layouts/common/appSidebar/userAvatar/userAvatar.scss b/app/src/layouts/common/appSidebar/userAvatar/userAvatar.scss deleted file mode 100644 index 263ba17d2a..0000000000 --- a/app/src/layouts/common/appSidebar/userAvatar/userAvatar.scss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2024 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -.avatar-block { - height: 48px; - width: 48px; - display: flex; - align-items: center; - justify-content: center; - background-color: transparent; - border-radius: 4px; - border: none; - cursor: pointer; - - &:focus-visible { - outline: none; - box-shadow: 0px 0px 0px 2px $COLOR--topaz-focused inset; - } -} - -.avatar-img { - height: 32px; - width: 32px; - border-radius: 50%; -} diff --git a/app/src/layouts/common/appSidebar/userControl/profileMenu/profileMenu.jsx b/app/src/layouts/common/appSidebar/userControl/profileMenu/profileMenu.jsx index dfa78e26d0..94e2ba484b 100644 --- a/app/src/layouts/common/appSidebar/userControl/profileMenu/profileMenu.jsx +++ b/app/src/layouts/common/appSidebar/userControl/profileMenu/profileMenu.jsx @@ -28,7 +28,7 @@ import styles from './profileMenu.scss'; const cx = classNames.bind(styles); -export const ProfileMenu = ({ closePopover, closeNavbar }) => { +export const ProfileMenu = ({ closePopover, closeSidebar }) => { const dispatch = useDispatch(); const onClickLogout = () => { @@ -45,7 +45,7 @@ export const ProfileMenu = ({ closePopover, closeNavbar }) => { activeClassName={cx('active')} onClick={() => { closePopover(); - closeNavbar(); + closeSidebar(); }} > {Parser(MyProfileIcon)} @@ -61,5 +61,5 @@ export const ProfileMenu = ({ closePopover, closeNavbar }) => { ProfileMenu.propTypes = { closePopover: PropTypes.func.isRequired, - closeNavbar: PropTypes.func.isRequired, + closeSidebar: PropTypes.func.isRequired, }; diff --git a/app/src/layouts/common/appSidebar/userControl/userControl.jsx b/app/src/layouts/common/appSidebar/userControl/userControl.jsx index 003e3fb8a4..86e9749c41 100644 --- a/app/src/layouts/common/appSidebar/userControl/userControl.jsx +++ b/app/src/layouts/common/appSidebar/userControl/userControl.jsx @@ -16,10 +16,14 @@ import { useSelector } from 'react-redux'; import Parser from 'html-react-parser'; +import PropTypes from 'prop-types'; import classNames from 'classnames/bind'; import { FormattedMessage } from 'react-intl'; +import { Image } from 'components/main/image'; +import DefaultUserImage from 'common/img/default-user-avatar.png'; +import { photoTimeStampSelector, userInfoSelector } from 'controllers/user'; +import { URLS } from 'common/urls'; import { ADMINISTRATOR } from 'common/constants/accountRoles'; -import { userInfoSelector } from 'controllers/user'; import { withPopover } from 'componentLibrary/popover'; import { ProfileMenu } from './profileMenu'; import ArrowRightIcon from '../img/arrow-right-inline.svg'; @@ -27,30 +31,45 @@ import styles from './userControl.scss'; const cx = classNames.bind(styles); -const UserControl = () => { +const UserControl = ({ onClick }) => { const { userRole, fullName, email } = useSelector(userInfoSelector); + const photoTimeStamp = useSelector(photoTimeStampSelector); return ( -
-
-
-
{fullName}
-
- {/* TODO: Need to manage this permission via common permission engine */} - {userRole === ADMINISTRATOR && ( -
- -
- )} - {Parser(ArrowRightIcon)} +
+ +
+
+
+
{fullName}
+
+ {/* TODO: Need to manage this permission via common permission engine */} + {userRole === ADMINISTRATOR && ( +
+ +
+ )} + {Parser(ArrowRightIcon)} +
+
{email}
-
{email}
); }; +UserControl.propTypes = { + onClick: PropTypes.func.isRequired, +}; + export const UserControlWithPopover = withPopover({ ContentComponent: ProfileMenu, side: 'right', diff --git a/app/src/layouts/common/appSidebar/userControl/userControl.scss b/app/src/layouts/common/appSidebar/userControl/userControl.scss index 146af921f4..18a8879247 100644 --- a/app/src/layouts/common/appSidebar/userControl/userControl.scss +++ b/app/src/layouts/common/appSidebar/userControl/userControl.scss @@ -21,11 +21,31 @@ max-width: $maxSize; } +.user-block-wrapper { + display: flex; + + &:hover { + background-color: $COLOR--darkmode-gray-500; + + .user-email, + .username { + color: $COLOR--white-two; + } + } + + .arrow-icon { + path { + fill: $COLOR--white-two; + } + } +} + .user-control { position: relative; display: block; color: $COLOR--darkmode-gray-100; - width: 100%; + width: 248px; + padding: 0px 16px; @media (max-width: $SCREEN_XS_MAX) { display: none; @@ -86,15 +106,13 @@ .popover { padding: 8px 16px; - margin-left: 4px; + margin-left: -4px; margin-top: -8px; } .popover-control { height: 48px; - width: 264px; - padding: 0 6px; - border: 2px solid transparent; + width: 328px; display: flex; align-items: center; @@ -104,3 +122,26 @@ border-radius: 4px; } } + +.avatar-block { + height: 48px; + width: 48px; + display: flex; + align-items: center; + justify-content: center; + background-color: transparent; + border-radius: 4px; + border: none; + cursor: pointer; + + &:focus-visible { + outline: none; + box-shadow: 0px 0px 0px 2px $COLOR--topaz-focused inset; + } +} + +.avatar-img { + height: 32px; + width: 32px; + border-radius: 50%; +} From 662492a935a73d7a1788dd64a9f005a11e27eb2b Mon Sep 17 00:00:00 2001 From: Siarhei Iukou Date: Tue, 4 Jun 2024 08:08:17 +0300 Subject: [PATCH 2/8] EPMRPP-90965 || fix style --- app/src/componentLibrary/sidebar/sidebar.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/componentLibrary/sidebar/sidebar.scss b/app/src/componentLibrary/sidebar/sidebar.scss index 9c993481e6..a15c88d7af 100644 --- a/app/src/componentLibrary/sidebar/sidebar.scss +++ b/app/src/componentLibrary/sidebar/sidebar.scss @@ -31,7 +31,6 @@ top: 0; display: flex; flex-direction: column; - align-items: center; padding: 16px 0px 24px 0; height: calc(100% - 40px); gap: 32px; From 2cec44891adb5db9043e0938606aa06efc86a865 Mon Sep 17 00:00:00 2001 From: Siarhei Iukou Date: Tue, 4 Jun 2024 08:15:29 +0300 Subject: [PATCH 3/8] EPMRPP-90965 || fix sonarcloud --- app/src/componentLibrary/sidebar/sidebar.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/componentLibrary/sidebar/sidebar.jsx b/app/src/componentLibrary/sidebar/sidebar.jsx index 2972cdcc47..8636147d0d 100644 --- a/app/src/componentLibrary/sidebar/sidebar.jsx +++ b/app/src/componentLibrary/sidebar/sidebar.jsx @@ -76,9 +76,10 @@ export const Sidebar = ({ {topSidebarItems.length > 0 && (
{topSidebarItems.map( - ({ icon, link, onClick, message, component }) => + ({ icon, link, onClick, message, name, component }) => component || ( Date: Wed, 5 Jun 2024 04:34:46 +0300 Subject: [PATCH 4/8] EPMRPP-90965 || pass closeSidebar function --- app/src/componentLibrary/sidebar/sidebar.jsx | 2 +- .../helpAndService/FAQcontent/FAQContent.jsx | 1 + .../servicesContent/servicesContent.jsx | 30 +++++-------------- .../servicesContent/servicesContent.scss | 25 ---------------- 4 files changed, 9 insertions(+), 49 deletions(-) diff --git a/app/src/componentLibrary/sidebar/sidebar.jsx b/app/src/componentLibrary/sidebar/sidebar.jsx index 8636147d0d..429e802b4a 100644 --- a/app/src/componentLibrary/sidebar/sidebar.jsx +++ b/app/src/componentLibrary/sidebar/sidebar.jsx @@ -90,7 +90,7 @@ export const Sidebar = ({ )}
)} -
{createFooterBlock(onOpenSidebar)}
+
{createFooterBlock(onOpenSidebar, onCloseSidebar)}
); diff --git a/app/src/layouts/common/appSidebar/helpAndService/FAQcontent/FAQContent.jsx b/app/src/layouts/common/appSidebar/helpAndService/FAQcontent/FAQContent.jsx index ec14bd698b..b7e2bb7e11 100644 --- a/app/src/layouts/common/appSidebar/helpAndService/FAQcontent/FAQContent.jsx +++ b/app/src/layouts/common/appSidebar/helpAndService/FAQcontent/FAQContent.jsx @@ -103,6 +103,7 @@ export const FAQContent = ({ onOpen, closeSidebar, closePopover }) => { /> ), }; + return ( <> {FAQContentItems.map((contentItem) => ( diff --git a/app/src/layouts/common/appSidebar/helpAndService/servicesContent/servicesContent.jsx b/app/src/layouts/common/appSidebar/helpAndService/servicesContent/servicesContent.jsx index 1a674522de..98fe20271a 100644 --- a/app/src/layouts/common/appSidebar/helpAndService/servicesContent/servicesContent.jsx +++ b/app/src/layouts/common/appSidebar/helpAndService/servicesContent/servicesContent.jsx @@ -18,7 +18,6 @@ import PropTypes from 'prop-types'; import classNames from 'classnames/bind'; import { useIntl } from 'react-intl'; import { API_PAGE } from 'controllers/pages'; -import { useState } from 'react'; import { referenceDictionary } from 'common/utils'; import { LinkItem } from '../linkItem'; import { FAQWithPopover } from '../index'; @@ -28,7 +27,6 @@ import { messages } from '../../messages'; const cx = classNames.bind(styles); export const ServicesContent = ({ closePopover, closeSidebar, isFaqTouched, onOpen }) => { - const [isHovered, setIsHovered] = useState(false); const { formatMessage } = useIntl(); const currentYear = new Date().getFullYear(); @@ -61,29 +59,15 @@ export const ServicesContent = ({ closePopover, closeSidebar, isFaqTouched, onOp }, ]; - const onClearHover = () => { - setIsHovered(false); - }; - - const onSetHover = () => { - setIsHovered(true); - }; - return ( <> - + {ServiceContentItems.map((contentItem) => ( Date: Wed, 5 Jun 2024 16:15:57 +0300 Subject: [PATCH 5/8] EPMRPP-90965 || Code Review fix - 1 --- app/src/componentLibrary/sidebar/sidebar.jsx | 33 ++++++++----------- app/src/componentLibrary/sidebar/sidebar.scss | 27 +++------------ .../sidebar/sidebarButton/sidebarButton.jsx | 8 ++--- .../organizationsControl.scss | 2 +- .../projectSidebar/projectSidebar.jsx | 14 ++++---- .../layouts/common/appSidebar/appSidebar.jsx | 18 ++++++---- .../layouts/common/appSidebar/appSidebar.scss | 20 +++++++++++ 7 files changed, 61 insertions(+), 61 deletions(-) diff --git a/app/src/componentLibrary/sidebar/sidebar.jsx b/app/src/componentLibrary/sidebar/sidebar.jsx index 429e802b4a..9a00044d16 100644 --- a/app/src/componentLibrary/sidebar/sidebar.jsx +++ b/app/src/componentLibrary/sidebar/sidebar.jsx @@ -16,7 +16,6 @@ import React, { useRef, useState, useCallback } from 'react'; import PropTypes from 'prop-types'; -import Parser from 'html-react-parser'; import classNames from 'classnames/bind'; import { useOnClickOutside } from 'common/hooks'; import { SidebarButton } from './sidebarButton'; @@ -25,10 +24,9 @@ import styles from './sidebar.scss'; const cx = classNames.bind(styles); export const Sidebar = ({ - logoLeftIcon, - logoRightIcon, + logoBlock, createMainBlock, - topSidebarItems, + items, createFooterBlock, shouldBeCollapsedOnLeave, }) => { @@ -66,25 +64,24 @@ export const Sidebar = ({ onMouseLeave={onLeaveSidebar} >