From b5014b0012e63774f52f2f73a96af81539f0d4c9 Mon Sep 17 00:00:00 2001 From: fritzSF Date: Mon, 12 Feb 2024 15:49:21 +0100 Subject: [PATCH 1/4] New navigation (#760) --- assets/styles/app.scss | 1 + assets/styles/breakpoints.scss | 6 + assets/styles/custom-display.scss | 4 + assets/styles/custom-variables.scss | 22 +- assets/styles/index.scss | 259 +------------------ assets/styles/sidenav.scss | 355 ++++++++++++++++++++++++++ assets/ui/components/ToolTip.tsx | 4 +- design_app/src/components/SideNav.jsx | 100 +++++--- design_app/src/index.js | 4 +- newsroom/templates/base_layout.html | 52 ++-- newsroom/templates/sidenav_icon.html | 28 +- 11 files changed, 500 insertions(+), 335 deletions(-) create mode 100644 assets/styles/sidenav.scss diff --git a/assets/styles/app.scss b/assets/styles/app.scss index d4270979d..4d9a0dba5 100644 --- a/assets/styles/app.scss +++ b/assets/styles/app.scss @@ -2,6 +2,7 @@ @import './color-functions.scss'; @import './custom.scss'; // Bootstrap customized @import './index.scss'; +@import './sidenav.scss'; @import './article-list.scss'; @import './icon-font.scss'; @import './icon-font-small.scss'; diff --git a/assets/styles/breakpoints.scss b/assets/styles/breakpoints.scss index 755dc9f1b..532beb73b 100644 --- a/assets/styles/breakpoints.scss +++ b/assets/styles/breakpoints.scss @@ -61,6 +61,12 @@ } } +@mixin large_phone { + @media only screen and (max-width: 768px) { + @content; + } +} + @mixin tablet { @media only screen and (orientation: portrait) and (min-width: 576px) and (max-width: 1439px), (orientation: landscape) and (min-width: 992px) and (max-width: 1439px) { @content; diff --git a/assets/styles/custom-display.scss b/assets/styles/custom-display.scss index d6129a07c..a63895b73 100644 --- a/assets/styles/custom-display.scss +++ b/assets/styles/custom-display.scss @@ -29,6 +29,10 @@ .d-phone-none {display: none;} .d-phone-block {display: block;} } +@include large_phone { + .d-phone-none {display: none;} + .d-phone-block {display: block;} +} @include tablet { .d-tablet-none {display: none;} diff --git a/assets/styles/custom-variables.scss b/assets/styles/custom-variables.scss index 847880db0..5ab96ce49 100644 --- a/assets/styles/custom-variables.scss +++ b/assets/styles/custom-variables.scss @@ -404,6 +404,7 @@ $container-max-widths: ( --sidenav-color-bg: var(--color-primary); --sidenav-color-item-bg: transparent; --sidenav-color-item-fg: hsla(0, 0%, 100%, 1); + --sidenav-color-item-bg--hover: hsla(0, 0%, 0%, 0.16); --sidenav-color-item-bg--active: hsla(0, 0%, 100%, 1); --sidenav-color-item-fg--active: var(--color-primary); --sidenav-color-badge-bg: hsla(0, 0%, 16%, 1); @@ -411,18 +412,29 @@ $container-max-widths: ( --sidenav-color-badge-fg: hsla(0, 0%, 98%, 1); --sidenav-color-badge-fg--active: hsla(0, 0%, 98%, 1); --sidenav-color-badge-outline--active: var(--sidenav-color-item-bg--active); + --sidenav-item-size: var(--space--5); + --sidenav-item-font-size: 0.875rem; --sidenav-item-badge-size: 1.25rem; --sidenav-item-badge-font-size: 0.6875rem; - --sidenav-item-helper-icon-size: 1.25rem; + --sidenav-item-helper-icon-size: 1.125rem; --sidenav-item-helper-icon-fg: var(--sidenav-color-bg); --sidenav-item-border-radius: var(--border-radius--s); --separator-dot-size: 3px; --separator-dot-color-bg: var(--sidenav-color-item-fg); // Title and size options - --sidenav-item-title-display: block; // set to none to hide the title - --sidenav-size-width: 80px; // width of the sidenav on desktop - --sidenav-item-gap: 8px; // left and right spacing between item and the bar on desktop - --sidenav-item-width: calc(var(--sidenav-size-width) - var(--sidenav-item-gap)); // width of the sidenav item on desktop + //--sidenav-item-title-display: block; // set to none to hide the title + // --sidenav-size-width: 56px; // width of the sidenav on desktop + // --sidenav-item-gap: 8px; // left and right spacing between item and the bar on desktop + // --sidenav-item-width: calc(var(--sidenav-size-width) - var(--sidenav-item-gap)); // width of the sidenav item on desktop + --sidenav-item-radius: var(--border-radius--s); + --sidenav-size: 3.5rem; + --sidenav-size-overlay: 14rem; + --sidenav-size-pinned: 14rem; + --sidenav-shadow-overlay: 4px 0 8px hsla(0, 0%, 0%, 0.24); + --sidenav-pin-button-color-bg-default: hsla(0, 0%, 16%, 0.2); + --sidenav-pin-button-color-bg-hover: hsla(0, 0%, 100%, 0.8); + --sidenav-pin-button-color-fg-default: hsla(0, 0%, 100%, 1); + --sidenav-pin-button-color-fg-hover: var(--color-primary); // COMPONENT: PROFILE MODAL --profile-header-height: 56px; diff --git a/assets/styles/index.scss b/assets/styles/index.scss index a89fc40be..e594fefc4 100644 --- a/assets/styles/index.scss +++ b/assets/styles/index.scss @@ -363,259 +363,6 @@ body.print { overflow: auto; } -.sidenav { - flex: 0 0 var(--navbar-height--mobile); - background-color: var(--sidenav-color-bg); - position: relative; - padding: 0 4px; - display: flex; - overflow-y: auto; - - &:dir(rtl) { - box-shadow: inset 3px 0px 8px rgba(0, 0, 0, 0.1); - } - - @include phone { - padding: 0 2px; - overflow-y: hidden; - } - @include md { - flex: 0 0 var(--sidenav-size-width); - } -} - -.sidenav-icons { - display: flex; - flex-direction: row; - margin: 0 auto; - gap: var(--space--0-5); - width: 100vw; - padding: 0; - list-style-type: none; - - @include md { - padding-block-start: var(--space--1); - flex-direction: column; - overflow: visible; - width: auto; - } - - - .sidenav-icons__item { - margin: 4px 0; - align-self: stretch; - position: relative; - display: flex !important; - justify-content: center; - a { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - gap: 2px; - &:hover { - text-decoration: none; - } - @include sm { - gap: 4px; - } - - - } - a, span { - border-radius: var(--sidenav-item-border-radius); - text-decoration: none; - width: 40px; - height: calc(var(--navbar-height--mobile) - var(--space--1)); - min-height: auto; - padding: 2px 0; - line-height: var(--navbar-height--mobile); - text-align: center; - background-color: var(--sidenav-color-item-bg); - - @include md { - width: var(--sidenav-item-width); - min-height: var(--navbar-height); - line-height: var(--navbar-height); - height: auto; - } - &:focus { - outline: none; - } - &:focus-visible { - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.6), 0 0 3px 4px rgba(255, 255, 255, .7); - } - i.icon--more { - opacity: .3; - @include sm { - transform: rotate(90deg); - } - } - } - span { - display: block; - min-height: 34px; - line-height: 34px; - @include phone { - width: 20px; - height: 24px; - line-height: 50px; - } - } - .sidenav-icons__item-title { - display: none; - color: var(--sidenav-color-item-fg); - font-size: 10px; - font-weight: 700; - line-height: 1; - letter-spacing: 0.3px; - text-transform: uppercase; - overflow-wrap: break-word; - align-self: stretch; - @include md { - display: var(--sidenav-item-title-display); - } - } - .badge { - background-color: var(--sidenav-color-badge-bg); - color: var(--sidenav-color-badge-fg); - outline: 2px solid var(--sidenav-color-bg); - &.badge--icon { - background-color: var(--sidenav-color-item-bg--active); - [class^="icon-small--"], - [class^="icon-small--"] { - color: var(--sidenav-color-item-fg--active) !important; - } - } - } - .sidenav-icons__badge, - .sidenav-icons__helper-icon { - position: absolute; - font-size: var(--sidenav-item-badge-font-size); - display: flex; - align-items: center; - justify-content: center; - border-radius: var(--border-radius--full); - background-color: var(--sidenav-color-badge-bg); - color: var(--sidenav-color-badge-fg); - outline: 2px solid var(--sidenav-color-bg); - } - .sidenav-icons__badge { - height: var(--sidenav-item-badge-size); - min-width: var(--sidenav-item-badge-size); - font-size: var(--sidenav-item-badge-font-size); - font-weight: 700; - line-height: 1; - inset-block-start: 3px; - inset-inline-end: 3px; - background-color: var(--sidenav-color-badge-bg); - color: var(--sidenav-color-badge-fg); - padding: 0.35em 0.6em; - &:empty { - display: none; - } - @include phone { - inset-block-start: 2px; - inset-inline-end: -4px; - } - } - - .sidenav-icons__helper-icon { - height: var(--sidenav-item-helper-icon-size); - width: var(--sidenav-item-helper-icon-size); - background-color: var(--sidenav-color-item-fg); - color: var(--sidenav-item-helper-icon-fg); - padding: 0; - inset-block-start: 2px; - inset-inline-end: 8px; - [class^="icon-small--"], - [class^="icon-small--"] { - color: var(--sidenav-item-helper-icon-fg) !important; - } - @include phone { - inset-block-start: 2px; - inset-inline-end: -4px; - } - } - - &.active { - .sidenav-icons__badge { - outline: 2px solid var(--sidenav-color-badge-outline--active); - background-color: var(--sidenav-color-badge-bg--active); - color: var(--sidenav-color-badge-fg--active); - } - - a { - background-color: var(--sidenav-color-item-bg--active); - border-radius: 4px; - text-decoration: none; - } - i, .sidenav-icons__item-title { - color: var(--sidenav-color-item-fg--active); - } - } - .badge--icon { - inset-block-start: 2px; - inset-inline-end: 7px; - } - [class^="icon--"], [class*=" icon--"] { - color: var(--sidenav-color-item-fg); - } - &--report { - position: absolute; - inset-block-end: 0; - inset-inline-start: auto; - inset-inline-end: 50px; - @include sm { - inset-inline-start: auto; - inset-inline-end: auto; - inset-block-end: 56px; - } - } - &--admin { - position: absolute; - inset-block-end: 0; - inset-inline-start: auto; - inset-inline-end: 4px; - - @include sm { - inset-inline-end: auto; - } - } - } - .sidenav-icons__stretch-separator { - flex-grow: 1; - align-self: stretch; - justify-self: stretch; - margin: auto; - } - .sidenav-icons__separator { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - flex-grow: 0; - flex-shrink: 0; - gap: calc(var(--separator-dot-size) * 1); - margin-block: auto; - margin-inline: var(--space--0-5); - .separator__dot { - border-radius: var(--border-radius--full); - display: block; - height: var(--separator-dot-size); - width: var(--separator-dot-size); - background-color: var(--separator-dot-color-bg); - opacity: 0.4; - } - @include md { - flex-direction: row; - margin-block: var(--space--1-5); - gap: calc(var(--separator-dot-size) * 1.5); - } - - } -} - .content-header { position: relative; } @@ -624,7 +371,7 @@ body.print { position: relative; } -.divider:after{ +.divider:after { content: ""; position: absolute; height: 0px; @@ -4415,3 +4162,7 @@ article.list { color: var(--color-text--muted); font-size: inherit; } + +.tooltip { + pointer-events: none; +} diff --git a/assets/styles/sidenav.scss b/assets/styles/sidenav.scss new file mode 100644 index 000000000..c1095dba9 --- /dev/null +++ b/assets/styles/sidenav.scss @@ -0,0 +1,355 @@ +.nav-block { + --pin-button-inset-end: 3.125rem; + --sidenav-transition: .3s ease; + background-color: var(--sidenav-color-bg); + position: relative; + overflow: visible; + z-index: 200; + transition: all var(--sidenav-transition); + flex: 0 0 var(--sidenav-size); + + &:dir(rtl) { + box-shadow: inset 3px 0px 8px rgba(0, 0, 0, 0.1); + } + + @include large_phone { + padding: 0 2px; + overflow-y: hidden; + flex: 0 0 var(--navbar-height--mobile); + + .sidenav { + flex-direction: row; + padding-block-start: var(--space--0-5); + padding-block-end: 0 ; + padding-inline-start: var(--space--0-5); + padding-inline-end: 0 !important; + gap: var(--space--0-5); + height: var(--navbar-height--mobile); + overflow-x: auto; + position: static; + width: 100% !important; + .sidenav__item { + position: relative; + height: var(--sidenav-item-size); + + a, .sidenav__item-button { + height: var(--sidenav-item-size); + width: var(--sidenav-item-size); + gap: 0; + flex-grow: 0; + flex-shrink: 0; + flex-direction: column; + } + .sidenav__badge { + inset-block-start: -2px; + inset-inline-end: -5px; + } + .sidenav__helper-icon { + inset-block-start: 0; + inset-inline-end: 0; + } + .sidenav__item-title { + position: absolute; + opacity: 0 !important; + width: 0 !important; + inset-block-start: -1000px; + font-size: 0.1px; + line-height: 1; + flex-grow: 0; + flex-shrink: 1; + } + } + .nav-block__pin-button { + display: none !important; + } + } + } + + + &.nav-block--pinned { + flex: 0 0 var(--sidenav-size-pinned); + padding-inline-end: var(--space--1-5); + .sidenav { + width: 100%; + box-shadow: none; + padding-inline-end: var(--space--1-5); + .sidenav__item-title { + opacity: 1; + width: 100%; + padding-inline-end: var(--space--2); + } + .nav-block__pin-button { + transform: translateX(calc(var(--sidenav-size-pinned) - var(--pin-button-inset-end))); + [class^="icon--"], [class*=" icon--"] { + transform: rotate(180deg); + } + } + } + @include large_phone { + flex: 0 0 var(--navbar-height--mobile) !important; + padding-inline-end: 0; + .sidenav { + height: var(--navbar-height--mobile); + } + } + } +} + +.sidenav { + z-index: 1; + padding: 0; + padding-block-start: var(--space--5); + padding-block-end: var(--space--2); + padding-inline: var(--space--1); + display: flex; + flex-direction: column; + margin: 0; + gap: var(--space--1); + list-style-type: none; + background-color: var(--sidenav-color-bg); + + position: absolute; + z-index: 100; + inset-block: 0; + inset-inline-start: 0; + + width: var(--sidenav-size); + min-width: var(--sidenav-size); + transition: all var(--sidenav-transition); + overflow-y: auto; + + .sidenav__item-icon { + --icon-block-radius: var(--sidenav-item-radius); + --icon-block-size: var(--sidenav-item-size); + position: relative; + background-color: transparent; + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + border-radius: var(--icon-block-radius); + height: var(--icon-block-size); + width: var(--icon-block-size); + transition: all var(--sidenav-transition); + } + + .sidenav__item-title { + opacity: 0; + width: 0; + color: var(--sidenav-color-item-fg); + font-size: var(--sidenav-item-font-size); + line-height: 1.1; + font-weight: 400; + overflow-wrap: break-word; + flex-grow: 1; + flex-shrink: 1; + transition: all var(--sidenav-transition); + overflow: hidden !important; + white-space: nowrap; + } + + .nav-block__pin-button { + --pin-button-size: 1.5rem; + background-color: var(--sidenav-pin-button-color-bg-default); + height: var(--pin-button-size); + width: var(--pin-button-size); + border-radius: var(--border-radius--full); + display: flex; + align-items: center; + justify-content: center; + z-index: 2; + border: none; + opacity: 0.6; + position: absolute; + inset-block-start: var(--space--1-5); + inset-inline-start: var(--space--2); + transform: translateX(0); + transition: all 0.5s ease; + + [class^="icon--"], [class*=" icon--"] { + --icon-size: 18px; + color: var(--sidenav-pin-button-color-fg-default); + } + + &:hover { + background-color: var(--sidenav-pin-button-color-bg-hover); + opacity: 1; + [class^="icon--"], [class*=" icon--"] { + color: var(--sidenav-pin-button-color-fg-hover); + } + } + &:active { + border: 2px solid var(--sidenav-color-bg); + } + &:focus { + outline: none; + } + &:focus-visible { + box-shadow: inset 0 0 0 1px hsla(0, 0%, 0%, 0.4), 0 0 2px 3px hsla(0, 0%, 100%, 0.5); + } + } + + &:hover { + width: var(--sidenav-size-overlay); + box-shadow: var(--sidenav-shadow-overlay); + padding-inline-end: var(--space--1-5); + .sidenav__item-title { + opacity: 1; + width: 100%; + padding-inline-end: var(--space--3); + } + + .nav-block__pin-button { + opacity: 1; + transform: translateX(calc(var(--sidenav-size-overlay) - var(--pin-button-inset-end))); + } + } + + .sidenav__item { + position: relative; + border-radius: var(--sidenav-item-border-radius); + transition: all var(--sidenav-transition); + &:hover { + background-color: var(--sidenav-color-item-bg--hover); + } + + a, + .sidenav__item-button { + border-radius: var(--sidenav-item-border-radius); + text-decoration: none; + height: var(--sidenav-item-size); + position: relative; + display: flex; + align-items: center; + justify-content: flex-start; + min-height: auto; + gap: var(--space--1); + flex-grow: 1; + flex-shrink: 1; + &:hover { + text-decoration: none; + } + &:focus { + outline: none; + } + &:focus-visible { + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.6), 0 0 3px 4px rgba(255, 255, 255, .7); + } + } + + .badge { + background-color: var(--sidenav-color-badge-bg); + color: var(--sidenav-color-badge-fg); + outline: 2px solid var(--sidenav-color-bg); + &.badge--icon { + background-color: var(--sidenav-color-item-bg--active); + [class^="icon-small--"], + [class^="icon-small--"] { + color: var(--sidenav-color-item-fg--active) !important; + } + } + } + .sidenav__badge, + .sidenav__helper-icon { + position: absolute; + font-size: var(--sidenav-item-badge-font-size); + display: flex; + align-items: center; + justify-content: center; + border-radius: var(--border-radius--full); + background-color: var(--sidenav-color-badge-bg); + color: var(--sidenav-color-badge-fg); + outline: 2px solid var(--sidenav-color-bg); + z-index: 1; + } + .sidenav__badge { + height: var(--sidenav-item-badge-size); + min-width: var(--sidenav-item-badge-size); + font-size: var(--sidenav-item-badge-font-size); + font-weight: 700; + line-height: 1; + inset-block-start: -7px; + inset-inline-end: -4px; + background-color: var(--sidenav-color-badge-bg); + color: var(--sidenav-color-badge-fg); + padding: 0.35em 0.6em; + &:empty { + display: none; + } + } + + .sidenav__helper-icon { + height: var(--sidenav-item-helper-icon-size); + width: var(--sidenav-item-helper-icon-size); + background-color: var(--sidenav-color-item-fg); + color: var(--sidenav-item-helper-icon-fg); + padding: 0; + inset-block-start: 0; + inset-inline-end: 0; + [class^="icon-small--"], + [class^="icon-small--"] { + color: var(--sidenav-item-helper-icon-fg) !important; + } + } + + &.active { + .sidenav__badge { + outline: none; + box-shadow: -2px 4px 0 -2px var(--sidenav-color-badge-outline--active); + background-color: var(--sidenav-color-badge-bg--active); + color: var(--sidenav-color-badge-fg--active); + } + + a { + background-color: var(--sidenav-color-item-bg--active); + border-radius: 4px; + text-decoration: none; + } + [class^="icon--"], + [class*=" icon--"], + .sidenav__item-title { + color: var(--sidenav-color-item-fg--active); + } + } + .badge--icon { + inset-block-start: 2px; + inset-inline-end: 7px; + } + [class^="icon--"], [class*=" icon--"] { + color: var(--sidenav-color-item-fg); + } + } + + + .sidenav__stretch-separator { + flex-grow: 1; + align-self: stretch; + justify-self: stretch; + margin: auto; + } + .sidenav__separator { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + flex-grow: 0; + flex-shrink: 0; + gap: calc(var(--separator-dot-size) * 1); + margin-block: auto; + margin-inline: var(--space--0-5); + .separator__dot { + border-radius: var(--border-radius--full); + display: block; + height: var(--separator-dot-size); + width: var(--separator-dot-size); + background-color: var(--separator-dot-color-bg); + opacity: 0.4; + } + @include md { + flex-direction: row; + margin-block: var(--space--1-5); + gap: calc(var(--separator-dot-size) * 1.5); + } + + } +} \ No newline at end of file diff --git a/assets/ui/components/ToolTip.tsx b/assets/ui/components/ToolTip.tsx index 653e64610..17e69e50f 100644 --- a/assets/ui/components/ToolTip.tsx +++ b/assets/ui/components/ToolTip.tsx @@ -31,7 +31,8 @@ export class ToolTip extends React.PureComponent { } else { this.tooltip = new Tooltip(child, { trigger: 'hover', - placement: this.props.placement || 'top' + placement: this.props.placement || 'top', + title: this.props.title, }); } } @@ -58,4 +59,5 @@ export class ToolTip extends React.PureComponent { ToolTip.propTypes = { children: PropTypes.node.isRequired, placement: PropTypes.string, + title: PropTypes.string, }; diff --git a/design_app/src/components/SideNav.jsx b/design_app/src/components/SideNav.jsx index 42b0a8b61..3e10b6840 100644 --- a/design_app/src/components/SideNav.jsx +++ b/design_app/src/components/SideNav.jsx @@ -1,81 +1,109 @@ -import React from 'react'; +import React, {useState} from 'react'; +import {ToolTip} from 'ui/components/ToolTip'; function SideNav() { + const [isNavExpanded, setIsNavExpanded] = useState(false); + const handleNavExpanded = event => { + setIsNavExpanded(current => !current); + } + return ( - -