[web] Add box shadows to scrollable part of sidebar (#22400)

* Add box shadows to scrollable part of sidebar

* Fix lint

* Fix `isAtBottom` boolean on Firefox

* Throttle the `scroll` event

* Remove wrong and unnecessary comment

GitOrigin-RevId: 7bcbb7fc860ab32f44203b3ae9ff37a3fed069a8
This commit is contained in:
Antoine Clausse
2024-12-13 12:23:34 +01:00
committed by Copybot
parent 001cdde628
commit 21e9cd888e
3 changed files with 127 additions and 58 deletions

View File

@@ -1,4 +1,5 @@
import { useState } from 'react'
import classnames from 'classnames'
import NewProjectButton from '../new-project-button'
import SidebarFilters from './sidebar-filters'
import AddAffiliation, { useAddAffiliation } from '../add-affiliation'
@@ -14,6 +15,7 @@ import { NavbarDropdownItemData } from '@/features/ui/components/types/navbar'
import { useContactUsModal } from '@/shared/hooks/use-contact-us-modal'
import { UserProvider } from '@/shared/context/user-context'
import { AccountMenuItems } from '@/features/ui/components/bootstrap-5/navbar/account-menu-items'
import { useScrolled } from '@/features/project-list/components/sidebar/use-scroll'
function SidebarDsNav() {
const { t } = useTranslation()
@@ -31,6 +33,7 @@ function SidebarDsNav() {
const helpItem = items.find(
item => item.text === 'help'
) as NavbarDropdownItemData
const { containerRef, scrolledUp, scrolledDown } = useScrolled()
return (
<div
className="project-list-sidebar-wrapper-react d-none d-md-flex"
@@ -40,82 +43,92 @@ function SidebarDsNav() {
},
})}
>
<NewProjectButton id="new-project-button-sidebar" />
<div className="project-list-sidebar-scroll">
<NewProjectButton
id="new-project-button-sidebar"
className={scrolledDown ? 'show-shadow' : undefined}
/>
<div className="project-list-sidebar-scroll" ref={containerRef}>
<SidebarFilters />
{showAddAffiliationWidget && <hr />}
<AddAffiliation />
</div>
<div className="project-list-sidebar-survey-wrapper">
<SurveyWidget variant="light" />
</div>
<div className="d-flex gap-3 mb-2">
{helpItem && (
<Dropdown
className="ds-nav-icon-dropdown"
onToggle={show => setShowHelpDropdown(show)}
>
<Dropdown.Toggle role="menuitem" aria-label={t('help')}>
<OLTooltip
description={t('help')}
id="help-icon"
overlayProps={{
placement: 'top',
show: showHelpDropdown ? false : undefined,
}}
>
<div>
<MaterialIcon type="help" size="2x" />
</div>
</OLTooltip>
</Dropdown.Toggle>
<Dropdown.Menu as="ul" role="menu" align="end">
<NavDropdownMenuItems
dropdown={helpItem.dropdown}
showContactUsModal={showContactUsModal}
/>
</Dropdown.Menu>
</Dropdown>
<div
className={classnames(
'ds-nav-sidebar-lower',
scrolledUp && 'show-shadow'
)}
{sessionUser && (
<>
>
<div className="project-list-sidebar-survey-wrapper">
<SurveyWidget variant="light" />
</div>
<div className="d-flex gap-3 mb-2">
{helpItem && (
<Dropdown
className="ds-nav-icon-dropdown"
onToggle={show => setShowAccountDropdown(show)}
onToggle={show => setShowHelpDropdown(show)}
>
<Dropdown.Toggle role="menuitem" aria-label={t('Account')}>
<Dropdown.Toggle role="menuitem" aria-label={t('help')}>
<OLTooltip
description={t('Account')}
id="open-account"
description={t('help')}
id="help-icon"
overlayProps={{
placement: 'top',
show: showAccountDropdown ? false : undefined,
show: showHelpDropdown ? false : undefined,
}}
>
<div>
<MaterialIcon type="person" size="2x" />
<MaterialIcon type="help" size="2x" />
</div>
</OLTooltip>
</Dropdown.Toggle>
<Dropdown.Menu as="ul" role="menu" align="end">
<AccountMenuItems
sessionUser={sessionUser}
showSubscriptionLink={showSubscriptionLink}
<NavDropdownMenuItems
dropdown={helpItem.dropdown}
showContactUsModal={showContactUsModal}
/>
</Dropdown.Menu>
</Dropdown>
<UserProvider>{contactUsModal}</UserProvider>
</>
)}
</div>
<div className="ds-nav-ds-link">
<a
target="_blank"
href="https://www.digital-science.com/"
rel="noopener"
>
Digital Science
</a>
)}
{sessionUser && (
<>
<Dropdown
className="ds-nav-icon-dropdown"
onToggle={show => setShowAccountDropdown(show)}
>
<Dropdown.Toggle role="menuitem" aria-label={t('Account')}>
<OLTooltip
description={t('Account')}
id="open-account"
overlayProps={{
placement: 'top',
show: showAccountDropdown ? false : undefined,
}}
>
<div>
<MaterialIcon type="person" size="2x" />
</div>
</OLTooltip>
</Dropdown.Toggle>
<Dropdown.Menu as="ul" role="menu" align="end">
<AccountMenuItems
sessionUser={sessionUser}
showSubscriptionLink={showSubscriptionLink}
/>
</Dropdown.Menu>
</Dropdown>
<UserProvider>{contactUsModal}</UserProvider>
</>
)}
</div>
<div className="ds-nav-ds-link">
<a
target="_blank"
href="https://www.digital-science.com/"
rel="noopener"
>
Digital Science
</a>
</div>
</div>
<div
{...getHandleProps({

View File

@@ -0,0 +1,39 @@
import { throttle } from 'lodash'
import { useEffect, useRef, useState } from 'react'
export const useScrolled = () => {
const containerRef = useRef<HTMLDivElement>(null)
const [scrolledUp, setScrolledUp] = useState(false)
const [scrolledDown, setScrolledDown] = useState(false)
const checkScrollPosition = useRef(
throttle(() => {
const container = containerRef.current
if (!container) {
return
}
setScrolledDown(container.scrollTop > 0)
const isAtBottom =
Math.abs(
// On Firefox, this value happen to be at 1 when scrolled to the bottom
container.scrollHeight - container.clientHeight - container.scrollTop
) <= 1
setScrolledUp(!isAtBottom)
}, 80)
).current
useEffect(() => {
const container = containerRef.current
if (!container) {
return
}
checkScrollPosition()
container.addEventListener('scroll', checkScrollPosition)
return () => {
checkScrollPosition.cancel()
container.removeEventListener('scroll', checkScrollPosition)
}
}, [checkScrollPosition])
return { containerRef, scrolledDown, scrolledUp }
}

View File

@@ -32,13 +32,30 @@
flex: 0 0 15%;
max-width: 320px;
min-width: 200px;
padding: var(--spacing-08) var(--spacing-08) 0 var(--spacing-05);
padding: var(--spacing-08) 0 0 0;
.new-project-dropdown {
padding: 0 var(--spacing-08) var(--spacing-05) var(--spacing-05);
&.show-shadow {
box-shadow: 0 2px 2px rgb(0 0 0 / 10%);
}
}
.project-list-sidebar-scroll {
flex: 1 1 auto;
overflow: auto;
margin: var(--spacing-05) calc(var(--spacing-07) * -1);
padding: var(--spacing-05) var(--spacing-07);
margin: 0 var(--spacing-02) 0 0;
padding: var(--spacing-05) var(--spacing-07) var(--spacing-05)
var(--spacing-05);
}
.ds-nav-sidebar-lower {
padding: var(--spacing-05) var(--spacing-08) 0 var(--spacing-05);
&.show-shadow {
box-shadow: 0 -2px 2px rgb(0 0 0 / 10%);
}
}
.project-list-sidebar-survey-link {