Skip to content
51 changes: 5 additions & 46 deletions src/Components/Catalog/DatasetDetailPage/DatasetDetailPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Text on this page has inline styling for font color because ag-grid's theme classes override mui classes when a dialog is opened
// from inside the grid

import React, { useEffect, useLayoutEffect, useState } from 'react';
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { Grid, Link, Typography, withStyles } from '@material-ui/core';
Expand All @@ -23,7 +23,7 @@ import NewsSection from './NewsSection';
import SectionHeader from './SectionHeader';
import SubscribeButton from '../../User/Subscriptions/SubscribeButton';
import { DownloadButtonOutlined } from '../DownloadDialog/DownloadButtons';
import styles from './DatasetDetailPage.style';
import ScrollHintOverlay from './ScrollHintOverlay';

import SkeletonWrapper from '../../UI/SkeletonWrapper';
import ErrorCard from '../../Common/ErrorCard';
Expand All @@ -42,6 +42,7 @@ import { fetchSubscriptions } from '../../../Redux/actions/user';
import states from '../../../enums/asyncRequestStates';
import colors from '../../../enums/colors';
import metaTags from '../../../enums/metaTags';
import styles from './DatasetDetailPage.style';

export const datasetDetailConfig = {
route: '/',
Expand Down Expand Up @@ -174,44 +175,6 @@ const DatasetFullPage = (props) => {
};
}, [longName]);

// Scroll to the top of the description content when the page loads to hint at scrollability
// (macOS won't show scrollbar unless scrolling). Copied from Stories.js.
let [ref, setRef] = useState(null);
let [intervalId, setIntervalId] = useState(null);
useLayoutEffect(() => {
if (ref) {
const s = () =>
ref.scroll({
top: 1,
left: 0,
behavior: 'instant',
});
const id = setInterval(s, 100);
setIntervalId(id);
}
}, [ref]);

const handleScroll = () => {
if (ref) {
const pos = ref.scrollTop;
if (pos < 1) {
const scrollBack = () => {
if (ref) {
ref.scroll({
top: 1,
left: 0,
behavior: 'instant',
});
}
};
setTimeout(scrollBack, 200);
}
}
if (intervalId) {
clearInterval(intervalId);
}
};

if (failed) {
let details = `You requested to view "${props.match.params.dataset}".`;
return (
Expand Down Expand Up @@ -253,16 +216,12 @@ const DatasetFullPage = (props) => {
<div className={classes.horizontalFlex}>
<div className={classes.descriptionContainer}>
<SectionHeader title={'Description'} />
<div
className={classes.descriptionContent}
ref={setRef}
onScroll={handleScroll}
>
<ScrollHintOverlay style={{ maxHeight: '60vh' }}>
<ReactMarkdown
source={description}
className={classes.markdown}
/>
</div>
</ScrollHintOverlay>
</div>
<NewsSection news={news} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,8 @@ const styles = (theme) => ({
},
descriptionContainer: {
flex: 2,
},
descriptionContent: {
maxHeight: '60vh',
...scrollableStyles,
display: 'flex',
flexDirection: 'column',
},
acknowledgmentContent: {
maxHeight: '30vh',
Expand Down
81 changes: 81 additions & 0 deletions src/Components/Catalog/DatasetDetailPage/ScrollHintOverlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useEffect, useRef, useState } from 'react';

export default function ScrollHintOverlay({ children, style }) {
const containerRef = useRef(null);
const [showHint, setShowHint] = useState(false);
const [hasScrolled, setHasScrolled] = useState(false);
const [scrollbarHeight, setScrollbarHeight] = useState(0);
const [animateFadeOut, setAnimateFadeOut] = useState(false);

useEffect(() => {
const updateHintVisibility = () => {
const container = containerRef.current;
if (!container) {
return;
}
const scrollable = container.scrollHeight > container.clientHeight;
const nativeScrollbarVisible =
container.offsetWidth > container.clientWidth;

const visibleRatio = container.clientHeight / container.scrollHeight;
const height = (container.clientHeight - 35) * visibleRatio;
setScrollbarHeight(height);

setShowHint(scrollable && !nativeScrollbarVisible && !hasScrolled);
};

updateHintVisibility();
window.addEventListener('resize', updateHintVisibility);
return () => window.removeEventListener('resize', updateHintVisibility);
}, [hasScrolled]);

const handleScroll = () => {
if (!hasScrolled) {
setHasScrolled(true);
setAnimateFadeOut(true);
setTimeout(() => {
setShowHint(false);
}, 750); // Match the duration of the fadeOut animation
}
};

return (
<div
ref={containerRef}
onScroll={handleScroll}
style={{
position: 'relative',
overflowY: 'auto',
maxHeight: '60vh',
paddingRight: '1em',
...style,
}}
>
<style>{`
@keyframes fadeOut {
0% { opacity: 1; }
80% { opacity: 1; }
100% { opacity: 0; }
}
`}</style>
{children}
{showHint && (
<div
style={{
position: 'absolute',
top: 0,
right: 2,
width: '7px',
height: `${scrollbarHeight}px`,
backgroundColor: '#5F9B2B',
borderRadius: '3px',
animation: animateFadeOut
? 'fadeOut 0.75s ease-out forwards'
: 'none',
pointerEvents: 'none',
}}
></div>
)}
</div>
);
}