mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: add inactive role to experimental theme (#11967)
This commit is contained in:
@@ -1,30 +1,21 @@
|
||||
import CircularProgress, {
|
||||
type CircularProgressProps,
|
||||
} from "@mui/material/CircularProgress";
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import {
|
||||
type FC,
|
||||
forwardRef,
|
||||
type HTMLAttributes,
|
||||
type ReactNode,
|
||||
useMemo,
|
||||
forwardRef,
|
||||
HTMLAttributes,
|
||||
} from "react";
|
||||
import { useTheme, type Interpolation, type Theme } from "@emotion/react";
|
||||
import type { ThemeRole } from "theme/experimental";
|
||||
import CircularProgress, {
|
||||
CircularProgressProps,
|
||||
} from "@mui/material/CircularProgress";
|
||||
|
||||
export type PillType = ThemeRole | keyof typeof themeOverrides;
|
||||
|
||||
export type PillProps = HTMLAttributes<HTMLDivElement> & {
|
||||
icon?: ReactNode;
|
||||
type?: PillType;
|
||||
type?: ThemeRole;
|
||||
};
|
||||
|
||||
const themeOverrides = {
|
||||
neutral: (theme) => ({
|
||||
backgroundColor: theme.experimental.l1.background,
|
||||
borderColor: theme.experimental.l1.outline,
|
||||
}),
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
||||
const themeStyles = (type: ThemeRole) => (theme: Theme) => {
|
||||
const palette = theme.experimental.roles[type];
|
||||
return {
|
||||
@@ -39,43 +30,13 @@ const PILL_ICON_SPACING = (PILL_HEIGHT - PILL_ICON_SIZE) / 2;
|
||||
|
||||
export const Pill: FC<PillProps> = forwardRef<HTMLDivElement, PillProps>(
|
||||
(props, ref) => {
|
||||
const { icon, type = "neutral", children, ...divProps } = props;
|
||||
const theme = useTheme();
|
||||
const typeStyles = useMemo(() => {
|
||||
if (type in themeOverrides) {
|
||||
return themeOverrides[type as keyof typeof themeOverrides];
|
||||
}
|
||||
return themeStyles(type as ThemeRole);
|
||||
}, [type]);
|
||||
const { icon, type = "inactive", children, ...divProps } = props;
|
||||
const typeStyles = useMemo(() => themeStyles(type), [type]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
css={[
|
||||
{
|
||||
fontSize: 12,
|
||||
color: theme.experimental.l1.text,
|
||||
cursor: "default",
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
whiteSpace: "nowrap",
|
||||
fontWeight: 400,
|
||||
borderWidth: 1,
|
||||
borderStyle: "solid",
|
||||
borderRadius: 99999,
|
||||
lineHeight: 1,
|
||||
height: PILL_HEIGHT,
|
||||
gap: PILL_ICON_SPACING,
|
||||
paddingRight: 12,
|
||||
paddingLeft: icon ? PILL_ICON_SPACING : 12,
|
||||
|
||||
"& svg": {
|
||||
width: PILL_ICON_SIZE,
|
||||
height: PILL_ICON_SIZE,
|
||||
},
|
||||
},
|
||||
typeStyles,
|
||||
]}
|
||||
css={[styles.pill, icon && styles.pillWithIcon, typeStyles]}
|
||||
{...divProps}
|
||||
>
|
||||
{icon}
|
||||
@@ -85,18 +46,45 @@ export const Pill: FC<PillProps> = forwardRef<HTMLDivElement, PillProps>(
|
||||
},
|
||||
);
|
||||
|
||||
export const PillSpinner = (props: CircularProgressProps) => {
|
||||
export const PillSpinner: FC<CircularProgressProps> = (props) => {
|
||||
return (
|
||||
<CircularProgress
|
||||
size={PILL_ICON_SIZE}
|
||||
css={(theme) => ({
|
||||
color: theme.experimental.l1.text,
|
||||
// It is necessary to align it with the MUI Icons internal padding
|
||||
"& svg": {
|
||||
transform: "scale(.75)",
|
||||
},
|
||||
})}
|
||||
{...props}
|
||||
/>
|
||||
<CircularProgress size={PILL_ICON_SIZE} css={styles.spinner} {...props} />
|
||||
);
|
||||
};
|
||||
|
||||
const styles = {
|
||||
pill: (theme) => ({
|
||||
fontSize: 12,
|
||||
color: theme.experimental.l1.text,
|
||||
cursor: "default",
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
whiteSpace: "nowrap",
|
||||
fontWeight: 400,
|
||||
borderWidth: 1,
|
||||
borderStyle: "solid",
|
||||
borderRadius: 99999,
|
||||
lineHeight: 1,
|
||||
height: PILL_HEIGHT,
|
||||
gap: PILL_ICON_SPACING,
|
||||
paddingLeft: 12,
|
||||
paddingRight: 12,
|
||||
|
||||
"& svg": {
|
||||
width: PILL_ICON_SIZE,
|
||||
height: PILL_ICON_SIZE,
|
||||
},
|
||||
}),
|
||||
|
||||
pillWithIcon: {
|
||||
paddingLeft: PILL_ICON_SPACING,
|
||||
},
|
||||
|
||||
spinner: (theme) => ({
|
||||
color: theme.experimental.l1.text,
|
||||
// It is necessary to align it with the MUI Icons internal padding
|
||||
"& svg": {
|
||||
transform: "scale(.75)",
|
||||
},
|
||||
}),
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
import { type CSSObject, type Interpolation, type Theme } from "@emotion/react";
|
||||
import Collapse from "@mui/material/Collapse";
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
import { type FC, useState } from "react";
|
||||
import userAgentParser from "ua-parser-js";
|
||||
import type { AuditLog } from "api/typesGenerated";
|
||||
import { type ThemeRole } from "theme/experimental";
|
||||
import { DropdownArrow } from "components/DropdownArrow/DropdownArrow";
|
||||
import { Pill, type PillType } from "components/Pill/Pill";
|
||||
import { Pill } from "components/Pill/Pill";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import { TimelineEntry } from "components/Timeline/TimelineEntry";
|
||||
import { UserAvatar } from "components/UserAvatar/UserAvatar";
|
||||
import { type FC, useState } from "react";
|
||||
import userAgentParser from "ua-parser-js";
|
||||
import { AuditLogDiff } from "./AuditLogDiff/AuditLogDiff";
|
||||
import { AuditLogDescription } from "./AuditLogDescription/AuditLogDescription";
|
||||
import { determineGroupDiff } from "./AuditLogDiff/auditUtils";
|
||||
|
||||
const httpStatusColor = (httpStatus: number): PillType => {
|
||||
// redirects are successful
|
||||
if (httpStatus === 307) {
|
||||
return "success";
|
||||
}
|
||||
|
||||
if (httpStatus >= 300 && httpStatus < 500) {
|
||||
return "warning";
|
||||
}
|
||||
|
||||
const httpStatusColor = (httpStatus: number): ThemeRole => {
|
||||
// Treat server errors (500) as errors
|
||||
if (httpStatus >= 500) {
|
||||
return "error";
|
||||
}
|
||||
|
||||
// Treat client errors (400) as warnings
|
||||
if (httpStatus >= 400) {
|
||||
return "warning";
|
||||
}
|
||||
|
||||
// OK (200) and redirects (300) are successful
|
||||
return "success";
|
||||
};
|
||||
|
||||
|
||||
@@ -86,17 +86,17 @@ export const VersionRow: FC<VersionRowProps> = ({
|
||||
</Pill>
|
||||
)}
|
||||
{jobStatus === "pending" && (
|
||||
<Pill role="status" type="warning">
|
||||
<Pill role="status" type="inactive">
|
||||
Pending…
|
||||
</Pill>
|
||||
)}
|
||||
{jobStatus === "running" && (
|
||||
<Pill role="status" type="warning">
|
||||
<Pill role="status" type="active">
|
||||
Building…
|
||||
</Pill>
|
||||
)}
|
||||
{(jobStatus === "canceling" || jobStatus === "canceled") && (
|
||||
<Pill role="status" type="neutral">
|
||||
<Pill role="status" type="inactive">
|
||||
Canceled
|
||||
</Pill>
|
||||
)}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { type TemplateVersion } from "api/typesGenerated";
|
||||
import { type FC, type ReactNode } from "react";
|
||||
import ErrorIcon from "@mui/icons-material/ErrorOutline";
|
||||
import CheckIcon from "@mui/icons-material/CheckOutlined";
|
||||
import { Pill, PillSpinner, type PillType } from "components/Pill/Pill";
|
||||
import type { TemplateVersion } from "api/typesGenerated";
|
||||
import { type ThemeRole } from "theme/experimental";
|
||||
import { Pill, PillSpinner } from "components/Pill/Pill";
|
||||
|
||||
interface TemplateVersionStatusBadgeProps {
|
||||
version: TemplateVersion;
|
||||
@@ -22,7 +23,7 @@ export const TemplateVersionStatusBadge: FC<
|
||||
export const getStatus = (
|
||||
version: TemplateVersion,
|
||||
): {
|
||||
type?: PillType;
|
||||
type?: ThemeRole;
|
||||
text: string;
|
||||
icon: ReactNode;
|
||||
} => {
|
||||
|
||||
@@ -175,6 +175,16 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
inactive: {
|
||||
background: colors.zinc[950],
|
||||
outline: colors.zinc[500],
|
||||
text: colors.zinc[50],
|
||||
fill: {
|
||||
solid: colors.zinc[400],
|
||||
outline: colors.zinc[400],
|
||||
text: colors.white,
|
||||
},
|
||||
},
|
||||
preview: {
|
||||
background: colors.violet[950],
|
||||
outline: colors.violet[500],
|
||||
|
||||
@@ -175,6 +175,16 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
inactive: {
|
||||
background: colors.zinc[950],
|
||||
outline: colors.zinc[500],
|
||||
text: colors.zinc[50],
|
||||
fill: {
|
||||
solid: colors.zinc[400],
|
||||
outline: colors.zinc[400],
|
||||
text: colors.white,
|
||||
},
|
||||
},
|
||||
preview: {
|
||||
background: colors.violet[950],
|
||||
outline: colors.violet[500],
|
||||
|
||||
@@ -29,19 +29,25 @@ export interface NewTheme {
|
||||
/** Selected, in progress, of particular relevance right now. */
|
||||
active: InteractiveRole;
|
||||
|
||||
/** For things that can be made "active", but are not currently so.
|
||||
* Paused, stopped, off, etc.
|
||||
*/
|
||||
inactive: Role;
|
||||
|
||||
/** Actions that have long lasting or irreversible effects.
|
||||
* Deletion, immutable parameters, etc.
|
||||
*/
|
||||
danger: InteractiveRole;
|
||||
|
||||
/** This isn't quite ready for prime-time, but you're welcome to look around!
|
||||
* Preview features, experiments, unstable etc.
|
||||
* Preview features, experiments, unstable, etc.
|
||||
*/
|
||||
preview: Role;
|
||||
};
|
||||
}
|
||||
|
||||
/** A set of colors which work together to fill a desirable "communication role"
|
||||
/**
|
||||
* A set of colors which work together to fill a desirable "communication role"
|
||||
* ie. I wish to communicate an error, I wish to communicate that this is dangerous, etc.
|
||||
*/
|
||||
export interface Role {
|
||||
|
||||
@@ -175,6 +175,16 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
inactive: {
|
||||
background: colors.gray[100],
|
||||
outline: colors.gray[400],
|
||||
text: colors.gray[950],
|
||||
fill: {
|
||||
solid: colors.gray[600],
|
||||
outline: colors.gray[600],
|
||||
text: colors.white,
|
||||
},
|
||||
},
|
||||
preview: {
|
||||
background: colors.violet[50],
|
||||
outline: colors.violet[500],
|
||||
|
||||
Reference in New Issue
Block a user