mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-01 21:31:36 +02:00
[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:
@@ -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({
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user