-
-
-
-
+
+
+
+
-
-
-
-
+
+ {displayName}
+ {beta && }
-
{displayName}
-
+
);
};
+
+const styles = {
+ container: (theme) => ({
+ backgroundColor: theme.palette.background.default,
+ border: `1px solid ${theme.palette.divider}`,
+ width: 220,
+ color: theme.palette.text.primary,
+ borderRadius: 6,
+ overflow: "clip",
+ userSelect: "none",
+ }),
+ containerActive: (theme) => ({
+ outline: `2px solid ${theme.experimental.roles.active.outline}`,
+ }),
+ page: (theme) => ({
+ backgroundColor: theme.palette.background.default,
+ color: theme.palette.text.primary,
+ }),
+ header: (theme) => ({
+ backgroundColor: theme.palette.background.paper,
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ padding: "6px 10px",
+ marginBottom: 8,
+ borderBottom: `1px solid ${theme.palette.divider}`,
+ }),
+ headerLinks: {
+ display: "flex",
+ alignItems: "center",
+ gap: 6,
+ },
+ headerLink: (theme) => ({
+ backgroundColor: theme.palette.text.secondary,
+ height: 6,
+ width: 20,
+ borderRadius: 3,
+ }),
+ activeHeaderLink: (theme) => ({
+ backgroundColor: theme.palette.text.primary,
+ }),
+ proxy: (theme) => ({
+ backgroundColor: theme.palette.success.light,
+ height: 6,
+ width: 12,
+ borderRadius: 3,
+ }),
+ user: (theme) => ({
+ backgroundColor: theme.palette.text.primary,
+ height: 8,
+ width: 8,
+ borderRadius: 4,
+ float: "right",
+ }),
+ body: {
+ width: 120,
+ margin: "auto",
+ },
+ title: (theme) => ({
+ backgroundColor: theme.palette.text.primary,
+ height: 8,
+ width: 45,
+ borderRadius: 4,
+ marginBottom: 6,
+ }),
+ table: (theme) => ({
+ border: `1px solid ${theme.palette.divider}`,
+ borderBottom: "none",
+ borderTopLeftRadius: 3,
+ borderTopRightRadius: 3,
+ overflow: "clip",
+ }),
+ tableHeader: (theme) => ({
+ backgroundColor: theme.palette.background.paper,
+ height: 10,
+ margin: -1,
+ }),
+ label: (theme) => ({
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ borderTop: `1px solid ${theme.palette.divider}`,
+ padding: "4px 12px",
+ fontSize: 14,
+ }),
+ workspace: (theme) => ({
+ borderTop: `1px solid ${theme.palette.divider}`,
+ height: 15,
+
+ "&::after": {
+ content: '""',
+ display: "block",
+ marginTop: 4,
+ marginLeft: 4,
+ backgroundColor: theme.palette.text.disabled,
+ height: 6,
+ width: 30,
+ borderRadius: 3,
+ },
+ }),
+} satisfies Record
>;
diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx
index 89e85424011cf..623faccb0d7df 100644
--- a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx
+++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx
@@ -6,7 +6,7 @@ import { AppearancePage } from "./AppearancePage";
import { MockUser } from "testHelpers/entities";
describe("appearance page", () => {
- it("changes theme to dark", async () => {
+ it("does nothing when selecting current theme", async () => {
renderWithAuth();
jest.spyOn(API, "updateAppearanceSettings").mockResolvedValueOnce({
@@ -18,10 +18,7 @@ describe("appearance page", () => {
await userEvent.click(dark);
// Check if the API was called correctly
- expect(API.updateAppearanceSettings).toBeCalledTimes(1);
- expect(API.updateAppearanceSettings).toHaveBeenCalledWith("me", {
- theme_preference: "dark",
- });
+ expect(API.updateAppearanceSettings).toBeCalledTimes(0);
});
it("changes theme to dark blue", async () => {
@@ -41,4 +38,22 @@ describe("appearance page", () => {
theme_preference: "darkBlue",
});
});
+
+ it("changes theme to light", async () => {
+ renderWithAuth();
+
+ jest.spyOn(API, "updateAppearanceSettings").mockResolvedValueOnce({
+ ...MockUser,
+ theme_preference: "light",
+ });
+
+ const light = await screen.findByText("Light");
+ await userEvent.click(light);
+
+ // Check if the API was called correctly
+ expect(API.updateAppearanceSettings).toBeCalledTimes(1);
+ expect(API.updateAppearanceSettings).toHaveBeenCalledWith("me", {
+ theme_preference: "light",
+ });
+ });
});
diff --git a/site/src/pages/UserSettingsPage/ExternalAuthPage/ExternalAuthPageView.stories.tsx b/site/src/pages/UserSettingsPage/ExternalAuthPage/ExternalAuthPageView.stories.tsx
index b65a86774c144..abdd999f6abf0 100644
--- a/site/src/pages/UserSettingsPage/ExternalAuthPage/ExternalAuthPageView.stories.tsx
+++ b/site/src/pages/UserSettingsPage/ExternalAuthPage/ExternalAuthPageView.stories.tsx
@@ -26,6 +26,16 @@ type Story = StoryObj;
export const NoProviders: Story = {};
+export const NoIcon: Story = {
+ args: {
+ ...meta.args,
+ auths: {
+ providers: [{ ...MockGithubExternalProvider, display_icon: "" }],
+ links: [MockGithubAuthLink],
+ },
+ },
+};
+
export const Authenticated: Story = {
args: {
...meta.args,
@@ -36,7 +46,7 @@ export const Authenticated: Story = {
},
};
-export const UnAuthenticated: Story = {
+export const Unauthenticated: Story = {
args: {
...meta.args,
auths: {
diff --git a/site/src/pages/UserSettingsPage/ExternalAuthPage/ExternalAuthPageView.tsx b/site/src/pages/UserSettingsPage/ExternalAuthPage/ExternalAuthPageView.tsx
index b789101fbc5ec..a095a39ed0a8c 100644
--- a/site/src/pages/UserSettingsPage/ExternalAuthPage/ExternalAuthPageView.tsx
+++ b/site/src/pages/UserSettingsPage/ExternalAuthPage/ExternalAuthPageView.tsx
@@ -131,9 +131,8 @@ const ExternalAuthRow: FC = ({
)
}
@@ -150,6 +149,7 @@ const ExternalAuthRow: FC = ({
message={authenticated ? "Authenticated" : "Click to Login"}
externalAuthPollingState={externalAuthPollingState}
startPollingExternalAuth={startPollingExternalAuth}
+ fullWidth={false}
/>
diff --git a/site/src/pages/UserSettingsPage/SSHKeysPage/SSHKeysPageView.stories.tsx b/site/src/pages/UserSettingsPage/SSHKeysPage/SSHKeysPageView.stories.tsx
index 1986c7ef0cbdd..a8736defdcf46 100644
--- a/site/src/pages/UserSettingsPage/SSHKeysPage/SSHKeysPageView.stories.tsx
+++ b/site/src/pages/UserSettingsPage/SSHKeysPage/SSHKeysPageView.stories.tsx
@@ -11,7 +11,8 @@ const meta: Meta = {
user_id: "test-user-id",
created_at: "2022-07-28T07:45:50.795918897Z",
updated_at: "2022-07-28T07:45:50.795919142Z",
- public_key: "SSH-Key",
+ public_key:
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICnKzATuWwmmt5+CKTPuRGN0R1PBemA+6/SStpLiyX+L",
},
},
};
diff --git a/site/src/pages/UsersPage/UsersTable/UserRoleCell.tsx b/site/src/pages/UsersPage/UsersTable/UserRoleCell.tsx
index 2143a15b5f463..5ad5c148fa606 100644
--- a/site/src/pages/UsersPage/UsersTable/UserRoleCell.tsx
+++ b/site/src/pages/UsersPage/UsersTable/UserRoleCell.tsx
@@ -14,18 +14,17 @@
* users like that, though, know that it will be painful
*/
import { useTheme } from "@emotion/react";
-import { type User, type Role } from "api/typesGenerated";
-
-import { EditRolesButton } from "./EditRolesButton";
-import { Pill } from "components/Pill/Pill";
import TableCell from "@mui/material/TableCell";
import Stack from "@mui/material/Stack";
-
+import { type FC } from "react";
+import { type User, type Role } from "api/typesGenerated";
+import { Pill } from "components/Pill/Pill";
import {
Popover,
PopoverTrigger,
PopoverContent,
} from "components/Popover/Popover";
+import { EditRolesButton } from "./EditRolesButton";
type UserRoleCellProps = {
canEditUsers: boolean;
@@ -36,14 +35,14 @@ type UserRoleCellProps = {
onUserRolesUpdate: (user: User, newRoleNames: string[]) => void;
};
-export function UserRoleCell({
+export const UserRoleCell: FC = ({
canEditUsers,
allAvailableRoles,
user,
isLoading,
oidcRoleSyncEnabled,
onUserRolesUpdate,
-}: UserRoleCellProps) {
+}) => {
const theme = useTheme();
const [mainDisplayRole = fallbackRole, ...extraRoles] =
@@ -75,11 +74,11 @@ export function UserRoleCell({
text={mainDisplayRole.display_name}
css={{
backgroundColor: hasOwnerRole
- ? theme.palette.info.dark
- : theme.palette.background.paper,
+ ? theme.experimental.roles.info.background
+ : theme.experimental.l2.background,
borderColor: hasOwnerRole
- ? theme.palette.info.light
- : theme.palette.divider,
+ ? theme.experimental.roles.info.outline
+ : theme.experimental.l2.outline,
}}
/>
@@ -87,13 +86,13 @@ export function UserRoleCell({
);
-}
+};
type OverflowRolePillProps = {
roles: readonly Role[];
};
-function OverflowRolePill({ roles }: OverflowRolePillProps) {
+const OverflowRolePill: FC = ({ roles }) => {
const theme = useTheme();
return (
@@ -144,7 +143,7 @@ function OverflowRolePill({ roles }: OverflowRolePillProps) {
);
-}
+};
const fallbackRole: Role = {
name: "member",
diff --git a/site/src/pages/UsersPage/UsersTable/UsersTable.stories.tsx b/site/src/pages/UsersPage/UsersTable/UsersTable.stories.tsx
index 801de67349586..ce6b0055ed543 100644
--- a/site/src/pages/UsersPage/UsersTable/UsersTable.stories.tsx
+++ b/site/src/pages/UsersPage/UsersTable/UsersTable.stories.tsx
@@ -4,6 +4,10 @@ import {
MockAssignableSiteRoles,
MockAuthMethodsPasswordOnly,
MockGroup,
+ MockUserAdminRole,
+ MockTemplateAdminRole,
+ MockMemberRole,
+ MockAuditorRole,
} from "testHelpers/entities";
import { UsersTable } from "./UsersTable";
import type { Meta, StoryObj } from "@storybook/react";
@@ -43,7 +47,12 @@ export const Editable: Story = {
...MockUser,
username: "John Doe",
email: "john.doe@coder.com",
- roles: [],
+ roles: [
+ MockUserAdminRole,
+ MockTemplateAdminRole,
+ MockMemberRole,
+ MockAuditorRole,
+ ],
status: "dormant",
},
{
diff --git a/site/src/pages/WorkspaceBuildPage/Sidebar.tsx b/site/src/pages/WorkspaceBuildPage/Sidebar.tsx
index 869f3d4be9e08..370d51cdf6777 100644
--- a/site/src/pages/WorkspaceBuildPage/Sidebar.tsx
+++ b/site/src/pages/WorkspaceBuildPage/Sidebar.tsx
@@ -32,7 +32,7 @@ export const SidebarItem: FC = ({
return (
{!enableAutoStart && (
-
+
)}
>
@@ -378,7 +378,7 @@ export const WorkspaceScheduleForm: FC<
{!enableAutoStop && (
-
+
)}
>
diff --git a/site/src/testHelpers/chromatic.ts b/site/src/testHelpers/chromatic.ts
new file mode 100644
index 0000000000000..a3282f2178c97
--- /dev/null
+++ b/site/src/testHelpers/chromatic.ts
@@ -0,0 +1,13 @@
+export const chromatic = {
+ modes: {
+ dark: { theme: "dark" },
+ light: { theme: "light" },
+ },
+};
+
+export const chromaticWithTablet = {
+ modes: {
+ "dark desktop": { theme: "dark" },
+ "light tablet": { theme: "light", viewport: "ipad" },
+ },
+};
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts
index 592f74baa02ce..6687acc82ae91 100644
--- a/site/src/testHelpers/entities.ts
+++ b/site/src/testHelpers/entities.ts
@@ -2933,7 +2933,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
created_at: "2023-05-01T19:15:56.606593Z",
updated_at: "2023-12-05T14:13:36.647535Z",
deleted: false,
- version: "v2.4.0-devel+5fad61102",
+ version: "v2.5.0-devel+5fad61102",
},
{
id: "9d786ce0-55b1-4ace-8acc-a4672ff8d41f",
@@ -2956,7 +2956,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
created_at: "2023-05-01T20:34:11.114005Z",
updated_at: "2023-12-05T14:13:45.941716Z",
deleted: false,
- version: "v2.4.0-devel+5fad61102",
+ version: "v2.5.0-devel+5fad61102",
},
{
id: "2e209786-73b1-4838-ba78-e01c9334450a",
@@ -2979,7 +2979,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
created_at: "2023-05-01T20:41:02.76448Z",
updated_at: "2023-12-05T14:13:41.968568Z",
deleted: false,
- version: "v2.4.0-devel+5fad61102",
+ version: "v2.5.0-devel+5fad61102",
},
{
id: "c272e80c-0cce-49d6-9782-1b5cf90398e8",
@@ -3050,7 +3050,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
created_at: "2023-12-01T09:21:15.996267Z",
updated_at: "2023-12-05T14:13:59.663174Z",
deleted: false,
- version: "v2.4.0-devel+5fad61102",
+ version: "v2.5.0-devel+5fad61102",
},
{
id: "72649dc9-03c7-46a8-bc95-96775e93ddc1",
@@ -3073,7 +3073,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
created_at: "2023-12-01T09:23:44.505529Z",
updated_at: "2023-12-05T14:13:55.769058Z",
deleted: false,
- version: "v2.4.0-devel+5fad61102",
+ version: "v2.5.0-devel+5fad61102",
},
{
id: "1f78398f-e5ae-4c38-aa89-30222181d443",
@@ -3096,12 +3096,12 @@ export const MockHealth: TypesGen.HealthcheckReport = {
created_at: "2023-12-01T09:36:00.231252Z",
updated_at: "2023-12-05T14:13:47.015031Z",
deleted: false,
- version: "v2.4.0-devel+5fad61102",
+ version: "v2.5.0-devel+5fad61102",
},
],
},
},
- coder_version: "v0.27.1-devel+c575292",
+ coder_version: "v2.5.0-devel+5fad61102",
};
export const MockListeningPortsResponse: TypesGen.WorkspaceAgentListeningPortsResponse =
@@ -3184,7 +3184,7 @@ export const DeploymentHealthUnhealthy: TypesGen.HealthcheckReport = {
created_at: "2023-11-23T15:37:25.513213Z",
updated_at: "2023-11-23T18:09:19.734747Z",
deleted: false,
- version: "v2.4.0-devel+89bae7eff",
+ version: "v2.5.0-devel+89bae7eff",
},
],
},
diff --git a/site/src/testHelpers/renderHelpers.tsx b/site/src/testHelpers/renderHelpers.tsx
index fad96f08e8676..4d16b40a44ded 100644
--- a/site/src/testHelpers/renderHelpers.tsx
+++ b/site/src/testHelpers/renderHelpers.tsx
@@ -7,7 +7,7 @@ import {
import { type ReactNode, useState } from "react";
import { QueryClient } from "react-query";
import { AppProviders } from "App";
-import { ThemeProviders } from "contexts/ThemeProviders";
+import { ThemeProvider } from "contexts/ThemeProvider";
import { DashboardLayout } from "components/Dashboard/DashboardLayout";
import { RequireAuth } from "components/RequireAuth/RequireAuth";
import { TemplateSettingsLayout } from "pages/TemplateSettingsPage/TemplateSettingsLayout";
@@ -265,6 +265,6 @@ export const waitForLoaderToBeRemoved = async (): Promise
=> {
export const renderComponent = (component: React.ReactElement) => {
return tlRender(component, {
- wrapper: ({ children }) => {children},
+ wrapper: ({ children }) => {children},
});
};
diff --git a/site/src/theme/dark/experimental.ts b/site/src/theme/dark/experimental.ts
index b5112ec5e23d0..7e929c4ea8e97 100644
--- a/site/src/theme/dark/experimental.ts
+++ b/site/src/theme/dark/experimental.ts
@@ -3,41 +3,41 @@ import colors from "../tailwind";
export default {
l1: {
- background: colors.gray[950],
- outline: colors.gray[700],
- fill: colors.gray[600],
+ background: colors.zinc[950],
+ outline: colors.zinc[700],
+ fill: colors.zinc[600],
text: colors.white,
},
l2: {
- background: colors.gray[900],
- outline: colors.gray[700],
- fill: "#f00",
- text: colors.white,
+ background: colors.zinc[900],
+ outline: colors.zinc[700],
+ fill: colors.zinc[500],
+ text: colors.zinc[50],
disabled: {
background: "#f00",
outline: "#f00",
- fill: "#f00",
- text: colors.gray[200],
+ fill: colors.zinc[500],
+ text: colors.zinc[200],
},
hover: {
- background: "#f00",
- outline: "#f00",
+ background: colors.zinc[800],
+ outline: colors.zinc[600],
fill: "#f00",
text: colors.white,
},
},
l3: {
- background: colors.gray[800],
- outline: colors.gray[700],
- fill: colors.gray[600],
+ background: colors.zinc[800],
+ outline: colors.zinc[700],
+ fill: colors.zinc[600],
text: colors.white,
disabled: {
background: "#f00",
outline: "#f00",
fill: "#f00",
- text: colors.gray[200],
+ text: colors.zinc[200],
},
hover: {
background: "#f00",
@@ -51,7 +51,7 @@ export default {
danger: {
background: colors.orange[950],
outline: colors.orange[500],
- fill: colors.orange[600],
+ fill: colors.orange[700],
text: colors.orange[50],
disabled: {
background: colors.orange[950],
@@ -68,8 +68,8 @@ export default {
},
error: {
background: colors.red[950],
- outline: colors.red[500],
- fill: colors.red[600],
+ outline: colors.red[600],
+ fill: colors.red[400],
text: colors.red[50],
},
warning: {
@@ -126,5 +126,11 @@ export default {
text: colors.white,
},
},
+ preview: {
+ background: colors.violet[950],
+ outline: colors.violet[500],
+ fill: colors.violet[400],
+ text: colors.violet[50],
+ },
},
} satisfies NewTheme;
diff --git a/site/src/theme/dark/index.ts b/site/src/theme/dark/index.ts
index 19a84fc4b2c0a..4a1d9094c6bc2 100644
--- a/site/src/theme/dark/index.ts
+++ b/site/src/theme/dark/index.ts
@@ -1,9 +1,11 @@
import colors from "./colors";
import experimental from "./experimental";
+import monaco from "./monaco";
import muiTheme from "./mui";
export default {
...muiTheme,
colors,
experimental,
+ monaco,
};
diff --git a/site/src/theme/dark/monaco.ts b/site/src/theme/dark/monaco.ts
new file mode 100644
index 0000000000000..ae020bdd1ba33
--- /dev/null
+++ b/site/src/theme/dark/monaco.ts
@@ -0,0 +1,37 @@
+import muiTheme from "./mui";
+import type * as monaco from "monaco-editor";
+
+export default {
+ base: "vs-dark",
+ inherit: true,
+ rules: [
+ {
+ token: "comment",
+ foreground: "6B737C",
+ },
+ {
+ token: "type",
+ foreground: "B392F0",
+ },
+ {
+ token: "string",
+ foreground: "9DB1C5",
+ },
+ {
+ token: "variable",
+ foreground: "DDDDDD",
+ },
+ {
+ token: "identifier",
+ foreground: "B392F0",
+ },
+ {
+ token: "delimiter.curly",
+ foreground: "EBB325",
+ },
+ ],
+ colors: {
+ "editor.foreground": muiTheme.palette.text.primary,
+ "editor.background": muiTheme.palette.background.paper,
+ },
+} satisfies monaco.editor.IStandaloneThemeData as monaco.editor.IStandaloneThemeData;
diff --git a/site/src/theme/dark/mui.ts b/site/src/theme/dark/mui.ts
index 31d00fd6fa001..ae26de7cf895b 100644
--- a/site/src/theme/dark/mui.ts
+++ b/site/src/theme/dark/mui.ts
@@ -1,4 +1,5 @@
-import colors from "./colors";
+// eslint-disable-next-line no-restricted-imports -- We need MUI here
+import { alertClasses } from "@mui/material/Alert";
import { createTheme, type ThemeOptions } from "@mui/material/styles";
import {
BODY_FONT_FAMILY,
@@ -8,17 +9,17 @@ import {
BUTTON_SM_HEIGHT,
BUTTON_XL_HEIGHT,
} from "../constants";
-// eslint-disable-next-line no-restricted-imports -- We need MUI here
-import { alertClasses } from "@mui/material/Alert";
+import tw from "../tailwind";
+import colors from "./colors";
let muiTheme = createTheme({
palette: {
mode: "dark",
primary: {
- main: colors.blue[7],
- contrastText: colors.blue[1],
- light: colors.blue[6],
- dark: colors.blue[9],
+ main: tw.sky[500],
+ contrastText: tw.sky[50],
+ light: tw.sky[300],
+ dark: tw.sky[400],
},
secondary: {
main: colors.gray[11],
@@ -489,6 +490,7 @@ muiTheme = createTheme(muiTheme, {
lineHeight: "150%",
borderRadius: 4,
background: muiTheme.palette.divider,
+ padding: "8px 16px",
},
},
},
diff --git a/site/src/theme/darkBlue/experimental.ts b/site/src/theme/darkBlue/experimental.ts
index f694eca5823e2..9b15df75a932b 100644
--- a/site/src/theme/darkBlue/experimental.ts
+++ b/site/src/theme/darkBlue/experimental.ts
@@ -12,17 +12,17 @@ export default {
l2: {
background: colors.gray[900],
outline: colors.gray[700],
- fill: "#f00",
- text: colors.white,
+ fill: colors.gray[500],
+ text: colors.gray[50],
disabled: {
background: "#f00",
outline: "#f00",
- fill: "#f00",
+ fill: colors.gray[500],
text: colors.gray[200],
},
hover: {
background: "#f00",
- outline: "#f00",
+ outline: colors.gray[600],
fill: "#f00",
text: colors.white,
},
@@ -50,7 +50,7 @@ export default {
roles: {
danger: {
background: colors.orange[950],
- outline: colors.orange[500],
+ outline: colors.orange[600],
fill: colors.orange[600],
text: colors.orange[50],
disabled: {
@@ -126,5 +126,11 @@ export default {
text: colors.white,
},
},
+ preview: {
+ background: colors.violet[950],
+ outline: colors.violet[500],
+ fill: colors.violet[400],
+ text: colors.violet[50],
+ },
},
} satisfies NewTheme;
diff --git a/site/src/theme/darkBlue/index.ts b/site/src/theme/darkBlue/index.ts
index 19a84fc4b2c0a..4a1d9094c6bc2 100644
--- a/site/src/theme/darkBlue/index.ts
+++ b/site/src/theme/darkBlue/index.ts
@@ -1,9 +1,11 @@
import colors from "./colors";
import experimental from "./experimental";
+import monaco from "./monaco";
import muiTheme from "./mui";
export default {
...muiTheme,
colors,
experimental,
+ monaco,
};
diff --git a/site/src/theme/darkBlue/monaco.ts b/site/src/theme/darkBlue/monaco.ts
new file mode 100644
index 0000000000000..ae020bdd1ba33
--- /dev/null
+++ b/site/src/theme/darkBlue/monaco.ts
@@ -0,0 +1,37 @@
+import muiTheme from "./mui";
+import type * as monaco from "monaco-editor";
+
+export default {
+ base: "vs-dark",
+ inherit: true,
+ rules: [
+ {
+ token: "comment",
+ foreground: "6B737C",
+ },
+ {
+ token: "type",
+ foreground: "B392F0",
+ },
+ {
+ token: "string",
+ foreground: "9DB1C5",
+ },
+ {
+ token: "variable",
+ foreground: "DDDDDD",
+ },
+ {
+ token: "identifier",
+ foreground: "B392F0",
+ },
+ {
+ token: "delimiter.curly",
+ foreground: "EBB325",
+ },
+ ],
+ colors: {
+ "editor.foreground": muiTheme.palette.text.primary,
+ "editor.background": muiTheme.palette.background.paper,
+ },
+} satisfies monaco.editor.IStandaloneThemeData as monaco.editor.IStandaloneThemeData;
diff --git a/site/src/theme/darkBlue/mui.ts b/site/src/theme/darkBlue/mui.ts
index 31d00fd6fa001..f9308dc00044b 100644
--- a/site/src/theme/darkBlue/mui.ts
+++ b/site/src/theme/darkBlue/mui.ts
@@ -489,6 +489,7 @@ muiTheme = createTheme(muiTheme, {
lineHeight: "150%",
borderRadius: 4,
background: muiTheme.palette.divider,
+ padding: "8px 16px",
},
},
},
diff --git a/site/src/theme/experimental.ts b/site/src/theme/experimental.ts
index 385ab548a98b2..7bbc247f2a8e1 100644
--- a/site/src/theme/experimental.ts
+++ b/site/src/theme/experimental.ts
@@ -19,6 +19,7 @@ export interface NewTheme {
info: Role; // just sharing :)
success: InteractiveRole; // yay!! it's working!!
active: InteractiveRole; // selected items, focused inputs, in progress
+ preview: Role; // experiments, alpha/beta features
};
}
diff --git a/site/src/theme/index.ts b/site/src/theme/index.ts
index 7e23c0345c89d..6f889785286f9 100644
--- a/site/src/theme/index.ts
+++ b/site/src/theme/index.ts
@@ -1,20 +1,23 @@
import type { Theme as MuiTheme } from "@mui/material/styles";
+import type * as monaco from "monaco-editor";
import dark from "./dark";
import darkBlue from "./darkBlue";
+import light from "./light";
import type { NewTheme } from "./experimental";
import type { Colors } from "./colors";
export interface Theme extends MuiTheme {
colors: Colors;
experimental: NewTheme;
+ monaco: monaco.editor.IStandaloneThemeData;
}
-export const DEFAULT_THEME = "auto";
+export const DEFAULT_THEME = "dark";
const theme = {
dark,
darkBlue,
- light: dark,
+ light,
} satisfies Record;
export default theme;
diff --git a/site/src/theme/light/colors.ts b/site/src/theme/light/colors.ts
new file mode 100644
index 0000000000000..374c120e8f289
--- /dev/null
+++ b/site/src/theme/light/colors.ts
@@ -0,0 +1,62 @@
+import tw from "../tailwind";
+
+export default {
+ white: "#fff",
+
+ gray: {
+ 17: tw.zinc[950],
+ 16: tw.zinc[900],
+ 14: tw.zinc[800],
+ 13: tw.zinc[700],
+ 12: tw.zinc[600],
+ 11: tw.zinc[500],
+ 9: tw.zinc[400],
+ 6: tw.zinc[300],
+ 4: tw.zinc[200],
+ 2: tw.zinc[100],
+ 1: tw.zinc[50],
+ },
+
+ 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: {
+ 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: {
+ 5: tw.yellow[300],
+ },
+
+ green: {
+ 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: {
+ 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],
+ },
+};
diff --git a/site/src/theme/light/experimental.ts b/site/src/theme/light/experimental.ts
new file mode 100644
index 0000000000000..87ea50527c9f9
--- /dev/null
+++ b/site/src/theme/light/experimental.ts
@@ -0,0 +1,136 @@
+import { type NewTheme } from "../experimental";
+import colors from "../tailwind";
+
+export default {
+ l1: {
+ background: colors.gray[50],
+ outline: colors.gray[300],
+ fill: colors.gray[700],
+ text: colors.black,
+ },
+
+ l2: {
+ background: colors.gray[100],
+ outline: colors.gray[500],
+ fill: colors.gray[500],
+ text: colors.gray[950],
+ disabled: {
+ background: "#f00",
+ outline: "#f00",
+ fill: colors.gray[500],
+ text: colors.gray[200],
+ },
+ hover: {
+ background: colors.gray[200],
+ outline: colors.gray[700],
+ fill: "#f00",
+ text: colors.black,
+ },
+ },
+
+ l3: {
+ background: colors.gray[200],
+ outline: colors.gray[700],
+ fill: colors.gray[600],
+ text: colors.black,
+ disabled: {
+ background: "#f00",
+ outline: "#f00",
+ fill: "#f00",
+ text: colors.gray[200],
+ },
+ hover: {
+ background: "#f00",
+ outline: "#f00",
+ fill: "#f00",
+ text: colors.black,
+ },
+ },
+
+ roles: {
+ danger: {
+ background: colors.orange[50],
+ outline: colors.orange[400],
+ fill: colors.orange[600],
+ text: colors.orange[950],
+ disabled: {
+ background: colors.orange[50],
+ outline: colors.orange[800],
+ fill: colors.orange[800],
+ text: colors.orange[800],
+ },
+ hover: {
+ background: colors.orange[100],
+ outline: colors.orange[500],
+ fill: colors.orange[500],
+ text: colors.black,
+ },
+ },
+ error: {
+ background: colors.red[100],
+ outline: colors.red[500],
+ fill: colors.red[600],
+ text: colors.red[950],
+ },
+ warning: {
+ background: colors.amber[50],
+ outline: colors.amber[300],
+ fill: "#f00",
+ text: colors.amber[950],
+ },
+ notice: {
+ background: colors.yellow[50],
+ outline: colors.yellow[600],
+ fill: colors.yellow[500],
+ text: colors.yellow[950],
+ },
+ info: {
+ background: colors.blue[50],
+ outline: colors.blue[400],
+ fill: colors.blue[600],
+ text: colors.blue[950],
+ },
+ success: {
+ background: colors.green[50],
+ outline: colors.green[500],
+ fill: colors.green[600],
+ text: colors.green[950],
+ disabled: {
+ background: colors.green[50],
+ outline: colors.green[800],
+ fill: colors.green[800],
+ text: colors.green[800],
+ },
+ hover: {
+ background: colors.green[100],
+ outline: colors.green[500],
+ fill: colors.green[500],
+ text: colors.black,
+ },
+ },
+ active: {
+ background: colors.sky[100],
+ outline: colors.sky[500],
+ fill: colors.sky[600],
+ text: colors.sky[950],
+ disabled: {
+ background: colors.sky[50],
+ outline: colors.sky[800],
+ fill: colors.sky[800],
+ text: colors.sky[200],
+ },
+ hover: {
+ background: colors.sky[200],
+ outline: colors.sky[400],
+ fill: colors.sky[500],
+ text: colors.black,
+ },
+ },
+ preview: {
+ background: colors.violet[50],
+ outline: colors.violet[500],
+ fill: colors.violet[600],
+ text: colors.violet[950],
+ },
+ },
+} satisfies NewTheme;
diff --git a/site/src/theme/light/index.ts b/site/src/theme/light/index.ts
new file mode 100644
index 0000000000000..4a1d9094c6bc2
--- /dev/null
+++ b/site/src/theme/light/index.ts
@@ -0,0 +1,11 @@
+import colors from "./colors";
+import experimental from "./experimental";
+import monaco from "./monaco";
+import muiTheme from "./mui";
+
+export default {
+ ...muiTheme,
+ colors,
+ experimental,
+ monaco,
+};
diff --git a/site/src/theme/light/monaco.ts b/site/src/theme/light/monaco.ts
new file mode 100644
index 0000000000000..6dc38d2be7c36
--- /dev/null
+++ b/site/src/theme/light/monaco.ts
@@ -0,0 +1,37 @@
+import muiTheme from "./mui";
+import type * as monaco from "monaco-editor";
+
+export default {
+ base: "vs",
+ inherit: true,
+ rules: [
+ {
+ token: "comment",
+ foreground: "6B737C",
+ },
+ {
+ token: "type",
+ foreground: "682CD7",
+ },
+ {
+ token: "string",
+ foreground: "1766B4",
+ },
+ {
+ token: "variable",
+ foreground: "444444",
+ },
+ {
+ token: "identifier",
+ foreground: "682CD7",
+ },
+ {
+ token: "delimiter.curly",
+ foreground: "EBB325",
+ },
+ ],
+ colors: {
+ "editor.foreground": muiTheme.palette.text.primary,
+ "editor.background": muiTheme.palette.background.paper,
+ },
+} satisfies monaco.editor.IStandaloneThemeData as monaco.editor.IStandaloneThemeData;
diff --git a/site/src/theme/light/mui.ts b/site/src/theme/light/mui.ts
new file mode 100644
index 0000000000000..23040ee3f7a2f
--- /dev/null
+++ b/site/src/theme/light/mui.ts
@@ -0,0 +1,576 @@
+// eslint-disable-next-line no-restricted-imports -- We need MUI here
+import { alertClasses } from "@mui/material/Alert";
+import { createTheme, type ThemeOptions } from "@mui/material/styles";
+import {
+ BODY_FONT_FAMILY,
+ borderRadius,
+ BUTTON_LG_HEIGHT,
+ BUTTON_MD_HEIGHT,
+ BUTTON_SM_HEIGHT,
+ BUTTON_XL_HEIGHT,
+} from "../constants";
+import tw from "../tailwind";
+
+let muiTheme = createTheme({
+ palette: {
+ mode: "light",
+ primary: {
+ main: tw.sky[600],
+ contrastText: tw.sky[50],
+ light: tw.sky[400],
+ dark: tw.sky[500],
+ },
+ secondary: {
+ main: tw.zinc[500],
+ contrastText: tw.zinc[800],
+ dark: tw.zinc[600],
+ },
+ background: {
+ default: tw.zinc[50],
+ paper: tw.zinc[100],
+ },
+ text: {
+ primary: tw.zinc[950],
+ secondary: tw.zinc[700],
+ disabled: tw.zinc[600],
+ },
+ divider: tw.zinc[200],
+ warning: {
+ light: tw.amber[500],
+ main: tw.amber[800],
+ dark: tw.amber[950],
+ },
+ success: {
+ main: tw.green[500],
+ dark: tw.green[600],
+ },
+ info: {
+ light: tw.blue[400],
+ main: tw.blue[600],
+ dark: tw.blue[950],
+ contrastText: tw.zinc[200],
+ },
+ error: {
+ light: tw.red[400],
+ main: tw.red[500],
+ dark: tw.red[950],
+ contrastText: tw.zinc[800],
+ },
+ action: {
+ hover: tw.zinc[100],
+ },
+ neutral: {
+ main: tw.zinc[950],
+ },
+ },
+ typography: {
+ fontFamily: BODY_FONT_FAMILY,
+
+ body1: {
+ fontSize: "1rem" /* 16px at default scaling */,
+ lineHeight: "160%",
+ },
+
+ body2: {
+ fontSize: "0.875rem" /* 14px at default scaling */,
+ lineHeight: "160%",
+ },
+ },
+ shape: {
+ borderRadius,
+ },
+});
+
+muiTheme = createTheme(muiTheme, {
+ components: {
+ MuiCssBaseline: {
+ styleOverrides: `
+ html, body, #root, #storybook-root {
+ height: 100%;
+ }
+
+ button, input {
+ font-family: ${BODY_FONT_FAMILY};
+ }
+
+ input:-webkit-autofill,
+ input:-webkit-autofill:hover,
+ input:-webkit-autofill:focus,
+ input:-webkit-autofill:active {
+ -webkit-box-shadow: 0 0 0 100px ${muiTheme.palette.background.default} inset !important;
+ }
+
+ ::placeholder {
+ color: ${muiTheme.palette.text.disabled};
+ }
+ `,
+ },
+ MuiAvatar: {
+ styleOverrides: {
+ root: {
+ width: 36,
+ height: 36,
+ fontSize: 18,
+
+ "& .MuiSvgIcon-root": {
+ width: "50%",
+ },
+ },
+ colorDefault: {
+ backgroundColor: tw.zinc[700],
+ },
+ },
+ },
+ // Button styles are based on
+ // https://tailwindui.com/components/application-ui/elements/buttons
+ MuiButtonBase: {
+ defaultProps: {
+ disableRipple: true,
+ },
+ },
+ MuiButton: {
+ defaultProps: {
+ variant: "outlined",
+ color: "neutral",
+ },
+ styleOverrides: {
+ root: {
+ textTransform: "none",
+ letterSpacing: "normal",
+ fontWeight: 500,
+ height: BUTTON_MD_HEIGHT,
+ padding: "8px 16px",
+ borderRadius: "6px",
+ fontSize: 14,
+
+ whiteSpace: "nowrap",
+ ":focus-visible": {
+ outline: `2px solid ${muiTheme.palette.primary.main}`,
+ },
+
+ "& .MuiLoadingButton-loadingIndicator": {
+ width: 14,
+ height: 14,
+ },
+
+ "& .MuiLoadingButton-loadingIndicator .MuiCircularProgress-root": {
+ width: "inherit !important",
+ height: "inherit !important",
+ },
+ },
+ sizeSmall: {
+ height: BUTTON_SM_HEIGHT,
+ },
+ sizeLarge: {
+ height: BUTTON_LG_HEIGHT,
+ },
+ sizeXlarge: {
+ height: BUTTON_XL_HEIGHT,
+ },
+ outlined: {
+ boxShadow: "0 1px 4px #0001",
+ ":hover": {
+ boxShadow: "0 1px 4px #0001",
+ border: `1px solid ${tw.zinc[500]}`,
+ },
+ "&.Mui-disabled": {
+ boxShadow: "none !important",
+ },
+ },
+ outlinedNeutral: {
+ borderColor: tw.zinc[300],
+
+ "&.Mui-disabled": {
+ borderColor: tw.zinc[200],
+ color: tw.zinc[500],
+
+ "& > .MuiLoadingButton-loadingIndicator": {
+ color: tw.zinc[500],
+ },
+ },
+ },
+ contained: {
+ boxShadow: "0 1px 4px #0001",
+ "&.Mui-disabled": {
+ boxShadow: "none !important",
+ },
+ ":hover": {
+ boxShadow: "0 1px 4px #0001",
+ },
+ },
+ containedNeutral: {
+ backgroundColor: tw.zinc[100],
+ border: `1px solid ${tw.zinc[200]}`,
+
+ "&.Mui-disabled": {
+ backgroundColor: tw.zinc[50],
+ border: `1px solid ${tw.zinc[100]}`,
+ },
+
+ "&:hover": {
+ backgroundColor: tw.zinc[200],
+ border: `1px solid ${tw.zinc[300]}`,
+ },
+ },
+ iconSizeMedium: {
+ "& > .MuiSvgIcon-root": {
+ fontSize: 14,
+ },
+ },
+ iconSizeSmall: {
+ "& > .MuiSvgIcon-root": {
+ fontSize: 13,
+ },
+ },
+ startIcon: {
+ marginLeft: "-2px",
+ },
+ },
+ },
+ MuiButtonGroup: {
+ styleOverrides: {
+ root: {
+ ">button:hover+button": {
+ // The !important is unfortunate, but necessary for the border.
+ borderLeftColor: `${tw.zinc[300]} !important`,
+ },
+ },
+ },
+ },
+ MuiLoadingButton: {
+ defaultProps: {
+ variant: "outlined",
+ color: "neutral",
+ },
+ },
+ MuiTableContainer: {
+ styleOverrides: {
+ root: {
+ borderRadius,
+ border: `1px solid ${muiTheme.palette.divider}`,
+ },
+ },
+ },
+ MuiTable: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ borderCollapse: "unset",
+ border: "none",
+ boxShadow: `0 0 0 1px ${muiTheme.palette.background.default} inset`,
+ overflow: "hidden",
+
+ "& td": {
+ paddingTop: 16,
+ paddingBottom: 16,
+ background: "transparent",
+ },
+
+ [theme.breakpoints.down("md")]: {
+ minWidth: 1000,
+ },
+ }),
+ },
+ },
+ MuiTableCell: {
+ styleOverrides: {
+ head: {
+ fontSize: 14,
+ color: muiTheme.palette.text.secondary,
+ fontWeight: 600,
+ background: muiTheme.palette.background.paper,
+ },
+ root: {
+ fontSize: 16,
+ background: muiTheme.palette.background.paper,
+ borderBottom: `1px solid ${muiTheme.palette.divider}`,
+ padding: "12px 8px",
+ // This targets the first+last td elements, and also the first+last elements
+ // of a TableCellLink.
+ "&:not(:only-child):first-of-type, &:not(:only-child):first-of-type > a":
+ {
+ paddingLeft: 32,
+ },
+ "&:not(:only-child):last-child, &:not(:only-child):last-child > a": {
+ paddingRight: 32,
+ },
+ },
+ },
+ },
+ MuiTableRow: {
+ styleOverrides: {
+ root: {
+ "&:last-child .MuiTableCell-body": {
+ borderBottom: 0,
+ },
+ },
+ },
+ },
+ MuiLink: {
+ defaultProps: {
+ underline: "hover",
+ },
+ },
+ MuiPaper: {
+ defaultProps: {
+ elevation: 0,
+ },
+ styleOverrides: {
+ root: {
+ border: `1px solid ${muiTheme.palette.divider}`,
+ backgroundImage: "none",
+ },
+ },
+ },
+ MuiSkeleton: {
+ styleOverrides: {
+ root: {
+ backgroundColor: muiTheme.palette.divider,
+ },
+ },
+ },
+ MuiLinearProgress: {
+ styleOverrides: {
+ root: {
+ borderRadius: 999,
+ },
+ },
+ },
+ MuiChip: {
+ styleOverrides: {
+ root: {
+ backgroundColor: tw.zinc[400],
+ },
+ },
+ },
+ MuiMenu: {
+ defaultProps: {
+ anchorOrigin: {
+ vertical: "bottom",
+ horizontal: "right",
+ },
+ transformOrigin: {
+ vertical: "top",
+ horizontal: "right",
+ },
+ },
+ styleOverrides: {
+ paper: {
+ marginTop: 8,
+ borderRadius: 4,
+ padding: "4px 0",
+ minWidth: 160,
+ },
+ root: {
+ // It should be the same as the menu padding
+ "& .MuiDivider-root": {
+ marginTop: `4px !important`,
+ marginBottom: `4px !important`,
+ },
+ },
+ },
+ },
+ MuiMenuItem: {
+ styleOverrides: {
+ root: {
+ gap: 12,
+
+ "& .MuiSvgIcon-root": {
+ fontSize: 20,
+ },
+ },
+ },
+ },
+ MuiSnackbar: {
+ styleOverrides: {
+ anchorOriginBottomRight: {
+ bottom: `${24 + 36}px !important`, // 36 is the bottom bar height
+ },
+ },
+ },
+ MuiSnackbarContent: {
+ styleOverrides: {
+ root: {
+ borderRadius: "4px !important",
+ },
+ },
+ },
+ MuiTextField: {
+ defaultProps: {
+ InputLabelProps: {
+ shrink: true,
+ },
+ },
+ },
+ MuiInputBase: {
+ defaultProps: {
+ color: "primary",
+ },
+ styleOverrides: {
+ root: {
+ height: BUTTON_LG_HEIGHT,
+ },
+ sizeSmall: {
+ height: BUTTON_MD_HEIGHT,
+ fontSize: 14,
+ },
+ multiline: {
+ height: "auto",
+ },
+ colorPrimary: {
+ // Same as button
+ "& .MuiOutlinedInput-notchedOutline": {
+ borderColor: tw.zinc[300],
+ },
+ // The default outlined input color is white, which seemed jarring.
+ "&:hover:not(.Mui-error):not(.Mui-focused) .MuiOutlinedInput-notchedOutline":
+ {
+ borderColor: tw.zinc[500],
+ },
+ },
+ },
+ },
+ MuiFormHelperText: {
+ defaultProps: {
+ sx: {
+ marginLeft: 0,
+ marginTop: 1,
+ },
+ },
+ },
+ MuiRadio: {
+ defaultProps: {
+ disableRipple: true,
+ },
+ },
+ MuiCheckbox: {
+ styleOverrides: {
+ root: {
+ /**
+ * Adds focus styling to checkboxes (which doesn't exist normally, for
+ * some reason?).
+ *
+ * The checkbox component is a root span with a checkbox input inside
+ * it. MUI does not allow you to use selectors like (& input) to
+ * target the inner checkbox (even though you can use & td to style
+ * tables). Tried every combination of selector possible (including
+ * lots of !important), and the main issue seems to be that the
+ * styling just never gets processed for it to get injected into the
+ * CSSOM.
+ *
+ * Had to settle for adding styling to the span itself (which does
+ * make the styling more obvious, even if there's not much room for
+ * customization).
+ */
+ "&.Mui-focusVisible": {
+ boxShadow: `0 0 0 2px ${tw.blue[600]}`,
+ },
+
+ "&.Mui-disabled": {
+ color: tw.zinc[500],
+ },
+ },
+ },
+ },
+ MuiSwitch: {
+ defaultProps: { color: "primary" },
+ styleOverrides: {
+ root: {
+ ".Mui-focusVisible .MuiSwitch-thumb": {
+ // Had to thicken outline to make sure that the focus color didn't
+ // bleed into the thumb and was still easily-visible
+ boxShadow: `0 0 0 3px ${tw.blue[600]}`,
+ },
+ },
+ },
+ },
+ MuiAutocomplete: {
+ styleOverrides: {
+ root: {
+ // Not sure why but since the input has padding we don't need it here
+ "& .MuiInputBase-root": {
+ padding: 0,
+ },
+ },
+ },
+ },
+ MuiList: {
+ defaultProps: {
+ disablePadding: true,
+ },
+ },
+ MuiTabs: {
+ defaultProps: {
+ textColor: "primary",
+ indicatorColor: "primary",
+ },
+ },
+ MuiTooltip: {
+ styleOverrides: {
+ tooltip: {
+ lineHeight: "150%",
+ borderRadius: 4,
+ background: muiTheme.palette.background.paper,
+ color: muiTheme.palette.secondary.contrastText,
+ border: `1px solid ${muiTheme.palette.divider}`,
+ padding: "8px 16px",
+ boxShadow: "0 1px 4px #0001",
+ },
+ },
+ },
+ MuiAlert: {
+ defaultProps: {
+ variant: "outlined",
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ background: theme.palette.background.paper,
+ }),
+ action: {
+ paddingTop: 2, // Idk why it is not aligned as expected
+ },
+ icon: {
+ fontSize: 16,
+ marginTop: "4px", // The size of text is 24 so (24 - 16)/2 = 4
+ },
+ message: ({ theme }) => ({
+ color: theme.palette.text.primary,
+ }),
+ outlinedWarning: {
+ [`& .${alertClasses.icon}`]: {
+ color: muiTheme.palette.warning.light,
+ },
+ },
+ outlinedInfo: {
+ [`& .${alertClasses.icon}`]: {
+ color: muiTheme.palette.primary.light,
+ },
+ },
+ outlinedError: {
+ [`& .${alertClasses.icon}`]: {
+ color: muiTheme.palette.error.light,
+ },
+ },
+ },
+ },
+ MuiAlertTitle: {
+ styleOverrides: {
+ root: {
+ fontSize: "inherit",
+ marginBottom: 0,
+ },
+ },
+ },
+
+ MuiIconButton: {
+ styleOverrides: {
+ root: {
+ "&.Mui-focusVisible": {
+ boxShadow: `0 0 0 2px ${tw.blue[600]}`,
+ },
+ },
+ },
+ },
+ },
+} as ThemeOptions);
+
+export default muiTheme;
diff --git a/site/src/utils/latency.ts b/site/src/utils/latency.ts
index 0a7f45d551cf3..4281fa17e990f 100644
--- a/site/src/utils/latency.ts
+++ b/site/src/utils/latency.ts
@@ -1,16 +1,16 @@
-import { Theme } from "@mui/material/styles";
+import type { Theme } from "@emotion/react";
export const getLatencyColor = (theme: Theme, latency?: number) => {
if (!latency) {
return theme.palette.text.secondary;
}
- let color = theme.palette.success.light;
+ let color = theme.experimental.roles.success.fill;
if (latency >= 150 && latency < 300) {
- color = theme.palette.warning.light;
+ color = theme.experimental.roles.warning.fill;
} else if (latency >= 300) {
- color = theme.palette.error.light;
+ color = theme.experimental.roles.error.fill;
}
return color;
};
diff --git a/site/src/utils/workspace.tsx b/site/src/utils/workspace.tsx
index 048af1cab10ab..3f823b659f686 100644
--- a/site/src/utils/workspace.tsx
+++ b/site/src/utils/workspace.tsx
@@ -1,15 +1,16 @@
-import { Theme } from "@mui/material/styles";
-import dayjs from "dayjs";
-import duration from "dayjs/plugin/duration";
-import minMax from "dayjs/plugin/minMax";
-import utc from "dayjs/plugin/utc";
-import semver from "semver";
-import * as TypesGen from "api/typesGenerated";
import CircularProgress from "@mui/material/CircularProgress";
import ErrorIcon from "@mui/icons-material/ErrorOutline";
import StopIcon from "@mui/icons-material/StopOutlined";
import PlayIcon from "@mui/icons-material/PlayArrowOutlined";
import QueuedIcon from "@mui/icons-material/HourglassEmpty";
+import dayjs from "dayjs";
+import duration from "dayjs/plugin/duration";
+import minMax from "dayjs/plugin/minMax";
+import utc from "dayjs/plugin/utc";
+import { type Theme } from "@emotion/react";
+import { type FC } from "react";
+import semver from "semver";
+import type * as TypesGen from "api/typesGenerated";
dayjs.extend(duration);
dayjs.extend(utc);
@@ -28,6 +29,15 @@ const DisplayAgentVersionLanguage = {
unknown: "Unknown",
};
+const LoadingIcon: FC = () => {
+ return (
+ ({ color: theme.experimental.l1.text })}
+ />
+ );
+};
+
export const getDisplayWorkspaceBuildStatus = (
theme: Theme,
build: TypesGen.WorkspaceBuild,
@@ -249,10 +259,6 @@ const getPendingWorkspaceStatusText = (
return "Position in queue: " + provisionerJob.queue_position;
};
-const LoadingIcon = () => {
- return ;
-};
-
export const hasJobError = (workspace: TypesGen.Workspace) => {
return workspace.latest_build.job.error !== undefined;
};