Compare commits

...

24 Commits

Author SHA1 Message Date
Red Adaya 08f2da159e fix model type 2024-04-10 21:55:12 +08:00
Red Adaya 641c8da1c7 use Button element for close trigger 2024-04-10 16:16:07 +08:00
Red Adaya 85c49032f7 simplify logic 2024-04-10 15:59:01 +08:00
Red Adaya a4f405451c fix wrong prop 2024-04-10 15:49:25 +08:00
Red Adaya bfe9d8f9ac add connection label. add New Conection item 2024-04-10 15:48:26 +08:00
Red Adaya 65cab8a59a add label to tab settings terminal theme dropdown 2024-04-10 14:58:53 +08:00
Red Adaya c737c9df57 add key and value validation 2024-04-10 10:14:33 +08:00
Red Adaya 17cc4769af fix issue where line in history view doesn't reflect the terminal theme 2024-04-10 09:21:13 +08:00
Red Adaya b4d04c3a57 merge main 2024-04-10 09:09:34 +08:00
Red Adaya 5e4eb738b3 remove file from another branch 2024-04-04 22:02:07 +08:00
Red Adaya 936e9fa7b4 cleanup 2024-04-04 11:15:38 +08:00
Red Adaya af6486e8bb remove old implementation 2024-04-04 11:11:08 +08:00
Red Adaya 1038a08789 revert changes in tabs2.less 2024-04-04 11:09:32 +08:00
Red Adaya 7a377c4a2a loadThemeStyles doesn't have to be async 2024-04-04 11:08:04 +08:00
Red Adaya 8afa62fff2 cleanup 2024-04-04 11:04:34 +08:00
Red Adaya 97595a7718 working 2024-04-04 11:02:27 +08:00
Red Adaya e4d353b5c1 remove selector prop from StyleBlock 2024-04-04 07:34:38 +08:00
Red Adaya 2462c64793 selector should always be :root 2024-04-04 07:33:10 +08:00
Red Adaya b451ee1ef9 change prop from classname to selector 2024-04-04 07:21:26 +08:00
Red Adaya 2c64668382 ability to inherit root styles 2024-04-03 22:22:05 +08:00
Red Adaya de21303fb1 root level 2024-04-03 22:12:48 +08:00
Red Adaya f6cdd53fd4 StyleBlock in elements dir 2024-04-03 20:50:47 +08:00
Red Adaya 840b69d100 reusable StyleBlock component 2024-04-03 20:48:13 +08:00
Red Adaya 683c66f386 save work 2024-04-03 16:37:15 +08:00
17 changed files with 233 additions and 172 deletions
+10 -2
View File
@@ -20,7 +20,7 @@ import { MainSideBar } from "./sidebar/main";
import { RightSideBar } from "./sidebar/right";
import { DisconnectedModal, ClientStopModal } from "@/modals";
import { ModalsProvider } from "@/modals/provider";
import { Button } from "@/elements";
import { Button, TermStyleBlock } from "@/elements";
import { ErrorBoundary } from "@/common/error/errorboundary";
import cn from "classnames";
import "./app.less";
@@ -124,9 +124,11 @@ class App extends React.Component<{}, {}> {
const rightSidebarCollapsed = GlobalModel.rightSidebarModel.getCollapsed();
const activeMainView = GlobalModel.activeMainView.get();
const lightDarkClass = GlobalModel.isDarkTheme.get() ? "is-dark" : "is-light";
const termTheme = GlobalModel.getTermTheme();
return (
<div
key={"version-" + renderVersion}
key={`version- + ${renderVersion}`}
id="main"
className={cn(
"platform-" + platform,
@@ -151,6 +153,12 @@ class App extends React.Component<{}, {}> {
</div>
</If>
<div ref={this.mainContentRef} className="main-content">
<TermStyleBlock
scope="main"
termTheme={termTheme}
themeSrcEl={this.mainContentRef.current}
themeKey="main"
/>
<MainSideBar parentRef={this.mainContentRef} />
<ErrorBoundary>
<PluginsView />
+4 -4
View File
@@ -76,14 +76,14 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
@boundMethod
handleChangeTermTheme(theme: string): void {
// For global terminal theme, the key is global, otherwise it's either
// For main terminal theme, the key is main, otherwise it's either
// sessionId or screenId.
const currTheme = GlobalModel.getTermTheme()["global"];
const currTheme = GlobalModel.getTermTheme()["main"];
if (currTheme == theme) {
return;
}
const prtn = GlobalCommandRunner.setGlobalTermTheme(theme, false);
const prtn = GlobalCommandRunner.setMainTermTheme(theme, false);
commandRtnHandler(prtn, this.errorMessage);
}
@@ -208,7 +208,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
const curFontFamily = GlobalModel.getTermFontFamily();
const curTheme = GlobalModel.getThemeSource();
const termThemes = getTermThemes(GlobalModel.termThemes, "Wave Default");
const currTermTheme = GlobalModel.getTermTheme()["global"] ?? termThemes[0].label;
const currTermTheme = GlobalModel.getTermTheme()["main"] ?? termThemes[0].label;
return (
<MainView className="clientsettings-view" title="Client Settings" onClose={this.handleClose}>
+5 -2
View File
@@ -5,7 +5,7 @@
width: 100%;
border: 2px solid var(--form-element-border-color);
border-radius: 6px;
line-height: 22px;
line-height: 20px;
background: var(--form-element-bg-color);
&.no-label {
@@ -63,11 +63,14 @@
display: flex;
min-width: 120px;
padding: 5px 8px;
justify-content: space-between;
align-items: center;
align-self: stretch;
border-radius: 6px;
i {
margin-right: 8px;
}
&-highlighted,
&:hover {
background: rgba(241, 246, 243, 0.08);
+8 -6
View File
@@ -163,7 +163,7 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
if (isOpen) {
const option = options[highlightedIndex];
if (option) {
this.handleSelect(option.value, undefined);
this.handleSelect(option, undefined);
}
} else {
this.toggleDropdown();
@@ -185,18 +185,19 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
handleKeyDown(event: React.KeyboardEvent) {}
@boundMethod
handleSelect(value: string, event?: React.MouseEvent | React.KeyboardEvent) {
handleSelect({ value, noop }: DropdownItem, event?: React.MouseEvent | React.KeyboardEvent) {
const { onChange } = this.props;
if (event) {
event.stopPropagation(); // This stops the event from bubbling up to the wrapper
}
if (!("value" in this.props)) {
this.setState({ internalValue: value });
}
onChange(value);
this.setState({ isOpen: false, isTouched: true });
this.unregisterKeybindings();
if (!("value" in this.props) && !noop) {
this.setState({ internalValue: value });
}
}
@boundMethod
@@ -245,10 +246,11 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
className={cn("wave-dropdown-item unselectable", {
"wave-dropdown-item-highlighted": index === highlightedIndex,
})}
onClick={(e) => this.handleSelect(option.value, e)}
onClick={(e) => this.handleSelect(option, e)}
onMouseEnter={() => this.setState({ highlightedIndex: index })}
onMouseLeave={() => this.setState({ highlightedIndex: -1 })}
>
{option.icon && <span className="wave-dropdown-item-icon">{option.icon}</span>}
{option.label}
</div>
))}
+1
View File
@@ -18,4 +18,5 @@ export { Toggle } from "./toggle";
export { Tooltip } from "./tooltip";
export { TabIcon } from "./tabicon";
export { DatePicker } from "./datepicker";
export { TermStyleBlock } from "./termstyleblock";
export { CopyButton } from "./copybutton";
+117
View File
@@ -0,0 +1,117 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { GlobalModel } from "@/models";
import { isBlank } from "@/util/util";
const VALID_CSS_VARIABLES = [
"--term-black",
"--term-red",
"--term-green",
"--term-yellow",
"--term-blue",
"--term-magenta",
"--term-cyan",
"--term-white",
"--term-bright-black",
"--term-bright-red",
"--term-bright-green",
"--term-bright-yellow",
"--term-bright-blue",
"--term-bright-magenta",
"--term-bright-cyan",
"--term-bright-white",
"--term-gray",
"--term-cmdtext",
"--term-foreground",
"--term-background",
"--term-selection-background",
"--term-cursor-accent",
];
@mobxReact.observer
class TermStyleBlock extends React.Component<
{ scope: "main" | "session" | "screen"; themeSrcEl: HTMLElement; themeKey: string; termTheme: TermThemeType },
{ styleRules: string }
> {
styleRules: OV<string> = mobx.observable.box("", { name: "StyleBlock-styleRules" });
theme: string;
componentDidMount(): void {
this.loadThemeStyles();
}
componentDidUpdate(prevProps): void {
const { themeKey, termTheme } = this.props;
const currTheme = termTheme[themeKey];
if (themeKey !== prevProps.themeKey || currTheme !== this.theme) {
this.loadThemeStyles();
}
}
isValidCSSColor(color) {
const element = document.createElement("div");
element.style.color = color;
return element.style.color !== "";
}
isValidTermCSSVariable(key, value) {
const cssVarName = `--term-${key}`;
console.log("cssVarName", cssVarName, "value", value);
return VALID_CSS_VARIABLES.includes(cssVarName);
}
camelCaseToKebabCase(str) {
return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
}
loadThemeStyles() {
const { themeKey, termTheme, scope } = this.props;
const currTheme = termTheme[themeKey];
if (currTheme && currTheme !== this.theme && currTheme) {
const rtn = GlobalModel.getTermThemeJson(currTheme);
rtn.then((termThemeJson) => {
if (termThemeJson && typeof termThemeJson === "object") {
const styleProperties = Object.entries(termThemeJson)
.filter(([key, value]) => {
const cssVarName = `--term-${this.camelCaseToKebabCase(key)}`;
return VALID_CSS_VARIABLES.includes(cssVarName) && this.isValidCSSColor(value);
})
.map(([key, value]) => `--term-${key}: ${value};`)
.join(" ");
mobx.action(() => {
this.styleRules.set(`:root { ${styleProperties} }`);
GlobalModel.termThemeSrcEls.set(scope, this.props.themeSrcEl);
})();
GlobalModel.bumpTermRenderVersion();
this.theme = currTheme;
} else {
console.error("termThemeJson is not an object:", termThemeJson);
}
}).catch((error) => {
console.error("error loading theme styles:", error);
});
} else {
mobx.action(() => {
this.styleRules.set("");
GlobalModel.termThemeSrcEls.set(scope, null);
})();
this.theme = currTheme;
GlobalModel.bumpTermRenderVersion();
}
}
render() {
if (isBlank(this.styleRules.get())) {
return null;
}
return <style>{this.styleRules.get()}</style>;
}
}
export { TermStyleBlock };
-5
View File
@@ -649,11 +649,6 @@ class LineContainer extends React.Component<{ historyId: string; width: number }
this.line = hvm.getLineById(this.historyItem.lineid);
}
componentDidMount(): void {
GlobalModel.bumpTermRenderVersion();
GlobalModel.termThemeSrcEl.set(null);
}
@boundMethod
handleHeightChange(lineNum: number, newHeight: number, oldHeight: number): void {
return;
+16 -51
View File
@@ -5,12 +5,10 @@ import { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components";
import cn from "classnames";
import { GlobalCommandRunner, GlobalModel, Screen } from "@/models";
import { Button, TextField, Dropdown } from "@/elements";
import { getRemoteStr, getRemoteStrWithAlias } from "@/common/prompt/prompt";
import { TextField, Dropdown } from "@/elements";
import { getRemoteStrWithAlias } from "@/common/prompt/prompt";
import * as util from "@/util/util";
import { TabIcon } from "@/elements/tabicon";
import { ReactComponent as EllipseIcon } from "@/assets/icons/ellipse.svg";
import { ReactComponent as Check12Icon } from "@/assets/icons/check12.svg";
import { ReactComponent as GlobeIcon } from "@/assets/icons/globe.svg";
import { ReactComponent as StatusCircleIcon } from "@/assets/icons/statuscircle.svg";
import * as appconst from "@/app/appconst";
@@ -18,52 +16,6 @@ import * as appconst from "@/app/appconst";
import "./screenview.less";
import "./tabs.less";
@mobxReact.observer
class NewTabSettings extends React.Component<{ screen: Screen }, {}> {
errorMessage: OV<string | null> = mobx.observable.box(null, { name: "NewTabSettings-errorMessage" });
constructor(props) {
super(props);
}
@boundMethod
clickNewConnection(): void {
GlobalModel.remotesModel.openAddModal({ remoteedit: true });
}
render() {
let { screen } = this.props;
let rptr = screen.curRemote.get();
return (
<div className="newtab-container">
<div className="newtab-section name-section">
<TabNameTextField screen={screen} errorMessage={this.errorMessage} />
</div>
<div className="newtab-spacer" />
<div className="newtab-section conn-section">
<div className="unselectable">
You're connected to <b>[{getRemoteStrWithAlias(rptr)}]</b>. Do you want to change it?
</div>
<div>
<TabRemoteSelector screen={screen} errorMessage={this.errorMessage} />
</div>
<div className="text-caption cr-help-text">
To change connection from the command line use `/connect [alias|user@host]`
</div>
</div>
<div className="newtab-spacer" />
<div className="newtab-section">
<TabIconSelector screen={screen} errorMessage={this.errorMessage} />
</div>
<div className="newtab-spacer" />
<div className="newtab-section">
<TabColorSelector screen={screen} errorMessage={this.errorMessage} />
</div>
</div>
);
}
}
@mobxReact.observer
class TabNameTextField extends React.Component<{ screen: Screen; errorMessage?: OV<string> }, {}> {
@boundMethod
@@ -163,6 +115,10 @@ class TabRemoteSelector extends React.Component<{ screen: Screen; errorMessage?:
@boundMethod
selectRemote(cname: string): void {
if (cname == null) {
GlobalModel.remotesModel.openAddModal({ remoteedit: true });
return;
}
mobx.action(() => {
this.selectedRemoteCN.set(cname);
})();
@@ -191,6 +147,14 @@ class TabRemoteSelector extends React.Component<{ screen: Screen; errorMessage?:
}
return a.remoteidx - b.remoteidx;
});
options.push({
label: "New Connection",
value: null,
icon: <i className="fa-sharp fa-solid fa-plus"></i>,
noop: true,
});
return options;
}
@@ -210,6 +174,7 @@ class TabRemoteSelector extends React.Component<{ screen: Screen; errorMessage?:
let curRemote = GlobalModel.getRemoteByName(selectedRemote);
return (
<Dropdown
label="Connection"
className="conn-dropdown"
options={this.getOptions()}
defaultValue={curRemote.remotecanonicalname}
@@ -227,4 +192,4 @@ class TabRemoteSelector extends React.Component<{ screen: Screen; errorMessage?:
}
}
export { NewTabSettings, TabColorSelector, TabIconSelector, TabNameTextField, TabRemoteSelector };
export { TabColorSelector, TabIconSelector, TabNameTextField, TabRemoteSelector };
+11 -2
View File
@@ -12,7 +12,7 @@ import { debounce } from "throttle-debounce";
import dayjs from "dayjs";
import { GlobalCommandRunner, ForwardLineContainer, GlobalModel, ScreenLines, Screen, Session } from "@/models";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { Button } from "@/elements";
import { Button, TermStyleBlock } from "@/elements";
import { Line } from "@/app/line/linecomps";
import { LinesView } from "@/app/line/linesview";
import * as util from "@/util/util";
@@ -184,10 +184,19 @@ class ScreenView extends React.Component<{ session: Session; screen: Screen }, {
winWidth = screenWidth - realWidth + "px";
sidebarWidth = realWidth - MagicLayout.ScreenSidebarWidthPadding + "px";
}
const termTheme = GlobalModel.getTermTheme();
const termRenderVersion = GlobalModel.termRenderVersion.get();
return (
<div className="screen-view" data-screenid={screen.screenId} ref={this.screenViewRef}>
<TermStyleBlock
scope="screen"
termTheme={termTheme}
themeSrcEl={this.screenViewRef.current}
themeKey={screen.screenId}
/>
<ScreenWindowView
key={screen.screenId + ":" + fontSize + ":" + dprStr}
key={screen.screenId + ":" + fontSize + ":" + dprStr + ":" + termRenderVersion}
session={session}
screen={screen}
width={winWidth}
+5 -1
View File
@@ -40,7 +40,7 @@
border-bottom: none;
}
.close-icon {
.close-button {
position: absolute;
right: 10px;
top: 10px;
@@ -187,4 +187,8 @@
}
}
}
.terminal-theme-dropdown {
width: 412px;
}
}
+15 -64
View File
@@ -15,10 +15,9 @@ import { ScreenTabs } from "./screen/tabs";
import { ErrorBoundary } from "@/common/error/errorboundary";
import { boundMethod } from "autobind-decorator";
import type { Screen } from "@/models";
import { Button } from "@/elements";
import { Button, Dropdown, TermStyleBlock } from "@/elements";
import { commandRtnHandler } from "@/util/util";
import { getTermThemes } from "@/util/themeutil";
import { Dropdown } from "@/elements/dropdown";
import { getRemoteStrWithAlias } from "@/common/prompt/prompt";
import { TabColorSelector, TabIconSelector, TabNameTextField, TabRemoteSelector } from "./screen/newtabsettings";
import * as util from "@/util/util";
@@ -175,6 +174,7 @@ class TabSettings extends React.Component<{ screen: Screen }, {}> {
<If condition={termThemes.length > 0}>
<div className="newtab-section">
<Dropdown
label="Terminal Theme"
className="terminal-theme-dropdown"
options={termThemes}
defaultValue={currTermTheme}
@@ -208,59 +208,6 @@ class TabSettings extends React.Component<{ screen: Screen }, {}> {
@mobxReact.observer
class WorkspaceView extends React.Component<{}, {}> {
sessionRef = React.createRef<HTMLDivElement>();
theme: string;
themeReactionDisposer: mobx.IReactionDisposer;
componentDidMount() {
this.setupThemeReaction();
}
componentDidUpdate() {
this.setupThemeReaction();
}
setupThemeReaction() {
if (this.themeReactionDisposer) {
this.themeReactionDisposer();
}
// This handles session and screen-level terminal theming.
// Ideally, screen-level theming should be handled in the inner-level component, but
// the frequent mounting and unmounting of the screen view make it really difficult to work.
this.themeReactionDisposer = mobx.reaction(
() => {
return {
termTheme: GlobalModel.getTermTheme(),
session: GlobalModel.getActiveSession(),
screen: GlobalModel.getActiveScreen(),
};
},
({ termTheme, session, screen }) => {
let currTheme = termTheme[session.sessionId];
if (termTheme[screen.screenId]) {
currTheme = termTheme[screen.screenId];
}
if (session && currTheme !== this.theme && this.sessionRef.current) {
const reset = currTheme == null;
const theme = currTheme ?? this.theme;
const themeSrcEl = reset ? null : this.sessionRef.current;
const rtn = GlobalModel.updateTermTheme(this.sessionRef.current, theme, reset);
rtn.then(() => {
GlobalModel.termThemeSrcEl.set(themeSrcEl);
}).then(() => {
GlobalModel.bumpTermRenderVersion();
});
this.theme = currTheme;
}
}
);
}
componentWillUnmount() {
if (this.themeReactionDisposer) {
this.themeReactionDisposer();
}
}
@boundMethod
toggleTabSettings() {
@@ -277,11 +224,11 @@ class WorkspaceView extends React.Component<{}, {}> {
sessionId = session.sessionId;
activeScreen = session.getActiveScreen();
}
const isHidden = GlobalModel.activeMainView.get() != "session";
const mainSidebarModel = GlobalModel.mainSidebarModel;
const termRenderVersion = GlobalModel.termRenderVersion.get();
const showTabSettings = GlobalModel.tabSettingsOpen.get();
const termTheme = GlobalModel.getTermTheme();
return (
<div
ref={this.sessionRef}
@@ -291,15 +238,23 @@ class WorkspaceView extends React.Component<{}, {}> {
width: `${window.innerWidth - mainSidebarModel.getWidth()}px`,
}}
>
<If condition={session != null}>
<TermStyleBlock
scope="session"
themeSrcEl={this.sessionRef.current}
themeKey={session.sessionId}
termTheme={termTheme}
/>
</If>
<If condition={!isHidden}>
<SessionKeybindings key="keybindings"></SessionKeybindings>
</If>
<ScreenTabs key={"tabs-" + sessionId} session={session} />
<If condition={activeScreen != null}>
<div key="pulldown" className={cn("tab-settings-pulldown", { closed: !showTabSettings })}>
<button className="close-icon" onClick={this.toggleTabSettings}>
<Button className="close-button secondary ghost" onClick={this.toggleTabSettings}>
<i className="fa-solid fa-sharp fa-xmark-large" />
</button>
</Button>
<TabSettings key={activeScreen.screenId} screen={activeScreen} />
<If condition={showTabSettings && !isHidden}>
<TabSettingsPulldownKeybindings />
@@ -307,11 +262,7 @@ class WorkspaceView extends React.Component<{}, {}> {
</div>
</If>
<ErrorBoundary key="eb">
<ScreenView
key={`screenview-${sessionId}-${termRenderVersion}`}
session={session}
screen={activeScreen}
/>
<ScreenView key={`screenview-${sessionId}`} session={session} screen={activeScreen} />
<If condition={activeScreen != null}>
<CmdInput key={"cmdinput-" + sessionId} />
</If>
+1 -2
View File
@@ -377,7 +377,7 @@ class CommandRunner {
return GlobalModel.submitCommand("client", "set", null, kwargs, interactive);
}
setGlobalTermTheme(theme: string, interactive: boolean): Promise<CommandRtnType> {
setMainTermTheme(theme: string, interactive: boolean): Promise<CommandRtnType> {
let kwargs = {
nohist: "1",
termtheme: theme,
@@ -386,7 +386,6 @@ class CommandRunner {
}
setSessionTermTheme(sessionId: string, name: string, interactive: boolean): Promise<CommandRtnType> {
console.log("setSessionTermTheme-------");
let kwargs = {
nohist: "1",
id: sessionId,
+32 -26
View File
@@ -144,13 +144,15 @@ class Model {
name: "terminalThemes",
deep: false,
});
termThemeSrcEl: OV<HTMLElement> = mobx.observable.box(null, {
name: "termThemeSrcEl",
});
termThemeSrcEls: OMap<string, HTMLElement> = mobx.observable.map(
{},
{
name: "termThemeSrcEls",
}
);
termRenderVersion: OV<number> = mobx.observable.box(0, {
name: "termRenderVersion",
});
currGlobalTermTheme: string;
private constructor() {
this.clientId = getApi().getId();
@@ -215,6 +217,16 @@ class Model {
};
}
getThemeSrcElForScope() {
const scopes = ["screen", "session", "main"];
for (let scope of scopes) {
if (this.termThemeSrcEls.get(scope)) {
return this.termThemeSrcEls.get(scope);
}
}
return document.documentElement;
}
readConfigKeybindings() {
const url = new URL(this.getBaseHostPort() + "/config/keybindings.json");
let prtn = fetch(url, { method: "get", body: null, headers: this.getFetchHeaders() });
@@ -253,19 +265,12 @@ class Model {
});
}
updateTermTheme(element: HTMLElement, themeFileName: string, reset: boolean) {
getTermThemeJson(themeFileName: string) {
const url = new URL(this.getBaseHostPort() + `/config/terminal-themes/${themeFileName}.json`);
return fetch(url, { method: "get", body: null, headers: this.getFetchHeaders() })
.then((resp) => resp.json())
.then((themeVars: TermThemeType) => {
Object.keys(themeVars).forEach((key) => {
if (reset) {
this.resetStyleVar(element, `--term-${key}`);
} else {
this.resetStyleVar(element, `--term-${key}`);
this.setStyleVar(element, `--term-${key}`, themeVars[key]);
}
});
return themeVars;
})
.catch((error) => {
console.error(`error applying theme: ${themeFileName}`, error);
@@ -1323,19 +1328,20 @@ class Model {
}
// Only for global terminal theme. For session and screen terminal theme,
// they are handled in workspace view.
if (newTermTheme) {
const el = document.documentElement;
const globaltt = newTermTheme["global"] ?? this.currGlobalTermTheme;
const reset = newTermTheme["global"] == null;
if (globaltt) {
const rtn = this.updateTermTheme(el, globaltt, reset);
rtn.then(() => {
if (ttUpdated) {
this.bumpTermRenderVersion();
}
});
this.currGlobalTermTheme = globaltt;
}
if (ttUpdated) {
// this.bumpTermRenderVersion();
// const el = document.documentElement;
// const globaltt = newTermTheme["global"] ?? this.currGlobalTermTheme;
// const reset = newTermTheme["global"] == null;
// if (globaltt) {
// const rtn = this.updateTermTheme(el, globaltt, reset);
// rtn.then(() => {
// if (ttUpdated) {
// this.bumpTermRenderVersion();
// }
// });
// this.currGlobalTermTheme = globaltt;
// }
}
}
+1 -1
View File
@@ -131,7 +131,7 @@ class TermWrap {
let cols = windowWidthToCols(opts.winSize.width, opts.fontSize);
this.termSize = { rows: opts.termOpts.rows, cols: cols };
}
const themeSrcEl = GlobalModel.termThemeSrcEl.get();
const themeSrcEl = GlobalModel.getThemeSrcElForScope();
let theme = getThemeFromCSSVars(themeSrcEl);
this.terminal = new Terminal({
rows: this.termSize.rows,
+3 -1
View File
@@ -308,7 +308,9 @@ declare global {
type DropdownItem = {
label: string;
value: string;
value?: string;
icon?: React.ReactNode;
noop?: boolean;
};
/**
+2 -3
View File
@@ -1,8 +1,7 @@
import * as React from "react";
import * as mobx from "mobx";
import * as electron from "electron";
import { parse } from "node:path";
import { v4 as uuidv4 } from "uuid";
import { Model } from "@/models";
import defaultKeybindingsFile from "../../assets/default-keybindings.json";
const defaultKeybindings: KeybindConfigArray = defaultKeybindingsFile;
@@ -52,7 +51,7 @@ class KeybindManager {
activeKeybindsVersion: OV<number>;
lastKeyData: { domain: string; keyPress: string };
constructor(GlobalModel: any) {
constructor(GlobalModel: Model) {
this.levelMap = new Map();
this.domainCallbacks = new Map();
this.levelArray = KeybindLevels;
+2 -2
View File
@@ -5814,9 +5814,9 @@ func ClientSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sc
feOpts.TermTheme = make(map[string]string)
}
if termthemeStr == "" {
delete(feOpts.TermTheme, "global")
delete(feOpts.TermTheme, "main")
} else {
feOpts.TermTheme["global"] = termthemeStr
feOpts.TermTheme["main"] = termthemeStr
}
err = sstore.UpdateClientFeOpts(ctx, feOpts)
if err != nil {