mirror of
https://github.com/coder/coder.git
synced 2025-07-18 14:17:22 +00:00
refactor: match StatusIndicator component with the new designs (#16458)
Reference: https://www.figma.com/design/WfqIgsTFXN2BscBSSyXWF8/Coder-kit?node-id=489-4278&m=dev
This commit is contained in:
@ -1,10 +1,17 @@
|
|||||||
import type { Meta, StoryObj } from "@storybook/react";
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
import { StatusIndicator } from "./StatusIndicator";
|
import { StatusIndicator, StatusIndicatorDot } from "./StatusIndicator";
|
||||||
|
|
||||||
const meta: Meta<typeof StatusIndicator> = {
|
const meta: Meta<typeof StatusIndicator> = {
|
||||||
title: "components/StatusIndicator",
|
title: "components/StatusIndicator",
|
||||||
component: StatusIndicator,
|
component: StatusIndicator,
|
||||||
args: {},
|
args: {
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<StatusIndicatorDot />
|
||||||
|
Status
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
@ -12,52 +19,37 @@ type Story = StoryObj<typeof StatusIndicator>;
|
|||||||
|
|
||||||
export const Success: Story = {
|
export const Success: Story = {
|
||||||
args: {
|
args: {
|
||||||
color: "success",
|
variant: "success",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SuccessOutline: Story = {
|
export const Failed: Story = {
|
||||||
args: {
|
args: {
|
||||||
color: "success",
|
variant: "failed",
|
||||||
variant: "outlined",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Warning: Story = {
|
|
||||||
args: {
|
|
||||||
color: "warning",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const WarningOutline: Story = {
|
|
||||||
args: {
|
|
||||||
color: "warning",
|
|
||||||
variant: "outlined",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Danger: Story = {
|
|
||||||
args: {
|
|
||||||
color: "danger",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DangerOutline: Story = {
|
|
||||||
args: {
|
|
||||||
color: "danger",
|
|
||||||
variant: "outlined",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Inactive: Story = {
|
export const Inactive: Story = {
|
||||||
args: {
|
args: {
|
||||||
color: "inactive",
|
variant: "inactive",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const InactiveOutline: Story = {
|
export const Warning: Story = {
|
||||||
args: {
|
args: {
|
||||||
color: "inactive",
|
variant: "warning",
|
||||||
variant: "outlined",
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Pending: Story = {
|
||||||
|
args: {
|
||||||
|
variant: "pending",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Small: Story = {
|
||||||
|
args: {
|
||||||
|
variant: "success",
|
||||||
|
size: "sm",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,33 +1,97 @@
|
|||||||
import { useTheme } from "@emotion/react";
|
import { type VariantProps, cva } from "class-variance-authority";
|
||||||
import type { FC } from "react";
|
import { type FC, createContext, useContext } from "react";
|
||||||
import type { ThemeRole } from "theme/roles";
|
import { cn } from "utils/cn";
|
||||||
|
|
||||||
interface StatusIndicatorProps {
|
const statusIndicatorVariants = cva(
|
||||||
color: ThemeRole;
|
"font-medium inline-flex items-center gap-2",
|
||||||
variant?: "solid" | "outlined";
|
{
|
||||||
}
|
variants: {
|
||||||
|
variant: {
|
||||||
|
success: "text-content-success",
|
||||||
|
failed: "text-content-destructive",
|
||||||
|
inactive: "text-highlight-grey",
|
||||||
|
warning: "text-content-warning",
|
||||||
|
pending: "text-highlight-sky",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
sm: "text-xs",
|
||||||
|
md: "text-sm",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "success",
|
||||||
|
size: "md",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
type StatusIndicatorContextValue = VariantProps<typeof statusIndicatorVariants>;
|
||||||
|
|
||||||
|
const StatusIndicatorContext = createContext<StatusIndicatorContextValue>({});
|
||||||
|
|
||||||
|
export interface StatusIndicatorProps
|
||||||
|
extends React.HTMLAttributes<HTMLDivElement>,
|
||||||
|
StatusIndicatorContextValue {}
|
||||||
|
|
||||||
export const StatusIndicator: FC<StatusIndicatorProps> = ({
|
export const StatusIndicator: FC<StatusIndicatorProps> = ({
|
||||||
color,
|
size,
|
||||||
variant = "solid",
|
variant,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
return (
|
||||||
|
<StatusIndicatorContext.Provider value={{ size, variant }}>
|
||||||
|
<div
|
||||||
|
className={cn(statusIndicatorVariants({ variant, size }), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</StatusIndicatorContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dotVariants = cva("rounded-full inline-block border-4 border-solid", {
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
success: "bg-content-success border-surface-green",
|
||||||
|
failed: "bg-content-destructive border-surface-destructive",
|
||||||
|
inactive: "bg-highlight-grey border-surface-grey",
|
||||||
|
warning: "bg-content-warning border-surface-orange",
|
||||||
|
pending: "bg-highlight-sky border-surface-sky",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
sm: "size-3 border-4",
|
||||||
|
md: "size-4 border-4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "success",
|
||||||
|
size: "md",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface StatusIndicatorDotProps
|
||||||
|
extends React.HTMLAttributes<HTMLDivElement>,
|
||||||
|
VariantProps<typeof dotVariants> {}
|
||||||
|
|
||||||
|
export const StatusIndicatorDot: FC<StatusIndicatorDotProps> = ({
|
||||||
|
className,
|
||||||
|
// We allow the size and variant to be overridden directly by the component.
|
||||||
|
// This allows StatusIndicatorDot to be used alone.
|
||||||
|
size,
|
||||||
|
variant,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
const { size: ctxSize, variant: ctxVariant } = useContext(
|
||||||
|
StatusIndicatorContext,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
css={[
|
className={cn(
|
||||||
{
|
dotVariants({ variant: variant ?? ctxVariant, size: size ?? ctxSize }),
|
||||||
height: 8,
|
className,
|
||||||
width: 8,
|
)}
|
||||||
borderRadius: 4,
|
{...props}
|
||||||
},
|
|
||||||
variant === "solid" && {
|
|
||||||
backgroundColor: theme.roles[color].fill.solid,
|
|
||||||
},
|
|
||||||
variant === "outlined" && {
|
|
||||||
border: `1px solid ${theme.roles[color].outline}`,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
--content-invert: 0 0% 98%;
|
--content-invert: 0 0% 98%;
|
||||||
--content-disabled: 240 5% 65%;
|
--content-disabled: 240 5% 65%;
|
||||||
--content-success: 142 72% 29%;
|
--content-success: 142 72% 29%;
|
||||||
--content-danger: 0 84% 60%;
|
|
||||||
--content-warning: 27 96% 61%;
|
--content-warning: 27 96% 61%;
|
||||||
|
--content-destructive: 0 84% 60%;
|
||||||
--surface-primary: 0 0% 98%;
|
--surface-primary: 0 0% 98%;
|
||||||
--surface-secondary: 240 5% 96%;
|
--surface-secondary: 240 5% 96%;
|
||||||
--surface-tertiary: 240 6% 90%;
|
--surface-tertiary: 240 6% 90%;
|
||||||
@ -24,6 +24,10 @@
|
|||||||
--surface-invert-primary: 240 4% 16%;
|
--surface-invert-primary: 240 4% 16%;
|
||||||
--surface-invert-secondary: 240 5% 26%;
|
--surface-invert-secondary: 240 5% 26%;
|
||||||
--surface-destructive: 0 93% 94%;
|
--surface-destructive: 0 93% 94%;
|
||||||
|
--surface-green: 141 79% 85%;
|
||||||
|
--surface-grey: 240 5% 96%;
|
||||||
|
--surface-orange: 34 100% 92%;
|
||||||
|
--surface-sky: 201 94% 86%;
|
||||||
--border-default: 240 6% 90%;
|
--border-default: 240 6% 90%;
|
||||||
--border-success: 142 76% 36%;
|
--border-success: 142 76% 36%;
|
||||||
--border-destructive: 0 84% 60%;
|
--border-destructive: 0 84% 60%;
|
||||||
@ -31,6 +35,8 @@
|
|||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
--highlight-purple: 262 83% 58%;
|
--highlight-purple: 262 83% 58%;
|
||||||
--highlight-green: 143 64% 24%;
|
--highlight-green: 143 64% 24%;
|
||||||
|
--highlight-grey: 240 5% 65%;
|
||||||
|
--highlight-sky: 201 90% 27%;
|
||||||
--border: 240 5.9% 90%;
|
--border: 240 5.9% 90%;
|
||||||
--input: 240 5.9% 90%;
|
--input: 240 5.9% 90%;
|
||||||
--ring: 240 10% 3.9%;
|
--ring: 240 10% 3.9%;
|
||||||
@ -45,8 +51,8 @@
|
|||||||
--content-invert: 240 10% 4%;
|
--content-invert: 240 10% 4%;
|
||||||
--content-disabled: 240 5% 26%;
|
--content-disabled: 240 5% 26%;
|
||||||
--content-success: 142 76% 36%;
|
--content-success: 142 76% 36%;
|
||||||
--content-danger: 0 91% 71%;
|
--content-warning: 31 97% 72%;
|
||||||
--content-warning: 27 96% 61%;
|
--content-destructive: 0 91% 71%;
|
||||||
--surface-primary: 240 10% 4%;
|
--surface-primary: 240 10% 4%;
|
||||||
--surface-secondary: 240 6% 10%;
|
--surface-secondary: 240 6% 10%;
|
||||||
--surface-tertiary: 240 4% 16%;
|
--surface-tertiary: 240 4% 16%;
|
||||||
@ -54,12 +60,18 @@
|
|||||||
--surface-invert-primary: 240 6% 90%;
|
--surface-invert-primary: 240 6% 90%;
|
||||||
--surface-invert-secondary: 240 5% 65%;
|
--surface-invert-secondary: 240 5% 65%;
|
||||||
--surface-destructive: 0 75% 15%;
|
--surface-destructive: 0 75% 15%;
|
||||||
|
--surface-green: 145 80% 10%;
|
||||||
|
--surface-grey: 240 6% 10%;
|
||||||
|
--surface-orange: 13 81% 15%;
|
||||||
|
--surface-sky: 204 80% 16%;
|
||||||
--border-default: 240 4% 16%;
|
--border-default: 240 4% 16%;
|
||||||
--border-success: 142 76% 36%;
|
--border-success: 142 76% 36%;
|
||||||
--border-destructive: 0 91% 71%;
|
--border-destructive: 0 91% 71%;
|
||||||
--overlay-default: 240 10% 4% / 80%;
|
--overlay-default: 240 10% 4% / 80%;
|
||||||
--highlight-purple: 252 95% 85%;
|
--highlight-purple: 252 95% 85%;
|
||||||
--highlight-green: 141 79% 85%;
|
--highlight-green: 141 79% 85%;
|
||||||
|
--highlight-grey: 240 4% 46%;
|
||||||
|
--highlight-sky: 198 93% 60%;
|
||||||
--border: 240 3.7% 15.9%;
|
--border: 240 3.7% 15.9%;
|
||||||
--input: 240 3.7% 15.9%;
|
--input: 240 3.7% 15.9%;
|
||||||
--ring: 240 4.9% 83.9%;
|
--ring: 240 4.9% 83.9%;
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
} from "components/HelpTooltip/HelpTooltip";
|
} from "components/HelpTooltip/HelpTooltip";
|
||||||
import { Pill } from "components/Pill/Pill";
|
import { Pill } from "components/Pill/Pill";
|
||||||
import { Stack } from "components/Stack/Stack";
|
import { Stack } from "components/Stack/Stack";
|
||||||
import { StatusIndicator } from "components/StatusIndicator/StatusIndicator";
|
import { StatusIndicatorDot } from "components/StatusIndicator/StatusIndicator";
|
||||||
import {
|
import {
|
||||||
Popover,
|
Popover,
|
||||||
PopoverContent,
|
PopoverContent,
|
||||||
@ -127,7 +127,7 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div css={{ display: "flex", alignItems: "center", gap: 16 }}>
|
<div css={{ display: "flex", alignItems: "center", gap: 16 }}>
|
||||||
<StatusIndicator color={hasWarning ? "warning" : "success"} />
|
<StatusIndicatorDot variant={hasWarning ? "warning" : "success"} />
|
||||||
<div
|
<div
|
||||||
css={{
|
css={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
@ -80,6 +80,7 @@ export const CreateTokenForm: FC<CreateTokenFormProps> = ({
|
|||||||
</FormFields>
|
</FormFields>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
<FormSection
|
<FormSection
|
||||||
|
data-chromatic="ignore"
|
||||||
title="Expiration"
|
title="Expiration"
|
||||||
description={
|
description={
|
||||||
form.values.lifetime
|
form.values.lifetime
|
||||||
|
@ -12,12 +12,6 @@ const meta: Meta<typeof CreateTokenPage> = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
decorators: [
|
|
||||||
(Story) => {
|
|
||||||
Date.now = () => new Date("01/01/2014").getTime();
|
|
||||||
return <Story />;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
@ -7,7 +7,10 @@ import {
|
|||||||
type UseFilterMenuOptions,
|
type UseFilterMenuOptions,
|
||||||
useFilterMenu,
|
useFilterMenu,
|
||||||
} from "components/Filter/menu";
|
} from "components/Filter/menu";
|
||||||
import { StatusIndicator } from "components/StatusIndicator/StatusIndicator";
|
import {
|
||||||
|
StatusIndicator,
|
||||||
|
StatusIndicatorDot,
|
||||||
|
} from "components/StatusIndicator/StatusIndicator";
|
||||||
import type { FC } from "react";
|
import type { FC } from "react";
|
||||||
import { docs } from "utils/docs";
|
import { docs } from "utils/docs";
|
||||||
|
|
||||||
@ -24,17 +27,17 @@ export const useStatusFilterMenu = ({
|
|||||||
{
|
{
|
||||||
value: "active",
|
value: "active",
|
||||||
label: "Active",
|
label: "Active",
|
||||||
startIcon: <StatusIndicator color="success" />,
|
startIcon: <StatusIndicatorDot variant="success" />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "dormant",
|
value: "dormant",
|
||||||
label: "Dormant",
|
label: "Dormant",
|
||||||
startIcon: <StatusIndicator color="warning" />,
|
startIcon: <StatusIndicatorDot variant="warning" />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "suspended",
|
value: "suspended",
|
||||||
label: "Suspended",
|
label: "Suspended",
|
||||||
startIcon: <StatusIndicator color="inactive" />,
|
startIcon: <StatusIndicatorDot variant="inactive" />,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
return useFilterMenu({
|
return useFilterMenu({
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useTheme } from "@emotion/react";
|
import { useTheme } from "@emotion/react";
|
||||||
import { Stack } from "components/Stack/Stack";
|
import { Stack } from "components/Stack/Stack";
|
||||||
import { StatusIndicator } from "components/StatusIndicator/StatusIndicator";
|
import { StatusIndicatorDot } from "components/StatusIndicator/StatusIndicator";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import relativeTime from "dayjs/plugin/relativeTime";
|
import relativeTime from "dayjs/plugin/relativeTime";
|
||||||
import { useTime } from "hooks/useTime";
|
import { useTime } from "hooks/useTime";
|
||||||
@ -18,19 +18,19 @@ export const LastUsed: FC<LastUsedProps> = ({ lastUsedAt }) => {
|
|||||||
const t = dayjs(lastUsedAt);
|
const t = dayjs(lastUsedAt);
|
||||||
const now = dayjs();
|
const now = dayjs();
|
||||||
let message = t.fromNow();
|
let message = t.fromNow();
|
||||||
let circle = <StatusIndicator color="info" variant="outlined" />;
|
let circle = <StatusIndicatorDot variant="inactive" />;
|
||||||
|
|
||||||
if (t.isAfter(now.subtract(1, "hour"))) {
|
if (t.isAfter(now.subtract(1, "hour"))) {
|
||||||
circle = <StatusIndicator color="success" />;
|
circle = <StatusIndicatorDot variant="success" />;
|
||||||
// Since the agent reports on a 10m interval,
|
// Since the agent reports on a 10m interval,
|
||||||
// the last_used_at can be inaccurate when recent.
|
// the last_used_at can be inaccurate when recent.
|
||||||
message = "Now";
|
message = "Now";
|
||||||
} else if (t.isAfter(now.subtract(3, "day"))) {
|
} else if (t.isAfter(now.subtract(3, "day"))) {
|
||||||
circle = <StatusIndicator color="info" />;
|
circle = <StatusIndicatorDot variant="pending" />;
|
||||||
} else if (t.isAfter(now.subtract(1, "month"))) {
|
} else if (t.isAfter(now.subtract(1, "month"))) {
|
||||||
circle = <StatusIndicator color="warning" />;
|
circle = <StatusIndicatorDot variant="warning" />;
|
||||||
} else if (t.isAfter(now.subtract(100, "year"))) {
|
} else if (t.isAfter(now.subtract(100, "year"))) {
|
||||||
circle = <StatusIndicator color="error" />;
|
circle = <StatusIndicatorDot variant="failed" />;
|
||||||
} else {
|
} else {
|
||||||
message = "Never";
|
message = "Never";
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,11 @@ import {
|
|||||||
type UseFilterMenuOptions,
|
type UseFilterMenuOptions,
|
||||||
useFilterMenu,
|
useFilterMenu,
|
||||||
} from "components/Filter/menu";
|
} from "components/Filter/menu";
|
||||||
import { StatusIndicator } from "components/StatusIndicator/StatusIndicator";
|
import {
|
||||||
|
StatusIndicator,
|
||||||
|
StatusIndicatorDot,
|
||||||
|
type StatusIndicatorDotProps,
|
||||||
|
} from "components/StatusIndicator/StatusIndicator";
|
||||||
import type { FC } from "react";
|
import type { FC } from "react";
|
||||||
import { getDisplayWorkspaceStatus } from "utils/workspace";
|
import { getDisplayWorkspaceStatus } from "utils/workspace";
|
||||||
|
|
||||||
@ -109,7 +113,9 @@ export const useStatusFilterMenu = ({
|
|||||||
return {
|
return {
|
||||||
label: display.text,
|
label: display.text,
|
||||||
value: status,
|
value: status,
|
||||||
startIcon: <StatusIndicator color={display.type ?? "warning"} />,
|
startIcon: (
|
||||||
|
<StatusIndicatorDot variant={getStatusIndicatorVariant(status)} />
|
||||||
|
),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return useFilterMenu({
|
return useFilterMenu({
|
||||||
@ -141,3 +147,26 @@ export const StatusMenu: FC<StatusMenuProps> = ({ width, menu }) => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getStatusIndicatorVariant = (
|
||||||
|
status: WorkspaceStatus,
|
||||||
|
): StatusIndicatorDotProps["variant"] => {
|
||||||
|
switch (status) {
|
||||||
|
case "running":
|
||||||
|
return "success";
|
||||||
|
case "starting":
|
||||||
|
case "pending":
|
||||||
|
return "pending";
|
||||||
|
case undefined:
|
||||||
|
case "canceling":
|
||||||
|
case "canceled":
|
||||||
|
case "stopping":
|
||||||
|
case "stopped":
|
||||||
|
return "inactive";
|
||||||
|
case "deleting":
|
||||||
|
case "deleted":
|
||||||
|
return "warning";
|
||||||
|
case "failed":
|
||||||
|
return "failed";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -31,8 +31,8 @@ module.exports = {
|
|||||||
disabled: "hsl(var(--content-disabled))",
|
disabled: "hsl(var(--content-disabled))",
|
||||||
invert: "hsl(var(--content-invert))",
|
invert: "hsl(var(--content-invert))",
|
||||||
success: "hsl(var(--content-success))",
|
success: "hsl(var(--content-success))",
|
||||||
danger: "hsl(var(--content-danger))",
|
|
||||||
link: "hsl(var(--content-link))",
|
link: "hsl(var(--content-link))",
|
||||||
|
destructive: "hsl(var(--content-destructive))",
|
||||||
warning: "hsl(var(--content-warning))",
|
warning: "hsl(var(--content-warning))",
|
||||||
},
|
},
|
||||||
surface: {
|
surface: {
|
||||||
@ -45,6 +45,10 @@ module.exports = {
|
|||||||
secondary: "hsl(var(--surface-invert-secondary))",
|
secondary: "hsl(var(--surface-invert-secondary))",
|
||||||
},
|
},
|
||||||
destructive: "hsl(var(--surface-destructive))",
|
destructive: "hsl(var(--surface-destructive))",
|
||||||
|
green: "hsl(var(--surface-green))",
|
||||||
|
grey: "hsl(var(--surface-grey))",
|
||||||
|
orange: "hsl(var(--surface-orange))",
|
||||||
|
sky: "hsl(var(--surface-sky))",
|
||||||
},
|
},
|
||||||
border: {
|
border: {
|
||||||
DEFAULT: "hsl(var(--border-default))",
|
DEFAULT: "hsl(var(--border-default))",
|
||||||
@ -56,6 +60,8 @@ module.exports = {
|
|||||||
highlight: {
|
highlight: {
|
||||||
purple: "hsl(var(--highlight-purple))",
|
purple: "hsl(var(--highlight-purple))",
|
||||||
green: "hsl(var(--highlight-green))",
|
green: "hsl(var(--highlight-green))",
|
||||||
|
grey: "hsl(var(--highlight-grey))",
|
||||||
|
sky: "hsl(var(--highlight-sky))",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
|
Reference in New Issue
Block a user