Skip to content

Commit

Permalink
console: Use scroll fader component
Browse files Browse the repository at this point in the history
  • Loading branch information
ryaplots authored and kschiffer committed Jun 11, 2024
1 parent 1993e03 commit 13c7164
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 98 deletions.
147 changes: 81 additions & 66 deletions pkg/webui/components/scroll-fader/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,85 +25,100 @@ import style from './scroll-fader.styl'
// indication that they are scrollable, but do not have a scrollbar.
// The indication only shows when the content is scrolled.

const ScrollFader = React.forwardRef(({ children, className, fadeHeight, light }, ref) => {
const internalRef = useRef()
const combinedRef = combineRefs([ref, internalRef])

const handleScroll = useCallback(() => {
const container = internalRef.current
const { scrollTop, scrollHeight, clientHeight } = container
const scrollable = scrollHeight - clientHeight
const scrollGradientTop = container.querySelector(`.${style.scrollGradientTop}`)
const scrollGradientBottom = container.querySelector(`.${style.scrollGradientBottom}`)

if (scrollGradientTop) {
const opacity = scrollTop < fadeHeight ? scrollTop / fadeHeight : 1
scrollGradientTop.style.opacity = opacity
}

if (scrollGradientBottom) {
const scrollEnd = scrollable - fadeHeight
const opacity = scrollTop < scrollEnd ? 1 : (scrollable - scrollTop) / fadeHeight
scrollGradientBottom.style.opacity = opacity
}
}, [fadeHeight])

useEffect(() => {
const container = internalRef.current
if (!container) return

const mutationObserver = new MutationObserver(() => {
handleScroll()
})

// Run the calculation whenever the children change.
mutationObserver.observe(container, { attributes: false, childList: true, subtree: false })

handleScroll() // Call once on mount if needed
container.addEventListener('scroll', handleScroll)
window.addEventListener('resize', handleScroll)

return () => {
// Cleanup observer and event listeners
mutationObserver.disconnect()
container.removeEventListener('scroll', handleScroll)
window.removeEventListener('resize', handleScroll)
}
}, [handleScroll])

return (
<div
ref={combinedRef}
onScroll={handleScroll}
className={className}
style={{
position: 'relative',
}}
>
const ScrollFader = React.forwardRef(
({ children, className, fadeHeight, light, faderHeight, topFaderOffset }, ref) => {
const internalRef = useRef()
const combinedRef = combineRefs([ref, internalRef])

const handleScroll = useCallback(() => {
const container = internalRef.current
const { scrollTop, scrollHeight, clientHeight } = container
const scrollable = scrollHeight - clientHeight
const scrollGradientTop = container.querySelector(`.${style.scrollGradientTop}`)
const scrollGradientBottom = container.querySelector(`.${style.scrollGradientBottom}`)

if (scrollGradientTop) {
const opacity = scrollTop < fadeHeight ? scrollTop / fadeHeight : 1
scrollGradientTop.style.opacity = opacity
}

if (scrollGradientBottom) {
const scrollEnd = scrollable - fadeHeight
const opacity = scrollTop < scrollEnd ? 1 : (scrollable - scrollTop) / fadeHeight
scrollGradientBottom.style.opacity = opacity
}
}, [fadeHeight])

useEffect(() => {
const container = internalRef.current
if (!container) return

const mutationObserver = new MutationObserver(() => {
handleScroll()
})

// Run the calculation whenever the children change.
mutationObserver.observe(container, { attributes: false, childList: true, subtree: false })

handleScroll() // Call once on mount if needed
container.addEventListener('scroll', handleScroll)
window.addEventListener('resize', handleScroll)

return () => {
// Cleanup observer and event listeners
mutationObserver.disconnect()
container.removeEventListener('scroll', handleScroll)
window.removeEventListener('resize', handleScroll)
}
}, [handleScroll])

return (
<div
className={classnames(style.scrollGradientTop, { [style.scrollGradientTopLight]: light })}
/>
{children}
<div
className={classnames(style.scrollGradientBottom, {
[style.scrollGradientBottomLight]: light,
})}
/>
</div>
)
})
ref={combinedRef}
onScroll={handleScroll}
className={className}
style={{
position: 'relative',
}}
>
<div
className={classnames(style.scrollGradientTop, { [style.scrollGradientTopLight]: light })}
style={{
height: faderHeight,
marginBottom: `-${faderHeight}`,
top: topFaderOffset,
}}
/>
{children}
<div
className={classnames(style.scrollGradientBottom, {
[style.scrollGradientBottomLight]: light,
})}
style={{
height: faderHeight,
marginTop: `-${faderHeight}`,
}}
/>
</div>
)
},
)

ScrollFader.propTypes = {
children: PropTypes.node.isRequired,
className: PropTypes.string,
fadeHeight: PropTypes.number,
faderHeight: PropTypes.string,
light: PropTypes.bool,
topFaderOffset: PropTypes.string,
}

ScrollFader.defaultProps = {
className: undefined,
fadeHeight: 40,
faderHeight: '1rem',
light: false,
topFaderOffset: '0',
}

export default ScrollFader
7 changes: 1 addition & 6 deletions pkg/webui/components/scroll-fader/scroll-fader.styl
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.

$scroll-gradient-height = 1rem

// Add a gradient to the bottom of the sidebar
// to signify that there is more content below.
.scroll-gradient-top, .scroll-gradient-bottom
position: sticky
left: 0
right: 0
height: $scroll-gradient-height
z-index: $zi.slight
z-index: $zi.slight + 1
opacity: 0
pointer-events: none

.scroll-gradient-top
top: 0
margin-bottom: - $scroll-gradient-height
background: linear-gradient(0deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, .05))

&-light
background: linear-gradient(0deg, rgba(255, 255, 255, 0), var(--c-bg-neutral-min))

.scroll-gradient-bottom
bottom: 0
margin-top: - $scroll-gradient-height
background: linear-gradient(180deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, .05))

&-light
Expand Down
20 changes: 12 additions & 8 deletions pkg/webui/console/containers/top-entities-dashboard-panel/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,18 @@ const EntitiesList = ({
)}
</div>
) : (
<div className={styles.topEntitiesPanelOuterTable}>
<ScrollFader className={styles.scrollGradient} ref={listRef} light>
<Table>
<Table.Head className={styles.topEntitiesPanelOuterTableHeader}>{columns}</Table.Head>
<Table.Body emptyMessage={m.empty}>{rows}</Table.Body>
</Table>
</ScrollFader>
</div>
<ScrollFader
className={styles.scrollFader}
ref={listRef}
faderHeight="4rem"
topFaderOffset="3rem"
light
>
<Table>
<Table.Head className={styles.topEntitiesPanelOuterTableHeader}>{columns}</Table.Head>
<Table.Body emptyMessage={m.empty}>{rows}</Table.Body>
</Table>
</ScrollFader>
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,18 @@
// limitations under the License.

.top-entities-panel
min-height: 31rem
height: 31rem
display: flex
flex-direction: column

&-outer-table
overflow-y: auto
height: 23rem
width: 100%
table-layout: fixed
scrollbar-width: none
&-outer-table-header
top: 0
position: sticky
background: var(--c-bg-neutral-min)
z-index: 1

&::-webkit-scrollbar
display: none

&-header
top: 0
position: sticky
background: var(--c-bg-neutral-min)
z-index: 1

.scroll-gradient
height: 3.5rem
.scroll-fader
overflow-y: auto
width: 100%
table-layout: fixed
scrollbar-width: none

0 comments on commit 13c7164

Please sign in to comment.