mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
site: new dark theme (#10331)
This commit is contained in:
@ -7,14 +7,21 @@ import { ThemeProvider as EmotionThemeProvider } from "@emotion/react";
|
||||
import { withRouter } from "storybook-addon-react-router-v6";
|
||||
import { HelmetProvider } from "react-helmet-async";
|
||||
import { dark } from "theme/mui";
|
||||
import { dark as experimental } from "theme/experimental";
|
||||
import colors from "theme/tailwind";
|
||||
import "theme/globalFonts";
|
||||
import { QueryClient, QueryClientProvider } from "react-query";
|
||||
|
||||
const theme = {
|
||||
...dark,
|
||||
experimental,
|
||||
};
|
||||
|
||||
export const decorators = [
|
||||
(Story) => (
|
||||
<StyledEngineProvider injectFirst>
|
||||
<MuiThemeProvider theme={dark}>
|
||||
<EmotionThemeProvider theme={dark}>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<EmotionThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<Story />
|
||||
</EmotionThemeProvider>
|
||||
@ -39,6 +46,19 @@ export const decorators = [
|
||||
];
|
||||
|
||||
export const parameters = {
|
||||
backgrounds: {
|
||||
default: "dark",
|
||||
values: [
|
||||
{
|
||||
name: "dark",
|
||||
value: colors.gray[950],
|
||||
},
|
||||
{
|
||||
name: "light",
|
||||
value: colors.gray[50],
|
||||
},
|
||||
],
|
||||
},
|
||||
actions: {
|
||||
argTypesRegex: "^(on|handler)[A-Z].*",
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
import CssBaseline from "@mui/material/CssBaseline";
|
||||
import { QueryClient, QueryClientProvider } from "react-query";
|
||||
import { AuthProvider } from "components/AuthProvider/AuthProvider";
|
||||
import { FC, PropsWithChildren, ReactNode } from "react";
|
||||
import type { FC, PropsWithChildren, ReactNode } from "react";
|
||||
import { HelmetProvider } from "react-helmet-async";
|
||||
import { AppRouter } from "./AppRouter";
|
||||
import { ErrorBoundary } from "./components/ErrorBoundary/ErrorBoundary";
|
||||
|
@ -10,62 +10,50 @@ const meta: Meta<typeof Avatar> = {
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Avatar>;
|
||||
|
||||
export const Letter: Story = {
|
||||
export const WithLetter: Story = {
|
||||
args: {
|
||||
children: "Coder",
|
||||
},
|
||||
};
|
||||
|
||||
export const LetterXL = {
|
||||
export const WithLetterXL = {
|
||||
args: {
|
||||
children: "Coder",
|
||||
size: "xl",
|
||||
},
|
||||
};
|
||||
|
||||
export const LetterDarken = {
|
||||
args: {
|
||||
children: "Coder",
|
||||
colorScheme: "darken",
|
||||
},
|
||||
};
|
||||
|
||||
export const Image = {
|
||||
export const WithImage = {
|
||||
args: {
|
||||
src: "https://avatars.githubusercontent.com/u/95932066?s=200&v=4",
|
||||
},
|
||||
};
|
||||
|
||||
export const ImageXL = {
|
||||
export const WithImageXL = {
|
||||
args: {
|
||||
src: "https://avatars.githubusercontent.com/u/95932066?s=200&v=4",
|
||||
size: "xl",
|
||||
},
|
||||
};
|
||||
|
||||
export const MuiIcon = {
|
||||
export const WithMuiIcon = {
|
||||
args: {
|
||||
background: true,
|
||||
children: <PauseIcon />,
|
||||
},
|
||||
};
|
||||
|
||||
export const MuiIconDarken = {
|
||||
args: {
|
||||
children: <PauseIcon />,
|
||||
colorScheme: "darken",
|
||||
},
|
||||
};
|
||||
|
||||
export const MuiIconXL = {
|
||||
export const WithMuiIconXL = {
|
||||
args: {
|
||||
background: true,
|
||||
children: <PauseIcon />,
|
||||
size: "xl",
|
||||
},
|
||||
};
|
||||
|
||||
export const AvatarIconDarken = {
|
||||
export const WithAvatarIcon = {
|
||||
args: {
|
||||
background: true,
|
||||
children: <AvatarIcon src="/icon/database.svg" alt="Database" />,
|
||||
colorScheme: "darken",
|
||||
},
|
||||
};
|
||||
|
@ -8,7 +8,7 @@ import { visuallyHidden } from "@mui/utils";
|
||||
|
||||
export type AvatarProps = MuiAvatarProps & {
|
||||
size?: "xs" | "sm" | "md" | "xl";
|
||||
colorScheme?: "light" | "darken";
|
||||
background?: boolean;
|
||||
fitImage?: boolean;
|
||||
};
|
||||
|
||||
@ -33,14 +33,6 @@ const sizeStyles = {
|
||||
},
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
||||
const colorStyles = {
|
||||
light: {},
|
||||
darken: (theme) => ({
|
||||
background: theme.palette.divider,
|
||||
color: theme.palette.text.primary,
|
||||
}),
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
||||
const fitImageStyles = css`
|
||||
& .MuiAvatar-img {
|
||||
object-fit: contain;
|
||||
@ -49,18 +41,24 @@ const fitImageStyles = css`
|
||||
|
||||
export const Avatar: FC<AvatarProps> = ({
|
||||
size = "md",
|
||||
colorScheme = "light",
|
||||
fitImage,
|
||||
children,
|
||||
background,
|
||||
...muiProps
|
||||
}) => {
|
||||
const fromName = !muiProps.src && typeof children === "string";
|
||||
|
||||
return (
|
||||
<MuiAvatar
|
||||
{...muiProps}
|
||||
css={[
|
||||
sizeStyles[size],
|
||||
colorStyles[colorScheme],
|
||||
fitImage && fitImageStyles,
|
||||
(theme) => ({
|
||||
background:
|
||||
background || fromName ? theme.palette.divider : undefined,
|
||||
color: theme.palette.text.primary,
|
||||
}),
|
||||
]}
|
||||
>
|
||||
{typeof children === "string" ? firstLetter(children) : children}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { type ReactNode } from "react";
|
||||
import { Avatar } from "components/Avatar/Avatar";
|
||||
import { type CSSObject, useTheme } from "@emotion/react";
|
||||
import { colors } from "theme/colors";
|
||||
|
||||
type AvatarCardProps = {
|
||||
header: string;
|
||||
imgUrl: string;
|
||||
altText: string;
|
||||
background?: boolean;
|
||||
|
||||
subtitle?: ReactNode;
|
||||
maxWidth?: number | "none";
|
||||
@ -16,6 +16,7 @@ export function AvatarCard({
|
||||
header,
|
||||
imgUrl,
|
||||
altText,
|
||||
background,
|
||||
subtitle,
|
||||
maxWidth = "none",
|
||||
}: AvatarCardProps) {
|
||||
@ -71,12 +72,7 @@ export function AvatarCard({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Avatar
|
||||
src={imgUrl}
|
||||
alt={altText}
|
||||
size="md"
|
||||
css={{ backgroundColor: colors.gray[7] }}
|
||||
>
|
||||
<Avatar background={background} src={imgUrl} alt={altText} size="md">
|
||||
{header}
|
||||
</Avatar>
|
||||
</div>
|
||||
|
38
site/src/components/Badges/Badges.stories.tsx
Normal file
38
site/src/components/Badges/Badges.stories.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import {
|
||||
Badges,
|
||||
AlphaBadge,
|
||||
EnabledBadge,
|
||||
EntitledBadge,
|
||||
EnterpriseBadge,
|
||||
} from "./Badges";
|
||||
|
||||
const meta: Meta<typeof Badges> = {
|
||||
title: "components/Badges",
|
||||
component: Badges,
|
||||
args: {},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Badges>;
|
||||
|
||||
export const Enabled: Story = {
|
||||
args: {
|
||||
children: <EnabledBadge />,
|
||||
},
|
||||
};
|
||||
export const Entitled: Story = {
|
||||
args: {
|
||||
children: <EntitledBadge />,
|
||||
},
|
||||
};
|
||||
export const Enterprise: Story = {
|
||||
args: {
|
||||
children: <EnterpriseBadge />,
|
||||
},
|
||||
};
|
||||
export const Alpha: Story = {
|
||||
args: {
|
||||
children: <AlphaBadge />,
|
||||
},
|
||||
};
|
@ -2,7 +2,7 @@ import type { PropsWithChildren, FC } from "react";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import { colors } from "theme/colors";
|
||||
import colors from "theme/tailwind";
|
||||
|
||||
const styles = {
|
||||
badge: {
|
||||
@ -20,16 +20,16 @@ const styles = {
|
||||
},
|
||||
|
||||
enabledBadge: (theme) => ({
|
||||
border: `1px solid ${theme.palette.success.light}`,
|
||||
backgroundColor: theme.palette.success.dark,
|
||||
border: `1px solid ${theme.experimental.roles.success.outline}`,
|
||||
backgroundColor: theme.experimental.roles.success.background,
|
||||
}),
|
||||
errorBadge: (theme) => ({
|
||||
border: `1px solid ${theme.palette.error.light}`,
|
||||
backgroundColor: theme.palette.error.dark,
|
||||
border: `1px solid ${theme.experimental.roles.error.outline}`,
|
||||
backgroundColor: theme.experimental.roles.error.background,
|
||||
}),
|
||||
warnBadge: (theme) => ({
|
||||
border: `1px solid ${theme.palette.warning.light}`,
|
||||
backgroundColor: theme.palette.warning.dark,
|
||||
border: `1px solid ${theme.experimental.roles.warning.outline}`,
|
||||
backgroundColor: theme.experimental.roles.warning.background,
|
||||
}),
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
||||
@ -111,9 +111,9 @@ export const AlphaBadge: FC = () => {
|
||||
css={[
|
||||
styles.badge,
|
||||
{
|
||||
border: `1px solid ${colors.violet[10]}`,
|
||||
backgroundColor: colors.violet[14],
|
||||
color: colors.violet[1],
|
||||
border: `1px solid ${colors.violet[600]}`,
|
||||
backgroundColor: colors.violet[950],
|
||||
color: colors.violet[50],
|
||||
},
|
||||
]}
|
||||
>
|
@ -46,7 +46,7 @@ export const BuildAvatar: FC<BuildAvatarProps> = ({ build, size }) => {
|
||||
}}
|
||||
badgeContent={<div></div>}
|
||||
>
|
||||
<Avatar size={size} colorScheme="darken">
|
||||
<Avatar background size={size}>
|
||||
<BuildIcon transition={build.transition} />
|
||||
</Avatar>
|
||||
</StyledBadge>
|
||||
|
@ -48,15 +48,13 @@ export const LicenseBannerView: React.FC<LicenseBannerViewProps> = ({
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
background-color: ${type === "error"
|
||||
? colors.red[12]
|
||||
: theme.palette.warning.main};
|
||||
background-color: ${type === "error" ? colors.red[10] : colors.orange[10]};
|
||||
`;
|
||||
|
||||
if (messages.length === 1) {
|
||||
return (
|
||||
<div css={containerStyles}>
|
||||
<Pill text={Language.licenseIssue} type={type} lightBorder />
|
||||
<Pill text={Language.licenseIssue} type={type} />
|
||||
<div css={styles.leftContent}>
|
||||
<span>{messages[0]}</span>
|
||||
|
||||
@ -70,11 +68,7 @@ export const LicenseBannerView: React.FC<LicenseBannerViewProps> = ({
|
||||
|
||||
return (
|
||||
<div css={containerStyles}>
|
||||
<Pill
|
||||
text={Language.licenseIssues(messages.length)}
|
||||
type={type}
|
||||
lightBorder
|
||||
/>
|
||||
<Pill text={Language.licenseIssues(messages.length)} type={type} />
|
||||
<div css={styles.leftContent}>
|
||||
<div>
|
||||
{Language.exceeded}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { Pill } from "components/Pill/Pill";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import { colors } from "theme/colors";
|
||||
import { useTheme } from "@mui/system";
|
||||
import { css } from "@emotion/react";
|
||||
import { css, useTheme } from "@emotion/react";
|
||||
import { readableForegroundColor } from "utils/colors";
|
||||
|
||||
export interface ServiceBannerViewProps {
|
||||
@ -43,7 +42,7 @@ export const ServiceBannerView: React.FC<ServiceBannerViewProps> = ({
|
||||
}
|
||||
`}
|
||||
>
|
||||
{isPreview && <Pill text="Preview" type="info" lightBorder />}
|
||||
{isPreview && <Pill text="Preview" type="info" />}
|
||||
<div
|
||||
css={css`
|
||||
margin-right: auto;
|
||||
|
@ -3,20 +3,12 @@ import CheckCircleOutlined from "@mui/icons-material/CheckCircleOutlined";
|
||||
import { css, useTheme } from "@emotion/react";
|
||||
import type { PropsWithChildren, FC } from "react";
|
||||
import { MONOSPACE_FONT_FAMILY } from "theme/constants";
|
||||
import { DisabledBadge, EnabledBadge } from "./Badges";
|
||||
import { DisabledBadge, EnabledBadge } from "../Badges/Badges";
|
||||
|
||||
export const OptionName: FC<PropsWithChildren> = (props) => {
|
||||
const { children } = props;
|
||||
|
||||
return (
|
||||
<span
|
||||
css={{
|
||||
display: "block",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
return <span css={{ display: "block" }}>{children}</span>;
|
||||
};
|
||||
|
||||
export const OptionDescription: FC<PropsWithChildren> = (props) => {
|
||||
|
@ -12,8 +12,8 @@ import { Stack } from "components/Stack/Stack";
|
||||
import type { ElementType, FC, PropsWithChildren, ReactNode } from "react";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { useDashboard } from "components/Dashboard/DashboardProvider";
|
||||
import { useTheme } from "@mui/system";
|
||||
import { css } from "@emotion/css";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
const SidebarNavItem: FC<
|
||||
PropsWithChildren<{ href: string; icon: ReactNode }>
|
||||
@ -74,11 +74,7 @@ export const Sidebar: React.FC = () => {
|
||||
const dashboard = useDashboard();
|
||||
|
||||
return (
|
||||
<nav
|
||||
css={{
|
||||
width: 245,
|
||||
}}
|
||||
>
|
||||
<nav css={{ width: 245 }}>
|
||||
<SidebarNavItem
|
||||
href="general"
|
||||
icon={<SidebarNavItemIcon icon={LaunchOutlined} />}
|
||||
|
@ -97,14 +97,14 @@ const styles = {
|
||||
}),
|
||||
successButton: (theme) => ({
|
||||
"&.MuiButton-contained": {
|
||||
backgroundColor: theme.palette.success.main,
|
||||
backgroundColor: theme.palette.success.dark,
|
||||
|
||||
"&:not(.MuiLoadingButton-loading)": {
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.success.dark,
|
||||
backgroundColor: theme.palette.success.main,
|
||||
|
||||
"@media (hover: none)": {
|
||||
backgroundColor: "transparent",
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
type PropsWithChildren,
|
||||
useContext,
|
||||
} from "react";
|
||||
import { AlphaBadge } from "components/DeploySettingsLayout/Badges";
|
||||
import { AlphaBadge } from "components/Badges/Badges";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import {
|
||||
FormFooter as BaseFormFooter,
|
||||
|
@ -37,7 +37,9 @@ export const GroupAvatar: FC<GroupAvatarProps> = ({ name, avatarURL }) => {
|
||||
}}
|
||||
badgeContent={<Group />}
|
||||
>
|
||||
<Avatar src={avatarURL}>{name}</Avatar>
|
||||
<Avatar src={avatarURL} background>
|
||||
{name}
|
||||
</Avatar>
|
||||
</StyledBadge>
|
||||
);
|
||||
};
|
||||
|
@ -15,6 +15,14 @@ export default meta;
|
||||
type Story = StoryObj<typeof InfoTooltip>;
|
||||
|
||||
export const Example: Story = {};
|
||||
|
||||
export const Notice: Story = {
|
||||
args: {
|
||||
type: "notice",
|
||||
message: "Unfortunately, there's a radio connected to my brain",
|
||||
},
|
||||
};
|
||||
|
||||
export const Warning: Story = {
|
||||
args: {
|
||||
type: "warning",
|
||||
|
@ -6,10 +6,11 @@ import {
|
||||
} from "components/HelpTooltip/HelpTooltip";
|
||||
import InfoIcon from "@mui/icons-material/InfoOutlined";
|
||||
import { css } from "@emotion/css";
|
||||
import { colors } from "theme/colors";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
interface InfoTooltipProps {
|
||||
type?: "warning" | "info";
|
||||
// TODO: use a `ThemeRole` type or something
|
||||
type?: "warning" | "notice" | "info";
|
||||
title: ReactNode;
|
||||
message: ReactNode;
|
||||
}
|
||||
@ -17,12 +18,15 @@ interface InfoTooltipProps {
|
||||
export const InfoTooltip: FC<InfoTooltipProps> = (props) => {
|
||||
const { title, message, type = "info" } = props;
|
||||
|
||||
const theme = useTheme();
|
||||
const iconColor = theme.experimental.roles[type].outline;
|
||||
|
||||
return (
|
||||
<HelpTooltip
|
||||
size="small"
|
||||
icon={InfoIcon}
|
||||
iconClassName={css`
|
||||
color: ${type === "info" ? colors.blue[5] : colors.yellow[5]};
|
||||
color: ${iconColor};
|
||||
`}
|
||||
buttonClassName={css`
|
||||
opacity: 1;
|
||||
|
@ -11,7 +11,7 @@ import { type FC, memo } from "react";
|
||||
import ReactMarkdown, { type Options } from "react-markdown";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import gfm from "remark-gfm";
|
||||
import { colors } from "theme/colors";
|
||||
import colors from "theme/tailwind";
|
||||
import { darcula } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
||||
|
||||
interface MarkdownProps {
|
||||
@ -227,7 +227,7 @@ const markdownStyles: Interpolation<Theme> = (theme: Theme) => ({
|
||||
},
|
||||
|
||||
"& .key, & .property, & .inserted, .keyword": {
|
||||
color: colors.turquoise[7],
|
||||
color: colors.teal[300],
|
||||
},
|
||||
|
||||
"& .deleted": {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import Box from "@mui/material/Box";
|
||||
import Chip from "@mui/material/Chip";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { type FC, type ReactNode } from "react";
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import { EnterpriseBadge } from "components/Badges/Badges";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
|
||||
export interface PaywallProps {
|
||||
@ -21,12 +21,7 @@ export const Paywall: FC<React.PropsWithChildren<PaywallProps>> = (props) => {
|
||||
<Typography variant="h5" css={styles.title}>
|
||||
{message}
|
||||
</Typography>
|
||||
<Chip
|
||||
css={styles.enterpriseChip}
|
||||
label="Enterprise"
|
||||
size="small"
|
||||
color="primary"
|
||||
/>
|
||||
<EnterpriseBadge />
|
||||
</Stack>
|
||||
|
||||
{description && (
|
||||
|
@ -9,38 +9,16 @@ const meta: Meta<typeof Pill> = {
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Pill>;
|
||||
|
||||
export const Primary: Story = {
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
text: "Primary",
|
||||
type: "primary",
|
||||
text: "Default",
|
||||
},
|
||||
};
|
||||
|
||||
export const Secondary: Story = {
|
||||
export const Danger: Story = {
|
||||
args: {
|
||||
text: "Secondary",
|
||||
type: "secondary",
|
||||
},
|
||||
};
|
||||
|
||||
export const Success: Story = {
|
||||
args: {
|
||||
text: "Success",
|
||||
type: "success",
|
||||
},
|
||||
};
|
||||
|
||||
export const Info: Story = {
|
||||
args: {
|
||||
text: "Information",
|
||||
type: "info",
|
||||
},
|
||||
};
|
||||
|
||||
export const Warning: Story = {
|
||||
args: {
|
||||
text: "Warning",
|
||||
type: "warning",
|
||||
text: "Danger",
|
||||
type: "danger",
|
||||
},
|
||||
};
|
||||
|
||||
@ -51,16 +29,37 @@ export const Error: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
text: "Default",
|
||||
},
|
||||
};
|
||||
|
||||
export const WarningLight: Story = {
|
||||
export const Warning: Story = {
|
||||
args: {
|
||||
text: "Warning",
|
||||
type: "warning",
|
||||
lightBorder: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const Notice: Story = {
|
||||
args: {
|
||||
text: "Notice",
|
||||
type: "notice",
|
||||
},
|
||||
};
|
||||
|
||||
export const Info: Story = {
|
||||
args: {
|
||||
text: "Information",
|
||||
type: "info",
|
||||
},
|
||||
};
|
||||
|
||||
export const Success: Story = {
|
||||
args: {
|
||||
text: "Success",
|
||||
type: "success",
|
||||
},
|
||||
};
|
||||
|
||||
export const Active: Story = {
|
||||
args: {
|
||||
text: "Active",
|
||||
type: "active",
|
||||
},
|
||||
};
|
||||
|
@ -1,65 +1,43 @@
|
||||
import { type FC, type ReactNode, useMemo, forwardRef } from "react";
|
||||
import { css, type Interpolation, type Theme } from "@emotion/react";
|
||||
import { colors } from "theme/colors";
|
||||
import type { ThemeRole } from "theme/experimental";
|
||||
|
||||
export type PillType =
|
||||
| "primary"
|
||||
| "secondary"
|
||||
| "error"
|
||||
| "warning"
|
||||
| "info"
|
||||
| "success"
|
||||
| "neutral";
|
||||
export type PillType = ThemeRole | keyof typeof themeOverrides;
|
||||
|
||||
export interface PillProps {
|
||||
className?: string;
|
||||
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) => ({
|
||||
neutral: {
|
||||
backgroundColor: colors.gray[13],
|
||||
borderColor: lightBorder ? colors.gray[6] : colors.gray[8],
|
||||
}),
|
||||
} satisfies Record<string, (lightBorder?: boolean) => Interpolation<Theme>>;
|
||||
borderColor: colors.gray[6],
|
||||
},
|
||||
} satisfies Record<string, 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,
|
||||
};
|
||||
const themeStyles = (type: ThemeRole) => (theme: Theme) => {
|
||||
const palette = theme.experimental.roles[type];
|
||||
return {
|
||||
backgroundColor: palette.background,
|
||||
borderColor: palette.outline,
|
||||
};
|
||||
};
|
||||
|
||||
export const Pill: FC<PillProps> = forwardRef<HTMLDivElement, PillProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
lightBorder,
|
||||
icon,
|
||||
text = null,
|
||||
type = "neutral",
|
||||
...attrs
|
||||
} = props;
|
||||
const { icon, text = null, type = "neutral", ...attrs } = props;
|
||||
|
||||
const typeStyles = useMemo(() => {
|
||||
if (type in themeOverrides) {
|
||||
return themeOverrides[type as keyof typeof themeOverrides](lightBorder);
|
||||
return themeOverrides[type as keyof typeof themeOverrides];
|
||||
}
|
||||
return themeStyles(type, lightBorder);
|
||||
}, [type, lightBorder]);
|
||||
return themeStyles(type as ThemeRole);
|
||||
}, [type]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -39,7 +39,7 @@ export const ResourceAvatar: FC<ResourceAvatarProps> = ({ resource }) => {
|
||||
: getIconPathResource(resource.type);
|
||||
|
||||
return (
|
||||
<Avatar colorScheme="darken">
|
||||
<Avatar background>
|
||||
<AvatarIcon src={avatarSrc} alt={resource.name} />
|
||||
</Avatar>
|
||||
);
|
||||
|
@ -9,7 +9,6 @@ import { type FC } from "react";
|
||||
import { TemplateVersionParameter } from "api/typesGenerated";
|
||||
import { MemoizedMarkdown } from "components/Markdown/Markdown";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import { colors } from "theme/colors";
|
||||
import { MultiTextField } from "./MultiTextField";
|
||||
|
||||
const isBoolean = (parameter: TemplateVersionParameter) => {
|
||||
@ -43,11 +42,6 @@ const styles = {
|
||||
fontSize: 14,
|
||||
},
|
||||
}),
|
||||
labelImmutable: {
|
||||
marginTop: 4,
|
||||
marginBottom: 4,
|
||||
color: colors.yellow[7],
|
||||
},
|
||||
textField: {
|
||||
".small & .MuiInputBase-root": {
|
||||
height: 36,
|
||||
|
@ -1,9 +1,7 @@
|
||||
import { useTheme } from "@mui/styles";
|
||||
import { useMonaco } from "@monaco-editor/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { hslToHex } from "utils/colors";
|
||||
import { editor } from "monaco-editor";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { type Theme, useTheme } from "@emotion/react";
|
||||
|
||||
// Theme based on https://github.com/brijeshb42/monaco-themes/blob/master/themes/Dracula.json
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- The theme is not typed
|
||||
@ -208,12 +206,11 @@ export const coderTheme = (theme: Theme): editor.IStandaloneThemeData => ({
|
||||
},
|
||||
],
|
||||
colors: {
|
||||
"editor.foreground": hslToHex(theme.palette.text.primary),
|
||||
"editor.background": hslToHex(theme.palette.background.paper),
|
||||
"editor.selectionBackground": hslToHex(theme.palette.action.hover),
|
||||
"editor.lineHighlightBackground": hslToHex(
|
||||
theme.palette.background.paperLight,
|
||||
),
|
||||
"editor.foreground": theme.palette.text.primary,
|
||||
"editor.background": theme.palette.background.paper,
|
||||
"editor.selectionBackground": theme.palette.action.hover,
|
||||
"editor.lineHighlightBackground": theme.palette.background.paperLight,
|
||||
|
||||
"editorCursor.foreground": "#f8f8f0",
|
||||
"editorWhitespace.foreground": "#3B3A32",
|
||||
"editorIndentGuide.activeBackground": "#9D550FB0",
|
||||
@ -224,7 +221,7 @@ export const coderTheme = (theme: Theme): editor.IStandaloneThemeData => ({
|
||||
export const useCoderTheme = (): { isLoading: boolean; name: string } => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const monaco = useMonaco();
|
||||
const theme = useTheme<Theme>();
|
||||
const theme = useTheme();
|
||||
const name = "coder";
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -3,7 +3,7 @@ import { NavLink, NavLinkProps } from "react-router-dom";
|
||||
import { combineClasses } from "utils/combineClasses";
|
||||
import { Margins } from "components/Margins/Margins";
|
||||
import { css } from "@emotion/css";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
export const Tabs = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Avatar, AvatarProps } from "components/Avatar/Avatar";
|
||||
import { FC } from "react";
|
||||
import { Avatar, type AvatarProps } from "components/Avatar/Avatar";
|
||||
import { type FC } from "react";
|
||||
|
||||
export type UserAvatarProps = {
|
||||
username: string;
|
||||
@ -12,7 +12,7 @@ export const UserAvatar: FC<UserAvatarProps> = ({
|
||||
...avatarProps
|
||||
}) => {
|
||||
return (
|
||||
<Avatar title={username} src={avatarURL} {...avatarProps}>
|
||||
<Avatar background title={username} src={avatarURL} {...avatarProps}>
|
||||
{username}
|
||||
</Avatar>
|
||||
);
|
||||
|
@ -1,11 +1,12 @@
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
import { type FC } from "react";
|
||||
import InfoIcon from "@mui/icons-material/InfoOutlined";
|
||||
import { useQuery } from "react-query";
|
||||
import Box from "@mui/material/Box";
|
||||
import Skeleton from "@mui/material/Skeleton";
|
||||
import Link from "@mui/material/Link";
|
||||
import { type FC } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { css } from "@emotion/css";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { templateVersion } from "api/queries/templates";
|
||||
import {
|
||||
HelpTooltip,
|
||||
@ -14,7 +15,6 @@ import {
|
||||
HelpTooltipText,
|
||||
HelpTooltipTitle,
|
||||
} from "components/HelpTooltip/HelpTooltip";
|
||||
import { colors } from "theme/colors";
|
||||
|
||||
export const Language = {
|
||||
outdatedLabel: "Outdated",
|
||||
@ -37,13 +37,14 @@ export const WorkspaceOutdatedTooltip: FC<TooltipProps> = ({
|
||||
templateName,
|
||||
}) => {
|
||||
const { data: activeVersion } = useQuery(templateVersion(latestVersionId));
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<HelpTooltip
|
||||
size="small"
|
||||
icon={InfoIcon}
|
||||
iconClassName={css`
|
||||
color: ${colors.yellow[5]};
|
||||
color: ${theme.experimental.roles.notice.outline};
|
||||
`}
|
||||
buttonClassName={css`
|
||||
opacity: 1;
|
||||
|
@ -73,7 +73,14 @@ export const WorkspaceStatusText: FC<
|
||||
role="status"
|
||||
data-testid="build-status"
|
||||
className={className}
|
||||
css={[styles.root, styles[`type-${type}`]]}
|
||||
css={[
|
||||
styles.root,
|
||||
(theme) => ({
|
||||
color: type
|
||||
? theme.experimental.roles[type].fill
|
||||
: theme.experimental.l1.text,
|
||||
}),
|
||||
]}
|
||||
>
|
||||
{text}
|
||||
</span>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import { type FC } from "react";
|
||||
import type { AuditLog } from "api/typesGenerated";
|
||||
import { colors } from "theme/colors";
|
||||
import colors from "theme/tailwind";
|
||||
import { MONOSPACE_FONT_FAMILY } from "theme/constants";
|
||||
|
||||
const getDiffValue = (value: unknown): string => {
|
||||
@ -79,10 +79,10 @@ const styles = {
|
||||
overflowWrap: "anywhere",
|
||||
},
|
||||
|
||||
diffOld: (theme) => ({
|
||||
backgroundColor: theme.palette.error.dark,
|
||||
color: theme.palette.error.contrastText,
|
||||
}),
|
||||
diffOld: {
|
||||
backgroundColor: colors.red[950],
|
||||
color: colors.red[50],
|
||||
},
|
||||
|
||||
diffRow: {
|
||||
display: "flex",
|
||||
@ -103,10 +103,10 @@ const styles = {
|
||||
flexShrink: 0,
|
||||
}),
|
||||
|
||||
diffNew: (theme) => ({
|
||||
backgroundColor: theme.palette.success.dark,
|
||||
color: theme.palette.success.contrastText,
|
||||
}),
|
||||
diffNew: {
|
||||
backgroundColor: colors.green[950],
|
||||
color: colors.green[50],
|
||||
},
|
||||
|
||||
diffValue: {
|
||||
padding: 1,
|
||||
@ -114,10 +114,10 @@ const styles = {
|
||||
},
|
||||
|
||||
diffValueOld: {
|
||||
backgroundColor: colors.red[12],
|
||||
backgroundColor: colors.red[800],
|
||||
},
|
||||
|
||||
diffValueNew: {
|
||||
backgroundColor: colors.green[12],
|
||||
backgroundColor: colors.green[800],
|
||||
},
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
@ -10,7 +10,7 @@ export const AuditPaywall: FC = () => {
|
||||
return (
|
||||
<Paywall
|
||||
message="Audit logs"
|
||||
description="Audit Logs allows Auditors to monitor user operations in their deployment. To use this feature, you have to upgrade your account."
|
||||
description="Audit Logs allows Auditors to monitor user operations in their deployment. To use this feature, you need an Enterprise license."
|
||||
cta={
|
||||
<Stack direction="row" alignItems="center">
|
||||
<Link href={docs("/admin/upgrade")} target="_blank" rel="noreferrer">
|
||||
|
@ -1,26 +1,25 @@
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
import Button from "@mui/material/Button";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Link from "@mui/material/Link";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useState } from "react";
|
||||
import { BlockPicker } from "react-color";
|
||||
import { useFormik } from "formik";
|
||||
import type { UpdateAppearanceConfig } from "api/typesGenerated";
|
||||
import { Header } from "components/DeploySettingsLayout/Header";
|
||||
import {
|
||||
Badges,
|
||||
DisabledBadge,
|
||||
EnterpriseBadge,
|
||||
EntitledBadge,
|
||||
} from "components/DeploySettingsLayout/Badges";
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
} from "components/Badges/Badges";
|
||||
import { Fieldset } from "components/DeploySettingsLayout/Fieldset";
|
||||
import { getFormHelpers } from "utils/formUtils";
|
||||
import Button from "@mui/material/Button";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import { BlockPicker } from "react-color";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import type { UpdateAppearanceConfig } from "api/typesGenerated";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import { useFormik } from "formik";
|
||||
import Link from "@mui/material/Link";
|
||||
import { getFormHelpers } from "utils/formUtils";
|
||||
import { colors } from "theme/colors";
|
||||
import { hslToHex } from "utils/colors";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
export type AppearanceSettingsPageViewProps = {
|
||||
appearance: UpdateAppearanceConfig;
|
||||
@ -31,7 +30,7 @@ export type AppearanceSettingsPageViewProps = {
|
||||
) => void;
|
||||
};
|
||||
|
||||
const fallbackBgColor = hslToHex(colors.blue[7]);
|
||||
const fallbackBgColor = colors.blue[7];
|
||||
|
||||
export const AppearanceSettingsPageView = ({
|
||||
appearance,
|
||||
|
@ -7,7 +7,7 @@ import TableHead from "@mui/material/TableHead";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import type { DeploymentValues, ExternalAuthConfig } from "api/typesGenerated";
|
||||
import { Alert } from "components/Alert/Alert";
|
||||
import { EnterpriseBadge } from "components/DeploySettingsLayout/Badges";
|
||||
import { EnterpriseBadge } from "components/Badges/Badges";
|
||||
import { Header } from "components/DeploySettingsLayout/Header";
|
||||
import { docs } from "utils/docs";
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import { type Interpolation, type Theme, useTheme } from "@emotion/react";
|
||||
import Button from "@mui/material/Button";
|
||||
import { useTheme } from "@mui/styles";
|
||||
import Skeleton from "@mui/material/Skeleton";
|
||||
import AddIcon from "@mui/icons-material/AddOutlined";
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
|
@ -1,9 +1,5 @@
|
||||
import { ClibaseOption } from "api/typesGenerated";
|
||||
import {
|
||||
Badges,
|
||||
EnabledBadge,
|
||||
DisabledBadge,
|
||||
} from "components/DeploySettingsLayout/Badges";
|
||||
import type { ClibaseOption } from "api/typesGenerated";
|
||||
import { Badges, EnabledBadge, DisabledBadge } from "components/Badges/Badges";
|
||||
import { Header } from "components/DeploySettingsLayout/Header";
|
||||
import OptionsTable from "components/DeploySettingsLayout/OptionsTable";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { ClibaseOption } from "api/typesGenerated";
|
||||
import type { ClibaseOption } from "api/typesGenerated";
|
||||
import {
|
||||
Badges,
|
||||
DisabledBadge,
|
||||
EnabledBadge,
|
||||
EnterpriseBadge,
|
||||
} from "components/DeploySettingsLayout/Badges";
|
||||
} from "components/Badges/Badges";
|
||||
import { Header } from "components/DeploySettingsLayout/Header";
|
||||
import OptionsTable from "components/DeploySettingsLayout/OptionsTable";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { ClibaseOption } from "api/typesGenerated";
|
||||
import type { ClibaseOption } from "api/typesGenerated";
|
||||
import {
|
||||
Badges,
|
||||
DisabledBadge,
|
||||
EnabledBadge,
|
||||
EnterpriseBadge,
|
||||
} from "components/DeploySettingsLayout/Badges";
|
||||
} from "components/Badges/Badges";
|
||||
import { Header } from "components/DeploySettingsLayout/Header";
|
||||
import OptionsTable from "components/DeploySettingsLayout/OptionsTable";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
|
@ -1,9 +1,5 @@
|
||||
import { ClibaseOption } from "api/typesGenerated";
|
||||
import {
|
||||
Badges,
|
||||
DisabledBadge,
|
||||
EnabledBadge,
|
||||
} from "components/DeploySettingsLayout/Badges";
|
||||
import type { ClibaseOption } from "api/typesGenerated";
|
||||
import { Badges, DisabledBadge, EnabledBadge } from "components/Badges/Badges";
|
||||
import { Header } from "components/DeploySettingsLayout/Header";
|
||||
import OptionsTable from "components/DeploySettingsLayout/OptionsTable";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
|
@ -86,11 +86,7 @@ const ExternalAuthPageView: FC<ExternalAuthPageViewProps> = ({
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Avatar
|
||||
size="sm"
|
||||
src={install.account.avatar_url}
|
||||
colorScheme="darken"
|
||||
>
|
||||
<Avatar size="sm" src={install.account.avatar_url}>
|
||||
{install.account.login}
|
||||
</Avatar>
|
||||
</Link>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import LinearProgress from "@mui/material/LinearProgress";
|
||||
import Box from "@mui/material/Box";
|
||||
import { styled, useTheme } from "@mui/material/styles";
|
||||
import { styled } from "@mui/material/styles";
|
||||
import { BoxProps } from "@mui/system";
|
||||
import { useQuery } from "react-query";
|
||||
import {
|
||||
@ -20,7 +20,7 @@ import { colors } from "theme/colors";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { getTemplatePageTitle } from "../utils";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import {
|
||||
import type {
|
||||
Entitlements,
|
||||
Template,
|
||||
TemplateAppUsage,
|
||||
@ -30,7 +30,8 @@ import {
|
||||
UserActivityInsightsResponse,
|
||||
UserLatencyInsightsResponse,
|
||||
} from "api/typesGenerated";
|
||||
import { ComponentProps, ReactNode } from "react";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { type ComponentProps, type ReactNode } from "react";
|
||||
import { subDays, addWeeks, format } from "date-fns";
|
||||
import "react-date-range/dist/styles.css";
|
||||
import "react-date-range/dist/theme/default.css";
|
||||
|
@ -80,13 +80,13 @@ export const VersionRow: React.FC<VersionRowProps> = ({
|
||||
{isLatest && <Pill text="Newest" type="info" />}
|
||||
|
||||
{jobStatus === "pending" && (
|
||||
<Pill text={<>Pending…</>} type="warning" lightBorder />
|
||||
<Pill text={<>Pending…</>} type="warning" />
|
||||
)}
|
||||
{jobStatus === "running" && (
|
||||
<Pill text={<>Building…</>} type="warning" lightBorder />
|
||||
<Pill text={<>Building…</>} type="warning" />
|
||||
)}
|
||||
{(jobStatus === "canceling" || jobStatus === "canceled") && (
|
||||
<Pill text="Canceled" type="neutral" lightBorder />
|
||||
<Pill text="Canceled" type="neutral" />
|
||||
)}
|
||||
{jobStatus === "failed" && <Pill text="Failed" type="error" />}
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { useTheme } from "@mui/styles";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import Editor, { loader } from "@monaco-editor/react";
|
||||
import * as monaco from "monaco-editor";
|
||||
import { FC, useLayoutEffect, useMemo, useState } from "react";
|
||||
import { MONOSPACE_FONT_FAMILY } from "theme/constants";
|
||||
import { hslToHex } from "utils/colors";
|
||||
import type { editor } from "monaco-editor";
|
||||
|
||||
loader.config({ monaco });
|
||||
@ -124,8 +123,8 @@ export const MonacoEditor: FC<{
|
||||
},
|
||||
],
|
||||
colors: {
|
||||
"editor.foreground": hslToHex(theme.palette.text.primary),
|
||||
"editor.background": hslToHex(theme.palette.background.default),
|
||||
"editor.foreground": theme.palette.text.primary,
|
||||
"editor.background": theme.palette.background.default,
|
||||
},
|
||||
});
|
||||
editor.updateOptions({
|
||||
|
@ -39,9 +39,9 @@ export const getStatus = (
|
||||
};
|
||||
case "pending":
|
||||
return {
|
||||
type: "info",
|
||||
text: "Pending",
|
||||
icon: <LoadingIcon />,
|
||||
type: "info",
|
||||
};
|
||||
case "canceling":
|
||||
return {
|
||||
|
@ -51,6 +51,7 @@ export function AccountUserGroups({
|
||||
{groups.map((group) => (
|
||||
<Grid item key={group.id} xs={1}>
|
||||
<AvatarCard
|
||||
background
|
||||
imgUrl={group.avatar_url}
|
||||
altText={group.display_name || group.name}
|
||||
header={group.display_name || group.name}
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { Region, WorkspaceProxy } from "api/typesGenerated";
|
||||
import type { Region, WorkspaceProxy } from "api/typesGenerated";
|
||||
import { AvatarData } from "components/AvatarData/AvatarData";
|
||||
import { Avatar } from "components/Avatar/Avatar";
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import { FC, ReactNode } from "react";
|
||||
import type { FC, ReactNode } from "react";
|
||||
import {
|
||||
HealthyBadge,
|
||||
NotHealthyBadge,
|
||||
NotReachableBadge,
|
||||
NotRegisteredBadge,
|
||||
} from "components/DeploySettingsLayout/Badges";
|
||||
import { ProxyLatencyReport } from "contexts/useProxyLatency";
|
||||
} from "components/Badges/Badges";
|
||||
import type { ProxyLatencyReport } from "contexts/useProxyLatency";
|
||||
import { getLatencyColor } from "utils/latency";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
TableLoaderSkeleton,
|
||||
TableRowSkeleton,
|
||||
} from "components/TableLoader/TableLoader";
|
||||
import { EnterpriseBadge } from "components/DeploySettingsLayout/Badges";
|
||||
import { EnterpriseBadge } from "components/Badges/Badges";
|
||||
import HideSourceOutlined from "@mui/icons-material/HideSourceOutlined";
|
||||
import KeyOutlined from "@mui/icons-material/KeyOutlined";
|
||||
import GitHub from "@mui/icons-material/GitHub";
|
||||
|
@ -8,12 +8,7 @@ import {
|
||||
import ScheduleIcon from "@mui/icons-material/TimerOutlined";
|
||||
import type { Workspace } from "api/typesGenerated";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import {
|
||||
type FC,
|
||||
type ComponentType,
|
||||
type PropsWithChildren,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
import { type FC, type PropsWithChildren, type ReactNode } from "react";
|
||||
import { Link, NavLink } from "react-router-dom";
|
||||
import { combineClasses } from "utils/combineClasses";
|
||||
import GeneralIcon from "@mui/icons-material/SettingsOutlined";
|
||||
@ -74,13 +69,7 @@ const SidebarNavItem: FC<
|
||||
);
|
||||
};
|
||||
|
||||
const SidebarNavItemIcon: FC<{
|
||||
icon: ComponentType<{ className?: string }>;
|
||||
}> = ({ icon: Icon }) => {
|
||||
return <Icon css={{ width: 16, height: 16 }} />;
|
||||
};
|
||||
|
||||
export const Sidebar: React.FC<{ username: string; workspace: Workspace }> = ({
|
||||
export const Sidebar: FC<{ username: string; workspace: Workspace }> = ({
|
||||
username,
|
||||
workspace,
|
||||
}) => {
|
||||
@ -98,18 +87,21 @@ export const Sidebar: React.FC<{ username: string; workspace: Workspace }> = ({
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<SidebarNavItem href="" icon={<SidebarNavItemIcon icon={GeneralIcon} />}>
|
||||
<SidebarNavItem
|
||||
href=""
|
||||
icon={<GeneralIcon css={styles.sidebarItemIcon} />}
|
||||
>
|
||||
General
|
||||
</SidebarNavItem>
|
||||
<SidebarNavItem
|
||||
href="parameters"
|
||||
icon={<SidebarNavItemIcon icon={ParameterIcon} />}
|
||||
icon={<ParameterIcon css={styles.sidebarItemIcon} />}
|
||||
>
|
||||
Parameters
|
||||
</SidebarNavItem>
|
||||
<SidebarNavItem
|
||||
href="schedule"
|
||||
icon={<SidebarNavItemIcon icon={ScheduleIcon} />}
|
||||
icon={<ScheduleIcon css={styles.sidebarItemIcon} />}
|
||||
>
|
||||
Schedule
|
||||
</SidebarNavItem>
|
||||
@ -122,6 +114,10 @@ const styles = {
|
||||
width: 245,
|
||||
flexShrink: 0,
|
||||
},
|
||||
sidebarItemIcon: {
|
||||
width: 16,
|
||||
height: 16,
|
||||
},
|
||||
workspaceInfo: (theme) => ({
|
||||
...(theme.typography.body2 as CSSObject),
|
||||
marginBottom: 16,
|
||||
|
@ -1,274 +1,62 @@
|
||||
// Based on https://codepen.io/hkfoster/pen/YzeYRwR
|
||||
|
||||
import { getMetadataAsJSON } from "utils/metadata";
|
||||
|
||||
// When in development mode the experiments meta tag won't exist,
|
||||
// so you can just set this to true.
|
||||
export const experimentalTheme =
|
||||
typeof document !== "undefined" &&
|
||||
(getMetadataAsJSON<string[]>("experiments")?.includes("dashboard_theme") ??
|
||||
false);
|
||||
import tw from "./tailwind";
|
||||
|
||||
export const colors = {
|
||||
white: "hsl(0, 0%, 100%)",
|
||||
white: "#fff",
|
||||
|
||||
gray: experimentalTheme
|
||||
? {
|
||||
17: "hsl(0, 0%, 4%)",
|
||||
16: "hsl(0, 0%, 7%)",
|
||||
15: "hsl(0, 0%, 10%)",
|
||||
14: "hsl(0, 0%, 14%)",
|
||||
13: "hsl(0, 0%, 17%)",
|
||||
12: "hsl(0, 0%, 20%)",
|
||||
11: "hsl(0, 0%, 23%)",
|
||||
10: "hsl(0, 0%, 27%)",
|
||||
9: "hsl(0, 0%, 31%)",
|
||||
8: "hsl(0, 0%, 35%)",
|
||||
7: "hsl(0, 0%, 62%)",
|
||||
6: "hsl(0, 0%, 69%)",
|
||||
5: "hsl(0, 0%, 75%)",
|
||||
4: "hsl(0, 0%, 82%)",
|
||||
3: "hsl(0, 0%, 90%)",
|
||||
2: "hsl(0, 0%, 93%)",
|
||||
1: "hsl(0, 0%, 96%)",
|
||||
}
|
||||
: {
|
||||
17: "hsl(220, 50%, 3%)",
|
||||
16: "hsl(223, 44%, 9%)",
|
||||
15: "hsl(222, 38%, 14%)",
|
||||
14: "hsl(222, 32%, 19%)",
|
||||
13: "hsl(222, 31%, 25%)",
|
||||
12: "hsl(222, 30%, 31%)",
|
||||
11: "hsl(219, 29%, 38%)",
|
||||
10: "hsl(219, 28%, 45%)",
|
||||
9: "hsl(219, 28%, 52%)",
|
||||
8: "hsl(218, 29%, 58%)",
|
||||
7: "hsl(219, 30%, 64%)",
|
||||
6: "hsl(219, 31%, 71%)",
|
||||
5: "hsl(218, 32%, 77%)",
|
||||
4: "hsl(223, 38%, 84%)",
|
||||
3: "hsl(218, 44%, 92%)",
|
||||
2: "hsl(220, 50%, 95%)",
|
||||
1: "hsl(220, 55%, 98%)",
|
||||
},
|
||||
gray: {
|
||||
17: tw.gray[950],
|
||||
16: tw.gray[900],
|
||||
14: tw.gray[800],
|
||||
13: tw.gray[700],
|
||||
12: tw.gray[600],
|
||||
11: tw.gray[500],
|
||||
9: tw.gray[400],
|
||||
6: tw.gray[300],
|
||||
4: tw.gray[200],
|
||||
2: tw.gray[100],
|
||||
1: tw.gray[50],
|
||||
},
|
||||
|
||||
red: experimentalTheme
|
||||
? {
|
||||
17: "hsl(355, 95%, 3%)",
|
||||
16: "hsl(355, 88%, 8%)",
|
||||
15: "hsl(355, 86%, 13%)",
|
||||
14: "hsl(355, 84%, 18%)",
|
||||
13: "hsl(355, 82%, 23%)",
|
||||
12: "hsl(355, 74%, 28%)",
|
||||
11: "hsl(355, 70%, 33%)",
|
||||
10: "hsl(355, 66%, 38%)",
|
||||
9: "hsl(355, 69%, 43%)",
|
||||
8: "hsl(355, 73%, 48%)",
|
||||
7: "hsl(355, 76%, 53%)",
|
||||
6: "hsl(355, 78%, 58%)",
|
||||
5: "hsl(355, 79%, 63%)",
|
||||
4: "hsl(355, 85%, 68%)",
|
||||
3: "hsl(355, 88%, 73%)",
|
||||
2: "hsl(355, 95%, 78%)",
|
||||
1: "hsl(355, 100%, 83%) ",
|
||||
}
|
||||
: {
|
||||
17: "hsl(355, 95%, 3%)",
|
||||
16: "hsl(355, 88%, 9%)",
|
||||
15: "hsl(355, 86%, 14%)",
|
||||
14: "hsl(355, 84%, 19%)",
|
||||
13: "hsl(355, 82%, 25%)",
|
||||
12: "hsl(355, 74%, 31%)",
|
||||
11: "hsl(355, 70%, 38%)",
|
||||
10: "hsl(355, 66%, 45%)",
|
||||
9: "hsl(355, 69%, 52%)",
|
||||
8: "hsl(355, 73%, 58%)",
|
||||
7: "hsl(355, 76%, 64%)",
|
||||
6: "hsl(355, 78%, 71%)",
|
||||
5: "hsl(355, 79%, 77%)",
|
||||
4: "hsl(355, 85%, 84%)",
|
||||
3: "hsl(355, 88%, 92%)",
|
||||
2: "hsl(355, 95%, 96%)",
|
||||
1: "hsl(355, 100%, 98%) ",
|
||||
},
|
||||
red: {
|
||||
15: tw.red[950],
|
||||
12: tw.red[800],
|
||||
10: tw.red[700],
|
||||
9: tw.red[600],
|
||||
8: tw.red[500],
|
||||
6: tw.red[400],
|
||||
2: tw.red[50],
|
||||
},
|
||||
|
||||
orange: {
|
||||
17: "hsl(20, 100%, 3%)",
|
||||
16: "hsl(20, 98%, 9%)",
|
||||
15: "hsl(20, 97%, 14%)",
|
||||
14: "hsl(20, 93%, 19%)",
|
||||
13: "hsl(20, 88%, 25%)",
|
||||
12: "hsl(20, 84%, 32%)",
|
||||
11: "hsl(20, 80%, 38%)",
|
||||
10: "hsl(20, 76%, 46%)",
|
||||
9: "hsl(20, 79%, 53%)",
|
||||
8: "hsl(20, 83%, 59%)",
|
||||
7: "hsl(20, 86%, 65%)",
|
||||
6: "hsl(20, 88%, 72%)",
|
||||
5: "hsl(20, 93%, 78%)",
|
||||
4: "hsl(20, 97%, 84%)",
|
||||
3: "hsl(20, 98%, 91%)",
|
||||
2: "hsl(20, 99%, 96%)",
|
||||
1: "hsl(20, 100%, 98%)",
|
||||
15: tw.amber[950],
|
||||
14: tw.amber[900],
|
||||
12: tw.amber[800],
|
||||
11: tw.amber[700],
|
||||
10: tw.amber[600],
|
||||
9: tw.amber[500],
|
||||
7: tw.amber[400],
|
||||
},
|
||||
|
||||
yellow: {
|
||||
17: "hsl(48, 100%, 3%)",
|
||||
16: "hsl(48, 87%, 9%)",
|
||||
15: "hsl(48, 83%, 14%)",
|
||||
14: "hsl(48, 88%, 19%)",
|
||||
13: "hsl(48, 82%, 25%)",
|
||||
12: "hsl(48, 74%, 32%)",
|
||||
11: "hsl(48, 70%, 38%)",
|
||||
10: "hsl(48, 66%, 46%)",
|
||||
9: "hsl(48, 69%, 53%)",
|
||||
8: "hsl(48, 73%, 59%)",
|
||||
7: "hsl(48, 76%, 65%)",
|
||||
6: "hsl(48, 78%, 72%)",
|
||||
5: "hsl(48, 79%, 78%)",
|
||||
4: "hsl(48, 85%, 84%)",
|
||||
3: "hsl(48, 90%, 89%)",
|
||||
2: "hsl(46, 95%, 93%)",
|
||||
1: "hsl(46, 100%, 97%)",
|
||||
5: tw.yellow[300],
|
||||
},
|
||||
|
||||
green: {
|
||||
17: "hsl(132, 98%, 3%)",
|
||||
16: "hsl(140, 94%, 8%)",
|
||||
15: "hsl(144, 93%, 12%)",
|
||||
14: "hsl(145, 99%, 16%)",
|
||||
13: "hsl(143, 83%, 22%)",
|
||||
12: "hsl(143, 74%, 27%)",
|
||||
11: "hsl(142, 64%, 34%)",
|
||||
10: "hsl(141, 57%, 41%)",
|
||||
9: "hsl(140, 50%, 49%)",
|
||||
8: "hsl(140, 51%, 54%)",
|
||||
7: "hsl(138, 54%, 61%)",
|
||||
6: "hsl(137, 56%, 68%)",
|
||||
5: "hsl(137, 55%, 75%)",
|
||||
4: "hsl(137, 60%, 82%)",
|
||||
3: "hsl(136, 74%, 91%)",
|
||||
2: "hsl(136, 82%, 95%)",
|
||||
1: "hsl(136, 100%, 97%)",
|
||||
},
|
||||
|
||||
turquoise: {
|
||||
17: "hsl(162, 88%, 3%)",
|
||||
16: "hsl(164, 84%, 8%)",
|
||||
15: "hsl(165, 76%, 14%)",
|
||||
14: "hsl(167, 85%, 18%)",
|
||||
13: "hsl(166, 74%, 25%)",
|
||||
12: "hsl(166, 65%, 32%)",
|
||||
11: "hsl(165, 61%, 38%)",
|
||||
10: "hsl(165, 56%, 46%)",
|
||||
9: "hsl(165, 56%, 53%)",
|
||||
8: "hsl(165, 60%, 57%)",
|
||||
7: "hsl(164, 65%, 64%)",
|
||||
6: "hsl(163, 66%, 70%)",
|
||||
5: "hsl(163, 66%, 77%)",
|
||||
4: "hsl(162, 74%, 83%)",
|
||||
3: "hsl(162, 97%, 91%)",
|
||||
2: "hsl(163, 93%, 94%)",
|
||||
1: "hsl(163, 100%, 97%)",
|
||||
},
|
||||
|
||||
cyan: {
|
||||
17: "hsl(186, 100%, 3%)",
|
||||
16: "hsl(185, 86%, 8%)",
|
||||
15: "hsl(186, 80%, 14%)",
|
||||
14: "hsl(185, 83%, 18%)",
|
||||
13: "hsl(185, 76%, 25%)",
|
||||
12: "hsl(185, 68%, 31%)",
|
||||
11: "hsl(185, 64%, 37%)",
|
||||
10: "hsl(185, 59%, 45%)",
|
||||
9: "hsl(185, 57%, 52%)",
|
||||
8: "hsl(185, 61%, 57%)",
|
||||
7: "hsl(185, 64%, 63%)",
|
||||
6: "hsl(185, 66%, 70%)",
|
||||
5: "hsl(185, 66%, 77%)",
|
||||
4: "hsl(185, 72%, 83%)",
|
||||
3: "hsl(185, 91%, 91%)",
|
||||
2: "hsl(182, 96%, 94%)",
|
||||
1: "hsl(182, 100%, 97%)",
|
||||
15: tw.green[950],
|
||||
13: tw.green[700],
|
||||
12: tw.green[600],
|
||||
11: tw.green[500],
|
||||
9: tw.green[400],
|
||||
8: tw.green[300],
|
||||
},
|
||||
|
||||
blue: {
|
||||
17: "hsl(215, 100%, 3%)",
|
||||
16: "hsl(215, 92%, 7%)",
|
||||
15: "hsl(215, 88%, 12%)",
|
||||
14: "hsl(215, 93%, 17%)",
|
||||
13: "hsl(215, 87%, 23%)",
|
||||
12: "hsl(215, 79%, 30%)",
|
||||
11: "hsl(215, 75%, 36%)",
|
||||
10: "hsl(215, 71%, 44%)",
|
||||
9: "hsl(215, 74%, 51%)",
|
||||
8: "hsl(215, 78%, 57%)",
|
||||
7: "hsl(215, 81%, 63%)",
|
||||
6: "hsl(215, 83%, 70%)",
|
||||
5: "hsl(215, 84%, 76%)",
|
||||
4: "hsl(215, 90%, 82%)",
|
||||
3: "hsl(215, 93%, 89%)",
|
||||
2: "hsl(215, 97%, 95%)",
|
||||
1: "hsl(215, 100%, 98%)",
|
||||
},
|
||||
|
||||
indigo: {
|
||||
17: "hsl(256, 100%, 3%)",
|
||||
16: "hsl(254, 87%, 9%)",
|
||||
15: "hsl(252, 83%, 14%)",
|
||||
14: "hsl(250, 88%, 19%)",
|
||||
13: "hsl(248, 82%, 25%)",
|
||||
12: "hsl(246, 74%, 32%)",
|
||||
11: "hsl(244, 70%, 38%)",
|
||||
10: "hsl(242, 66%, 44%)",
|
||||
9: "hsl(240, 67%, 53%)",
|
||||
8: "hsl(238, 70%, 59%)",
|
||||
7: "hsl(232, 74%, 63%)",
|
||||
6: "hsl(236, 78%, 72%)",
|
||||
5: "hsl(234, 79%, 78%)",
|
||||
4: "hsl(232, 85%, 84%)",
|
||||
3: "hsl(230, 90%, 91%)",
|
||||
2: "hsl(228, 95%, 96%)",
|
||||
1: "hsl(226, 100%, 98%)",
|
||||
},
|
||||
|
||||
violet: {
|
||||
17: "hsl(264, 100%, 3%)",
|
||||
16: "hsl(265, 87%, 9%)",
|
||||
15: "hsl(265, 83%, 14%)",
|
||||
14: "hsl(265, 88%, 19%)",
|
||||
13: "hsl(265, 82%, 25%)",
|
||||
12: "hsl(265, 74%, 32%)",
|
||||
11: "hsl(265, 70%, 38%)",
|
||||
10: "hsl(265, 66%, 46%)",
|
||||
9: "hsl(265, 69%, 53%)",
|
||||
8: "hsl(265, 73%, 59%)",
|
||||
7: "hsl(265, 76%, 65%)",
|
||||
6: "hsl(265, 78%, 72%)",
|
||||
5: "hsl(265, 79%, 78%)",
|
||||
4: "hsl(264, 85%, 84%)",
|
||||
3: "hsl(265, 90%, 91%)",
|
||||
2: "hsl(265, 95%, 96%)",
|
||||
1: "hsl(265, 100%, 98%)",
|
||||
},
|
||||
|
||||
magenta: {
|
||||
17: "hsl(316, 100%, 3%)",
|
||||
16: "hsl(316, 86%, 9%)",
|
||||
15: "hsl(314, 83%, 14%)",
|
||||
14: "hsl(315, 85%, 19%)",
|
||||
13: "hsl(315, 80%, 25%)",
|
||||
12: "hsl(315, 71%, 31%)",
|
||||
11: "hsl(315, 68%, 38%)",
|
||||
10: "hsl(315, 62%, 45%)",
|
||||
9: "hsl(315, 63%, 52%)",
|
||||
8: "hsl(315, 67%, 58%)",
|
||||
7: "hsl(315, 70%, 64%)",
|
||||
6: "hsl(315, 71%, 71%)",
|
||||
5: "hsl(315, 72%, 77%)",
|
||||
4: "hsl(315, 79%, 84%)",
|
||||
3: "hsl(316, 88%, 92%)",
|
||||
2: "hsl(315, 95%, 96%)",
|
||||
1: "hsl(315, 100%, 98%)",
|
||||
14: tw.blue[950],
|
||||
9: tw.blue[600],
|
||||
8: tw.blue[500],
|
||||
7: tw.blue[400],
|
||||
6: tw.blue[300],
|
||||
3: tw.blue[200],
|
||||
1: tw.blue[50],
|
||||
},
|
||||
};
|
||||
|
@ -1,5 +1,7 @@
|
||||
import colors from "./tailwind";
|
||||
|
||||
export type ThemeRole = keyof NewTheme["roles"];
|
||||
|
||||
export interface NewTheme {
|
||||
l1: Role; // page background, things which sit at the "root level"
|
||||
l2: InteractiveRole; // sidebars, table headers, navigation
|
||||
@ -34,7 +36,7 @@ export const dark: NewTheme = {
|
||||
l1: {
|
||||
background: colors.gray[950],
|
||||
outline: colors.gray[700],
|
||||
fill: "#f00",
|
||||
fill: colors.gray[600],
|
||||
text: colors.white,
|
||||
},
|
||||
|
||||
@ -60,7 +62,7 @@ export const dark: NewTheme = {
|
||||
l3: {
|
||||
background: colors.gray[800],
|
||||
outline: colors.gray[700],
|
||||
fill: "#f00",
|
||||
fill: colors.gray[600],
|
||||
text: colors.white,
|
||||
disabled: {
|
||||
background: "#f00",
|
||||
@ -117,7 +119,7 @@ export const dark: NewTheme = {
|
||||
notice: {
|
||||
background: colors.yellow[950],
|
||||
outline: colors.yellow[200],
|
||||
fill: "#f00",
|
||||
fill: colors.yellow[500],
|
||||
text: colors.yellow[50],
|
||||
},
|
||||
info: {
|
||||
@ -147,7 +149,7 @@ export const dark: NewTheme = {
|
||||
active: {
|
||||
background: colors.sky[950],
|
||||
outline: colors.sky[500],
|
||||
fill: "#f00",
|
||||
fill: colors.sky[600],
|
||||
text: colors.sky[50],
|
||||
},
|
||||
},
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { colors, experimentalTheme } from "./colors";
|
||||
import { colors } from "./colors";
|
||||
import { createTheme, type ThemeOptions } from "@mui/material/styles";
|
||||
import {
|
||||
BODY_FONT_FAMILY,
|
||||
@ -32,27 +32,27 @@ export let dark = createTheme({
|
||||
secondary: {
|
||||
main: colors.gray[11],
|
||||
contrastText: colors.gray[4],
|
||||
dark: colors.indigo[7],
|
||||
dark: colors.gray[9],
|
||||
},
|
||||
background: {
|
||||
default: colors.gray[17],
|
||||
paper: colors.gray[16],
|
||||
paperLight: colors.gray[15],
|
||||
paperLight: colors.gray[14],
|
||||
},
|
||||
text: {
|
||||
primary: colors.gray[1],
|
||||
secondary: colors.gray[5],
|
||||
disabled: colors.gray[7],
|
||||
secondary: colors.gray[4],
|
||||
disabled: colors.gray[9],
|
||||
},
|
||||
divider: colors.gray[13],
|
||||
warning: {
|
||||
light: experimentalTheme ? colors.orange[9] : colors.orange[7],
|
||||
main: experimentalTheme ? colors.orange[11] : colors.orange[9],
|
||||
light: colors.orange[9],
|
||||
main: colors.orange[12],
|
||||
dark: colors.orange[15],
|
||||
},
|
||||
success: {
|
||||
main: colors.green[11],
|
||||
dark: colors.green[15],
|
||||
dark: colors.green[12],
|
||||
},
|
||||
info: {
|
||||
light: colors.blue[7],
|
||||
@ -172,7 +172,7 @@ dark = createTheme(dark, {
|
||||
},
|
||||
outlined: {
|
||||
":hover": {
|
||||
border: `1px solid ${colors.gray[10]}`,
|
||||
border: `1px solid ${colors.gray[11]}`,
|
||||
},
|
||||
},
|
||||
outlinedNeutral: {
|
||||
@ -214,7 +214,7 @@ dark = createTheme(dark, {
|
||||
root: {
|
||||
">button:hover+button": {
|
||||
// The !important is unfortunate, but necessary for the border.
|
||||
borderLeftColor: `${colors.gray[10]} !important`,
|
||||
borderLeftColor: `${colors.gray[11]} !important`,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -407,7 +407,7 @@ dark = createTheme(dark, {
|
||||
// The default outlined input color is white, which seemed jarring.
|
||||
"&:hover:not(.Mui-error):not(.Mui-focused) .MuiOutlinedInput-notchedOutline":
|
||||
{
|
||||
borderColor: colors.gray[10],
|
||||
borderColor: colors.gray[11],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -173,43 +173,43 @@ export const getDisplayWorkspaceStatus = (
|
||||
} as const;
|
||||
case "starting":
|
||||
return {
|
||||
type: "success",
|
||||
type: "active",
|
||||
text: "Starting",
|
||||
icon: <LoadingIcon />,
|
||||
} as const;
|
||||
case "stopping":
|
||||
return {
|
||||
type: "warning",
|
||||
type: "notice",
|
||||
text: "Stopping",
|
||||
icon: <LoadingIcon />,
|
||||
} as const;
|
||||
case "stopped":
|
||||
return {
|
||||
type: "warning",
|
||||
type: "notice",
|
||||
text: "Stopped",
|
||||
icon: <StopIcon />,
|
||||
} as const;
|
||||
case "deleting":
|
||||
return {
|
||||
type: "warning",
|
||||
type: "danger",
|
||||
text: "Deleting",
|
||||
icon: <LoadingIcon />,
|
||||
} as const;
|
||||
case "deleted":
|
||||
return {
|
||||
type: "error",
|
||||
type: "danger",
|
||||
text: "Deleted",
|
||||
icon: <ErrorIcon />,
|
||||
} as const;
|
||||
case "canceling":
|
||||
return {
|
||||
type: "warning",
|
||||
type: "notice",
|
||||
text: "Canceling",
|
||||
icon: <LoadingIcon />,
|
||||
} as const;
|
||||
case "canceled":
|
||||
return {
|
||||
type: "warning",
|
||||
type: "notice",
|
||||
text: "Canceled",
|
||||
icon: <ErrorIcon />,
|
||||
} as const;
|
||||
@ -221,7 +221,7 @@ export const getDisplayWorkspaceStatus = (
|
||||
} as const;
|
||||
case "pending":
|
||||
return {
|
||||
type: "info",
|
||||
type: undefined,
|
||||
text: getPendingWorkspaceStatusText(provisionerJob),
|
||||
icon: <QueuedIcon />,
|
||||
} as const;
|
||||
|
Reference in New Issue
Block a user