From 4b97ac269be7c30258c92ce2422b5efe621ce6e1 Mon Sep 17 00:00:00 2001 From: Kayla Washburn Date: Tue, 3 Oct 2023 10:47:28 -0600 Subject: [PATCH] chore: refactor `Pill` styles (#10004) --- site/src/components/Pill/Pill.tsx | 147 +++++++++++------- .../AuditPage/AuditLogRow/AuditLogRow.tsx | 5 +- .../TemplateVersionStatusBadge.tsx | 9 +- site/src/theme/theme.ts | 16 +- 4 files changed, 107 insertions(+), 70 deletions(-) diff --git a/site/src/components/Pill/Pill.tsx b/site/src/components/Pill/Pill.tsx index f9c4d9c092..f3c7190252 100644 --- a/site/src/components/Pill/Pill.tsx +++ b/site/src/components/Pill/Pill.tsx @@ -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 Interpolation>; + +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 = (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 (
- {icon &&
{icon}
} + {icon && ( +
img, + & > svg { + width: ${theme.spacing(1.75)}; + height: ${theme.spacing(1.75)}; + } + `} + > + {icon} +
+ )} {text}
); }; - -const useStyles = makeStyles((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), - }, - }, -})); diff --git a/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx b/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx index 64fcc22a6c..3537b37d29 100644 --- a/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx +++ b/site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx @@ -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"; diff --git a/site/src/pages/TemplateVersionEditorPage/TemplateVersionStatusBadge.tsx b/site/src/pages/TemplateVersionEditorPage/TemplateVersionStatusBadge.tsx index 776609b7a9..1580cad6a4 100644 --- a/site/src/pages/TemplateVersionEditorPage/TemplateVersionStatusBadge.tsx +++ b/site/src/pages/TemplateVersionEditorPage/TemplateVersionStatusBadge.tsx @@ -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; } => { diff --git a/site/src/theme/theme.ts b/site/src/theme/theme.ts index f0485947cf..0c24af51b7 100644 --- a/site/src/theme/theme.ts +++ b/site/src/theme/theme.ts @@ -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: {