Skip to content

Commit 4b97ac2

Browse files
authored
chore: refactor Pill styles (#10004)
1 parent 5e3bf27 commit 4b97ac2

File tree

4 files changed

+107
-70
lines changed

4 files changed

+107
-70
lines changed

site/src/components/Pill/Pill.tsx

Lines changed: 88 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,104 @@
1-
import { PaletteColor, Theme } from "@mui/material/styles";
2-
import { makeStyles } from "@mui/styles";
3-
import { FC } from "react";
4-
import { PaletteIndex } from "theme/theme";
5-
import { combineClasses } from "utils/combineClasses";
1+
import { type FC, type ReactNode, useMemo } from "react";
2+
import { css, type Interpolation, type Theme, useTheme } from "@emotion/react";
3+
import { colors } from "theme/colors";
4+
5+
export type PillType =
6+
| "primary"
7+
| "secondary"
8+
| "error"
9+
| "warning"
10+
| "info"
11+
| "success"
12+
| "neutral";
613

714
export interface PillProps {
815
className?: string;
9-
icon?: React.ReactNode;
10-
text: string;
11-
type?: PaletteIndex;
16+
icon?: ReactNode;
17+
text: ReactNode;
18+
type?: PillType;
1219
lightBorder?: boolean;
1320
title?: string;
1421
}
1522

23+
const themeOverrides = {
24+
primary: (lightBorder) => ({
25+
backgroundColor: colors.blue[13],
26+
borderColor: lightBorder ? colors.blue[5] : colors.blue[7],
27+
}),
28+
secondary: (lightBorder) => ({
29+
backgroundColor: colors.indigo[13],
30+
borderColor: lightBorder ? colors.indigo[6] : colors.indigo[8],
31+
}),
32+
neutral: (lightBorder) => ({
33+
backgroundColor: colors.gray[13],
34+
borderColor: lightBorder ? colors.gray[6] : colors.gray[8],
35+
}),
36+
} satisfies Record<string, (lightBorder?: boolean) => Interpolation<Theme>>;
37+
38+
const themeStyles =
39+
(type: PillType, lightBorder?: boolean) => (theme: Theme) => {
40+
const palette = theme.palette[type];
41+
return {
42+
backgroundColor: palette.dark,
43+
borderColor: lightBorder ? palette.light : palette.main,
44+
};
45+
};
46+
1647
export const Pill: FC<PillProps> = (props) => {
17-
const { className, icon, text = false, title } = props;
18-
const styles = useStyles(props);
48+
const { lightBorder, icon, text = null, type = "neutral", ...attrs } = props;
49+
const theme = useTheme();
50+
51+
const typeStyles = useMemo(() => {
52+
if (type in themeOverrides) {
53+
return themeOverrides[type as keyof typeof themeOverrides](lightBorder);
54+
}
55+
return themeStyles(type, lightBorder);
56+
}, [type, lightBorder]);
57+
1958
return (
2059
<div
21-
className={combineClasses([styles.wrapper, styles.pillColor, className])}
60+
css={[
61+
{
62+
display: "inline-flex",
63+
alignItems: "center",
64+
borderWidth: 1,
65+
borderStyle: "solid",
66+
borderRadius: 99999,
67+
fontSize: 12,
68+
color: "#FFF",
69+
height: theme.spacing(3),
70+
paddingLeft: icon ? theme.spacing(0.75) : theme.spacing(1.5),
71+
paddingRight: theme.spacing(1.5),
72+
whiteSpace: "nowrap",
73+
fontWeight: 400,
74+
},
75+
typeStyles,
76+
]}
2277
role="status"
23-
title={title}
78+
{...attrs}
2479
>
25-
{icon && <div className={styles.iconWrapper}>{icon}</div>}
80+
{icon && (
81+
<div
82+
css={css`
83+
margin-right: ${theme.spacing(0.5)};
84+
width: ${theme.spacing(1.75)};
85+
height: ${theme.spacing(1.75)};
86+
line-height: 0;
87+
display: flex;
88+
align-items: center;
89+
justify-content: center;
90+
91+
& > img,
92+
& > svg {
93+
width: ${theme.spacing(1.75)};
94+
height: ${theme.spacing(1.75)};
95+
}
96+
`}
97+
>
98+
{icon}
99+
</div>
100+
)}
26101
{text}
27102
</div>
28103
);
29104
};
30-
31-
const useStyles = makeStyles<Theme, PillProps>((theme) => ({
32-
wrapper: {
33-
display: "inline-flex",
34-
alignItems: "center",
35-
borderWidth: 1,
36-
borderStyle: "solid",
37-
borderRadius: 99999,
38-
fontSize: 12,
39-
color: "#FFF",
40-
height: theme.spacing(3),
41-
paddingLeft: ({ icon }) =>
42-
icon ? theme.spacing(0.75) : theme.spacing(1.5),
43-
paddingRight: theme.spacing(1.5),
44-
whiteSpace: "nowrap",
45-
fontWeight: 400,
46-
},
47-
48-
pillColor: {
49-
backgroundColor: ({ type }) =>
50-
type
51-
? (theme.palette[type] as PaletteColor).dark
52-
: theme.palette.text.secondary,
53-
borderColor: ({ type, lightBorder }) =>
54-
type
55-
? lightBorder
56-
? (theme.palette[type] as PaletteColor).light
57-
: (theme.palette[type] as PaletteColor).main
58-
: theme.palette.text.secondary,
59-
},
60-
61-
iconWrapper: {
62-
marginRight: theme.spacing(0.5),
63-
width: theme.spacing(1.75),
64-
height: theme.spacing(1.75),
65-
lineHeight: 0,
66-
display: "flex",
67-
alignItems: "center",
68-
justifyContent: "center",
69-
70-
"& > svg": {
71-
width: theme.spacing(1.75),
72-
height: theme.spacing(1.75),
73-
},
74-
},
75-
}));

site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,17 @@ import {
66
CloseDropdown,
77
OpenDropdown,
88
} from "components/DropdownArrows/DropdownArrows";
9-
import { Pill } from "components/Pill/Pill";
9+
import { Pill, type PillType } from "components/Pill/Pill";
1010
import { Stack } from "components/Stack/Stack";
1111
import { TimelineEntry } from "components/Timeline/TimelineEntry";
1212
import { UserAvatar } from "components/UserAvatar/UserAvatar";
1313
import { useState } from "react";
1414
import userAgentParser from "ua-parser-js";
1515
import { AuditLogDiff } from "./AuditLogDiff/AuditLogDiff";
1616
import { AuditLogDescription } from "./AuditLogDescription/AuditLogDescription";
17-
import { PaletteIndex } from "theme/theme";
1817
import { determineGroupDiff } from "./AuditLogDiff/auditUtils";
1918

20-
const httpStatusColor = (httpStatus: number): PaletteIndex => {
19+
const httpStatusColor = (httpStatus: number): PillType => {
2120
// redirects are successful
2221
if (httpStatus === 307) {
2322
return "success";

site/src/pages/TemplateVersionEditorPage/TemplateVersionStatusBadge.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { TemplateVersion } from "api/typesGenerated";
2-
import { FC, ReactNode } from "react";
1+
import { type TemplateVersion } from "api/typesGenerated";
2+
import { type FC, type ReactNode } from "react";
33
import CircularProgress from "@mui/material/CircularProgress";
44
import ErrorIcon from "@mui/icons-material/ErrorOutline";
55
import CheckIcon from "@mui/icons-material/CheckOutlined";
6-
import { Pill } from "components/Pill/Pill";
7-
import { PaletteIndex } from "theme/theme";
6+
import { Pill, type PillType } from "components/Pill/Pill";
87

98
export const TemplateVersionStatusBadge: FC<{
109
version: TemplateVersion;
@@ -27,7 +26,7 @@ const LoadingIcon: FC = () => {
2726
export const getStatus = (
2827
version: TemplateVersion,
2928
): {
30-
type?: PaletteIndex;
29+
type?: PillType;
3130
text: string;
3231
icon: ReactNode;
3332
} => {

site/src/theme/theme.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
import { colors } from "./colors";
2-
import { ThemeOptions, createTheme, Theme } from "@mui/material/styles";
2+
import { createTheme, type ThemeOptions } from "@mui/material/styles";
33
import { BODY_FONT_FAMILY, borderRadius } from "./constants";
44

55
// MUI does not have aligned heights for buttons and inputs so we have to "hack" it a little bit
66
export const BUTTON_LG_HEIGHT = 40;
77
export const BUTTON_MD_HEIGHT = 36;
88
export const BUTTON_SM_HEIGHT = 32;
99

10-
export type PaletteIndex = keyof Theme["palette"];
10+
export type PaletteIndex =
11+
| "primary"
12+
| "secondary"
13+
| "background"
14+
| "text"
15+
| "error"
16+
| "warning"
17+
| "info"
18+
| "success"
19+
| "action"
20+
| "neutral";
1121

1222
export let dark = createTheme({
1323
palette: {
@@ -46,7 +56,7 @@ export let dark = createTheme({
4656
info: {
4757
light: colors.blue[7],
4858
main: colors.blue[9],
49-
dark: colors.blue[15],
59+
dark: colors.blue[14],
5060
contrastText: colors.gray[4],
5161
},
5262
error: {

0 commit comments

Comments
 (0)