restore docs position after hide/show

Previously, the docs iframe was removed from the DOM when the docs
were hidden. This caused the docs to always go back to the main page
when shown.

This fixes it by using CSS to hide the docs instead of removing them
from the DOM. However, this comes with its own complications regarding
maintaining the scroll position.
This commit is contained in:
David Lechner
2021-01-27 15:38:51 -06:00
parent 64e6b3739e
commit ca8192084d
2 changed files with 87 additions and 14 deletions
+81 -14
View File
@@ -22,7 +22,7 @@ function App(): JSX.Element {
<div className="app">
<Toolbar />
<SplitterLayout
customClassName="h-body"
customClassName={`h-body ${showDocs ? 'pb-show-docs' : 'pb-hide-docs'}`}
onDragStart={(): void => setDragging(true)}
onDragEnd={(): void => setDragging(false)}
percentage={true}
@@ -48,19 +48,86 @@ function App(): JSX.Element {
<Terminal />
</div>
</SplitterLayout>
{showDocs && (
<div className="h-100 w-100">
{dragging && <div className="h-100 w-100 p-absolute" />}
<iframe
src="static/docs/index.html"
allowFullScreen={true}
title="docs"
width="100%"
height="100%"
frameBorder="none"
/>
</div>
)}
<div className="h-100 w-100">
{dragging && <div className="h-100 w-100 p-absolute" />}
<iframe
onLoad={(e) => {
// HACK: this mess restores the scroll position when
// the documentation iframe visibility is toggled.
// The iframe will be automatically scrolled to 0 when
// CSS `display: none` is set.
const target = e.target as HTMLIFrameElement;
const contentWindow = target.contentWindow;
if (!contentWindow) {
console.error('could not get iframe content window');
return;
}
// the last "good" scrollY value of the iframe
let iframeScroll = 0;
// This bit monitors the visibility.
// https://stackoverflow.com/a/44670818/1976323
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
// Restore the scroll position when the
// iframe is shown. Toggling the visibility
// prevents flashing the contents from the
// top of the page before the scroll is
// done.
if (entry.intersectionRatio > 0) {
contentWindow.scrollTo(0, iframeScroll);
contentWindow.document.documentElement.style.visibility =
'visible';
} else {
contentWindow.document.documentElement.style.visibility =
'hidden';
}
});
},
{
root: target.parentElement,
},
);
observer.observe(target);
// Have to remove he observer, otherwise we end up
// with conflicting values when a new page is loaded
// in the iframe.
contentWindow.addEventListener('unload', () => {
observer.unobserve(target);
});
// And this keeps track of the scroll position.
contentWindow.addEventListener('scroll', () => {
if (contentWindow.scrollY !== 0) {
// Record the current scroll position.
// If it is 0, it could be that the iframe
// has been hidden or the user scrolled
// there. So we have to ignore 0. But we
// don't want to be one pixel off if the
// user really did scroll there, so we
// assume that if the last scroll is 1, then
// the user probably went all the way to 0.
if (contentWindow.scrollY === 1) {
iframeScroll = 0;
} else {
iframeScroll = contentWindow.scrollY;
}
}
});
}}
src="static/docs/index.html"
allowFullScreen={true}
title="docs"
width="100%"
height="100%"
frameBorder="none"
/>
</div>
</SplitterLayout>
<StatusBar />
<SettingsDrawer />
+6
View File
@@ -22,3 +22,9 @@
.terminal-padding {
padding-left: 10px;
}
// hide the docs and resize separator
div.pb-hide-docs > :not(.layout-pane-primary) {
display: none;
}