mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
button refactor (#383)
Refactored to be more flexible. Now, it has three types - solid - outline - ghost and subtypes - green - grey - red - yellow It defaults to solid and green when no className is provided. It concatenates defaults if custom classNames are provided.
This commit is contained in:
parent
dbdcc49ff2
commit
09f4616ae0
@ -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 = <i className="fa-sharp fa-solid fa-rotate-right"></i>;
|
||||
reconClassName = clsx(reconClassName, "font-size-12 vertical-padding-5 horizontal-padding-6");
|
||||
|
@ -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;
|
||||
|
||||
i {
|
||||
fill: var(--main-text-color);
|
||||
}
|
||||
|
||||
&.primary:not(.ghost),
|
||||
&.secondary:not(.ghost) {
|
||||
color: var(--button-primary-text-color);
|
||||
background: var(--accent-color);
|
||||
&:hover {
|
||||
color: var(--main-text-color);
|
||||
}
|
||||
|
||||
i {
|
||||
fill: var(--main-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.primary.danger {
|
||||
background: var(--error-color);
|
||||
}
|
||||
|
||||
&.primary.warning {
|
||||
background: #e6ba1e;
|
||||
}
|
||||
|
||||
&.primary.ghost {
|
||||
background: none;
|
||||
|
||||
i {
|
||||
fill: var(--accent-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.primary.ghost.danger {
|
||||
i {
|
||||
fill: var(--app-error-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary,
|
||||
&.link-button {
|
||||
background: var(--highlight-bg-color);
|
||||
}
|
||||
|
||||
&.secondary.ghost {
|
||||
background: none;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
color: 1px solid var(--main-text-color);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.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);
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary.danger {
|
||||
color: var(--error-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);
|
||||
}
|
||||
}
|
||||
|
||||
&.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);
|
||||
}
|
||||
}
|
||||
|
||||
&.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.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 {
|
||||
border: 1px solid var(--main-text-color);
|
||||
color: var(--button-green-bg);
|
||||
}
|
||||
}
|
||||
|
||||
&.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;
|
||||
}
|
||||
|
@ -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<HTMLButtonElement> {
|
||||
@ -11,15 +8,25 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
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 (
|
||||
<button
|
||||
tabIndex={disabled ? -1 : 0}
|
||||
className={clsx("button", className, {
|
||||
className={clsx("button", finalClassName, {
|
||||
disabled,
|
||||
hasIcon,
|
||||
})}
|
||||
|
@ -1,12 +1,21 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
.button {
|
||||
&.link-button {
|
||||
&.link-button {
|
||||
text-decoration: none;
|
||||
|
||||
.button-inner {
|
||||
display: flex;
|
||||
border-radius: 6px;
|
||||
padding: 8px 12px;
|
||||
background-color: var(--button-grey-bg);
|
||||
border: 1px solid var(--button-grey-border-color);
|
||||
color: var(--button-grey-text-color);
|
||||
i {
|
||||
margin-right: 4px;
|
||||
}
|
||||
&:hover {
|
||||
color: var(--button-grey-text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ interface LinkButtonProps {
|
||||
|
||||
const LinkButton = ({ leftIcon, rightIcon, children, className, ...rest }: LinkButtonProps) => {
|
||||
return (
|
||||
<a {...rest} className="button link-button">
|
||||
<span className={clsx("button-inner", className)}>
|
||||
<a {...rest} className={clsx("link-button", className)}>
|
||||
<span className="button-inner">
|
||||
{leftIcon && <span className="icon-left">{leftIcon}</span>}
|
||||
{children}
|
||||
{rightIcon && <span className="icon-right">{rightIcon}</span>}
|
||||
|
@ -45,7 +45,7 @@ const Modal = forwardRef<HTMLDivElement, ModalProps>(
|
||||
<div className="modal-wrapper">
|
||||
{renderBackdrop(onClickBackdrop)}
|
||||
<div ref={ref} className={clsx(`modal`, className)}>
|
||||
<Button className="secondary ghost modal-close-btn" onClick={onClose} title="Close (ESC)">
|
||||
<Button className="grey ghost modal-close-btn" onClick={onClose} title="Close (ESC)">
|
||||
<i className="fa-sharp fa-solid fa-xmark"></i>
|
||||
</Button>
|
||||
<div className="content-wrapper">
|
||||
@ -81,15 +81,11 @@ const ModalFooter = ({ onCancel, onOk, cancelLabel = "Cancel", okLabel = "Ok" }:
|
||||
return (
|
||||
<footer className="modal-footer">
|
||||
{onCancel && (
|
||||
<Button className="secondary ghost" onClick={onCancel}>
|
||||
<Button className="grey ghost" onClick={onCancel}>
|
||||
{cancelLabel}
|
||||
</Button>
|
||||
)}
|
||||
{onOk && (
|
||||
<Button className="primary" onClick={onOk}>
|
||||
{okLabel}
|
||||
</Button>
|
||||
)}
|
||||
{onOk && <Button onClick={onOk}>{okLabel}</Button>}
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
@ -205,11 +205,7 @@ const Tab = React.memo(
|
||||
>
|
||||
{tabData?.name}
|
||||
</div>
|
||||
<Button
|
||||
className="secondary ghost close"
|
||||
onClick={onClose}
|
||||
onMouseDown={handleMouseDownOnClose}
|
||||
>
|
||||
<Button className="grey ghost close" onClick={onClose} onMouseDown={handleMouseDownOnClose}>
|
||||
<i className="fa fa-solid fa-xmark" />
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user