mirror of
https://github.com/urbit/shrub.git
synced 2024-12-22 10:21:31 +03:00
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:
parent
81e7808247
commit
d355d3b71c
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user