webterm: improve style & dark mode reactivity

Now reacts to changes in light/dark more, uses Landscape font set,
covers up container gaps.
This commit is contained in:
fang 2021-03-13 00:38:06 +01:00
parent 81e7808247
commit d355d3b71c
No known key found for this signature in database
GPG Key ID: EB035760C1BBA972
2 changed files with 47 additions and 170 deletions

View File

@ -1,21 +1,21 @@
import React, { import React, {
Component,
useState,
useEffect, useEffect,
useRef, useRef,
useCallback useCallback
} from 'react'; } from 'react';
import Helmet from 'react-helmet'; import Helmet from 'react-helmet';
import useTermState, { TermState } from '~/logic/state/term'; import useTermState from '~/logic/state/term';
import useSettingsState from "~/logic/state/settings";
import useLocalState from "~/logic/state/local";
import { Terminal, ITerminalOptions } from 'xterm'; import { Terminal, ITerminalOptions, ITheme } from 'xterm';
import { FitAddon } from 'xterm-addon-fit'; import { FitAddon } from 'xterm-addon-fit';
import { saveAs } from 'file-saver'; import { saveAs } from 'file-saver';
import { Box, Col } from '@tlon/indigo-react'; import { Box, Col } from '@tlon/indigo-react';
import './css/custom.css'; import '../../../../node_modules/xterm/css/xterm.css'
import GlobalApi from '~/logic/api/global'; import GlobalApi from '~/logic/api/global';
import { Belt } from '~/logic/api/term'; import { Belt } from '~/logic/api/term';
import { Blit, Stye, Stub, Tint, Deco } from '~/types/term-update'; import { Blit, Stye, Stub, Tint, Deco } from '~/types/term-update';
@ -28,6 +28,26 @@ type TermAppProps = {
notificationsCount: number; notificationsCount: number;
} }
const makeTheme = (dark: boolean): ITheme => {
let fg, bg: string;
if (dark) {
fg = 'white';
bg = 'black';
} else {
fg = 'black';
bg = 'white';
}
//TODO indigo colors.
// we can't pluck these from ThemeContext because they have transparency.
// technically xterm supports transparency, but it degrades performance.
return {
foreground: fg,
background: bg,
brightBlack: '#7f7f7f', //NOTE slogs
cursor: fg,
}
}
const termConfig: ITerminalOptions = { const termConfig: ITerminalOptions = {
logLevel: 'warn', logLevel: 'warn',
// //
@ -37,13 +57,9 @@ const termConfig: ITerminalOptions = {
cols: 80, cols: 80,
scrollback: 10000, scrollback: 10000,
// //
theme: { //TODO vary with landscape theme? fontFamily: '"Source Code Pro","Roboto mono","Courier New",monospace',
foreground: 'black', //NOTE theme colors configured dynamically
background: 'white', //
cursor: 'black',
cursorAccent: 'white',
//TODO selection color
},
bellStyle: 'sound', bellStyle: 'sound',
bellSound: bel, bellSound: bel,
// //
@ -111,10 +127,13 @@ export default function TermApp(props: TermAppProps) {
const { api } = props; const { api } = props;
const container = useRef<HTMLElement>(null); const container = useRef<HTMLElement>(null);
//TODO allow switching of selected //TODO allow switching of selected
const { sessions, selected, set } = useTermState(); const { sessions, selected, set } = useTermState();
const osDark = useLocalState((state) => state.dark);
const theme = useSettingsState(s => s.display.theme);
const dark = theme === 'dark' || (theme === 'auto' && osDark);
const onSlog = useCallback((slog) => { const onSlog = useCallback((slog) => {
if (!sessions['']) { if (!sessions['']) {
console.log('default session mia!', 'slog:', slog); console.log('default session mia!', 'slog:', slog);
@ -323,6 +342,20 @@ export default function TermApp(props: TermAppProps) {
}; };
}, []); }, []);
// on dark mode change, change terminals' theme
//
useEffect(() => {
const theme = makeTheme(dark);
for (let ses in sessions) {
sessions[ses].term.setOption('theme', theme);
}
if (container.current) {
container.current.style.backgroundColor = theme.background || '';
}
}, [dark, sessions]);
// on selected change, maybe setup the term, or put it into the container
//
useEffect(() => { useEffect(() => {
let ses = sessions[selected]; let ses = sessions[selected];
@ -332,6 +365,7 @@ export default function TermApp(props: TermAppProps) {
// set up terminal // set up terminal
// //
let term = new Terminal(termConfig); let term = new Terminal(termConfig);
term.setOption('theme', makeTheme(dark));
const fit = new FitAddon(); const fit = new FitAddon();
term.loadAddon(fit); term.loadAddon(fit);

View File

@ -1,157 +0,0 @@
input#term {
background-color: inherit;
color: inherit;
}
.blink {
animation: 4s ease-in-out infinite opacity_blink;
}
@keyframes opacity_blink {
0% { opacity: 0; }
10% { opacity: 1; }
80% { opacity: 1; }
90% { opacity: 0; }
100% { opacity: 0; }
}
/**
* Default styles for xterm.js
* TODO import from xterm in node_modules, but how?
*/
.xterm {
font-feature-settings: "liga" 0;
position: relative;
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
}
.xterm.focus,
.xterm:focus {
outline: none;
}
.xterm .xterm-helpers {
position: absolute;
top: 0;
/**
* The z-index of the helpers must be higher than the canvases in order for
* IMEs to appear on top.
*/
z-index: 5;
}
.xterm .xterm-helper-textarea {
padding: 0;
border: 0;
margin: 0;
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
position: absolute;
opacity: 0;
left: -9999em;
top: 0;
width: 0;
height: 0;
z-index: -5;
/** Prevent wrapping so the IME appears against the textarea at the correct position */
white-space: nowrap;
overflow: hidden;
resize: none;
}
.xterm .composition-view {
/* TODO: Composition position got messed up somewhere */
background: #000;
color: #FFF;
display: none;
position: absolute;
white-space: nowrap;
z-index: 1;
}
.xterm .composition-view.active {
display: block;
}
.xterm .xterm-viewport {
/* On OS X this is required in order for the scroll bar to appear fully opaque */
background-color: #000;
overflow-y: scroll;
cursor: default;
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 0;
}
.xterm .xterm-screen {
position: relative;
}
.xterm .xterm-screen canvas {
position: absolute;
left: 0;
top: 0;
}
.xterm .xterm-scroll-area {
visibility: hidden;
}
.xterm-char-measure-element {
display: inline-block;
visibility: hidden;
position: absolute;
top: 0;
left: -9999em;
line-height: normal;
}
.xterm {
cursor: text;
}
.xterm.enable-mouse-events {
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
cursor: default;
}
.xterm.xterm-cursor-pointer {
cursor: pointer;
}
.xterm.column-select.focus {
/* Column selection mode */
cursor: crosshair;
}
.xterm .xterm-accessibility,
.xterm .xterm-message {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 10;
color: transparent;
}
.xterm .live-region {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
.xterm-dim {
opacity: 0.5;
}
.xterm-underline {
text-decoration: underline;
}