chore: refactor `Pill` styles (#10004)

This commit is contained in:
Kayla Washburn 2023-10-03 10:47:28 -06:00 committed by GitHub
parent 5e3bf275da
commit 4b97ac269b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 70 deletions

View File

@ -1,75 +1,104 @@
import { PaletteColor, Theme } from "@mui/material/styles";
import { makeStyles } from "@mui/styles";
import { FC } from "react";
import { PaletteIndex } from "theme/theme";
import { combineClasses } from "utils/combineClasses";
import { type FC, type ReactNode, useMemo } from "react";
import { css, type Interpolation, type Theme, useTheme } from "@emotion/react";
import { colors } from "theme/colors";
export type PillType =
| "primary"
| "secondary"
| "error"
| "warning"
| "info"
| "success"
| "neutral";
export interface PillProps {
className?: string;
icon?: React.ReactNode;
text: string;
type?: PaletteIndex;
icon?: ReactNode;
text: ReactNode;
type?: PillType;
lightBorder?: boolean;
title?: string;
}
const themeOverrides = {
primary: (lightBorder) => ({
backgroundColor: colors.blue[13],
borderColor: lightBorder ? colors.blue[5] : colors.blue[7],
}),
secondary: (lightBorder) => ({
backgroundColor: colors.indigo[13],
borderColor: lightBorder ? colors.indigo[6] : colors.indigo[8],
}),
neutral: (lightBorder) => ({
backgroundColor: colors.gray[13],
borderColor: lightBorder ? colors.gray[6] : colors.gray[8],
}),
} satisfies Record<string, (lightBorder?: boolean) => Interpolation<Theme>>;
const themeStyles =
(type: PillType, lightBorder?: boolean) => (theme: Theme) => {
const palette = theme.palette[type];
return {
backgroundColor: palette.dark,
borderColor: lightBorder ? palette.light : palette.main,
};
};
export const Pill: FC<PillProps> = (props) => {
const { className, icon, text = false, title } = props;
const styles = useStyles(props);
const { lightBorder, icon, text = null, type = "neutral", ...attrs } = props;
const theme = useTheme();
const typeStyles = useMemo(() => {
if (type in themeOverrides) {
return themeOverrides[type as keyof typeof themeOverrides](lightBorder);
}
return themeStyles(type, lightBorder);
}, [type, lightBorder]);
return (
<div
className={combineClasses([styles.wrapper, styles.pillColor, className])}
css={[
{
display: "inline-flex",
alignItems: "center",
borderWidth: 1,
borderStyle: "solid",
borderRadius: 99999,
fontSize: 12,
color: "#FFF",
height: theme.spacing(3),
paddingLeft: icon ? theme.spacing(0.75) : theme.spacing(1.5),
paddingRight: theme.spacing(1.5),
whiteSpace: "nowrap",
fontWeight: 400,
},
typeStyles,
]}
role="status"
title={title}
{...attrs}
>
{icon && <div className={styles.iconWrapper}>{icon}</div>}
{icon && (
<div
css={css`
margin-right: ${theme.spacing(0.5)};
width: ${theme.spacing(1.75)};
height: ${theme.spacing(1.75)};
line-height: 0;
display: flex;
align-items: center;
justify-content: center;
& > img,
& > svg {
width: ${theme.spacing(1.75)};
height: ${theme.spacing(1.75)};
}
`}
>
{icon}
</div>
)}
{text}
</div>
);
};
const useStyles = makeStyles<Theme, PillProps>((theme) => ({
wrapper: {
display: "inline-flex",
alignItems: "center",
borderWidth: 1,
borderStyle: "solid",
borderRadius: 99999,
fontSize: 12,
color: "#FFF",
height: theme.spacing(3),
paddingLeft: ({ icon }) =>
icon ? theme.spacing(0.75) : theme.spacing(1.5),
paddingRight: theme.spacing(1.5),
whiteSpace: "nowrap",
fontWeight: 400,
},
pillColor: {
backgroundColor: ({ type }) =>
type
? (theme.palette[type] as PaletteColor).dark
: theme.palette.text.secondary,
borderColor: ({ type, lightBorder }) =>
type
? lightBorder
? (theme.palette[type] as PaletteColor).light
: (theme.palette[type] as PaletteColor).main
: theme.palette.text.secondary,
},
iconWrapper: {
marginRight: theme.spacing(0.5),
width: theme.spacing(1.75),
height: theme.spacing(1.75),
lineHeight: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
"& > svg": {
width: theme.spacing(1.75),
height: theme.spacing(1.75),
},
},
}));

View File

@ -6,7 +6,7 @@ import {
CloseDropdown,
OpenDropdown,
} from "components/DropdownArrows/DropdownArrows";
import { Pill } from "components/Pill/Pill";
import { Pill, type PillType } from "components/Pill/Pill";
import { Stack } from "components/Stack/Stack";
import { TimelineEntry } from "components/Timeline/TimelineEntry";
import { UserAvatar } from "components/UserAvatar/UserAvatar";
@ -14,10 +14,9 @@ import { useState } from "react";
import userAgentParser from "ua-parser-js";
import { AuditLogDiff } from "./AuditLogDiff/AuditLogDiff";
import { AuditLogDescription } from "./AuditLogDescription/AuditLogDescription";
import { PaletteIndex } from "theme/theme";
import { determineGroupDiff } from "./AuditLogDiff/auditUtils";
const httpStatusColor = (httpStatus: number): PaletteIndex => {
const httpStatusColor = (httpStatus: number): PillType => {
// redirects are successful
if (httpStatus === 307) {
return "success";

View File

@ -1,10 +1,9 @@
import { TemplateVersion } from "api/typesGenerated";
import { FC, ReactNode } from "react";
import { type TemplateVersion } from "api/typesGenerated";
import { type FC, type ReactNode } from "react";
import CircularProgress from "@mui/material/CircularProgress";
import ErrorIcon from "@mui/icons-material/ErrorOutline";
import CheckIcon from "@mui/icons-material/CheckOutlined";
import { Pill } from "components/Pill/Pill";
import { PaletteIndex } from "theme/theme";
import { Pill, type PillType } from "components/Pill/Pill";
export const TemplateVersionStatusBadge: FC<{
version: TemplateVersion;
@ -27,7 +26,7 @@ const LoadingIcon: FC = () => {
export const getStatus = (
version: TemplateVersion,
): {
type?: PaletteIndex;
type?: PillType;
text: string;
icon: ReactNode;
} => {

View File

@ -1,5 +1,5 @@
import { colors } from "./colors";
import { ThemeOptions, createTheme, Theme } from "@mui/material/styles";
import { createTheme, type ThemeOptions } from "@mui/material/styles";
import { BODY_FONT_FAMILY, borderRadius } from "./constants";
// MUI does not have aligned heights for buttons and inputs so we have to "hack" it a little bit
@ -7,7 +7,17 @@ export const BUTTON_LG_HEIGHT = 40;
export const BUTTON_MD_HEIGHT = 36;
export const BUTTON_SM_HEIGHT = 32;
export type PaletteIndex = keyof Theme["palette"];
export type PaletteIndex =
| "primary"
| "secondary"
| "background"
| "text"
| "error"
| "warning"
| "info"
| "success"
| "action"
| "neutral";
export let dark = createTheme({
palette: {
@ -46,7 +56,7 @@ export let dark = createTheme({
info: {
light: colors.blue[7],
main: colors.blue[9],
dark: colors.blue[15],
dark: colors.blue[14],
contrastText: colors.gray[4],
},
error: {