devex: improved resize behavior

- only resize when necessary (check the container's height)
- refactor CSS: use position relative / absolute to stack Buffers instead of display:none; this affects the calcuations used by fit()
- fix dark mode styles, tweak viewport height (100vh --> 99vh) to prevent overflow scroller
This commit is contained in:
tomholford 2022-04-19 03:41:40 -07:00
parent 65f9f904c7
commit 2d3e803704
3 changed files with 32 additions and 10 deletions

View File

@ -14,7 +14,7 @@ import React from 'react';
import { Box, Col } from '@tlon/indigo-react'; import { Box, Col } from '@tlon/indigo-react';
import { makeTheme } from './lib/theme'; import { makeTheme } from './lib/theme';
import { showBlit, csi, hasBell } from './lib/blit'; import { showBlit, csi, hasBell } from './lib/blit';
import { DEFAULT_SESSION, RESIZE_DEBOUNCE_MS } from './constants'; import { DEFAULT_SESSION, RESIZE_DEBOUNCE_MS, RESIZE_THRESHOLD_PX } from './constants';
import { retry } from './lib/retry'; import { retry } from './lib/retry';
const termConfig: ITerminalOptions = { const termConfig: ITerminalOptions = {
@ -124,6 +124,7 @@ const readInput = (term: Terminal, e: string): Belt[] => {
const onResize = async (name: string, session: Session) => { const onResize = async (name: string, session: Session) => {
if (session) { if (session) {
session.fit.fit(); session.fit.fit();
api.poke(pokeTask(name, { blew: { w: session.term.cols, h: session.term.rows } }));
} }
}; };
@ -171,9 +172,6 @@ export default function Buffer({ name, selected, dark }: BufferProps) {
// //
term.onData(e => onInput(name, ses, e)); term.onData(e => onInput(name, ses, e));
term.onBinary(e => onInput(name, ses, e)); term.onBinary(e => onInput(name, ses, e));
term.onResize((e) => {
api.poke(pokeTask(name, { blew: { w: e.cols, h: e.rows } }));
});
// open subscription // open subscription
// //
@ -218,11 +216,22 @@ export default function Buffer({ name, selected, dark }: BufferProps) {
}); });
}, []); }, []);
const shouldResize = useCallback(() => {
if(!session) {
return false;
}
const containerHeight = document.querySelector('.buffer-container')?.clientHeight || Infinity;
const terminalHeight = session.term.element?.clientHeight || 0;
return (containerHeight - terminalHeight) >= RESIZE_THRESHOLD_PX;
}, [session]);
const onSelect = useCallback(async () => { const onSelect = useCallback(async () => {
if (session && selected) { if (session && selected && shouldResize()) {
session.fit.fit(); session.fit.fit();
session.term.focus();
await api.poke(pokeTask(name, { blew: { w: session.term.cols, h: session.term.rows } })); await api.poke(pokeTask(name, { blew: { w: session.term.cols, h: session.term.rows } }));
session.term.focus();
} }
}, [session, selected]); }, [session, selected]);
@ -243,13 +252,14 @@ export default function Buffer({ name, selected, dark }: BufferProps) {
} }
}, [session, containerRef]); }, [session, containerRef]);
// on-init, open slogstream and fetch existing sessions // initialize resize listeners
// //
useEffect(() => { useEffect(() => {
if(!session) { if(!session) {
return; return;
} }
// TODO: use ResizeObserver for improved performance?
const debouncedResize = debounce(() => onResize(name, session), RESIZE_DEBOUNCE_MS); const debouncedResize = debounce(() => onResize(name, session), RESIZE_DEBOUNCE_MS);
window.addEventListener('resize', debouncedResize); window.addEventListener('resize', debouncedResize);
@ -285,7 +295,8 @@ export default function Buffer({ name, selected, dark }: BufferProps) {
bg='white' bg='white'
fontFamily='mono' fontFamily='mono'
overflow='hidden' overflow='hidden'
style={selected ? {} : { display: 'none' }} className="terminal-container"
style={selected ? { zIndex: 999 } : {}}
> >
<Col <Col
width='100%' width='100%'

View File

@ -1,6 +1,7 @@
export const DEFAULT_SESSION = ''; export const DEFAULT_SESSION = '';
export const DEFAULT_HANDLER = 'hood'; export const DEFAULT_HANDLER = 'hood';
export const RESIZE_DEBOUNCE_MS = 100; export const RESIZE_DEBOUNCE_MS = 100;
export const RESIZE_THRESHOLD_PX = 15;
/** /**
* Session ID validity: * Session ID validity:

View File

@ -23,13 +23,19 @@
<link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap" rel="stylesheet">
<style> <style>
body, #root { body, #root {
height: 100vh; height: 99vh; /* prevent scrollbar on outer frame */
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
.buffer-container { .buffer-container {
height: calc(100% - 40px); height: calc(100% - 40px);
position: relative;
}
.terminal-container {
position: absolute;
top: 0;
} }
div.header { div.header {
@ -93,6 +99,10 @@
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
html {
background-color: rgb(26,26,26);
}
div.tabs { div.tabs {
background-color: rgb(26, 26, 26); background-color: rgb(26, 26, 26);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
@ -112,7 +122,7 @@
} }
div.tabs > div.selected { div.tabs > div.selected {
border-bottom: black solid 1px; border-bottom: rgb(26,26,26) solid 1px;
} }
button.info-btn { button.info-btn {