diff --git a/pkg/interface/src/views/apps/term/app.tsx b/pkg/interface/src/views/apps/term/app.tsx index 6772560c07..090fb5dce6 100644 --- a/pkg/interface/src/views/apps/term/app.tsx +++ b/pkg/interface/src/views/apps/term/app.tsx @@ -1,21 +1,21 @@ import React, { - Component, - useState, useEffect, useRef, useCallback } from 'react'; 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 { saveAs } from 'file-saver'; 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 { Belt } from '~/logic/api/term'; import { Blit, Stye, Stub, Tint, Deco } from '~/types/term-update'; @@ -28,6 +28,26 @@ type TermAppProps = { 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 = { logLevel: 'warn', // @@ -37,13 +57,9 @@ const termConfig: ITerminalOptions = { cols: 80, scrollback: 10000, // - theme: { //TODO vary with landscape theme? - foreground: 'black', - background: 'white', - cursor: 'black', - cursorAccent: 'white', - //TODO selection color - }, + fontFamily: '"Source Code Pro","Roboto mono","Courier New",monospace', + //NOTE theme colors configured dynamically + // bellStyle: 'sound', bellSound: bel, // @@ -111,10 +127,13 @@ export default function TermApp(props: TermAppProps) { const { api } = props; const container = useRef(null); - //TODO allow switching of selected 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) => { if (!sessions['']) { 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(() => { let ses = sessions[selected]; @@ -332,6 +365,7 @@ export default function TermApp(props: TermAppProps) { // set up terminal // let term = new Terminal(termConfig); + term.setOption('theme', makeTheme(dark)); const fit = new FitAddon(); term.loadAddon(fit); diff --git a/pkg/interface/src/views/apps/term/css/custom.css b/pkg/interface/src/views/apps/term/css/custom.css deleted file mode 100644 index b5222f5e67..0000000000 --- a/pkg/interface/src/views/apps/term/css/custom.css +++ /dev/null @@ -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; -} -