mirror of https://github.com/coder/coder.git
chore: refactor `Pill` styles (#10004)
This commit is contained in:
parent
5e3bf275da
commit
4b97ac269b
|
@ -1,75 +1,104 @@
|
||||||
import { PaletteColor, Theme } from "@mui/material/styles";
|
import { type FC, type ReactNode, useMemo } from "react";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { css, type Interpolation, type Theme, useTheme } from "@emotion/react";
|
||||||
import { FC } from "react";
|
import { colors } from "theme/colors";
|
||||||
import { PaletteIndex } from "theme/theme";
|
|
||||||
import { combineClasses } from "utils/combineClasses";
|
export type PillType =
|
||||||
|
| "primary"
|
||||||
|
| "secondary"
|
||||||
|
| "error"
|
||||||
|
| "warning"
|
||||||
|
| "info"
|
||||||
|
| "success"
|
||||||
|
| "neutral";
|
||||||
|
|
||||||
export interface PillProps {
|
export interface PillProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
icon?: React.ReactNode;
|
icon?: ReactNode;
|
||||||
text: string;
|
text: ReactNode;
|
||||||
type?: PaletteIndex;
|
type?: PillType;
|
||||||
lightBorder?: boolean;
|
lightBorder?: boolean;
|
||||||
title?: string;
|
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) => {
|
export const Pill: FC<PillProps> = (props) => {
|
||||||
const { className, icon, text = false, title } = props;
|
const { lightBorder, icon, text = null, type = "neutral", ...attrs } = props;
|
||||||
const styles = useStyles(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 (
|
return (
|
||||||
<div
|
<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"
|
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}
|
{text}
|
||||||
</div>
|
</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),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
CloseDropdown,
|
CloseDropdown,
|
||||||
OpenDropdown,
|
OpenDropdown,
|
||||||
} from "components/DropdownArrows/DropdownArrows";
|
} 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 { Stack } from "components/Stack/Stack";
|
||||||
import { TimelineEntry } from "components/Timeline/TimelineEntry";
|
import { TimelineEntry } from "components/Timeline/TimelineEntry";
|
||||||
import { UserAvatar } from "components/UserAvatar/UserAvatar";
|
import { UserAvatar } from "components/UserAvatar/UserAvatar";
|
||||||
|
@ -14,10 +14,9 @@ import { useState } from "react";
|
||||||
import userAgentParser from "ua-parser-js";
|
import userAgentParser from "ua-parser-js";
|
||||||
import { AuditLogDiff } from "./AuditLogDiff/AuditLogDiff";
|
import { AuditLogDiff } from "./AuditLogDiff/AuditLogDiff";
|
||||||
import { AuditLogDescription } from "./AuditLogDescription/AuditLogDescription";
|
import { AuditLogDescription } from "./AuditLogDescription/AuditLogDescription";
|
||||||
import { PaletteIndex } from "theme/theme";
|
|
||||||
import { determineGroupDiff } from "./AuditLogDiff/auditUtils";
|
import { determineGroupDiff } from "./AuditLogDiff/auditUtils";
|
||||||
|
|
||||||
const httpStatusColor = (httpStatus: number): PaletteIndex => {
|
const httpStatusColor = (httpStatus: number): PillType => {
|
||||||
// redirects are successful
|
// redirects are successful
|
||||||
if (httpStatus === 307) {
|
if (httpStatus === 307) {
|
||||||
return "success";
|
return "success";
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import { TemplateVersion } from "api/typesGenerated";
|
import { type TemplateVersion } from "api/typesGenerated";
|
||||||
import { FC, ReactNode } from "react";
|
import { type FC, type ReactNode } from "react";
|
||||||
import CircularProgress from "@mui/material/CircularProgress";
|
import CircularProgress from "@mui/material/CircularProgress";
|
||||||
import ErrorIcon from "@mui/icons-material/ErrorOutline";
|
import ErrorIcon from "@mui/icons-material/ErrorOutline";
|
||||||
import CheckIcon from "@mui/icons-material/CheckOutlined";
|
import CheckIcon from "@mui/icons-material/CheckOutlined";
|
||||||
import { Pill } from "components/Pill/Pill";
|
import { Pill, type PillType } from "components/Pill/Pill";
|
||||||
import { PaletteIndex } from "theme/theme";
|
|
||||||
|
|
||||||
export const TemplateVersionStatusBadge: FC<{
|
export const TemplateVersionStatusBadge: FC<{
|
||||||
version: TemplateVersion;
|
version: TemplateVersion;
|
||||||
|
@ -27,7 +26,7 @@ const LoadingIcon: FC = () => {
|
||||||
export const getStatus = (
|
export const getStatus = (
|
||||||
version: TemplateVersion,
|
version: TemplateVersion,
|
||||||
): {
|
): {
|
||||||
type?: PaletteIndex;
|
type?: PillType;
|
||||||
text: string;
|
text: string;
|
||||||
icon: ReactNode;
|
icon: ReactNode;
|
||||||
} => {
|
} => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { colors } from "./colors";
|
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";
|
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
|
// 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_MD_HEIGHT = 36;
|
||||||
export const BUTTON_SM_HEIGHT = 32;
|
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({
|
export let dark = createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
|
@ -46,7 +56,7 @@ export let dark = createTheme({
|
||||||
info: {
|
info: {
|
||||||
light: colors.blue[7],
|
light: colors.blue[7],
|
||||||
main: colors.blue[9],
|
main: colors.blue[9],
|
||||||
dark: colors.blue[15],
|
dark: colors.blue[14],
|
||||||
contrastText: colors.gray[4],
|
contrastText: colors.gray[4],
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
|
|
Loading…
Reference in New Issue