diff --git a/public/index-dev.html b/public/index-dev.html index fffbee524..cd5b16f8a 100644 --- a/public/index-dev.html +++ b/public/index-dev.html @@ -11,6 +11,8 @@ + +
diff --git a/public/index.html b/public/index.html index 03b504a26..af410542c 100644 --- a/public/index.html +++ b/public/index.html @@ -11,6 +11,8 @@ + +
diff --git a/src/app/root.less b/public/themes/default.css similarity index 82% rename from src/app/root.less rename to public/themes/default.css index 7bc1eb238..c69d9549f 100644 --- a/src/app/root.less +++ b/public/themes/default.css @@ -1,18 +1,18 @@ -// Copyright 2024, Command Line Inc. -// SPDX-License-Identifier: Apache-2.0 +/* Copyright 2024, Command Line Inc. + SPDX-License-Identifier: Apache-2.0 */ :root { --fa-style-family: "Font Awesome 6 Sharp"; - // these variables are overridden by user settings + /* these variables are overridden by user settings */ --termfontfamily: "JetBrains Mono", monospace; --termfontsize: 12px; --termlineheight: 15px; - --termpad: 7px; // padding value (scaled to termfontsize) + --termpad: 7px; /* padding value (scaled to termfontsize) */ --termfontsize-sm: 10px; --termlineheight-sm: 13px; - // other fonts + /* other fonts */ --base-font-family: "Lato", sans-serif; --base-font-size: 15px; --base-font-weight: normal; @@ -29,19 +29,19 @@ --markdown-font-size: 14px; - --screentabs-height: 38px; // magic - --screentabs-line-height: 21px; // magic + --screentabs-height: 38px; /* magic */ + --screentabs-line-height: 21px; /* magic */ --screentabs-font-size: 15px; --screentabs-font-weight: normal; --screentabs-selected-font-weight: bold; --screen-tab-width: 11.4em; - // floating logo settings + /* floating logo settings */ --floating-logo-width-darwin: 110px; --floating-logo-width: 40px; --floating-logo-height: var(--screentabs-height); - // global colors + /* global colors */ --app-bg-color: black; --app-accent-color: rgb(88, 193, 66); --app-error-color: rgb(204, 0, 0); @@ -56,19 +56,19 @@ --app-panel-bg-color: rgba(21, 23, 21, 1); --app-panel-bg-color-dev: rgb(21, 23, 48); - // global generic colors + /* global generic colors */ --app-black: rgb(0, 0, 0); - // scrollbar colors - // --scrollbar-background-color: rgba(21, 23, 21, 1); + /* scrollbar colors */ + /* --scrollbar-background-color: rgba(21, 23, 21, 1); */ --scrollbar-background-color: #030303; --scrollbar-thumb-color: #333; --scrollbar-thumb-hover-color: rgb(211, 215, 207); - // code color + /* code color */ --pre-bg-color: rgb(0, 0, 0); - // tab colors + /* tab colors */ --tab-red: rgb(229, 77, 46); --tab-orange: rgb(239, 113, 59); --tab-yellow: rgb(224, 185, 86); @@ -80,7 +80,7 @@ --tab-pink: rgb(224, 86, 119); --tab-white: rgb(255, 255, 255); - // term colors + /* term colors */ --term-black: #000000; --term-red: #cc0000; --term-green: #4e9a06; @@ -97,80 +97,78 @@ --term-bright-magenta: #ad7fa8; --term-bright-cyan: #34e2e2; --term-bright-white: #ffffff; - --term-gray: rgb(139, 145, 138); // not an official terminal color + --term-gray: rgb(139, 145, 138); /* not an official terminal color */ - // button colors + /* button colors */ --button-text-color: rgb(255, 255, 255); --button-primary-bg-color: rgb(78, 154, 6); --button-secondary-bg-color: rgba(255, 255, 255, 0.09); --button-warning-bg-color: rgb(204, 0, 0); - // input colors + /* input colors */ --checkbox-text-color: rgb(255, 255, 255); --checkbox-bg-color: rgb(78, 154, 6); --checkbox-check-color: rgb(255, 255, 255); - // dropdown colors + /* dropdown colors */ --dropdown-text-color: rgb(211, 215, 207); --dropdown-error-color: rgb(229, 77, 46); --dropdown-focus-color: rgb(78, 154, 6); - // textfield colors + /* textfield colors */ --textfield-focused-border-color: rgb(78, 154, 6); --textfield-error-border-color: rgb(229, 77, 46); --textfield-label-color: rgb(195, 200, 194); --textfield-text-color: rgb(255, 255, 255); --textfield-bg-color: rgba(48, 49, 48, 0.6); - // toggle colors + /* toggle colors */ --toggle-bg-color: rgb(51, 51, 51); --toggle-thumb-color: rgb(211, 215, 207); --toggle-checked-bg-color: rgb(78, 154, 6); - // cmdstrcode colors + /* cmdstrcode colors */ --cmdstrcode-bg-color: rgb(0, 0, 0); --cmdstrcode-text-color: rgb(211, 215, 207); - // markdown colors + /* markdown colors */ --markdown-bg-color: rgb(35, 35, 35); --markdown-outline-color: rgb(78, 154, 6); - // status(remote) colors - // todo: all status colors must be unified + /* status(remote) colors */ + /* todo: all status colors must be unified */ --status-connected-color: rgb(70, 167, 88); --status-connecting-color: rgb(245, 217, 10); --status-error-color: rgb(229, 77, 46); --status-disconnected-color: rgb(195, 200, 194); - // status indicator colors - // todo: all status colors must be unified + /* status indicator colors */ + /* todo: all status colors must be unified */ --status-indicator-color: rgb(211, 215, 207); --status-indicator-error: rgb(204, 0, 0); --status-indicator-success: rgb(78, 154, 6); - // status(version) colors - // todo: all status colors must be unified + /* status(version) colors */ + /* todo: all status colors must be unified */ --status-outdated-color: rgb(196, 160, 0); --status-updated-color: rgb(78, 154, 6); - // term status colors - // todo: all status colors must be unified + /* term status colors */ + /* todo: all status colors must be unified */ --term-error-color: rgb(204, 0, 0); --term-warning-color: rgb(196, 160, 0); - // hotkey colors + /* hotkey colors */ --hotkey-text-color: rgb(195, 200, 194); - // sidebar colors - --sidebar-settings-color: rgb(255, 255, 255); - --sidebar-separator-color: var(--app-border-color); + /* sidebar colors */ --sidebar-highlight-color: rgba(241, 246, 243, 0.08); --sidebar-font-size: 15px; --sidebar-line-height: 1.5; --sidebar-font-weight: normal; --sidebar-highlight-font-weight: bold; - // line colors + /* line colors */ --line-sidebar-message-color: rgb(196, 160, 0); --line-background: rgba(21, 23, 21, 1); --line-avatar-color: #eceeec; @@ -199,21 +197,21 @@ --line-actions-inactive-color: rgba(255, 255, 255, 0.5); --line-actions-active-color: rgba(255, 255, 255, 1); - // view colors - // todo: bookmarks is a view, colors must be unified with --view* colors + /* view colors */ + /* todo: bookmarks is a view, colors must be unified with --view* colors */ --bookmarks-text-color: rgb(211, 215, 207); --bookmarks-textarea-bg-color: rgb(0, 0, 0); --bookmarks-disabled-text-color: rgb(173, 173, 173); --bookmarks-control-hover-color: rgb(255, 255, 255); - // view colors + /* view colors */ --view-error-color: rgb(204, 0, 0); --view-text-color: rgb(195, 200, 194); - // session colors + /* session colors */ --session-bg-color: rgba(13, 13, 13, 0.85); - // cmdinput colors + /* cmdinput colors */ --cmdinput-textarea-bg-color: #171717; --cmdinput-text-error-color: rgb(239, 41, 41); --cmdinput-title-color: rgb(114, 159, 207); @@ -225,9 +223,9 @@ --cmdinput-disabled-icon-color: rgb(76, 81, 75, 1); --cmdinput-history-bg-color: rgb(21, 23, 21, 1); - // screen view color + /* screen view color */ --screen-view-text-caption-color: rgb(139, 145, 138); - // plugins colors + /* plugins colors */ --code-gutter-bg-color: rgba(88, 193, 66, 0.4); } diff --git a/public/themes/light.css b/public/themes/light.css new file mode 100644 index 000000000..25fb2eb9e --- /dev/null +++ b/public/themes/light.css @@ -0,0 +1,16 @@ +/* Copyright 2024, Command Line Inc. + SPDX-License-Identifier: Apache-2.0 */ + +@import "./default.css"; + +:root { + --app-bg-color: #ffffff; + --app-text-color: #000000; + + /* sidebar colors */ + --app-panel-bg-color: #cccccc; + --app-panel-bg-color-dev: #eeeeff; + + --term-black: #ffffff; + --term-white: #000000; +} diff --git a/src/app/app.less b/src/app/app.less index 2cc6197e0..a49dbe3a8 100644 --- a/src/app/app.less +++ b/src/app/app.less @@ -1,9 +1,6 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 -@import "./root.less"; -@import "./overrides.less"; - html, body { overflow: hidden; diff --git a/src/app/appconst.ts b/src/app/appconst.ts index 4bbbac464..6f93da9b9 100644 --- a/src/app/appconst.ts +++ b/src/app/appconst.ts @@ -27,6 +27,7 @@ export const DevServerEndpoint = "http://127.0.0.1:8090"; export const DevServerWsEndpoint = "ws://127.0.0.1:8091"; export const DefaultTermFontSize = 12; export const DefaultTermFontFamily = "JetBrains Mono"; +export const DefaultTheme = "dark"; export const MinFontSize = 8; export const MaxFontSize = 24; export const InputChunkSize = 500; diff --git a/src/app/clientsettings/clientsettings.tsx b/src/app/clientsettings/clientsettings.tsx index 5763e5291..6e8419467 100644 --- a/src/app/clientsettings/clientsettings.tsx +++ b/src/app/clientsettings/clientsettings.tsx @@ -44,6 +44,15 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove commandRtnHandler(prtn, this.errorMessage); } + @boundMethod + handleChangeTheme(theme: string): void { + if (GlobalModel.getTheme() == theme) { + return; + } + const prtn = GlobalCommandRunner.setTheme(theme, false); + commandRtnHandler(prtn, this.errorMessage); + } + @boundMethod handleChangeTelemetry(val: boolean): void { let prtn: Promise = null; @@ -82,6 +91,13 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove return availableFontFamilies; } + getThemes(): DropdownItem[] { + const themes: DropdownItem[] = []; + themes.push({ label: "Dark", value: "dark" }); + themes.push({ label: "Light", value: "light" }); + return themes; + } + @boundMethod inlineUpdateOpenAIModel(newModel: string): void { const prtn = GlobalCommandRunner.setClientOpenAISettings({ model: newModel }); @@ -148,6 +164,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove ); const curFontSize = GlobalModel.getTermFontSize(); const curFontFamily = GlobalModel.getTermFontFamily(); + const curTheme = GlobalModel.getTheme(); return ( @@ -174,6 +191,17 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove /> +
+
Theme
+
+ +
+
Client ID
{cdata.clientid}
diff --git a/src/app/common/themes/themes.less b/src/app/common/themes/themes.less deleted file mode 100644 index 747c50501..000000000 --- a/src/app/common/themes/themes.less +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2024, Command Line Inc. -// SPDX-License-Identifier: Apache-2.0 - -@base-color: #eceeec; -@base-background: rgba(21, 23, 21, 1); -@base-background-transparent: rgba(15, 17, 15, 0.7); -@base-background-dev: rgba(21, 23, 48, 1); -@base-border: rgba(241, 246, 243, 0.08); -@background-session: rgba(13, 13, 13, 0.85); -@background-session-components: rgba(48, 49, 48, 0.6); -@background-session-components-solid: rgb(33, 34, 33); -@wave-green: rgb(88, 193, 66); -@disabled-background: rgba(76, 81, 75, 1); -@disabled-color: #adadad; -@scrollbar-background: rgba(21, 23, 21, 1); -@scrollbar-thumb: rgb(134, 134, 134); -@button-background: rgb(38, 38, 38); -@button-disabled-background: rgb(30, 29, 29); -@success-green: rgb(38, 97, 26); -@error-red: #cc0000; -@error-red-brightened: #ff8888; -@warning-yellow: #ffa500; -@textarea-background: #171717; - -@text-primary: #fff; -@text-secondary: #c3c8c2; -@text-caption: #8b918a; - -@accent-color: #3b3f3a; - -@status-outline: #151715; -@dropdown-menu: rgba(21, 23, 21, 1); - -@status-connected: #46a758; -@status-connecting: #f5d90a; -@status-error: #e54d2e; -@status-disconnected: #c3c8c2; - -@term-black: #000000; -@term-red: #cc0000; -@term-green: #4e9a06; -@term-yellow: #c4a000; -@term-blue: #3465a4; -@term-magenta: #75507b; -@term-cyan: #06989a; -@term-white: #d3d7cf; -@term-bright-black: #555753; -@term-bright-red: #ef2929; -@term-bright-green: #58c142; -@term-bright-yellow: #fce94f; -@term-bright-blue: #32afff; -@term-bright-magenta: #ad7fa8; -@term-bright-cyan: #34e2e2; -@term-bright-white: #ffffff; - -@tab-red: #e54d2e; -@tab-orange: #ef713b; -@tab-yellow: #e0b956; -@tab-green: #58c142; -@tab-mint: #4bffa9; -@tab-cyan: #4bdfff; -@tab-blue: #3971ff; -@tab-violet: #ba76ff; -@tab-pink: #e05677; -@tab-white: #ffffff; - -@tab-black-text: #333; -@tab-white-text: #d7d7d7; - -@soft-blue: #729fcf; - -@active-menu-color: rgb(0, 71, 171); - -// @font-face declaration lives in app.less -@fixed-font: "Martian Mono", sans-serif; -@terminal-font: "JetBrains Mono", sans-serif; - -@text-s1-font: "Martian Mono", sans-serif; - -// to match Github -@markdown-font: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, - "Apple Color Emoji", "Segoe UI Emoji"; -@markdown-highlight: rgb(35, 35, 35); - -@thin-border-color: #333; -@main-content-bottom-background: #333; diff --git a/src/app/overrides.less b/src/app/overrides.less deleted file mode 100644 index 538180ece..000000000 --- a/src/app/overrides.less +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2024, Command Line Inc. -// SPDX-License-Identifier: Apache-2.0 - -:root { - // can put dev overrides for testing here -} diff --git a/src/app/sidebar/sidebar.less b/src/app/sidebar/sidebar.less index 93946fed2..d650933c0 100644 --- a/src/app/sidebar/sidebar.less +++ b/src/app/sidebar/sidebar.less @@ -55,7 +55,7 @@ .separator { height: 1px; margin: 16px 0; - background-color: var(--sidebar-separator-color); + background-color: var(--app-border-color); } .item.workspaces-item { @@ -64,7 +64,7 @@ .middle { padding: 4px 6px 8px 6px; - border-bottom: 1px solid var(--sidebar-separator-color); + border-bottom: 1px solid var(--app-border-color); .item { &.active { background-color: var(--sidebar-highlight-color); diff --git a/src/models/commandrunner.ts b/src/models/commandrunner.ts index 139c9b2e9..98150ccee 100644 --- a/src/models/commandrunner.ts +++ b/src/models/commandrunner.ts @@ -361,6 +361,14 @@ class CommandRunner { return GlobalModel.submitCommand("client", "set", null, kwargs, interactive); } + setTheme(theme: string, interactive: boolean): Promise { + let kwargs = { + nohist: "1", + theme: theme, + }; + return GlobalModel.submitCommand("client", "set", null, kwargs, interactive); + } + setClientOpenAISettings(opts: { model?: string; apitoken?: string; maxtokens?: string }): Promise { let kwargs = { nohist: "1", diff --git a/src/models/model.ts b/src/models/model.ts index 025fd4e63..ba81d85e3 100644 --- a/src/models/model.ts +++ b/src/models/model.ts @@ -14,6 +14,7 @@ import { isBlank, } from "@/util/util"; import { loadFonts } from "@/util/fontutil"; +import { loadTheme } from "@/util/themeutil"; import { WSControl } from "./ws"; import { cmdStatusIsRunning } from "@/app/line/lineutil"; import * as appconst from "@/app/appconst"; @@ -340,6 +341,15 @@ class Model { return ff; } + getTheme(): string { + let cdata = this.clientData.get(); + let theme = cdata?.feopts?.theme; + if (theme == null) { + theme = appconst.DefaultTheme; + } + return theme; + } + getTermFontSize(): number { return this.termFontSize.get(); } @@ -1173,6 +1183,12 @@ class Model { } const ffUpdated = newFontFamily != this.getTermFontFamily(); const fsUpdated = newFontSize != this.getTermFontSize(); + + let newTheme = clientData?.feopts?.theme; + if (newTheme == null) { + newTheme = appconst.DefaultTheme; + } + const themeUpdated = newTheme != this.getTheme(); mobx.action(() => { this.clientData.set(clientData); })(); @@ -1192,6 +1208,9 @@ class Model { } else if (fsUpdated) { this.updateTermFontSizeVars(); } + if (themeUpdated) { + loadTheme(newTheme); + } } submitCommandPacket(cmdPk: FeCmdPacketType, interactive: boolean): Promise { diff --git a/src/types/custom.d.ts b/src/types/custom.d.ts index 56a286269..c43cacb02 100644 --- a/src/types/custom.d.ts +++ b/src/types/custom.d.ts @@ -562,6 +562,7 @@ declare global { type FeOptsType = { termfontsize: number; termfontfamily: string; + theme: string; }; type ConfirmFlagsType = { diff --git a/src/util/themeutil.ts b/src/util/themeutil.ts new file mode 100644 index 000000000..1c6222480 --- /dev/null +++ b/src/util/themeutil.ts @@ -0,0 +1,10 @@ +function loadTheme(theme: string) { + const linkTag: any = document.getElementById("theme-stylesheet"); + if (theme === "dark") { + linkTag.href = "public/themes/default.css"; + } else { + linkTag.href = `public/themes/${theme}.css`; + } +} + +export { loadTheme }; diff --git a/wavesrv/pkg/cmdrunner/cmdrunner.go b/wavesrv/pkg/cmdrunner/cmdrunner.go index 6dfbcc9a1..97a3b8c38 100644 --- a/wavesrv/pkg/cmdrunner/cmdrunner.go +++ b/wavesrv/pkg/cmdrunner/cmdrunner.go @@ -97,6 +97,7 @@ var RemoteColorNames = []string{"red", "green", "yellow", "blue", "magenta", "cy var RemoteSetArgs = []string{"alias", "connectmode", "key", "password", "autoinstall", "color"} var ConfirmFlags = []string{"hideshellprompt"} var SidebarNames = []string{"main"} +var ThemeNames = []string{"light", "dark"} var ScreenCmds = []string{"run", "comment", "cd", "cr", "clear", "sw", "reset", "signal", "chat"} var NoHistCmds = []string{"_compgen", "line", "history", "_killserver"} @@ -5198,6 +5199,26 @@ func ClientSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sc } varsUpdated = append(varsUpdated, "termfontfamily") } + if themeStr, found := pk.Kwargs["theme"]; found { + newTheme := themeStr + found := false + for _, theme := range ThemeNames { + if newTheme == theme { + found = true + break + } + } + if !found { + return nil, fmt.Errorf("invalid theme name") + } + feOpts := clientData.FeOpts + feOpts.Theme = newTheme + err = sstore.UpdateClientFeOpts(ctx, feOpts) + if err != nil { + return nil, fmt.Errorf("error updating client feopts: %v", err) + } + varsUpdated = append(varsUpdated, "theme") + } if apiToken, found := pk.Kwargs["openaiapitoken"]; found { err = validateOpenAIAPIToken(apiToken) if err != nil { diff --git a/wavesrv/pkg/sstore/sstore.go b/wavesrv/pkg/sstore/sstore.go index 09dbb20cf..1ae9f9199 100644 --- a/wavesrv/pkg/sstore/sstore.go +++ b/wavesrv/pkg/sstore/sstore.go @@ -297,6 +297,7 @@ type ClientOptsType struct { type FeOptsType struct { TermFontSize int `json:"termfontsize,omitempty"` TermFontFamily string `json:"termfontfamily,omitempty"` + Theme string `json:"theme,omitempty"` } type ReleaseInfoType struct {