diff --git a/frontend/app/block/blockframe.tsx b/frontend/app/block/blockframe.tsx index 96cef3a74..1ee2c8ed4 100644 --- a/frontend/app/block/blockframe.tsx +++ b/frontend/app/block/blockframe.tsx @@ -319,7 +319,7 @@ const ConnStatusOverlay = React.memo( showReconnect = false; } let reconDisplay = null; - let reconClassName = "outlined"; + let reconClassName = "outlined grey"; if (width && width < 350) { reconDisplay = ; reconClassName = clsx(reconClassName, "font-size-12 vertical-padding-5 horizontal-padding-6"); diff --git a/frontend/app/element/button.less b/frontend/app/element/button.less index e53aa7bfc..3e1772365 100644 --- a/frontend/app/element/button.less +++ b/frontend/app/element/button.less @@ -5,8 +5,8 @@ // override default button appearance border: 1px solid transparent; outline: 1px solid transparent; + border: none; - background: var(--accent-color); cursor: pointer; display: flex; padding-top: 8px; @@ -21,75 +21,128 @@ white-space: nowrap; user-select: none; font-size: 14px; - color: var(--secondary-text-color); font-weight: normal; + opacity: 0.8; - i { - fill: var(--main-text-color); + &:hover { + opacity: 1; } - &.primary:not(.ghost), - &.secondary:not(.ghost) { - color: var(--button-primary-text-color); - background: var(--accent-color); - &:hover { - color: var(--main-text-color); + &.solid { + &.green { + color: var(--button-green-text-color); + background-color: var(--button-green-bg); + border: 1px solid var(--button-green-border-color); + &:hover { + color: var(--button-green-text-color); + } } - i { - fill: var(--main-text-color); + &.grey { + background-color: var(--button-grey-bg); + border: 1px solid var(--button-grey-border-color); + color: var(--button-grey-text-color); + &:hover { + color: var(--button-grey-text-color); + } } - } - &.primary.danger { - background: var(--error-color); - } - - &.primary.warning { - background: #e6ba1e; - } - - &.primary.ghost { - background: none; - - i { - fill: var(--accent-color); + &.red { + background-color: var(--button-red-bg); + border: 1px solid var(--button-red-border-color); + color: var(--button-red-text-color); + &:hover { + color: var(--button-red-text-color); + } } - } - &.primary.ghost.danger { - i { - fill: var(--app-error-color); + &.yellow { + color: var(--button-yellow-text-color); + background-color: var(--button-yellow-bg); + border: 1px solid var(--button-yellow-border-color); + &:hover { + color: var(--button-yellow-text-color); + } } } - &.secondary, - &.link-button { - background: var(--highlight-bg-color); - } - - &.secondary.ghost { - background: none; - - &:hover { - color: 1px solid var(--main-text-color); - } - } - - &.secondary.danger { - color: var(--error-color); - } - &.outlined { - background: none; - border: 1px solid var(--secondary-text-color); + background-color: transparent; + &.green { + color: var(--button-green-bg); + border: 1px solid var(--button-green-bg); + &:hover { + color: var(--button-green-bg); + } + } - &:hover { - border: 1px solid var(--main-text-color); + &.grey { + border: 1px solid var(--button-grey-border-color); + color: var(--button-grey-text-color); + &:hover { + color: var(--button-grey-text-color); + } + } + + &.red { + border: 1px solid var(--button-red-bg); + color: var(--button-red-bg); + &:hover { + color: var(--button-red-bg); + } + } + + &.yellow { + color: var(--button-yellow-bg); + border: 1px solid var(--button-yellow-bg); + &:hover { + color: var(--button-yellow-bg); + } + } + } + + &.ghost { + background-color: transparent; + padding-top: 8px; + padding-bottom: 8px; + padding-left: 8px; + padding-right: 8px; + + &.green { + border: none; + color: var(--button-green-bg); + &:hover { + color: var(--button-green-bg); + } + } + + &.grey { + border: none; + color: var(--button-grey-text-color); + &:hover { + color: var(--button-grey-text-color); + } + } + + &.red { + border: none; + color: var(--button-red-bg); + &:hover { + color: var(--button-red-bg); + } + } + + &.yellow { + border: none; + color: var(--button-yellow-bg); + &:hover { + color: var(--button-yellow-bg); + } } } &.disabled { + cursor: default; opacity: 0.5; } @@ -99,9 +152,8 @@ outline-offset: 2px; } - /* - * customs styles here - */ + // customs styles here + &.border-radius-2 { border-radius: 4px; } diff --git a/frontend/app/element/button.tsx b/frontend/app/element/button.tsx index 04acf8852..a1db5c49b 100644 --- a/frontend/app/element/button.tsx +++ b/frontend/app/element/button.tsx @@ -1,8 +1,5 @@ -// Copyright 2024, Command Line Inc. -// SPDX-License-Identifier: Apache-2.0 - import clsx from "clsx"; -import React from "react"; +import { Children, isValidElement, memo } from "react"; import "./button.less"; interface ButtonProps extends React.ButtonHTMLAttributes { @@ -11,15 +8,25 @@ interface ButtonProps extends React.ButtonHTMLAttributes { children?: React.ReactNode; } -const Button = React.memo(({ className = "primary", children, disabled, ...props }: ButtonProps) => { - const hasIcon = React.Children.toArray(children).some( - (child) => React.isValidElement(child) && (child as React.ReactElement).type === "svg" +const Button = memo(({ className = "", children, disabled, ...props }: ButtonProps) => { + const hasIcon = Children.toArray(children).some( + (child) => isValidElement(child) && (child as React.ReactElement).type === "svg" ); + // Check if the className contains any of the categories: solid, outlined, or ghost + const containsButtonCategory = /(solid|outline|ghost)/.test(className); + // If no category is present, default to 'solid' + const categoryClassName = containsButtonCategory ? className : `solid ${className}`; + + // Check if the className contains any of the color options: green, grey, red, or yellow + const containsColor = /(green|grey|red|yellow)/.test(categoryClassName); + // If no color is present, default to 'green' + const finalClassName = containsColor ? categoryClassName : `green ${categoryClassName}`; + return (
@@ -81,15 +81,11 @@ const ModalFooter = ({ onCancel, onOk, cancelLabel = "Cancel", okLabel = "Ok" }: return (
{onCancel && ( - )} - {onOk && ( - - )} + {onOk && }
); }; diff --git a/frontend/app/tab/tab.tsx b/frontend/app/tab/tab.tsx index 11855a958..3c4faa6fc 100644 --- a/frontend/app/tab/tab.tsx +++ b/frontend/app/tab/tab.tsx @@ -205,11 +205,7 @@ const Tab = React.memo( > {tabData?.name}
- diff --git a/frontend/app/theme.less b/frontend/app/theme.less index 9398402a0..80208749c 100644 --- a/frontend/app/theme.less +++ b/frontend/app/theme.less @@ -69,7 +69,7 @@ // xterm-decoration-overview-ruler: 8 // xterm-decoration-top: 2 - /* modal colors */ + // modal colors --modal-bg-color: #232323; --modal-header-bottom-border-color: rgba(241, 246, 243, 0.15); --modal-border-color: rgba(255, 255, 255, 0.12); /* toggle colors */ @@ -78,15 +78,10 @@ --toggle-thumb-color: var(--main-text-color); --toggle-checked-bg-color: var(--accent-color); - /* link color */ + // link color --link-color: #58c142; - /* button colors */ - --button-primary-color: #58c142; - --button-focus-border-color: rgba(88, 193, 66, 0.8); - --button-primary-text-color: #000000; - - /* form colors */ + // form colors --form-element-border-color: rgba(241, 246, 243, 0.15); --form-element-bg-color: var(--main-bg-color); --form-element-text-color: var(--main-text-color); @@ -106,4 +101,45 @@ --conn-icon-color-8: #58c142; --bulb-color: rgb(255, 221, 51); + + // term colors (16 + 6) form the base terminal theme + // for consistency these colors should be used by plugins/applications + --term-black: #000000; + --term-red: #cc0000; + --term-green: #4e9a06; + --term-yellow: #c4a000; + --term-blue: #3465a4; + --term-magenta: #bc3fbc; + --term-cyan: #06989a; + --term-white: #d0d0d0; + --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: #e7e7e7; + + --term-gray: #8b918a; // not an official terminal color + --term-cmdtext: #ffffff; + --term-foreground: #d3d7cf; + --term-background: #000000; + --term-selection-background: #ffffff60; + --term-cursor-accent: #000000; + + // button colors + --button-focus-border-color: rgba(88, 193, 66, 0.5); + --button-green-text-color: var(--term-black); + --button-green-bg: var(--term-green); + --button-green-border-color: rgb(26, 52, 21); + --button-grey-text-color: var(--main-text-color); + --button-grey-bg: rgba(255, 255, 255, 0.04); + --button-grey-border-color: rgba(255, 255, 255, 0.1); + --button-red-text-color: var(--main-text-color); + --button-red-bg: var(--term-red); + --button-red-border-color: #ff1818; + --button-yellow-text-color: var(--term-black); + --button-yellow-bg: var(--term-yellow); + --button-yellow-border-color: #fbd93f; } diff --git a/frontend/app/view/preview/preview.tsx b/frontend/app/view/preview/preview.tsx index d4eba1e46..0a504182c 100644 --- a/frontend/app/view/preview/preview.tsx +++ b/frontend/app/view/preview/preview.tsx @@ -289,9 +289,9 @@ export class PreviewModel implements ViewModel { onClick: () => this.updateOpenFileModalAndError(true), }, ]; - let saveClassName = "secondary"; + let saveClassName = "grey"; if (get(this.newFileContent) !== null) { - saveClassName = "primary"; + saveClassName = "green"; } if (isCeView) { viewTextChildren.push({ @@ -307,7 +307,7 @@ export class PreviewModel implements ViewModel { elemtype: "textbutton", text: "Preview", className: - "secondary border-radius-4 vertical-padding-2 horizontal-padding-10 font-size-11 font-weight-500", + "grey border-radius-4 vertical-padding-2 horizontal-padding-10 font-size-11 font-weight-500", onClick: () => this.setEditMode(false), }); } @@ -316,7 +316,7 @@ export class PreviewModel implements ViewModel { elemtype: "textbutton", text: "Edit", className: - "secondary border-radius-4 vertical-padding-2 horizontal-padding-10 font-size-11 font-weight-500", + "grey border-radius-4 vertical-padding-2 horizontal-padding-10 font-size-11 font-weight-500", onClick: () => this.setEditMode(true), }); }