mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-15 02:54:07 +00:00
This way it still works when the docs are focused. Otherwise the browser would try to bookmark the page.
158 lines
7.3 KiB
TypeScript
158 lines
7.3 KiB
TypeScript
// SPDX-License-Identifier: MIT
|
|
// Copyright (c) 2020 The Pybricks Authors
|
|
|
|
import React, { useState } from 'react';
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
import SplitterLayout from 'react-splitter-layout';
|
|
import { toggleBoolean } from '../actions/settings';
|
|
import { RootState } from '../reducers';
|
|
import { SettingId } from '../settings/user';
|
|
import { isMacOS } from '../utils/os';
|
|
import Editor from './Editor';
|
|
import SettingsDrawer from './SettingsDrawer';
|
|
import StatusBar from './StatusBar';
|
|
import Terminal from './Terminal';
|
|
import Toolbar from './Toolbar';
|
|
|
|
import 'react-splitter-layout/lib/index.css';
|
|
import './app.scss';
|
|
|
|
function App(): JSX.Element {
|
|
const showDocs = useSelector((s: RootState): boolean => s.settings.showDocs);
|
|
const [dragging, setDragging] = useState(false);
|
|
const dispatch = useDispatch();
|
|
|
|
return (
|
|
<div className="app">
|
|
<Toolbar />
|
|
<SplitterLayout
|
|
customClassName={`h-body ${showDocs ? 'pb-show-docs' : 'pb-hide-docs'}`}
|
|
onDragStart={(): void => setDragging(true)}
|
|
onDragEnd={(): void => setDragging(false)}
|
|
percentage={true}
|
|
secondaryInitialSize={Number(
|
|
localStorage.getItem('app-docs-split') || 30,
|
|
)}
|
|
onSecondaryPaneSizeChange={(value): void =>
|
|
localStorage.setItem('app-docs-split', String(value))
|
|
}
|
|
>
|
|
<SplitterLayout
|
|
vertical={true}
|
|
percentage={true}
|
|
secondaryInitialSize={Number(
|
|
localStorage.getItem('app-terminal-split') || 30,
|
|
)}
|
|
onSecondaryPaneSizeChange={(value): void =>
|
|
localStorage.setItem('app-terminal-split', String(value))
|
|
}
|
|
>
|
|
<Editor />
|
|
<div className="terminal-padding h-100">
|
|
<Terminal />
|
|
</div>
|
|
</SplitterLayout>
|
|
<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;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Override browser default key bindings in iframe.
|
|
contentWindow.document.addEventListener('keydown', (e) => {
|
|
// use Ctrl-D/Cmd-D to toggle docs
|
|
if (
|
|
(isMacOS()
|
|
? e.metaKey && !e.ctrlKey
|
|
: e.ctrlKey && !e.metaKey) &&
|
|
!e.altKey &&
|
|
e.key == 'd'
|
|
) {
|
|
e.preventDefault();
|
|
dispatch(toggleBoolean(SettingId.ShowDocs));
|
|
}
|
|
});
|
|
}}
|
|
src="static/docs/index.html"
|
|
allowFullScreen={true}
|
|
title="docs"
|
|
width="100%"
|
|
height="100%"
|
|
frameBorder="none"
|
|
/>
|
|
</div>
|
|
</SplitterLayout>
|
|
<StatusBar />
|
|
<SettingsDrawer />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default App;
|