mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-21 16:38:23 +01:00
terminal themes, use terminal bg to style the full block
This commit is contained in:
parent
9afb5a7bc1
commit
d68d32f96c
@ -264,6 +264,7 @@ const BlockFrame_Default_Component = ({
|
||||
const headerTextUnion = util.useAtomValueSafe(viewModel.viewText);
|
||||
const preIconButton = util.useAtomValueSafe(viewModel.preIconButton);
|
||||
const endIconButtons = util.useAtomValueSafe(viewModel.endIconButtons);
|
||||
const customBg = util.useAtomValueSafe(viewModel.blockBg);
|
||||
if (preview) {
|
||||
isFocused = true;
|
||||
}
|
||||
@ -381,6 +382,16 @@ const BlockFrame_Default_Component = ({
|
||||
layoutModel?.onMagnifyToggle();
|
||||
}
|
||||
|
||||
const innerStyle: React.CSSProperties = {};
|
||||
if (customBg?.bg != null) {
|
||||
innerStyle.background = customBg.bg;
|
||||
if (customBg["bg:opacity"] != null) {
|
||||
innerStyle.opacity = customBg["bg:opacity"];
|
||||
}
|
||||
if (customBg["bg:blendmode"] != null) {
|
||||
innerStyle.backgroundBlendMode = customBg["bg:blendmode"];
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
@ -397,7 +408,7 @@ const BlockFrame_Default_Component = ({
|
||||
style={style}
|
||||
>
|
||||
<div className="block-mask"></div>
|
||||
<div className="block-frame-default-inner">
|
||||
<div className="block-frame-default-inner" style={innerStyle}>
|
||||
<div
|
||||
className="block-frame-default-header"
|
||||
ref={layoutModel?.dragHandleRef}
|
||||
|
@ -6,31 +6,17 @@ import { VDomView } from "@/app/view/term/vdom";
|
||||
import { WOS, atoms, getEventORefSubject, globalStore, useBlockAtom, useSettingsAtom } from "@/store/global";
|
||||
import * as services from "@/store/services";
|
||||
import * as keyutil from "@/util/keyutil";
|
||||
import * as util from "@/util/util";
|
||||
import clsx from "clsx";
|
||||
import { produce } from "immer";
|
||||
import * as jotai from "jotai";
|
||||
import * as React from "react";
|
||||
import { TermStickers } from "./termsticker";
|
||||
import { TermThemeUpdater } from "./termtheme";
|
||||
import { computeTheme } from "./termutil";
|
||||
import { TermWrap } from "./termwrap";
|
||||
|
||||
import "public/xterm.css";
|
||||
|
||||
function computeTheme(settings: SettingsConfigType, themeName: string) {
|
||||
let defaultThemeName = "default-dark";
|
||||
themeName = themeName ?? "default-dark";
|
||||
const defaultTheme: TermThemeType = settings?.termthemes?.[defaultThemeName] || ({} as any);
|
||||
const theme: TermThemeType = settings?.termthemes?.[themeName] || ({} as any);
|
||||
const combinedTheme = { ...defaultTheme };
|
||||
for (const key in theme) {
|
||||
if (!util.isBlank(theme[key])) {
|
||||
combinedTheme[key] = theme[key];
|
||||
}
|
||||
}
|
||||
return combinedTheme;
|
||||
}
|
||||
|
||||
const keyMap = {
|
||||
Enter: "\r",
|
||||
Backspace: "\x7f",
|
||||
@ -130,6 +116,7 @@ class TermViewModel {
|
||||
viewIcon: jotai.Atom<string>;
|
||||
viewText: jotai.Atom<string>;
|
||||
viewName: jotai.Atom<string>;
|
||||
blockBg: jotai.Atom<MetaType>;
|
||||
|
||||
constructor(blockId: string) {
|
||||
this.blockId = blockId;
|
||||
@ -152,6 +139,15 @@ class TermViewModel {
|
||||
const blockData = get(this.blockAtom);
|
||||
return blockData?.meta?.title ?? "";
|
||||
});
|
||||
this.blockBg = jotai.atom((get) => {
|
||||
const blockData = get(this.blockAtom);
|
||||
const settings = globalStore.get(atoms.settingsConfigAtom);
|
||||
const theme = computeTheme(settings, blockData?.meta?.["term:theme"]);
|
||||
if (theme != null && theme.background != null) {
|
||||
return { bg: theme.background };
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
giveFocus(): boolean {
|
||||
@ -169,6 +165,23 @@ class TermViewModel {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
setTerminalTheme(themeName: string) {
|
||||
WshServer.SetMetaCommand({ oref: WOS.makeORef("block", this.blockId), meta: { "term:theme": themeName } });
|
||||
}
|
||||
|
||||
getSettingsMenuItems(): ContextMenuItem[] {
|
||||
return [
|
||||
{
|
||||
label: "Themes",
|
||||
submenu: [
|
||||
{ label: "Default Dark", click: () => this.setTerminalTheme("default") },
|
||||
{ label: "Dracula", click: () => this.setTerminalTheme("dracula") },
|
||||
{ label: "Campbell", click: () => this.setTerminalTheme("campbell") },
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function makeTerminalModel(blockId: string): TermViewModel {
|
||||
@ -220,11 +233,13 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||
}
|
||||
const settings = globalStore.get(atoms.settingsConfigAtom);
|
||||
const termTheme = computeTheme(settings, blockData?.meta?.["term:theme"]);
|
||||
const themeCopy = { ...termTheme };
|
||||
themeCopy.background = "#00000000";
|
||||
const termWrap = new TermWrap(
|
||||
blockId,
|
||||
connectElemRef.current,
|
||||
{
|
||||
theme: termTheme,
|
||||
theme: themeCopy,
|
||||
fontSize: termSettings?.fontsize ?? 12,
|
||||
fontFamily: termSettings?.fontfamily ?? "Hack",
|
||||
drawBoldTextInBrightColors: false,
|
||||
|
@ -29,7 +29,9 @@ const TermThemeUpdater = ({ blockId, termRef }: TermThemeProps) => {
|
||||
}
|
||||
}
|
||||
if (termRef.current?.terminal) {
|
||||
termRef.current.terminal.options.theme = combinedTheme;
|
||||
let themeCopy = { ...combinedTheme };
|
||||
themeCopy.background = "#00000000";
|
||||
termRef.current.terminal.options.theme = themeCopy;
|
||||
}
|
||||
}, [defaultTheme, theme]);
|
||||
|
||||
|
20
frontend/app/view/term/termutil.ts
Normal file
20
frontend/app/view/term/termutil.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import * as util from "@/util/util";
|
||||
|
||||
function computeTheme(settings: SettingsConfigType, themeName: string): TermThemeType {
|
||||
let defaultThemeName = "default-dark";
|
||||
themeName = themeName ?? "default-dark";
|
||||
const defaultTheme: TermThemeType = settings?.termthemes?.[defaultThemeName] || ({} as any);
|
||||
const theme: TermThemeType = settings?.termthemes?.[themeName] || ({} as any);
|
||||
const combinedTheme = { ...defaultTheme };
|
||||
for (const key in theme) {
|
||||
if (!util.isBlank(theme[key])) {
|
||||
combinedTheme[key] = theme[key];
|
||||
}
|
||||
}
|
||||
return combinedTheme;
|
||||
}
|
||||
|
||||
export { computeTheme };
|
1
frontend/types/custom.d.ts
vendored
1
frontend/types/custom.d.ts
vendored
@ -166,6 +166,7 @@ declare global {
|
||||
viewText?: jotai.Atom<string | HeaderElem[]>;
|
||||
preIconButton?: jotai.Atom<HeaderIconButton>;
|
||||
endIconButtons?: jotai.Atom<HeaderIconButton[]>;
|
||||
blockBg?: jotai.Atom<MetaType>;
|
||||
|
||||
onBack?: () => void;
|
||||
onForward?: () => void;
|
||||
|
@ -125,10 +125,60 @@ var DefaultTermDarkTheme = TermThemeType{
|
||||
CmdText: "#f0f0f0",
|
||||
Foreground: "#c1c1c1",
|
||||
SelectionBackground: "",
|
||||
Background: "#00000000",
|
||||
Background: "#00000077",
|
||||
CursorAccent: "",
|
||||
}
|
||||
|
||||
var DraculaTheme = TermThemeType{
|
||||
Black: "#21222C", // AnsiBlack
|
||||
Red: "#FF5555", // AnsiRed
|
||||
Green: "#50FA7B", // AnsiGreen
|
||||
Yellow: "#F1FA8C", // AnsiYellow
|
||||
Blue: "#BD93F9", // AnsiBlue
|
||||
Magenta: "#FF79C6", // AnsiMagenta
|
||||
Cyan: "#8BE9FD", // AnsiCyan
|
||||
White: "#F8F8F2", // AnsiWhite
|
||||
BrightBlack: "#6272A4", // AnsiBrightBlack
|
||||
BrightRed: "#FF6E6E", // AnsiBrightRed
|
||||
BrightGreen: "#69FF94", // AnsiBrightGreen
|
||||
BrightYellow: "#FFFFA5", // AnsiBrightYellow
|
||||
BrightBlue: "#D6ACFF", // AnsiBrightBlue
|
||||
BrightMagenta: "#FF92DF", // AnsiBrightMagenta
|
||||
BrightCyan: "#A4FFFF", // AnsiBrightCyan
|
||||
BrightWhite: "#FFFFFF", // AnsiBrightWhite
|
||||
Gray: "#6272A4", // Comment or closest approximation
|
||||
CmdText: "#F8F8F2", // Foreground
|
||||
Foreground: "#F8F8F2", // Foreground
|
||||
SelectionBackground: "#44475a", // Selection
|
||||
Background: "#282a36", // Background
|
||||
CursorAccent: "#f8f8f2", // Foreground (used for cursor accent)
|
||||
}
|
||||
|
||||
var CampbellTheme = TermThemeType{
|
||||
Black: "#0C0C0C", // Black
|
||||
Red: "#C50F1F", // Red
|
||||
Green: "#13A10E", // Green
|
||||
Yellow: "#C19C00", // Yellow
|
||||
Blue: "#0037DA", // Blue
|
||||
Magenta: "#881798", // Purple (used as Magenta)
|
||||
Cyan: "#3A96DD", // Cyan
|
||||
White: "#CCCCCC", // White
|
||||
BrightBlack: "#767676", // BrightBlack
|
||||
BrightRed: "#E74856", // BrightRed
|
||||
BrightGreen: "#16C60C", // BrightGreen
|
||||
BrightYellow: "#F9F1A5", // BrightYellow
|
||||
BrightBlue: "#3B78FF", // BrightBlue
|
||||
BrightMagenta: "#B4009E", // BrightPurple (used as BrightMagenta)
|
||||
BrightCyan: "#61D6D6", // BrightCyan
|
||||
BrightWhite: "#F2F2F2", // BrightWhite
|
||||
Gray: "#767676", // BrightBlack or closest approximation
|
||||
CmdText: "#CCCCCC", // Foreground
|
||||
Foreground: "#CCCCCC", // Foreground
|
||||
SelectionBackground: "#3A96DD", // Cyan (chosen for selection background)
|
||||
Background: "#0C0C0C", // Background
|
||||
CursorAccent: "#CCCCCC", // Foreground (used for cursor accent)
|
||||
}
|
||||
|
||||
func applyDefaultSettings(settings *SettingsConfigType) {
|
||||
defaultMimeTypes := map[string]MimeTypeConfigType{
|
||||
"audio": {Icon: "file-audio"},
|
||||
@ -229,4 +279,10 @@ func applyDefaultSettings(settings *SettingsConfigType) {
|
||||
if _, found := settings.TermThemes["default-dark"]; !found {
|
||||
settings.TermThemes["default-dark"] = DefaultTermDarkTheme
|
||||
}
|
||||
if _, found := settings.TermThemes["dracula"]; !found {
|
||||
settings.TermThemes["dracula"] = DraculaTheme
|
||||
}
|
||||
if _, found := settings.TermThemes["campbell"]; !found {
|
||||
settings.TermThemes["campbell"] = CampbellTheme
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user