Make color usage more consistent (#3842)

* Tweak overrides - should not cause visual change

* Use closest color for avatar

* Change hover color of contained buttons

* Change nav item color (matches avatar now)

* Format

* Use lighter border for contained button hover

This looks more clickable than lightening the background

* Delete unused component

* Make dropdown arrow consistent

Same up as down. Contrast text everywhere except nav, where it matches links and avatar.

* No need to fade right arrows

* Add hover color

* Consistent box shadows

* Format

* Delete unused DialogSearch

* Deleting unused button types to avoid confusion

* Use disabled arrow on disabled action buttons
This commit is contained in:
Presley Pizzo
2022-09-06 10:58:12 -04:00
committed by GitHub
parent 8e1dfc2763
commit 1f55135765
17 changed files with 52 additions and 271 deletions
@@ -1,5 +1,5 @@
import Popover, { PopoverProps } from "@material-ui/core/Popover"
import { fade, makeStyles } from "@material-ui/core/styles"
import { makeStyles } from "@material-ui/core/styles"
import { FC, PropsWithChildren } from "react"
type BorderedMenuVariant = "admin-dropdown" | "user-dropdown"
@@ -41,6 +41,6 @@ const useStyles = makeStyles((theme) => ({
width: "292px",
border: `2px solid ${theme.palette.secondary.dark}`,
borderRadius: theme.shape.borderRadius,
boxShadow: `4px 4px 0px ${fade(theme.palette.secondary.dark, 0.2)}`,
boxShadow: theme.shadows[6],
},
}))
@@ -1,5 +1,5 @@
import Box from "@material-ui/core/Box"
import { fade, makeStyles, Theme } from "@material-ui/core/styles"
import { makeStyles, Theme } from "@material-ui/core/styles"
import Table from "@material-ui/core/Table"
import TableBody from "@material-ui/core/TableBody"
import TableCell from "@material-ui/core/TableCell"
@@ -115,7 +115,7 @@ export const BuildsTable: FC<React.PropsWithChildren<BuildsTableProps>> = ({
const useStyles = makeStyles((theme) => ({
clickableTableRow: {
"&:hover td": {
backgroundColor: fade(theme.palette.primary.dark, 0.1),
backgroundColor: theme.palette.action.hover,
},
"&:focus": {
@@ -127,7 +127,7 @@ const useStyles = makeStyles((theme) => ({
},
},
arrowRight: {
color: fade(theme.palette.primary.contrastText, 0.7),
color: theme.palette.text.secondary,
width: 20,
height: 20,
},
-50
View File
@@ -1,12 +1,9 @@
import MuiDialog, { DialogProps as MuiDialogProps } from "@material-ui/core/Dialog"
import MuiDialogTitle from "@material-ui/core/DialogTitle"
import InputAdornment from "@material-ui/core/InputAdornment"
import OutlinedInput, { OutlinedInputProps } from "@material-ui/core/OutlinedInput"
import { darken, fade, lighten, makeStyles } from "@material-ui/core/styles"
import SvgIcon from "@material-ui/core/SvgIcon"
import * as React from "react"
import { combineClasses } from "../../util/combineClasses"
import { SearchIcon } from "../Icons/SearchIcon"
import { LoadingButton, LoadingButtonProps } from "../LoadingButton/LoadingButton"
import { ConfirmDialogType } from "./types"
@@ -300,53 +297,6 @@ const useButtonStyles = makeStyles((theme) => ({
},
}))
export type DialogSearchProps = Omit<
OutlinedInputProps,
"className" | "fullWidth" | "labelWidth" | "startAdornment"
>
/**
* Formats a search bar right below the title of a Dialog. Passes all props
* through to the Material UI OutlinedInput component contained within.
*/
export const DialogSearch: React.FC<DialogSearchProps> = (props) => {
const styles = useSearchStyles()
return (
<div className={styles.root}>
<OutlinedInput
{...props}
fullWidth
labelWidth={0}
className={styles.input}
startAdornment={
<InputAdornment position="start">
<SearchIcon className={styles.icon} />
</InputAdornment>
}
/>
</div>
)
}
const useSearchStyles = makeStyles(
(theme) => ({
root: {
position: "relative",
padding: `${theme.spacing(2)}px ${theme.spacing(4)}px`,
boxShadow: `0 2px 6px ${fade("#1D407E", 0.2)}`,
zIndex: 2,
},
input: {
margin: 0,
},
icon: {
width: 16,
height: 16,
},
}),
{ name: "CdrDialogSearch" },
)
export type DialogProps = MuiDialogProps
/**
@@ -1,31 +1,32 @@
import { fade, makeStyles, Theme } from "@material-ui/core/styles"
import { makeStyles, Theme } from "@material-ui/core/styles"
import KeyboardArrowDown from "@material-ui/icons/KeyboardArrowDown"
import KeyboardArrowUp from "@material-ui/icons/KeyboardArrowUp"
import { FC } from "react"
const useStyles = makeStyles<Theme, ArrowProps>((theme: Theme) => ({
arrowIcon: {
color: fade(theme.palette.primary.contrastText, 0.7),
color: ({ color }) => color ?? theme.palette.primary.contrastText,
marginLeft: ({ margin }) => (margin ? theme.spacing(1) : 0),
width: 16,
height: 16,
},
arrowIconUp: {
color: theme.palette.primary.contrastText,
color: ({ color }) => color ?? theme.palette.primary.contrastText,
},
}))
interface ArrowProps {
margin?: boolean
color?: string
}
export const OpenDropdown: FC<ArrowProps> = ({ margin = true }) => {
const styles = useStyles({ margin })
export const OpenDropdown: FC<ArrowProps> = ({ margin = true, color }) => {
const styles = useStyles({ margin, color })
return <KeyboardArrowDown aria-label="open-dropdown" className={styles.arrowIcon} />
}
export const CloseDropdown: FC<ArrowProps> = ({ margin = true }) => {
const styles = useStyles({ margin })
export const CloseDropdown: FC<ArrowProps> = ({ margin = true, color }) => {
const styles = useStyles({ margin, color })
return (
<KeyboardArrowUp
aria-label="close-dropdown"
@@ -1,6 +1,6 @@
import Button from "@material-ui/core/Button"
import Popover from "@material-ui/core/Popover"
import { makeStyles } from "@material-ui/core/styles"
import { makeStyles, useTheme } from "@material-ui/core/styles"
import { CloseDropdown, OpenDropdown } from "components/DropdownArrows/DropdownArrows"
import { DropdownContent } from "components/DropdownButton/DropdownContent/DropdownContent"
import { FC, ReactNode, useRef, useState } from "react"
@@ -20,9 +20,11 @@ export const DropdownButton: FC<DropdownButtonProps> = ({
handleCancel,
}) => {
const styles = useStyles()
const theme = useTheme()
const anchorRef = useRef<HTMLButtonElement>(null)
const [isOpen, setIsOpen] = useState(false)
const id = isOpen ? "action-popover" : undefined
const canOpen = secondaryActions.length > 0
return (
<span className={styles.buttonContainer}>
@@ -41,12 +43,16 @@ export const DropdownButton: FC<DropdownButtonProps> = ({
aria-haspopup="true"
className={styles.dropdownButton}
ref={anchorRef}
disabled={!secondaryActions.length}
disabled={!canOpen}
onClick={() => {
setIsOpen(true)
}}
>
{isOpen ? <CloseDropdown /> : <OpenDropdown />}
{isOpen ? (
<CloseDropdown />
) : (
<OpenDropdown color={canOpen ? undefined : theme.palette.action.disabled} />
)}
</Button>
<Popover
classes={{ paper: styles.popoverPaper }}
@@ -2,10 +2,11 @@ import Drawer from "@material-ui/core/Drawer"
import IconButton from "@material-ui/core/IconButton"
import List from "@material-ui/core/List"
import ListItem from "@material-ui/core/ListItem"
import { fade, makeStyles } from "@material-ui/core/styles"
import { makeStyles } from "@material-ui/core/styles"
import MenuIcon from "@material-ui/icons/Menu"
import { useState } from "react"
import { NavLink, useLocation } from "react-router-dom"
import { colors } from "theme/colors"
import * as TypesGen from "../../api/typesGenerated"
import { navHeight } from "../../theme/constants"
import { combineClasses } from "../../util/combineClasses"
@@ -169,7 +170,7 @@ const useStyles = makeStyles((theme) => ({
},
link: {
alignItems: "center",
color: "hsl(220, 11%, 71%)",
color: colors.gray[6],
display: "flex",
fontSize: 16,
padding: `${theme.spacing(1.5)}px ${theme.spacing(2)}px`,
@@ -177,7 +178,7 @@ const useStyles = makeStyles((theme) => ({
transition: "background-color 0.3s ease",
"&:hover": {
backgroundColor: fade(theme.palette.primary.light, 0.05),
backgroundColor: theme.palette.action.hover,
},
// NavLink adds this class when the current route matches.
+1 -2
View File
@@ -1,5 +1,4 @@
import { makeStyles } from "@material-ui/core/styles"
import { fade } from "@material-ui/core/styles/colorManipulator"
import Typography from "@material-ui/core/Typography"
import { FC } from "react"
import { combineClasses } from "../../util/combineClasses"
@@ -59,7 +58,7 @@ Section.Action = SectionAction
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: theme.palette.background.paper,
boxShadow: `0px 18px 12px 6px ${fade(theme.palette.common.black, 0.02)}`,
boxShadow: theme.shadows[6],
marginBottom: theme.spacing(1),
padding: theme.spacing(6),
borderRadius: theme.shape.borderRadius,
@@ -1,57 +0,0 @@
import { fireEvent, render, screen } from "@testing-library/react"
import { SplitButton, SplitButtonProps } from "./SplitButton"
namespace Helpers {
export type SplitButtonOptions = "a" | "b" | "c"
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
export const callback = (selectedOption: SplitButtonOptions): void => {}
export const options: SplitButtonProps<SplitButtonOptions>["options"] = [
{
label: "test a",
value: "a",
},
{
label: "test b",
value: "b",
},
{
label: "test c",
value: "c",
},
]
}
describe("SplitButton", () => {
describe("onClick", () => {
it("is called when primary action is clicked", () => {
// Given
const mockedAndSpyedCallback = jest.fn(Helpers.callback)
// When
render(<SplitButton onClick={mockedAndSpyedCallback} options={Helpers.options} />)
fireEvent.click(screen.getByText("test a"))
// Then
expect(mockedAndSpyedCallback.mock.calls.length).toBe(1)
expect(mockedAndSpyedCallback.mock.calls[0][0]).toBe("a")
})
it("is called when clicking option in pop-up", () => {
// Given
const mockedAndSpyedCallback = jest.fn(Helpers.callback)
// When
render(<SplitButton onClick={mockedAndSpyedCallback} options={Helpers.options} />)
const buttons = screen.getAllByRole("button")
const dropdownButton = buttons[1]
fireEvent.click(dropdownButton)
fireEvent.click(screen.getByText("test c"))
// Then
expect(mockedAndSpyedCallback.mock.calls.length).toBe(1)
expect(mockedAndSpyedCallback.mock.calls[0][0]).toBe("c")
})
})
})
@@ -1,122 +0,0 @@
import Button, { ButtonProps } from "@material-ui/core/Button"
import ButtonGroup from "@material-ui/core/ButtonGroup"
import ClickAwayListener from "@material-ui/core/ClickAwayListener"
import MenuItem from "@material-ui/core/MenuItem"
import MenuList from "@material-ui/core/MenuList"
import Paper from "@material-ui/core/Paper"
import Popper from "@material-ui/core/Popper"
import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown"
import React, { useRef, useState } from "react"
interface SplitButtonOptions<T> {
/**
* label is shown in the SplitButton UI
*/
label: string
/**
* value is any value for this option
*/
value: T
}
export interface SplitButtonProps<T> extends Pick<ButtonProps, "color" | "disabled" | "startIcon"> {
/**
* onClick is called with the selectedOption
*/
onClick: (selectedOption: T) => void
/**
* options is a list of options
*/
options: SplitButtonOptions<T>[]
/**
* textTransform is applied to the primary button text. Defaults PropsWithto
* uppercase
*/
textTransform?: React.CSSProperties["textTransform"]
}
/**
* SplitButton is a button with a primary option and a dropdown with secondary
* options.
* @remark The primary option is the 0th index (first option) in the array.
* @see https://mui.com/components/button-group/#split-button
*/
export const SplitButton = <T,>({
color,
disabled,
onClick,
options,
startIcon,
textTransform,
}: SplitButtonProps<T>): ReturnType<React.FC> => {
const [isPopperOpen, setIsPopperOpen] = useState<boolean>(false)
const anchorRef = useRef<HTMLDivElement>(null)
const displayedLabel = options[0].label
const handleClick = () => {
onClick(options[0].value)
}
const handleClose = (e: React.MouseEvent<Document, MouseEvent>) => {
if (anchorRef.current && anchorRef.current.contains(e.target as HTMLElement)) {
return
}
setIsPopperOpen(false)
}
const handleSelectOpt = (e: React.MouseEvent<HTMLLIElement, MouseEvent>, opt: number) => {
onClick(options[opt].value)
setIsPopperOpen(false)
}
const handleTogglePopper = () => {
setIsPopperOpen((prevOpen) => !prevOpen)
}
return (
<>
<ButtonGroup aria-label="split button" color={color} ref={anchorRef} variant="contained">
<Button
disabled={disabled}
onClick={handleClick}
startIcon={startIcon}
style={{ textTransform }}
>
{displayedLabel}
</Button>
<Button
aria-controls={isPopperOpen ? "split-button-menu" : undefined}
aria-expanded={isPopperOpen ? "true" : undefined}
aria-label="select merge strategy"
aria-haspopup="menu"
disabled={disabled}
size="small"
onClick={handleTogglePopper}
>
<ArrowDropDownIcon />
</Button>
</ButtonGroup>
<Popper
anchorEl={anchorRef.current}
disablePortal
open={isPopperOpen}
role={undefined}
style={{ zIndex: 1 }}
transition
>
{() => (
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList id="split-button-menu">
{options.map((opt, idx) => (
<MenuItem key={opt.label} onClick={(e) => handleSelectOpt(e, idx)}>
{opt.label}
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
)}
</Popper>
</>
)
}
@@ -1,7 +1,8 @@
import Badge from "@material-ui/core/Badge"
import MenuItem from "@material-ui/core/MenuItem"
import { fade, makeStyles } from "@material-ui/core/styles"
import { makeStyles } from "@material-ui/core/styles"
import React, { useState } from "react"
import { colors } from "theme/colors"
import * as TypesGen from "../../api/typesGenerated"
import { navHeight } from "../../theme/constants"
import { BorderedMenu } from "../BorderedMenu/BorderedMenu"
@@ -39,7 +40,11 @@ export const UserDropdown: React.FC<React.PropsWithChildren<UserDropdownProps>>
<Badge overlap="circle">
<UserAvatar username={user.username} avatarURL={user.avatar_url} />
</Badge>
{anchorEl ? <CloseDropdown /> : <OpenDropdown />}
{anchorEl ? (
<CloseDropdown color={colors.gray[6]} />
) : (
<OpenDropdown color={colors.gray[6]} />
)}
</div>
</MenuItem>
@@ -83,7 +88,7 @@ export const useStyles = makeStyles((theme) => ({
padding: `${theme.spacing(1.5)}px ${theme.spacing(2.75)}px`,
"&:hover": {
backgroundColor: fade(theme.palette.primary.light, 0.05),
backgroundColor: theme.palette.action.hover,
transition: "background-color 0.3s ease",
},
},
@@ -3,7 +3,7 @@ import Divider from "@material-ui/core/Divider"
import ListItemIcon from "@material-ui/core/ListItemIcon"
import ListItemText from "@material-ui/core/ListItemText"
import MenuItem from "@material-ui/core/MenuItem"
import { fade, makeStyles } from "@material-ui/core/styles"
import { makeStyles } from "@material-ui/core/styles"
import Typography from "@material-ui/core/Typography"
import AccountIcon from "@material-ui/icons/AccountCircleOutlined"
import { FC } from "react"
@@ -146,7 +146,7 @@ const useStyles = makeStyles((theme) => ({
padding: `${theme.spacing(1.5)}px ${theme.spacing(2.75)}px`,
"&:hover": {
backgroundColor: fade(theme.palette.primary.light, 0.05),
backgroundColor: theme.palette.action.hover,
transition: "background-color 0.3s ease",
},
},
@@ -4,7 +4,6 @@ import { getWorkspaceStatus, WorkspaceStateEnum, WorkspaceStatus } from "util/wo
import { Workspace } from "../../api/typesGenerated"
import {
ActionLoadingButton,
CancelButton,
DeleteButton,
DisabledButton,
Language,
@@ -70,11 +69,9 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
[ButtonTypesEnum.stopping]: <ActionLoadingButton label={Language.stopping} />,
[ButtonTypesEnum.delete]: <DeleteButton handleAction={handleDelete} />,
[ButtonTypesEnum.deleting]: <ActionLoadingButton label={Language.deleting} />,
[ButtonTypesEnum.cancel]: <CancelButton handleAction={handleCancel} />,
[ButtonTypesEnum.canceling]: <DisabledButton workspaceState={workspaceState} />,
[ButtonTypesEnum.disabled]: <DisabledButton workspaceState={workspaceState} />,
[ButtonTypesEnum.queued]: <DisabledButton workspaceState={workspaceState} />,
[ButtonTypesEnum.error]: <DisabledButton workspaceState={workspaceState} />,
[ButtonTypesEnum.loading]: <DisabledButton workspaceState={workspaceState} />,
}
@@ -10,8 +10,6 @@ export enum ButtonTypesEnum {
delete = "delete",
deleting = "deleting",
update = "update",
cancel = "cancel",
error = "error",
// disabled buttons
canceling = "canceling",
disabled = "disabled",
@@ -1,4 +1,4 @@
import { fade, makeStyles, Theme } from "@material-ui/core/styles"
import { makeStyles, Theme } from "@material-ui/core/styles"
import TableRow from "@material-ui/core/TableRow"
import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight"
import useTheme from "@material-ui/styles/useTheme"
@@ -101,7 +101,7 @@ export const WorkspacesRow: FC<
const useStyles = makeStyles((theme) => ({
clickableTableRow: {
"&:hover td": {
backgroundColor: fade(theme.palette.primary.dark, 0.1),
backgroundColor: theme.palette.action.hover,
},
"&:focus": {
@@ -113,7 +113,7 @@ const useStyles = makeStyles((theme) => ({
},
},
arrowRight: {
color: fade(theme.palette.primary.contrastText, 0.7),
color: theme.palette.text.secondary,
width: 20,
height: 20,
},
@@ -1,5 +1,5 @@
import Link from "@material-ui/core/Link"
import { fade, makeStyles, Theme } from "@material-ui/core/styles"
import { makeStyles, Theme } from "@material-ui/core/styles"
import Table from "@material-ui/core/Table"
import TableBody from "@material-ui/core/TableBody"
import TableCell from "@material-ui/core/TableCell"
@@ -211,7 +211,7 @@ const useStyles = makeStyles((theme) => ({
},
clickableTableRow: {
"&:hover td": {
backgroundColor: fade(theme.palette.primary.dark, 0.1),
backgroundColor: theme.palette.action.hover,
},
"&:focus": {
@@ -223,7 +223,7 @@ const useStyles = makeStyles((theme) => ({
},
},
arrowRight: {
color: fade(theme.palette.primary.contrastText, 0.7),
color: theme.palette.text.secondary,
width: 20,
height: 20,
},
+6 -6
View File
@@ -1,5 +1,4 @@
import { Theme } from "@material-ui/core/styles"
import { SimplePaletteColorOptions } from "@material-ui/core/styles/createPalette"
import { lighten, Theme } from "@material-ui/core/styles"
import { Overrides } from "@material-ui/core/styles/overrides"
import { colors } from "./colors"
import { borderRadius, MONOSPACE_FONT_FAMILY } from "./constants"
@@ -26,7 +25,7 @@ export const getOverrides = ({ palette, breakpoints }: Theme): Overrides => {
fontSize: 18,
},
colorDefault: {
backgroundColor: "#a1adc9",
backgroundColor: colors.gray[6],
},
},
MuiButton: {
@@ -46,7 +45,8 @@ export const getOverrides = ({ palette, breakpoints }: Theme): Overrides => {
backgroundColor: colors.gray[17],
"&:hover": {
boxShadow: "none",
backgroundColor: "#000000",
backgroundColor: colors.gray[17],
borderColor: lighten(palette.divider, 0.2),
},
},
sizeSmall: {
@@ -112,7 +112,7 @@ export const getOverrides = ({ palette, breakpoints }: Theme): Overrides => {
MuiTableCell: {
head: {
fontSize: 14,
color: colors.gray[5],
color: palette.text.secondary,
fontWeight: 600,
},
root: {
@@ -162,7 +162,7 @@ export const getOverrides = ({ palette, breakpoints }: Theme): Overrides => {
},
MuiLink: {
root: {
color: (palette.primary as SimplePaletteColorOptions).light,
color: palette.primary.light,
},
},
MuiPaper: {
+3
View File
@@ -45,4 +45,7 @@ export const darkPalette: PaletteOptions = {
dark: colors.red[15],
contrastText: colors.gray[3],
},
action: {
hover: colors.gray[13],
},
}