From 1412d72ed43fd8cc75f753d411d38b183c0ecf0f Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Wed, 27 Dec 2023 14:00:20 +0100 Subject: [PATCH 1/4] console: Remove duplicate button --- pkg/webui/components/button-v2/button.styl | 144 ---------- pkg/webui/components/button-v2/index.js | 230 ---------------- pkg/webui/components/button-v2/story.js | 118 --------- pkg/webui/components/button/button.styl | 96 +++++-- pkg/webui/components/button/index.js | 73 ++++- pkg/webui/components/button/story.js | 249 +++++------------- pkg/webui/components/header-v2/index.js | 2 +- .../navigation/side-v2/item/index.js | 4 +- .../components/profile-dropdown-v2/index.js | 2 +- .../sidebar/dedicated-entity/index.js | 2 +- .../components/sidebar/search-button/index.js | 2 +- .../components/sidebar/section-label/index.js | 2 +- .../components/sidebar/side-footer/index.js | 2 +- .../components/sidebar/side-header/index.js | 2 +- 14 files changed, 219 insertions(+), 709 deletions(-) delete mode 100644 pkg/webui/components/button-v2/button.styl delete mode 100644 pkg/webui/components/button-v2/index.js delete mode 100644 pkg/webui/components/button-v2/story.js diff --git a/pkg/webui/components/button-v2/button.styl b/pkg/webui/components/button-v2/button.styl deleted file mode 100644 index 3cb57a9b1d..0000000000 --- a/pkg/webui/components/button-v2/button.styl +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. -// -// 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. - -.button - reset-button() - position: relative - display: inline-flex - transition: 0.2s all ease-in-out - border-radius: $br.l - outline: 0 - cursor: pointer - align-items: center - gap: $cs.xxs - height: 2.5rem - text-decoration: none - padding: 0 $cs.m - white-space: nowrap - - .arrow-icon - transform: rotate(0deg) - transition: transform .2s - - .arrow-icon-expanded - transform: rotate(180deg) - transition: transform .2s - - &.primary - transition: 0.2s all ease-in-out - color: white - background-color: $c-active-blue - - &.disabled - background-color: $c-divider-dark - - &:not(.disabled) - &:hover - transition: 0.2s all ease-in-out - background-color: hoverize($c-active-blue) - - +focus-visible() - background-color: hoverize($c-active-blue) - - &:active - transition: 0.2s all ease-in-out - background-color: activize($c-active-blue) - - &.grey - background-color: $c.grey-500 - - &:not(.disabled) - &:hover - background-color: hoverize($c.grey-500) - - +focus-visible() - background-color: hoverize($c.grey-500) - - &:active - background-color: activize($c.grey-500) - - &.disabled - background-color: transparentify($c.grey-500, #fff, .25) - - &.secondary - transition: 0.2s all ease-in-out - color: $tc-deep-gray - background-color: white - box-shadow: 0px 2px 2px 0px rgba(0 0 0 4.5%), inset 0px 0px 0px 1px white - background: linear-gradient(to bottom, white, white) padding-box, linear-gradient(to bottom, #E8E7EC, #D7D7D7) border-box - border: 1px solid transparent - - - &:hover - transition: 0.2s all ease-in-out - background: linear-gradient(to bottom, $c-focus, $c-focus) padding-box, linear-gradient(to bottom, #E8E7EC, #D7D7D7) border-box - - +focus-visible() - background: linear-gradient(to bottom, $c-focus, $c-focus) padding-box, linear-gradient(to bottom, #E8E7EC, #D7D7D7) border-box - - &:active - transition: 0.2s all ease-in-out - background: linear-gradient(to bottom, $c-focus, $c-focus) padding-box, linear-gradient(to bottom, #E8E7EC, #D7D7D7) border-box - box-shadow: none - - &.naked - transition: 0.2s all ease-in-out - border: none - background-color: none - box-shadow: unset - color: $tc-subtle-gray - - &:not(.disabled) - &:hover - background-color: $c-backdrop - - +focus-visible() - background-color: $c-backdrop - - &:active - transition-duration: $ad.xs - background-color: $c-backdrop - - &.only-icon - width: 2.5rem - padding: 0 $cs.xs 0 0.73rem - - &.with-dropdown - padding: 0 $cs.xxs 0 $cs.xs - - &.with-dropdown&.only-icon - width: fit-content - .icon - margin-left: 0 - - &.with-icon - line-height: 1.3 - - &.responsive-label - padding: $cs.xs - - +media-query($bp.xxs) - .icon - margin-left: 0 - margin-right: 0 - - .link-button-message - display: none - -.content - position: relative - -.icon - margin-left: - $cs.xxs - diff --git a/pkg/webui/components/button-v2/index.js b/pkg/webui/components/button-v2/index.js deleted file mode 100644 index 3e68834e78..0000000000 --- a/pkg/webui/components/button-v2/index.js +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. -// -// 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 React, { useCallback, forwardRef, useMemo, useState } from 'react' -import classnames from 'classnames' -import { useIntl } from 'react-intl' - -import Icon from '@ttn-lw/components/icon' -import Dropdown from '@ttn-lw/components/dropdown-v2' - -import Message from '@ttn-lw/lib/components/message' - -import PropTypes from '@ttn-lw/lib/prop-types' - -import style from './button.styl' - -const filterDataProps = props => - Object.keys(props) - .filter(key => key.startsWith('data-')) - .reduce((acc, key) => { - acc[key] = props[key] - return acc - }, {}) - -const assembleClassnames = ({ - message, - primary, - secondary, - naked, - grey, - icon, - dropdownItems, - className, -}) => - classnames( - style.button, - { - [style.primary]: primary, - [style.secondary]: secondary, - [style.naked]: naked, - [style.grey]: grey, - [style.withIcon]: icon !== undefined && message, - [style.onlyIcon]: icon !== undefined && !message, - [style.withDropdown]: Boolean(dropdownItems), - }, - className, - ) - -const buttonChildren = props => { - const { dropdownItems, icon, message, expanded, noDropdownIcon, dropdownClassName, children } = - props - - const content = Boolean(children) ? ( - children - ) : ( - <> - {icon ? : null} - {message ? : null} - {dropdownItems ? ( - <> - {!noDropdownIcon && ( - - )} - - {dropdownItems} - - - ) : null} - - ) - - return content -} - -const Button = forwardRef((props, ref) => { - const { - autoFocus, - dropdownItems, - name, - type, - value, - title: rawTitle, - onBlur, - onClick, - form, - ...rest - } = props - const [expanded, setExpanded] = useState(false) - - const dataProps = useMemo(() => filterDataProps(rest), [rest]) - - const handleClickOutside = useCallback( - e => { - if (ref.current && !ref.current.contains(e.target)) { - setExpanded(false) - } - }, - [ref], - ) - - const toggleDropdown = useCallback(() => { - setExpanded(oldExpanded => { - const newState = !oldExpanded - if (newState) document.addEventListener('mousedown', handleClickOutside) - else document.removeEventListener('mousedown', handleClickOutside) - return newState - }) - }, [handleClickOutside]) - - const handleClick = useCallback( - evt => { - if (dropdownItems) { - toggleDropdown() - return - } - // Passing a value to the onClick handler is useful for components that - // are rendered multiple times, e.g. in a list. The value can be used to - // identify the component that was clicked. - onClick(evt, value) - }, - [dropdownItems, onClick, toggleDropdown, value], - ) - - const intl = useIntl() - - let title = rawTitle - if (typeof rawTitle === 'object' && rawTitle.id && rawTitle.defaultMessage) { - title = intl.formatMessage(title) - } - - const htmlProps = { autoFocus, name, type, value, title, onBlur, form, ...dataProps } - const buttonClassNames = assembleClassnames(props) - return ( -   -   - - - ) - } - - @bind - toggle() { - this.setState(state => ({ - busy: !state.busy, - })) - } - - @bind - disable() { - this.setState(state => ({ - disabled: !state.disabled, - })) - } - - @bind - error() { - this.setState({ - error: true, - }) - setTimeout( - function () { - this.setState({ - error: false, - }) - }.bind(this), - 1200, - ) - } -} - export default { - title: 'Button', + title: 'Button V2', + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/7pBLWK4tsjoAbyJq2viMAQ/2023-console-redesign?type=design&node-id=590%3A51411&mode=design&t=Hbk2Qngeg1xqg4V3-1', + }, + }, } -export const Default = () => ( -
-
-) - -export const Warning = () => ( -
-
-) - -export const Danger = () => ( -
-
+const dropdownItems = ( + + + + ) export const Primary = () => ( -
+
) export const WithIcon = () => ( -
-
) -export const Naked = () => ( -
-
) -export const NakedWithIcon = () => ( -
-
+ ) +} + +export const PrimayOnlyIconDropdown = () => { + const ref = useRef() + + return ( +
+
+ ) +} + +export const Secondary = () => ( +
+
) -export const OnlyIcon = () => ( -
-
) -export const CustomContent = () => ( -
- -
-
- -
-
- +export const SecondaryOnlyIcon = () => ( +
+
) -CustomContent.story = { - name: 'Custom content', +export const SecondaryDropdown = () => { + const ref = useRef() + + return ( +
+
+ ) } -export const Toggle = () => +export const SecondaryOnlyIconDropdown = () => { + const ref = useRef() + + return ( +
+
+ ) +} diff --git a/pkg/webui/components/header-v2/index.js b/pkg/webui/components/header-v2/index.js index d1180edde3..dd31c4afe6 100644 --- a/pkg/webui/components/header-v2/index.js +++ b/pkg/webui/components/header-v2/index.js @@ -16,7 +16,7 @@ import React, { useRef } from 'react' import classnames from 'classnames' import { Breadcrumbs } from '@ttn-lw/components/breadcrumbs/breadcrumbs' -import Button from '@ttn-lw/components/button-v2' +import Button from '@ttn-lw/components/button' import ProfileDropdown from '@ttn-lw/components/profile-dropdown-v2' import Link from '@ttn-lw/components/link' diff --git a/pkg/webui/components/navigation/side-v2/item/index.js b/pkg/webui/components/navigation/side-v2/item/index.js index a87411fd0b..454b689a29 100644 --- a/pkg/webui/components/navigation/side-v2/item/index.js +++ b/pkg/webui/components/navigation/side-v2/item/index.js @@ -17,7 +17,7 @@ import classnames from 'classnames' import Dropdown from '@ttn-lw/components/dropdown-v2' import MenuLink from '@ttn-lw/components/sidebar/side-menu-link' -import Button from '@ttn-lw/components/button-v2' +import Button from '@ttn-lw/components/button' import Icon from '@ttn-lw/components/icon' import Message from '@ttn-lw/lib/components/message' @@ -148,7 +148,7 @@ const CollapsableItem = ({ 'pl-0': !isMinimized, [style.buttonActive]: isMinimized && subItemActive, })} - naked + unstyled onClick={onClick} > {icon && } diff --git a/pkg/webui/components/profile-dropdown-v2/index.js b/pkg/webui/components/profile-dropdown-v2/index.js index 0b557ea93f..4a79f00fd5 100644 --- a/pkg/webui/components/profile-dropdown-v2/index.js +++ b/pkg/webui/components/profile-dropdown-v2/index.js @@ -18,7 +18,7 @@ import classnames from 'classnames' import Icon from '@ttn-lw/components/icon' import Dropdown from '@ttn-lw/components/dropdown-v2' import ProfilePicture from '@ttn-lw/components/profile-picture' -import Button from '@ttn-lw/components/button-v2' +import Button from '@ttn-lw/components/button' import style from '@ttn-lw/components/button-v2/button.styl' import PropTypes from '@ttn-lw/lib/prop-types' diff --git a/pkg/webui/components/sidebar/dedicated-entity/index.js b/pkg/webui/components/sidebar/dedicated-entity/index.js index 8bf68e8eb1..9255137997 100644 --- a/pkg/webui/components/sidebar/dedicated-entity/index.js +++ b/pkg/webui/components/sidebar/dedicated-entity/index.js @@ -16,7 +16,7 @@ import React from 'react' import { NavLink } from 'react-router-dom' import classnames from 'classnames' -import Button from '@ttn-lw/components/button-v2' +import Button from '@ttn-lw/components/button' import Message from '@ttn-lw/lib/components/message' diff --git a/pkg/webui/components/sidebar/search-button/index.js b/pkg/webui/components/sidebar/search-button/index.js index 2d47a29ba3..601f622f51 100644 --- a/pkg/webui/components/sidebar/search-button/index.js +++ b/pkg/webui/components/sidebar/search-button/index.js @@ -15,7 +15,7 @@ import React, { useCallback, useContext } from 'react' import classnames from 'classnames' -import Button from '@ttn-lw/components/button-v2' +import Button from '@ttn-lw/components/button' import Icon from '@ttn-lw/components/icon' import Message from '@ttn-lw/lib/components/message' diff --git a/pkg/webui/components/sidebar/section-label/index.js b/pkg/webui/components/sidebar/section-label/index.js index 88ee21981a..a1a9fcfae8 100644 --- a/pkg/webui/components/sidebar/section-label/index.js +++ b/pkg/webui/components/sidebar/section-label/index.js @@ -15,7 +15,7 @@ import React from 'react' import classnames from 'classnames' -import Button from '@ttn-lw/components/button-v2' +import Button from '@ttn-lw/components/button' import Message from '@ttn-lw/lib/components/message' diff --git a/pkg/webui/components/sidebar/side-footer/index.js b/pkg/webui/components/sidebar/side-footer/index.js index aa85a59682..7cd0f915ab 100644 --- a/pkg/webui/components/sidebar/side-footer/index.js +++ b/pkg/webui/components/sidebar/side-footer/index.js @@ -15,7 +15,7 @@ import React, { useCallback, useContext, useRef } from 'react' import classnames from 'classnames' -import Button from '@ttn-lw/components/button-v2' +import Button from '@ttn-lw/components/button' import Dropdown from '@ttn-lw/components/dropdown-v2' import { LanguageContext } from '@ttn-lw/lib/components/with-locale' diff --git a/pkg/webui/components/sidebar/side-header/index.js b/pkg/webui/components/sidebar/side-header/index.js index d3885d1627..aa18230693 100644 --- a/pkg/webui/components/sidebar/side-header/index.js +++ b/pkg/webui/components/sidebar/side-header/index.js @@ -17,7 +17,7 @@ import classnames from 'classnames' import LAYOUT from '@ttn-lw/constants/layout' -import Button from '@ttn-lw/components/button-v2' +import Button from '@ttn-lw/components/button' import SidebarContext from '@console/containers/side-bar/context' From 4059587df65562554a9c0f7cda66894cc5b59014 Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Wed, 27 Dec 2023 14:02:37 +0100 Subject: [PATCH 2/4] console: Remove old dropdown --- .../components/dropdown-v2/dropdown.styl | 134 ----------- pkg/webui/components/dropdown-v2/index.js | 215 ------------------ pkg/webui/components/dropdown/dropdown.styl | 95 ++++++-- pkg/webui/components/dropdown/index.js | 101 +++++++- .../{dropdown-v2 => dropdown}/story.js | 0 pkg/webui/components/header-v2/story.js | 2 +- .../navigation/side-v2/item/index.js | 2 +- .../components/profile-dropdown-v2/index.js | 2 +- .../components/profile-dropdown-v2/story.js | 2 +- .../components/sidebar/side-footer/index.js | 2 +- 10 files changed, 170 insertions(+), 385 deletions(-) delete mode 100644 pkg/webui/components/dropdown-v2/dropdown.styl delete mode 100644 pkg/webui/components/dropdown-v2/index.js rename pkg/webui/components/{dropdown-v2 => dropdown}/story.js (100%) diff --git a/pkg/webui/components/dropdown-v2/dropdown.styl b/pkg/webui/components/dropdown-v2/dropdown.styl deleted file mode 100644 index aa1b0e9207..0000000000 --- a/pkg/webui/components/dropdown-v2/dropdown.styl +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. -// -// 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. - -ul.dropdown - font-size: $fs.m - border-radius: $br.l - border: 1px solid $c.grey-200 - list-style-type: none - background: $c.white - box-shadow: 0px 3px 16px 0px rgba(0, 0, 0, 0.06) - position: absolute - padding: $cs.s - min-width: 14rem - z-index: $zi.dropdown - margin: $cs.xxs 0 0 - opacity: 0 - visibility: hidden - transition: opacity 0.2s ease-in-out, visibility 0s linear 0.2s - - &.open - opacity: 1 - visibility: visible - transition: opacity 0.2s ease-in-out, visibility 0s linear - - &.below - bottom: auto - top: calc(100% + 7px) - - &.above - top: auto - bottom: calc(100% + 7px) - - &.left - left: 0 - right: auto - - &.right - right: 0 - left: auto - - &.example - bottom: auto - top: 0 - left: 0 - right: auto - - &.larger - li.dropdown-item - & > a.button, & > button.button - padding: $cs.l - - hr - height: 1px - background-color: $c.grey-200 - - li.dropdown-header-item - display: block - margin-bottom: 0 - font-weight: $fw.bold - - span - line-height: 1 - display: block - padding: $cs.m - - li.dropdown-item - margin-bottom: 0 - text-align: left - - button.button - reset-button() - - & > a.button, & > button.button - box-sizing: border-box - line-height: 1 - display: flex - align-items: center - text-decoration: none - padding: $cs.xs - width: 100% - min-height: 2.429rem - &:not(.active) - color: $c.grey-700 - - .icon - color: $c.grey-700 - - &.active - border-radius: $br.m - background: $c.tts-primary-150 - transition: background 0.1s ease-in-out - color: $tc-deep-gray - - .icon - color: $tc-deep-gray - - &:hover - color: $tc-deep-gray - background: $c.tts-primary-150 - transition: background 0.1s ease-in-out - border-radius: $br.m - - .icon - color: $tc-deep-gray - - .icon - margin-right: $cs.xs - - &:hover - color: $tc-deep-gray - text-decoration: none - - .submenu-container - bottom: 0px - left: 0px - position: absolute - width: 180% - height: 5rem - z-index: 9999 - - .submenu-dropdown - bottom: -0px !important - left: calc(100% + -213px) !important diff --git a/pkg/webui/components/dropdown-v2/index.js b/pkg/webui/components/dropdown-v2/index.js deleted file mode 100644 index 8cf1d800ec..0000000000 --- a/pkg/webui/components/dropdown-v2/index.js +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. -// -// 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 React, { useCallback, useEffect, useRef, useState } from 'react' -import classnames from 'classnames' -import { NavLink } from 'react-router-dom' - -import Icon from '@ttn-lw/components/icon' -import Link from '@ttn-lw/components/link' - -import Message from '@ttn-lw/lib/components/message' - -import PropTypes from '@ttn-lw/lib/prop-types' - -import style from './dropdown.styl' - -const Dropdown = ({ className, children, larger, onItemsClick, open }) => { - const ref = useRef(null) - const [isBelow, setIsBelow] = useState(false) - const [isOnRight, setIsOnRight] = useState(false) - - const positionDropdown = useCallback(() => { - if (ref.current) { - const parentRect = ref.current.parentElement.getBoundingClientRect() - const spaceBelow = window.innerHeight - parentRect.bottom - const spaceAbove = parentRect.top - const dropdownHeight = ref.current.clientHeight - const dropdownWidth = ref.current.clientWidth - const spaceOnLeft = parentRect.left - - setIsBelow(spaceBelow > dropdownHeight || spaceAbove < dropdownHeight) - - setIsOnRight(spaceOnLeft > dropdownWidth) - } - }, []) - - useEffect(() => { - if (open) positionDropdown() - }, [positionDropdown, open]) - - useEffect(() => { - window.addEventListener('scroll', positionDropdown) - window.addEventListener('resize', positionDropdown) - - return () => { - window.removeEventListener('resize', positionDropdown) - window.removeEventListener('scroll', positionDropdown) - } - }, [positionDropdown]) - - return ( -
    - {children} -
- ) -} - -Dropdown.propTypes = { - children: PropTypes.node.isRequired, - className: PropTypes.string, - larger: PropTypes.bool, - onItemsClick: PropTypes.func, - open: PropTypes.bool.isRequired, -} - -Dropdown.defaultProps = { - className: undefined, - larger: false, - onItemsClick: () => null, -} - -const DropdownItem = ({ - active, - icon, - title, - path, - action, - exact, - showActive, - tabIndex, - external, - submenuItems, - ...rest -}) => { - const [expandedSubmenu, setExpandedSubmenu] = useState(false) - const iconElement = icon && - const activeClassName = classnames({ - [style.active]: (!Boolean(action) && showActive) || active, - }) - const cls = useCallback( - ({ isActive }) => classnames(style.button, { [activeClassName]: isActive }), - [activeClassName], - ) - const ItemElement = action ? ( - - ) : external ? ( - - {Boolean(iconElement) ? iconElement : null} - - - ) : ( - - {iconElement} - - - ) - - const handleMouseEnter = useCallback(() => { - setExpandedSubmenu(true) - }, [setExpandedSubmenu]) - - const handleMouseLeave = useCallback(() => { - setExpandedSubmenu(false) - }, [setExpandedSubmenu]) - - const withSubmenu = ( - - ) - - return ( -
  • - {Boolean(submenuItems) ? withSubmenu : ItemElement} -
  • - ) -} - -DropdownItem.propTypes = { - action: PropTypes.func, - active: PropTypes.bool, - exact: PropTypes.bool, - external: PropTypes.bool, - icon: PropTypes.string, - path: PropTypes.string, - showActive: PropTypes.bool, - submenuItems: PropTypes.arrayOf(PropTypes.node), - tabIndex: PropTypes.string, - title: PropTypes.message.isRequired, -} - -DropdownItem.defaultProps = { - active: false, - action: undefined, - exact: false, - external: false, - icon: undefined, - path: undefined, - showActive: true, - tabIndex: '0', - submenuItems: undefined, -} - -const DropdownHeaderItem = ({ title }) => ( -
  • - - - -
  • -) - -DropdownHeaderItem.propTypes = { - title: PropTypes.message.isRequired, -} - -Dropdown.Item = DropdownItem -Dropdown.HeaderItem = DropdownHeaderItem - -export default Dropdown diff --git a/pkg/webui/components/dropdown/dropdown.styl b/pkg/webui/components/dropdown/dropdown.styl index ef553c6f83..aa1b0e9207 100644 --- a/pkg/webui/components/dropdown/dropdown.styl +++ b/pkg/webui/components/dropdown/dropdown.styl @@ -1,4 +1,4 @@ -// Copyright © 2020 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,15 +13,47 @@ // limitations under the License. ul.dropdown - border-normal() - z-index: $zi.nav - right: 0 + font-size: $fs.m + border-radius: $br.l + border: 1px solid $c.grey-200 + list-style-type: none + background: $c.white + box-shadow: 0px 3px 16px 0px rgba(0, 0, 0, 0.06) position: absolute - background: white - padding: 0 + padding: $cs.s min-width: 14rem z-index: $zi.dropdown - margin: 0 + margin: $cs.xxs 0 0 + opacity: 0 + visibility: hidden + transition: opacity 0.2s ease-in-out, visibility 0s linear 0.2s + + &.open + opacity: 1 + visibility: visible + transition: opacity 0.2s ease-in-out, visibility 0s linear + + &.below + bottom: auto + top: calc(100% + 7px) + + &.above + top: auto + bottom: calc(100% + 7px) + + &.left + left: 0 + right: auto + + &.right + right: 0 + left: auto + + &.example + bottom: auto + top: 0 + left: 0 + right: auto &.larger li.dropdown-item @@ -29,9 +61,8 @@ ul.dropdown padding: $cs.l hr - margin-top: 0 - height: .1rem - background-color: $c-divider + height: 1px + background-color: $c.grey-200 li.dropdown-header-item display: block @@ -44,8 +75,8 @@ ul.dropdown padding: $cs.m li.dropdown-item - display: block margin-bottom: 0 + text-align: left button.button reset-button() @@ -53,25 +84,51 @@ ul.dropdown & > a.button, & > button.button box-sizing: border-box line-height: 1 - display: block + display: flex + align-items: center text-decoration: none - padding: $cs.m + padding: $cs.xs width: 100% + min-height: 2.429rem &:not(.active) - color: $tc-deep-gray + color: $c.grey-700 + + .icon + color: $c.grey-700 &.active - border-left: $c-active-blue 5px solid - color: $c-active-blue + border-radius: $br.m + background: $c.tts-primary-150 + transition: background 0.1s ease-in-out + color: $tc-deep-gray + + .icon + color: $tc-deep-gray &:hover - color: white + color: $tc-deep-gray + background: $c.tts-primary-150 + transition: background 0.1s ease-in-out + border-radius: $br.m .icon - color: white + color: $tc-deep-gray .icon margin-right: $cs.xs &:hover - background-color: $c-active-blue + color: $tc-deep-gray + text-decoration: none + + .submenu-container + bottom: 0px + left: 0px + position: absolute + width: 180% + height: 5rem + z-index: 9999 + + .submenu-dropdown + bottom: -0px !important + left: calc(100% + -213px) !important diff --git a/pkg/webui/components/dropdown/index.js b/pkg/webui/components/dropdown/index.js index 1a39a90e3a..8cf1d800ec 100644 --- a/pkg/webui/components/dropdown/index.js +++ b/pkg/webui/components/dropdown/index.js @@ -1,4 +1,4 @@ -// Copyright © 2020 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React, { useCallback } from 'react' +import React, { useCallback, useEffect, useRef, useState } from 'react' import classnames from 'classnames' import { NavLink } from 'react-router-dom' @@ -25,21 +25,64 @@ import PropTypes from '@ttn-lw/lib/prop-types' import style from './dropdown.styl' -const Dropdown = React.forwardRef(({ className, children, larger, onItemsClick }, ref) => ( -
      - {children} -
    -)) +const Dropdown = ({ className, children, larger, onItemsClick, open }) => { + const ref = useRef(null) + const [isBelow, setIsBelow] = useState(false) + const [isOnRight, setIsOnRight] = useState(false) + + const positionDropdown = useCallback(() => { + if (ref.current) { + const parentRect = ref.current.parentElement.getBoundingClientRect() + const spaceBelow = window.innerHeight - parentRect.bottom + const spaceAbove = parentRect.top + const dropdownHeight = ref.current.clientHeight + const dropdownWidth = ref.current.clientWidth + const spaceOnLeft = parentRect.left + + setIsBelow(spaceBelow > dropdownHeight || spaceAbove < dropdownHeight) + + setIsOnRight(spaceOnLeft > dropdownWidth) + } + }, []) + + useEffect(() => { + if (open) positionDropdown() + }, [positionDropdown, open]) + + useEffect(() => { + window.addEventListener('scroll', positionDropdown) + window.addEventListener('resize', positionDropdown) + + return () => { + window.removeEventListener('resize', positionDropdown) + window.removeEventListener('scroll', positionDropdown) + } + }, [positionDropdown]) + + return ( +
      + {children} +
    + ) +} Dropdown.propTypes = { children: PropTypes.node.isRequired, className: PropTypes.string, larger: PropTypes.bool, onItemsClick: PropTypes.func, + open: PropTypes.bool.isRequired, } Dropdown.defaultProps = { @@ -58,8 +101,10 @@ const DropdownItem = ({ showActive, tabIndex, external, + submenuItems, ...rest }) => { + const [expandedSubmenu, setExpandedSubmenu] = useState(false) const iconElement = icon && const activeClassName = classnames({ [style.active]: (!Boolean(action) && showActive) || active, @@ -90,9 +135,39 @@ const DropdownItem = ({ ) + + const handleMouseEnter = useCallback(() => { + setExpandedSubmenu(true) + }, [setExpandedSubmenu]) + + const handleMouseLeave = useCallback(() => { + setExpandedSubmenu(false) + }, [setExpandedSubmenu]) + + const withSubmenu = ( + + ) + return (
  • - {ItemElement} + {Boolean(submenuItems) ? withSubmenu : ItemElement}
  • ) } @@ -105,6 +180,7 @@ DropdownItem.propTypes = { icon: PropTypes.string, path: PropTypes.string, showActive: PropTypes.bool, + submenuItems: PropTypes.arrayOf(PropTypes.node), tabIndex: PropTypes.string, title: PropTypes.message.isRequired, } @@ -118,6 +194,7 @@ DropdownItem.defaultProps = { path: undefined, showActive: true, tabIndex: '0', + submenuItems: undefined, } const DropdownHeaderItem = ({ title }) => ( diff --git a/pkg/webui/components/dropdown-v2/story.js b/pkg/webui/components/dropdown/story.js similarity index 100% rename from pkg/webui/components/dropdown-v2/story.js rename to pkg/webui/components/dropdown/story.js diff --git a/pkg/webui/components/header-v2/story.js b/pkg/webui/components/header-v2/story.js index 5da2147ecc..4c48bbb031 100644 --- a/pkg/webui/components/header-v2/story.js +++ b/pkg/webui/components/header-v2/story.js @@ -16,7 +16,7 @@ import React from 'react' import TtsLogo from '@assets/static/tts-logo.svg' -import Dropdown from '@ttn-lw/components/dropdown-v2' +import Dropdown from '@ttn-lw/components/dropdown' import ExampleLogo from '@ttn-lw/components/logo/story-logo-new.svg' import Breadcrumb from '@ttn-lw/components/breadcrumbs/breadcrumb' diff --git a/pkg/webui/components/navigation/side-v2/item/index.js b/pkg/webui/components/navigation/side-v2/item/index.js index 454b689a29..b5ad39610a 100644 --- a/pkg/webui/components/navigation/side-v2/item/index.js +++ b/pkg/webui/components/navigation/side-v2/item/index.js @@ -15,7 +15,7 @@ import React, { useCallback, useEffect, useState } from 'react' import classnames from 'classnames' -import Dropdown from '@ttn-lw/components/dropdown-v2' +import Dropdown from '@ttn-lw/components/dropdown' import MenuLink from '@ttn-lw/components/sidebar/side-menu-link' import Button from '@ttn-lw/components/button' import Icon from '@ttn-lw/components/icon' diff --git a/pkg/webui/components/profile-dropdown-v2/index.js b/pkg/webui/components/profile-dropdown-v2/index.js index 4a79f00fd5..1515543001 100644 --- a/pkg/webui/components/profile-dropdown-v2/index.js +++ b/pkg/webui/components/profile-dropdown-v2/index.js @@ -16,7 +16,7 @@ import React, { useCallback, useRef, useState } from 'react' import classnames from 'classnames' import Icon from '@ttn-lw/components/icon' -import Dropdown from '@ttn-lw/components/dropdown-v2' +import Dropdown from '@ttn-lw/components/dropdown' import ProfilePicture from '@ttn-lw/components/profile-picture' import Button from '@ttn-lw/components/button' import style from '@ttn-lw/components/button-v2/button.styl' diff --git a/pkg/webui/components/profile-dropdown-v2/story.js b/pkg/webui/components/profile-dropdown-v2/story.js index dfbef0d5e4..a08ba25b67 100644 --- a/pkg/webui/components/profile-dropdown-v2/story.js +++ b/pkg/webui/components/profile-dropdown-v2/story.js @@ -14,7 +14,7 @@ import React from 'react' -import Dropdown from '@ttn-lw/components/dropdown-v2' +import Dropdown from '@ttn-lw/components/dropdown' import ExampleLogo from '@ttn-lw/components/logo/story-logo-new.svg' import ProfileDropdown from '.' diff --git a/pkg/webui/components/sidebar/side-footer/index.js b/pkg/webui/components/sidebar/side-footer/index.js index 7cd0f915ab..df57bfb492 100644 --- a/pkg/webui/components/sidebar/side-footer/index.js +++ b/pkg/webui/components/sidebar/side-footer/index.js @@ -16,7 +16,7 @@ import React, { useCallback, useContext, useRef } from 'react' import classnames from 'classnames' import Button from '@ttn-lw/components/button' -import Dropdown from '@ttn-lw/components/dropdown-v2' +import Dropdown from '@ttn-lw/components/dropdown' import { LanguageContext } from '@ttn-lw/lib/components/with-locale' From 4e0ec4095b5d0c609fc2c338e9bfa669a731ffa4 Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Wed, 27 Dec 2023 14:21:29 +0100 Subject: [PATCH 3/4] console: Remove old header --- .../components/breadcrumbs/breadcrumbs.styl | 1 - pkg/webui/components/header-v2/header-v2.styl | 26 ---- pkg/webui/components/header-v2/index.js | 110 ------------- pkg/webui/components/header-v2/story.js | 95 ------------ pkg/webui/components/header/header.styl | 127 +-------------- pkg/webui/components/header/index.js | 144 ++++++++---------- pkg/webui/components/header/story.js | 113 ++++++++------ .../components/profile-dropdown-v2/index.js | 2 +- pkg/webui/console/containers/header/index.js | 129 ++++------------ pkg/webui/console/views/app/index.js | 3 - 10 files changed, 163 insertions(+), 587 deletions(-) delete mode 100644 pkg/webui/components/header-v2/header-v2.styl delete mode 100644 pkg/webui/components/header-v2/index.js delete mode 100644 pkg/webui/components/header-v2/story.js diff --git a/pkg/webui/components/breadcrumbs/breadcrumbs.styl b/pkg/webui/components/breadcrumbs/breadcrumbs.styl index 0429d38e0f..8c23a52e43 100644 --- a/pkg/webui/components/breadcrumbs/breadcrumbs.styl +++ b/pkg/webui/components/breadcrumbs/breadcrumbs.styl @@ -28,6 +28,5 @@ display: none &-container - border-normal('bottom') box-sizing: border-box height: $breadcrumbs-bar-height diff --git a/pkg/webui/components/header-v2/header-v2.styl b/pkg/webui/components/header-v2/header-v2.styl deleted file mode 100644 index 4f555e5b5b..0000000000 --- a/pkg/webui/components/header-v2/header-v2.styl +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. -// -// 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. - -.container - padding: 0 $cs.m - background: $c['tts-primary-050'] - z-index: $zi.nav - border-bottom: 1px solid $c-divider - display: flex - justify-content: space-between - align-items: center - height: 4rem - -.logo - height: $cs.l diff --git a/pkg/webui/components/header-v2/index.js b/pkg/webui/components/header-v2/index.js deleted file mode 100644 index dd31c4afe6..0000000000 --- a/pkg/webui/components/header-v2/index.js +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. -// -// 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 React, { useRef } from 'react' -import classnames from 'classnames' - -import { Breadcrumbs } from '@ttn-lw/components/breadcrumbs/breadcrumbs' -import Button from '@ttn-lw/components/button' -import ProfileDropdown from '@ttn-lw/components/profile-dropdown-v2' -import Link from '@ttn-lw/components/link' - -import PropTypes from '@ttn-lw/lib/prop-types' - -import style from './header-v2.styl' - -const Header = ({ - brandLogo, - logo, - breadcrumbs, - className, - addDropdownItems, - starDropdownItems, - profileDropdownItems, - user, - onMenuClick, - ...rest -}) => { - const addRef = useRef(null) - const starRef = useRef(null) - - // Const isGuest = !Boolean(user) - - return ( -
    - -
    -
    - -
    -
    -
    - ) -} - -const imgPropType = PropTypes.shape({ - src: PropTypes.string.isRequired, - alt: PropTypes.string.isRequired, -}) - -Header.propTypes = { - /** The dropdown items when the add button is clicked. */ - addDropdownItems: PropTypes.node.isRequired, - brandLogo: imgPropType, - /** A list of breadcrumb elements. */ - breadcrumbs: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.element])) - .isRequired, - /** The classname applied to the component. */ - className: PropTypes.string, - logo: imgPropType.isRequired, - /** A handler for when the menu button is clicked. */ - onMenuClick: PropTypes.func.isRequired, - /** The dropdown items when the profile button is clicked. */ - profileDropdownItems: PropTypes.node.isRequired, - /** The dropdown items when the star button is clicked. */ - starDropdownItems: PropTypes.node.isRequired, - /** - * The User object, retrieved from the API. If it is `undefined`, then the - * guest header is rendered. - */ - user: PropTypes.user, -} - -Header.defaultProps = { - className: undefined, - user: undefined, - brandLogo: undefined, -} - -export default Header diff --git a/pkg/webui/components/header-v2/story.js b/pkg/webui/components/header-v2/story.js deleted file mode 100644 index 4c48bbb031..0000000000 --- a/pkg/webui/components/header-v2/story.js +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. -// -// 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 React from 'react' - -import TtsLogo from '@assets/static/tts-logo.svg' - -import Dropdown from '@ttn-lw/components/dropdown' -import ExampleLogo from '@ttn-lw/components/logo/story-logo-new.svg' -import Breadcrumb from '@ttn-lw/components/breadcrumbs/breadcrumb' - -import Header from '.' - -const user = { - name: 'johndoe', - ids: { - user_id: 'jdoe300', - }, -} - -export default { - title: 'Header V2', -} - -const plusDropdownItems = ( - <> - - - - - -) - -const starDropdownItems = ( - <> - - - - - - - -) - -const profileDropdownItems = ( - <> - - - - -
    - - - -
    - - -) - -export const Default = () => { - const breadcrumbs = [ - , - , - , - ] - - return ( -
    -
    -
    - ) -} diff --git a/pkg/webui/components/header/header.styl b/pkg/webui/components/header/header.styl index 9433fef1fb..4f555e5b5b 100644 --- a/pkg/webui/components/header/header.styl +++ b/pkg/webui/components/header/header.styl @@ -1,4 +1,4 @@ -// Copyright © 2019 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,128 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -mobile-styles($breakpoint) - +media-query($breakpoint) - &.mobile-menu-open - position: fixed - z-index: $zi.mobile-menu - top: 0 - left: 0 - height: 100vh - background-color: white - - .hamburger img - width: 1.5rem - - .mobile-menu-button - display: block - - .nav-list - display: none - - .profile-dropdown - display: none - - .mobile-menu - display: flex - - +media-query-between($bp.s, $breakpoint) - .mobile-menu - height: 'calc(100vh - %s)' % $header-height - - +media-query($bp.s) - z-index: $zi.mobile-menu - position: fixed - top: 0 - - & + main - padding-top: $header-height - +media-query($bp.s) - padding-top: $header-height-mobile - - .bar - height: $header-height-mobile - background-color: white - padding: 0 $ls.xxs - - .mobile-menu - height: 'calc(100vh - %s)' % $header-height-mobile - top: $header-height-mobile - - .mobile-menu-button - width: $header-height-mobile - margin-right: $ls.xxs * -1 - .container - mobile-styles($bp.m) - background-color: white + padding: 0 $cs.m + background: $c['tts-primary-050'] z-index: $zi.nav - width: 100% - -.bar - border-normal('bottom') - background: linear-gradient(bottom left, 0% #F8F8F8, 60% white) // @stylint ignore - height: $header-height - box-sizing: border-box - position: relative + border-bottom: 1px solid $c-divider display: flex - padding: 0 $ls.s justify-content: space-between - flex: none - -.logo - display: inline-flex align-items: center - justify-content: flex-start + height: 4rem - img - nudge('up') - -.nav-list - display: flex - align-items: stretch - justify-content: flex-start - padding: 0 $ls.m - flex-grow: 2 - height: 100% - max-width: 56rem - flex-shrink: 0 - -.profile-dropdown - margin-right: -2rem - -.mobile-menu-button - reset-button() - display: none - width: $header-height - margin-right: $ls.s * -1 - height: 100% - position: relative - - .hamburger - center-absolute() - display: block - width: 2rem - height: 100% - - img - center-absolute() - width: 2rem - -.left - display: flex - align-items: center - max-width: 42rem - flex-grow: 1 - -.right - padding-left: $cs.l - display: flex - align-items: center - justify-content: flex-end - max-width: 25rem - flex-grow: 2 - - & > div:first-child - max-width: 15rem - border-color: $c-divider-dark +.logo + height: $cs.l diff --git a/pkg/webui/components/header/index.js b/pkg/webui/components/header/index.js index d7af0b5d8a..95f1aa0723 100644 --- a/pkg/webui/components/header/index.js +++ b/pkg/webui/components/header/index.js @@ -1,4 +1,4 @@ -// Copyright © 2019 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,107 +12,88 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React, { useState, useCallback } from 'react' +import React, { useRef } from 'react' import classnames from 'classnames' -import hamburgerMenuNormal from '@assets/misc/hamburger-menu-normal.svg' -import hamburgerMenuClose from '@assets/misc/hamburger-menu-close.svg' - -import NavigationBar from '@ttn-lw/components/navigation/bar' -import ProfileDropdown from '@ttn-lw/components/profile-dropdown' -import MobileMenu from '@ttn-lw/components/mobile-menu' -import Input from '@ttn-lw/components/input' +import { Breadcrumbs } from '@ttn-lw/components/breadcrumbs/breadcrumbs' +import Button from '@ttn-lw/components/button' +import ProfileDropdown from '@ttn-lw/components/profile-dropdown-v2' +import Link from '@ttn-lw/components/link' import PropTypes from '@ttn-lw/lib/prop-types' import style from './header.styl' const Header = ({ + brandLogo, + logo, + breadcrumbs, className, - dropdownItems, - navigationEntries, + addDropdownItems, + starDropdownItems, + profileDropdownItems, user, - searchable, - logo, - mobileDropdownItems, - onLogout, - onSearchRequest, + onMenuClick, ...rest }) => { - const isGuest = !Boolean(user) - - const [mobileMenuOpen, setMobileMenuOpen] = useState(false) - const handleMobileMenuClick = useCallback(() => { - setMobileMenuOpen(!mobileMenuOpen) - }, [mobileMenuOpen]) - - const handleMobileMenuItemsClick = useCallback(() => { - setMobileMenuOpen(false) - }, []) + const addRef = useRef(null) + const starRef = useRef(null) - const classNames = classnames(className, style.container, { - [style.mobileMenuOpen]: mobileMenuOpen, - }) - - const hamburgerGraphic = mobileMenuOpen ? hamburgerMenuClose : hamburgerMenuNormal + // Const isGuest = !Boolean(user) return ( -
    -
    -
    - {logo} - {!isGuest && {navigationEntries}} -
    - {!isGuest && ( -
    - {searchable && } - - {dropdownItems} - - -
    - )} +
    +
    +
    +
    - {mobileMenuOpen && ( - +
    ) } +const imgPropType = PropTypes.shape({ + src: PropTypes.string.isRequired, + alt: PropTypes.string.isRequired, +}) + Header.propTypes = { + /** The dropdown items when the add button is clicked. */ + addDropdownItems: PropTypes.node.isRequired, + brandLogo: imgPropType, + /** A list of breadcrumb elements. */ + breadcrumbs: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.element])) + .isRequired, /** The classname applied to the component. */ className: PropTypes.string, - /** The child node of the dropdown component. */ - dropdownItems: PropTypes.node, - /** The logo component. */ - logo: PropTypes.node.isRequired, - /** The child node of the mobile dropdown. */ - mobileDropdownItems: PropTypes.node, - /** The Child node of the navigation bar. */ - navigationEntries: PropTypes.node, - /** A handler for when the user used the search input. */ - onLogout: PropTypes.func, - /** Handler of the search function. */ - onSearchRequest: PropTypes.func, - /* A flag indicating whether the header has a search input. */ - searchable: PropTypes.bool, + logo: imgPropType.isRequired, + /** A handler for when the menu button is clicked. */ + onMenuClick: PropTypes.func.isRequired, + /** The dropdown items when the profile button is clicked. */ + profileDropdownItems: PropTypes.node.isRequired, + /** The dropdown items when the star button is clicked. */ + starDropdownItems: PropTypes.node.isRequired, /** * The User object, retrieved from the API. If it is `undefined`, then the * guest header is rendered. @@ -122,13 +103,8 @@ Header.propTypes = { Header.defaultProps = { className: undefined, - dropdownItems: undefined, - navigationEntries: undefined, - mobileDropdownItems: null, - onSearchRequest: () => null, - onLogout: () => null, - searchable: false, user: undefined, + brandLogo: undefined, } export default Header diff --git a/pkg/webui/components/header/story.js b/pkg/webui/components/header/story.js index 3d1610df6c..4c48bbb031 100644 --- a/pkg/webui/components/header/story.js +++ b/pkg/webui/components/header/story.js @@ -1,4 +1,4 @@ -// Copyright © 2019 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 The Things Network Foundation, The Things Industries B.V. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,70 +13,83 @@ // limitations under the License. import React from 'react' -import { action } from '@storybook/addon-actions' -import TtsLogo from '@assets/static/logo.svg' +import TtsLogo from '@assets/static/tts-logo.svg' import Dropdown from '@ttn-lw/components/dropdown' -import NavigationBar from '@ttn-lw/components/navigation/bar' -import Logo from '@ttn-lw/components/logo' -import ExampleLogo from '@ttn-lw/components/logo/story-logo.svg' +import ExampleLogo from '@ttn-lw/components/logo/story-logo-new.svg' +import Breadcrumb from '@ttn-lw/components/breadcrumbs/breadcrumb' import Header from '.' const user = { - name: 'kschiffer', + name: 'johndoe', ids: { - user_id: 'ksc300', + user_id: 'jdoe300', }, } -const singleLogo = -const doubleLogo = ( - -) +export default { + title: 'Header V2', +} -const navigationEntries = ( - - - - - - +const plusDropdownItems = ( + <> + + + + + ) -const items = ( - - - - +const starDropdownItems = ( + <> + + + + + + + ) -export default { - title: 'Header', -} - -export const SingleLogo = () => ( -
    +const profileDropdownItems = ( + <> + + + + +
    + + + +
    + + ) -export const DoubleLogo = () => ( -
    -) +export const Default = () => { + const breadcrumbs = [ + , + , + , + ] + + return ( +
    +
    +
    + ) +} diff --git a/pkg/webui/components/profile-dropdown-v2/index.js b/pkg/webui/components/profile-dropdown-v2/index.js index 1515543001..760e6327cf 100644 --- a/pkg/webui/components/profile-dropdown-v2/index.js +++ b/pkg/webui/components/profile-dropdown-v2/index.js @@ -19,7 +19,7 @@ import Icon from '@ttn-lw/components/icon' import Dropdown from '@ttn-lw/components/dropdown' import ProfilePicture from '@ttn-lw/components/profile-picture' import Button from '@ttn-lw/components/button' -import style from '@ttn-lw/components/button-v2/button.styl' +import style from '@ttn-lw/components/button/button.styl' import PropTypes from '@ttn-lw/lib/prop-types' diff --git a/pkg/webui/console/containers/header/index.js b/pkg/webui/console/containers/header/index.js index 8bbb7283fc..55f5d05c40 100644 --- a/pkg/webui/console/containers/header/index.js +++ b/pkg/webui/console/containers/header/index.js @@ -16,11 +16,11 @@ import React, { useCallback } from 'react' import { useDispatch, useSelector } from 'react-redux' import HeaderComponent from '@ttn-lw/components/header' -import NavigationBar from '@ttn-lw/components/navigation/bar' import Dropdown from '@ttn-lw/components/dropdown' import PropTypes from '@ttn-lw/lib/prop-types' import sharedMessages from '@ttn-lw/lib/shared-messages' +import { selectAssetsRootPath, selectBrandingRootPath } from '@ttn-lw/lib/selectors/env' import selectAccountUrl from '@console/lib/selectors/app-config' import { @@ -39,12 +39,11 @@ import Logo from '../logo' const accountUrl = selectAccountUrl() -const Header = ({ searchable, handleSearchRequest }) => { +const Header = () => { const dispatch = useDispatch() const handleLogout = useCallback(() => dispatch(logout()), [dispatch]) const user = useSelector(selectUser) - const isUserAdmin = useSelector(selectUserIsAdmin) const mayViewApps = useSelector(state => user ? checkFromState(mayViewApplications, state) : false, ) @@ -56,40 +55,26 @@ const Header = ({ searchable, handleSearchRequest }) => { user ? checkFromState(mayViewOrEditApiKeys, state) : false, ) - const navigation = [ - { - title: sharedMessages.overview, - icon: 'overview', - path: '', - exact: true, - hidden: !mayViewApps && !mayViewGateways, - }, - { - title: sharedMessages.applications, - icon: 'application', - path: '/applications', - hidden: !mayViewApps, - }, - { - title: sharedMessages.gateways, - icon: 'gateway', - path: '/gateways', - hidden: !mayViewGtws, - }, - { - title: sharedMessages.organizations, - icon: 'organization', - path: '/organizations', - hidden: !mayViewOrgs, - }, - ] - - const navigationEntries = ( - - {navigation.map( - ({ hidden, ...rest }) => !hidden && , + const plusDropdownItems = ( + <> + {mayViewApps && ( + )} - + {mayViewGtws && } + {mayViewOrgs && ( + + )} + + + ) const dropdownItems = ( @@ -126,74 +111,24 @@ const Header = ({ searchable, handleSearchRequest }) => { ) - const mobileDropdownItems = ( - - {navigation.map( - ({ hidden, ...rest }) => !hidden && , - )} - -
    - -
    - {mayHandleApiKeys && ( - - )} - {isUserAdmin && ( - - )} -
    - - -
    - ) + const hasCustomBranding = selectBrandingRootPath() !== selectAssetsRootPath() + const brandLogo = hasCustomBranding + ? { + src: `${selectBrandingRootPath()}/logo.svg`, + alt: 'Logo', + } + : undefined return ( } /> ) } -Header.propTypes = { - /** A handler for when the user used the search input. */ - handleSearchRequest: PropTypes.func, - /** A flag identifying whether the header should display the search input. */ - searchable: PropTypes.bool, -} - -Header.defaultProps = { - handleSearchRequest: () => null, - searchable: false, -} - export default Header diff --git a/pkg/webui/console/views/app/index.js b/pkg/webui/console/views/app/index.js index f2d8c6819c..4b14826288 100644 --- a/pkg/webui/console/views/app/index.js +++ b/pkg/webui/console/views/app/index.js @@ -141,10 +141,7 @@ const Layout = () => { rights={rights} isAdmin={isAdmin} > -
    -