with Tailwind shadow/border classes instead.",
- "@mui/material/Popover": "Use components/Popover/Popover instead.",
- // "@mui/material/Radio": "Use shadcn/ui RadioGroup instead.",
- // "@mui/material/RadioGroup": "Use shadcn/ui RadioGroup instead.",
- // "@mui/material/Select": "Use shadcn/ui Select component instead.",
- "@mui/material/Skeleton": "Use shadcn/ui Skeleton component instead.",
- // "@mui/material/Snackbar": "Use components/GlobalSnackbar instead.",
- // "@mui/material/Stack": "Use Tailwind flex utilities instead (e.g.,
).",
- // "@mui/material/styles": "Use Tailwind CSS instead.",
- "@mui/material/SvgIcon": "Use lucide-react icons instead.",
- "@mui/material/Switch": "Use shadcn/ui Switch component instead.",
- "@mui/material/Table": "Import from components/Table/Table instead.",
- "@mui/material/TableRow": "Import from components/Table/Table instead.",
- // "@mui/material/TextField": "Use shadcn/ui Input component instead.",
- // "@mui/material/ToggleButton": "Use shadcn/ui Toggle or custom component instead.",
- // "@mui/material/ToggleButtonGroup": "Use shadcn/ui Toggle or custom component instead.",
- "@mui/material/Tooltip": "Use components/Tooltip/Tooltip instead.",
- "@mui/material/Typography": "Use native HTML elements instead. Eg:
, ,
, etc.",
- "@mui/material/useMediaQuery": "Use Tailwind responsive classes or custom hook instead.",
- // "@mui/system": "Use Tailwind CSS instead.",
- "@mui/utils": "Use native alternatives or utility libraries instead.",
- // "@emotion/css": "Use Tailwind CSS instead.",
- // "@emotion/react": "Use Tailwind CSS instead.",
- "@emotion/styled": "Use Tailwind CSS instead.",
- // "@emotion/cache": "Use Tailwind CSS instead.",
// "#/components/Stack/Stack": "Use Tailwind flex utilities instead (e.g., ).",
"lodash": "Use lodash/
instead."
}
diff --git a/docs/about/contributing/frontend.md b/docs/about/contributing/frontend.md
index 731055af5c9..07a3056c14f 100644
--- a/docs/about/contributing/frontend.md
+++ b/docs/about/contributing/frontend.md
@@ -182,14 +182,6 @@ Components should be atomic, reusable and free of business logic. Modules are
similar to components except that they can be more complex and can contain
business logic specific to the product.
-### MUI
-
-The codebase is currently using MUI v5. Please see the
-[official documentation](https://mui.com/material-ui/getting-started/). In
-general, favor building a custom component via MUI instead of plain React/HTML,
-as MUI's suite of components is thoroughly battle-tested and accessible right
-out of the box.
-
### Structure
Each component and module gets its own folder. Module folders may group multiple
@@ -246,7 +238,10 @@ new conventions, but all new components should follow these guidelines.
## Styling
-We use [Emotion](https://emotion.sh/) to handle CSS styles.
+We use [Tailwind CSS](https://tailwindcss.com/) to handle CSS styles. Reusable UI
+primitives come from [shadcn/ui](https://ui.shadcn.com/) components in
+`site/src/components`. Use the `cn` helper from `#/utils/cn` to compose and
+conditionally apply classes.
## Forms
diff --git a/site/.storybook/preview.tsx b/site/.storybook/preview.tsx
index 5d554465f08..a3873be2f85 100644
--- a/site/.storybook/preview.tsx
+++ b/site/.storybook/preview.tsx
@@ -1,11 +1,5 @@
import "../src/index.css";
import "../src/theme/globalFonts";
-import { ThemeProvider as EmotionThemeProvider } from "@emotion/react";
-import CssBaseline from "@mui/material/CssBaseline";
-import {
- ThemeProvider as MuiThemeProvider,
- StyledEngineProvider,
-} from "@mui/material/styles";
import { DecoratorHelpers } from "@storybook/addon-themes";
import type { Decorator, Parameters } from "@storybook/react-vite";
import { StrictMode } from "react";
@@ -14,6 +8,7 @@ import { withRouter } from "storybook-addon-remix-react-router";
import { TooltipProvider } from "../src/components/Tooltip/Tooltip";
import themes, { baseModeFor, isConcreteThemeName } from "../src/theme";
import { AppearanceProvider } from "../src/theme/appearance";
+import { ThemeContextProvider } from "../src/theme/context";
DecoratorHelpers.initializeThemeState(Object.keys(themes), "dark");
@@ -112,20 +107,15 @@ const withTheme: Decorator = (Story, context) => {
return (
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
);
};
diff --git a/site/AGENTS.md b/site/AGENTS.md
index 915674b3c20..6640567b485 100644
--- a/site/AGENTS.md
+++ b/site/AGENTS.md
@@ -80,7 +80,6 @@ Debug logs and pprof dumps use the same job name and commit SHA convention.
## Components
-- MUI components are deprecated - migrate away from these when encountered
- Use shadcn/ui components first - check `site/src/components` for existing implementations.
- Do not use shadcn CLI - manually add components to maintain consistency
- The modules folder should contain components with business logic specific to the codebase.
@@ -103,9 +102,8 @@ Debug logs and pprof dumps use the same job name and commit SHA convention.
## Styling
-- Emotion CSS is deprecated. Use Tailwind CSS instead.
+- Use Tailwind CSS for styling.
- Use custom Tailwind classes in tailwind.config.js.
-- Tailwind CSS reset is currently not used to maintain compatibility with MUI
- Responsive design - use Tailwind's responsive prefixes (sm:, md:, lg:, xl:)
- Do not use `dark:` prefix for dark mode
@@ -279,23 +277,6 @@ Debug logs and pprof dumps use the same job name and commit SHA convention.
audit the diff against FE1 to FE10 and fix every FAIL before creating
the PR
-## Migration (MUI → shadcn) (Emotion → Tailwind)
-
-### Migration Strategy
-
-- Identify MUI components in current feature
-- Find shadcn equivalent in existing components
-- Create wrapper if needed for missing functionality
-- Update tests to reflect new component structure
-- Remove MUI imports once migration complete
-
-### Migration Guidelines
-
-- Use Tailwind classes for all new styling
-- Replace Emotion `css` prop with Tailwind classes
-- Leverage custom color tokens: `content-primary`, `surface-secondary`, etc.
-- Use `className` with `clsx` for conditional styling
-
## React Rules
### 1. Purity & Immutability
diff --git a/site/package.json b/site/package.json
index 7c256e374cd..f2c88be0c87 100644
--- a/site/package.json
+++ b/site/package.json
@@ -42,9 +42,6 @@
"@dnd-kit/utilities": "3.2.2",
"@emoji-mart/data": "1.2.1",
"@emoji-mart/react": "1.1.1",
- "@emotion/cache": "11.14.0",
- "@emotion/react": "11.14.0",
- "@emotion/styled": "11.14.1",
"@fontsource-variable/geist": "5.3.0",
"@fontsource-variable/geist-mono": "5.2.7",
"@fontsource/fira-code": "5.2.7",
@@ -54,7 +51,6 @@
"@lexical/react": "0.44.0",
"@lexical/utils": "0.48.0",
"@monaco-editor/react": "4.7.0",
- "@mui/material": "5.18.0",
"@novnc/novnc": "^1.5.0",
"@pierre/diffs": "1.3.3",
"@pierre/trees": "1.0.0-beta.4",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 36e1eb8bcb8..10f6177fca8 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -47,15 +47,6 @@ importers:
'@emoji-mart/react':
specifier: 1.1.1
version: 1.1.1(emoji-mart@5.6.0)(react@19.2.8)
- '@emotion/cache':
- specifier: 11.14.0
- version: 11.14.0
- '@emotion/react':
- specifier: 11.14.0
- version: 11.14.0(@types/react@19.2.18)(react@19.2.8)
- '@emotion/styled':
- specifier: 11.14.1
- version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)
'@fontsource-variable/geist':
specifier: 5.3.0
version: 5.3.0
@@ -83,9 +74,6 @@ importers:
'@monaco-editor/react':
specifier: 4.7.0
version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
- '@mui/material':
- specifier: 5.18.0
- version: 5.18.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
'@novnc/novnc':
specifier: ^1.5.0
version: 1.5.0
@@ -509,10 +497,6 @@ packages:
resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==, tarball: https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz}
engines: {node: '>=6.9.0'}
- '@babel/helper-module-imports@7.27.1':
- resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==, tarball: https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-module-imports@7.29.7':
resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==, tarball: https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz}
engines: {node: '>=6.9.0'}
@@ -752,60 +736,12 @@ packages:
emoji-mart: ^5.2
react: ^16.8 || ^17 || ^18
- '@emotion/babel-plugin@11.13.5':
- resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==, tarball: https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz}
-
- '@emotion/cache@11.14.0':
- resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==, tarball: https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz}
-
- '@emotion/hash@0.9.2':
- resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==, tarball: https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz}
-
'@emotion/is-prop-valid@1.4.0':
resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==, tarball: https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz}
'@emotion/memoize@0.9.0':
resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==, tarball: https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz}
- '@emotion/react@11.14.0':
- resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==, tarball: https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz}
- peerDependencies:
- '@types/react': '*'
- react: '>=16.8.0'
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@emotion/serialize@1.3.3':
- resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==, tarball: https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz}
-
- '@emotion/sheet@1.4.0':
- resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==, tarball: https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz}
-
- '@emotion/styled@11.14.1':
- resolution: {integrity: sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==, tarball: https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz}
- peerDependencies:
- '@emotion/react': ^11.0.0-rc.0
- '@types/react': '*'
- react: '>=16.8.0'
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@emotion/unitless@0.10.0':
- resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==, tarball: https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz}
-
- '@emotion/use-insertion-effect-with-fallbacks@1.2.0':
- resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==, tarball: https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz}
- peerDependencies:
- react: '>=16.8.0'
-
- '@emotion/utils@1.4.2':
- resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==, tarball: https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz}
-
- '@emotion/weak-memoize@0.4.0':
- resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==, tarball: https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz}
-
'@esbuild/aix-ppc64@0.25.12':
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==, tarball: https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz}
engines: {node: '>=18'}
@@ -1199,83 +1135,6 @@ packages:
resolution: {integrity: sha512-SSnyl/4ni/2ViHKkiZb8eajA/eN1DNFaHjhGiLUdZvDz6PKF4COSf/17xqSz64nOo2Ia29SA6B2KNCsyCbVmaQ==, tarball: https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.35.9.tgz}
engines: {node: '>=18'}
- '@mui/core-downloads-tracker@5.18.0':
- resolution: {integrity: sha512-jbhwoQ1AY200PSSOrNXmrFCaSDSJWP7qk6urkTmIirvRXDROkqe+QwcLlUiw/PrREwsIF/vm3/dAXvjlMHF0RA==, tarball: https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.18.0.tgz}
-
- '@mui/material@5.18.0':
- resolution: {integrity: sha512-bbH/HaJZpFtXGvWg3TsBWG4eyt3gah3E7nCNU8GLyRjVoWcA91Vm/T+sjHfUcwgJSw9iLtucfHBoq+qW/T30aA==, tarball: https://registry.npmjs.org/@mui/material/-/material-5.18.0.tgz}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@emotion/react': ^11.5.0
- '@emotion/styled': ^11.3.0
- '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
- react: ^17.0.0 || ^18.0.0 || ^19.0.0
- react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- '@emotion/react':
- optional: true
- '@emotion/styled':
- optional: true
- '@types/react':
- optional: true
-
- '@mui/private-theming@5.17.1':
- resolution: {integrity: sha512-XMxU0NTYcKqdsG8LRmSoxERPXwMbp16sIXPcLVgLGII/bVNagX0xaheWAwFv8+zDK7tI3ajllkuD3GZZE++ICQ==, tarball: https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.17.1.tgz}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
- react: ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@mui/styled-engine@5.18.0':
- resolution: {integrity: sha512-BN/vKV/O6uaQh2z5rXV+MBlVrEkwoS/TK75rFQ2mjxA7+NBo8qtTAOA4UaM0XeJfn7kh2wZ+xQw2HAx0u+TiBg==, tarball: https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.18.0.tgz}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@emotion/react': ^11.4.1
- '@emotion/styled': ^11.3.0
- react: ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- '@emotion/react':
- optional: true
- '@emotion/styled':
- optional: true
-
- '@mui/system@5.18.0':
- resolution: {integrity: sha512-ojZGVcRWqWhu557cdO3pWHloIGJdzVtxs3rk0F9L+x55LsUjcMUVkEhiF7E4TMxZoF9MmIHGGs0ZX3FDLAf0Xw==, tarball: https://registry.npmjs.org/@mui/system/-/system-5.18.0.tgz}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@emotion/react': ^11.5.0
- '@emotion/styled': ^11.3.0
- '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
- react: ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- '@emotion/react':
- optional: true
- '@emotion/styled':
- optional: true
- '@types/react':
- optional: true
-
- '@mui/types@7.2.24':
- resolution: {integrity: sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==, tarball: https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz}
- peerDependencies:
- '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@mui/utils@5.17.1':
- resolution: {integrity: sha512-jEZ8FTqInt2WzxDV8bhImWBqeQRD99c/id/fq83H0ER9tFl+sfZlaAoCdznGvbSQQ9ividMxqSV2c7cC1vBcQg==, tarball: https://registry.npmjs.org/@mui/utils/-/utils-5.17.1.tgz}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
- react: ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
'@napi-rs/wasm-runtime@1.0.7':
resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==, tarball: https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz}
@@ -1463,9 +1322,6 @@ packages:
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==, tarball: https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz}
- '@popperjs/core@2.11.8':
- resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==, tarball: https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz}
-
'@preact/signals-core@1.14.2':
resolution: {integrity: sha512-RZHdBj9ZF4n40Rp4jS052EHHjBWf96P9oNdXPfhQTovCuWY9iQn3Gq+gOTJSgBO9A/JBuPfMOWsSX/lIU9Pc/A==, tarball: https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.14.2.tgz}
@@ -2765,12 +2621,6 @@ packages:
'@types/novnc__novnc@1.5.0':
resolution: {integrity: sha512-9DrDJK1hUT6Cbp4t03IsU/DsR6ndnIrDgZVrzITvspldHQ7n81F3wUDfq89zmPM3wg4GErH11IQa0QuTgLMf+w==, tarball: https://registry.npmjs.org/@types/novnc__novnc/-/novnc__novnc-1.5.0.tgz}
- '@types/parse-json@4.0.2':
- resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==, tarball: https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz}
-
- '@types/prop-types@15.7.15':
- resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==, tarball: https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz}
-
'@types/qs@6.9.7':
resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==, tarball: https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz}
@@ -2795,11 +2645,6 @@ packages:
'@types/react-syntax-highlighter@15.5.13':
resolution: {integrity: sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==, tarball: https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz}
- '@types/react-transition-group@4.4.12':
- resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==, tarball: https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz}
- peerDependencies:
- '@types/react': '*'
-
'@types/react-virtualized-auto-sizer@1.0.8':
resolution: {integrity: sha512-keJpNyhiwfl2+N12G1ocCVA5ZDBArbPLe/S90X3kt7fam9naeHdaYYWbpe2sHczp70JWJ+2QLhBE8kLvLuVNjA==, tarball: https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.8.tgz}
deprecated: This is a stub types definition. react-virtualized-auto-sizer provides its own type definitions, so you do not need this installed.
@@ -3057,10 +2902,6 @@ packages:
axios@1.18.1:
resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==, tarball: https://registry.npmjs.org/axios/-/axios-1.18.1.tgz}
- babel-plugin-macros@3.1.0:
- resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==, tarball: https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz}
- engines: {node: '>=10', npm: '>=6'}
-
babel-plugin-react-compiler@1.0.0:
resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==, tarball: https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz}
@@ -3142,10 +2983,6 @@ packages:
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==, tarball: https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz}
engines: {node: '>= 0.4'}
- callsites@3.1.0:
- resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, tarball: https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz}
- engines: {node: '>=6'}
-
camelcase-css@2.0.1:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==, tarball: https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz}
engines: {node: '>= 6'}
@@ -3303,9 +3140,6 @@ packages:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==, tarball: https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz}
engines: {node: '>= 0.6'}
- convert-source-map@1.9.0:
- resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==, tarball: https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz}
-
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, tarball: https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz}
@@ -3329,10 +3163,6 @@ packages:
cose-base@2.2.0:
resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==, tarball: https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz}
- cosmiconfig@7.1.0:
- resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==, tarball: https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz}
- engines: {node: '>=10'}
-
cpu-features@0.0.10:
resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==, tarball: https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz}
engines: {node: '>=10.0.0'}
@@ -3369,9 +3199,6 @@ packages:
resolution: {integrity: sha512-OytmFH+13/QXONJcC75QNdMtKpceNk3u8ThBjyyYjkEcy/ekBwR1mMAuNvi3gdBPW3N5TlCzQ0WZw8H0lN/bDw==, tarball: https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.3.tgz}
engines: {node: '>=20'}
- csstype@3.1.3:
- resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==, tarball: https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz}
-
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==, tarball: https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz}
@@ -3727,9 +3554,6 @@ packages:
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==, tarball: https://registry.npmjs.org/entities/-/entities-6.0.1.tgz}
engines: {node: '>=0.12'}
- error-ex@1.3.2:
- resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, tarball: https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz}
-
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, tarball: https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz}
engines: {node: '>= 0.4'}
@@ -3764,10 +3588,6 @@ packages:
escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, tarball: https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz}
- escape-string-regexp@4.0.0:
- resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, tarball: https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz}
- engines: {node: '>=10'}
-
escape-string-regexp@5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==, tarball: https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz}
engines: {node: '>=12'}
@@ -3854,9 +3674,6 @@ packages:
resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==, tarball: https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz}
engines: {node: '>= 0.8'}
- find-root@1.1.0:
- resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==, tarball: https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz}
-
follow-redirects@1.16.0:
resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==, tarball: https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz}
engines: {node: '>=4.0'}
@@ -4107,10 +3924,6 @@ packages:
immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==, tarball: https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz}
- import-fresh@3.3.1:
- resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, tarball: https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz}
- engines: {node: '>=6'}
-
indent-string@4.0.0:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, tarball: https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz}
engines: {node: '>=8'}
@@ -4155,9 +3968,6 @@ packages:
is-array-buffer@3.0.2:
resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==, tarball: https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz}
- is-arrayish@0.2.1:
- resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, tarball: https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz}
-
is-bigint@1.0.4:
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==, tarball: https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz}
@@ -4342,9 +4152,6 @@ packages:
engines: {node: '>=6'}
hasBin: true
- json-parse-even-better-errors@2.3.1:
- resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, tarball: https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz}
-
json-rpc-2.0@1.7.1:
resolution: {integrity: sha512-JqZjhjAanbpkXIzFE7u8mE/iFblawwlXtONaCvRqI+pyABVz7B4M1EUNpyVW+dZjqgQ2L5HFmZCmOCgUKm00hg==, tarball: https://registry.npmjs.org/json-rpc-2.0/-/json-rpc-2.0-1.7.1.tgz}
@@ -4929,20 +4736,12 @@ packages:
pako@1.0.11:
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==, tarball: https://registry.npmjs.org/pako/-/pako-1.0.11.tgz}
- parent-module@1.0.1:
- resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, tarball: https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz}
- engines: {node: '>=6'}
-
parse-entities@2.0.0:
resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==, tarball: https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz}
parse-entities@4.0.2:
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==, tarball: https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz}
- parse-json@5.2.0:
- resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, tarball: https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz}
- engines: {node: '>=8'}
-
parse5@7.3.0:
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==, tarball: https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz}
@@ -4983,10 +4782,6 @@ packages:
path-to-regexp@6.3.0:
resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==, tarball: https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz}
- path-type@4.0.0:
- resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, tarball: https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz}
- engines: {node: '>=8'}
-
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==, tarball: https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz}
@@ -5259,9 +5054,6 @@ packages:
react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==, tarball: https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz}
- react-is@19.1.1:
- resolution: {integrity: sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==, tarball: https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz}
-
react-markdown@9.1.0:
resolution: {integrity: sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw==, tarball: https://registry.npmjs.org/react-markdown/-/react-markdown-9.1.0.tgz}
peerDependencies:
@@ -5453,10 +5245,6 @@ packages:
resize-observer-polyfill@1.5.1:
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==, tarball: https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz}
- resolve-from@4.0.0:
- resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, tarball: https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz}
- engines: {node: '>=4'}
-
resolve@1.22.11:
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==, tarball: https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz}
engines: {node: '>= 0.4'}
@@ -5621,10 +5409,6 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, tarball: https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz}
engines: {node: '>=0.10.0'}
- source-map@0.5.7:
- resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==, tarball: https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz}
- engines: {node: '>=0.10.0'}
-
source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, tarball: https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz}
engines: {node: '>=0.10.0'}
@@ -5748,9 +5532,6 @@ packages:
style-to-object@1.0.9:
resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==, tarball: https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz}
- stylis@4.2.0:
- resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==, tarball: https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz}
-
stylis@4.3.6:
resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==, tarball: https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz}
@@ -6496,13 +6277,6 @@ snapshots:
'@babel/helper-globals@7.29.7': {}
- '@babel/helper-module-imports@7.27.1':
- dependencies:
- '@babel/traverse': 7.29.7
- '@babel/types': 7.29.7
- transitivePeerDependencies:
- - supports-color
-
'@babel/helper-module-imports@7.29.7':
dependencies:
'@babel/traverse': 7.29.7
@@ -6727,88 +6501,13 @@ snapshots:
emoji-mart: 5.6.0
react: 19.2.8
- '@emotion/babel-plugin@11.13.5':
- dependencies:
- '@babel/helper-module-imports': 7.27.1
- '@babel/runtime': 7.26.10
- '@emotion/hash': 0.9.2
- '@emotion/memoize': 0.9.0
- '@emotion/serialize': 1.3.3
- babel-plugin-macros: 3.1.0
- convert-source-map: 1.9.0
- escape-string-regexp: 4.0.0
- find-root: 1.1.0
- source-map: 0.5.7
- stylis: 4.2.0
- transitivePeerDependencies:
- - supports-color
-
- '@emotion/cache@11.14.0':
- dependencies:
- '@emotion/memoize': 0.9.0
- '@emotion/sheet': 1.4.0
- '@emotion/utils': 1.4.2
- '@emotion/weak-memoize': 0.4.0
- stylis: 4.2.0
-
- '@emotion/hash@0.9.2': {}
-
'@emotion/is-prop-valid@1.4.0':
dependencies:
'@emotion/memoize': 0.9.0
+ optional: true
- '@emotion/memoize@0.9.0': {}
-
- '@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8)':
- dependencies:
- '@babel/runtime': 7.26.10
- '@emotion/babel-plugin': 11.13.5
- '@emotion/cache': 11.14.0
- '@emotion/serialize': 1.3.3
- '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.8)
- '@emotion/utils': 1.4.2
- '@emotion/weak-memoize': 0.4.0
- hoist-non-react-statics: 3.3.2
- react: 19.2.8
- optionalDependencies:
- '@types/react': 19.2.18
- transitivePeerDependencies:
- - supports-color
-
- '@emotion/serialize@1.3.3':
- dependencies:
- '@emotion/hash': 0.9.2
- '@emotion/memoize': 0.9.0
- '@emotion/unitless': 0.10.0
- '@emotion/utils': 1.4.2
- csstype: 3.2.3
-
- '@emotion/sheet@1.4.0': {}
-
- '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)':
- dependencies:
- '@babel/runtime': 7.26.10
- '@emotion/babel-plugin': 11.13.5
- '@emotion/is-prop-valid': 1.4.0
- '@emotion/react': 11.14.0(@types/react@19.2.18)(react@19.2.8)
- '@emotion/serialize': 1.3.3
- '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.8)
- '@emotion/utils': 1.4.2
- react: 19.2.8
- optionalDependencies:
- '@types/react': 19.2.18
- transitivePeerDependencies:
- - supports-color
-
- '@emotion/unitless@0.10.0': {}
-
- '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.8)':
- dependencies:
- react: 19.2.8
-
- '@emotion/utils@1.4.2': {}
-
- '@emotion/weak-memoize@0.4.0': {}
+ '@emotion/memoize@0.9.0':
+ optional: true
'@esbuild/aix-ppc64@0.25.12':
optional: true
@@ -7223,82 +6922,6 @@ snapshots:
outvariant: 1.4.3
strict-event-emitter: 0.5.1
- '@mui/core-downloads-tracker@5.18.0': {}
-
- '@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)':
- dependencies:
- '@babel/runtime': 7.26.10
- '@mui/core-downloads-tracker': 5.18.0
- '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)
- '@mui/types': 7.2.24(@types/react@19.2.18)
- '@mui/utils': 5.17.1(@types/react@19.2.18)(react@19.2.8)
- '@popperjs/core': 2.11.8
- '@types/react-transition-group': 4.4.12(@types/react@19.2.18)
- clsx: 2.1.1
- csstype: 3.1.3
- prop-types: 15.8.1
- react: 19.2.8
- react-dom: 19.2.8(react@19.2.8)
- react-is: 19.1.1
- react-transition-group: 4.4.5(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
- optionalDependencies:
- '@emotion/react': 11.14.0(@types/react@19.2.18)(react@19.2.8)
- '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)
- '@types/react': 19.2.18
-
- '@mui/private-theming@5.17.1(@types/react@19.2.18)(react@19.2.8)':
- dependencies:
- '@babel/runtime': 7.26.10
- '@mui/utils': 5.17.1(@types/react@19.2.18)(react@19.2.8)
- prop-types: 15.8.1
- react: 19.2.8
- optionalDependencies:
- '@types/react': 19.2.18
-
- '@mui/styled-engine@5.18.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)':
- dependencies:
- '@babel/runtime': 7.26.10
- '@emotion/cache': 11.14.0
- '@emotion/serialize': 1.3.3
- csstype: 3.1.3
- prop-types: 15.8.1
- react: 19.2.8
- optionalDependencies:
- '@emotion/react': 11.14.0(@types/react@19.2.18)(react@19.2.8)
- '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)
-
- '@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)':
- dependencies:
- '@babel/runtime': 7.26.10
- '@mui/private-theming': 5.17.1(@types/react@19.2.18)(react@19.2.8)
- '@mui/styled-engine': 5.18.0(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)
- '@mui/types': 7.2.24(@types/react@19.2.18)
- '@mui/utils': 5.17.1(@types/react@19.2.18)(react@19.2.8)
- clsx: 2.1.1
- csstype: 3.1.3
- prop-types: 15.8.1
- react: 19.2.8
- optionalDependencies:
- '@emotion/react': 11.14.0(@types/react@19.2.18)(react@19.2.8)
- '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.18)(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)
- '@types/react': 19.2.18
-
- '@mui/types@7.2.24(@types/react@19.2.18)':
- optionalDependencies:
- '@types/react': 19.2.18
-
- '@mui/utils@5.17.1(@types/react@19.2.18)(react@19.2.8)':
- dependencies:
- '@babel/runtime': 7.26.10
- '@mui/types': 7.2.24(@types/react@19.2.18)
- '@types/prop-types': 15.7.15
- clsx: 2.1.1
- prop-types: 15.8.1
- react: 19.2.8
- react-is: 19.1.1
- optionalDependencies:
- '@types/react': 19.2.18
-
'@napi-rs/wasm-runtime@1.0.7':
dependencies:
'@emnapi/core': 1.11.3
@@ -7436,8 +7059,6 @@ snapshots:
'@polka/url@1.0.0-next.29': {}
- '@popperjs/core@2.11.8': {}
-
'@preact/signals-core@1.14.2': {}
'@protobufjs/aspromise@1.1.2': {}
@@ -8810,10 +8431,6 @@ snapshots:
'@types/novnc__novnc@1.5.0': {}
- '@types/parse-json@4.0.2': {}
-
- '@types/prop-types@15.7.15': {}
-
'@types/qs@6.9.7': {}
'@types/range-parser@1.2.4': {}
@@ -8835,10 +8452,6 @@ snapshots:
dependencies:
'@types/react': 19.2.18
- '@types/react-transition-group@4.4.12(@types/react@19.2.18)':
- dependencies:
- '@types/react': 19.2.18
-
'@types/react-virtualized-auto-sizer@1.0.8(react-dom@19.2.8(react@19.2.8))(react@19.2.8)':
dependencies:
react-virtualized-auto-sizer: 1.0.26(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@@ -9122,12 +8735,6 @@ snapshots:
- debug
- supports-color
- babel-plugin-macros@3.1.0:
- dependencies:
- '@babel/runtime': 7.26.10
- cosmiconfig: 7.1.0
- resolve: 1.22.12
-
babel-plugin-react-compiler@1.0.0:
dependencies:
'@babel/types': 7.28.5
@@ -9231,8 +8838,6 @@ snapshots:
call-bind-apply-helpers: 1.0.2
get-intrinsic: 1.3.0
- callsites@3.1.0: {}
-
camelcase-css@2.0.1: {}
caniuse-lite@1.0.30001806: {}
@@ -9378,8 +8983,6 @@ snapshots:
content-type@1.0.5: {}
- convert-source-map@1.9.0: {}
-
convert-source-map@2.0.0: {}
cookie-signature@1.0.7: {}
@@ -9398,14 +9001,6 @@ snapshots:
dependencies:
layout-base: 2.0.1
- cosmiconfig@7.1.0:
- dependencies:
- '@types/parse-json': 4.0.2
- import-fresh: 3.3.1
- parse-json: 5.2.0
- path-type: 4.0.0
- yaml: 2.8.3
-
cpu-features@0.0.10:
dependencies:
buildcheck: 0.0.6
@@ -9441,8 +9036,6 @@ snapshots:
'@csstools/css-syntax-patches-for-csstree': 1.0.20
css-tree: 3.1.0
- csstype@3.1.3: {}
-
csstype@3.2.3: {}
cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1):
@@ -9760,7 +9353,7 @@ snapshots:
dom-helpers@5.2.1:
dependencies:
'@babel/runtime': 7.26.10
- csstype: 3.1.3
+ csstype: 3.2.3
dompurify@3.4.0:
optionalDependencies:
@@ -9806,10 +9399,6 @@ snapshots:
entities@6.0.1: {}
- error-ex@1.3.2:
- dependencies:
- is-arrayish: 0.2.1
-
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
@@ -9872,8 +9461,6 @@ snapshots:
escape-html@1.0.3: {}
- escape-string-regexp@4.0.0: {}
-
escape-string-regexp@5.0.0: {}
esm-env@1.2.2: {}
@@ -9985,8 +9572,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- find-root@1.1.0: {}
-
follow-redirects@1.16.0: {}
for-each@0.3.4:
@@ -10301,11 +9886,6 @@ snapshots:
immediate@3.0.6: {}
- import-fresh@3.3.1:
- dependencies:
- parent-module: 1.0.1
- resolve-from: 4.0.0
-
indent-string@4.0.0: {}
inherits@2.0.4: {}
@@ -10349,8 +9929,6 @@ snapshots:
get-intrinsic: 1.3.0
is-typed-array: 1.1.15
- is-arrayish@0.2.1: {}
-
is-bigint@1.0.4:
dependencies:
has-bigints: 1.0.2
@@ -10527,8 +10105,6 @@ snapshots:
jsesc@3.1.0: {}
- json-parse-even-better-errors@2.3.1: {}
-
json-rpc-2.0@1.7.1: {}
json5@2.2.3: {}
@@ -11320,10 +10896,6 @@ snapshots:
pako@1.0.11: {}
- parent-module@1.0.1:
- dependencies:
- callsites: 3.1.0
-
parse-entities@2.0.0:
dependencies:
character-entities: 1.2.4
@@ -11343,13 +10915,6 @@ snapshots:
is-decimal: 2.0.1
is-hexadecimal: 2.0.1
- parse-json@5.2.0:
- dependencies:
- '@babel/code-frame': 7.29.7
- error-ex: 1.3.2
- json-parse-even-better-errors: 2.3.1
- lines-and-columns: 1.2.4
-
parse5@7.3.0:
dependencies:
entities: 6.0.1
@@ -11381,8 +10946,6 @@ snapshots:
path-to-regexp@6.3.0: {}
- path-type@4.0.0: {}
-
pathe@2.0.3: {}
pathval@2.0.1: {}
@@ -11694,8 +11257,6 @@ snapshots:
react-is@18.3.1: {}
- react-is@19.1.1: {}
-
react-markdown@9.1.0(@types/react@19.2.18)(react@19.2.8):
dependencies:
'@types/hast': 3.0.4
@@ -11948,8 +11509,6 @@ snapshots:
resize-observer-polyfill@1.5.1: {}
- resolve-from@4.0.0: {}
-
resolve@1.22.11:
dependencies:
is-core-module: 2.16.1
@@ -12160,8 +11719,6 @@ snapshots:
source-map-js@1.2.1: {}
- source-map@0.5.7: {}
-
source-map@0.6.1: {}
source-map@0.7.4: {}
@@ -12310,8 +11867,6 @@ snapshots:
dependencies:
inline-style-parser: 0.2.4
- stylis@4.2.0: {}
-
stylis@4.3.6: {}
sucrase@3.35.1:
@@ -12862,7 +12417,8 @@ snapshots:
yallist@3.1.1: {}
- yaml@2.8.3: {}
+ yaml@2.8.3:
+ optional: true
yargs-parser@21.1.1: {}
diff --git a/site/src/@types/emotion.d.ts b/site/src/@types/emotion.d.ts
deleted file mode 100644
index 6724c41e408..00000000000
--- a/site/src/@types/emotion.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type { Theme as CoderTheme } from "#/theme";
-
-declare module "@emotion/react" {
- interface Theme extends CoderTheme {}
-}
diff --git a/site/src/@types/mui.d.ts b/site/src/@types/mui.d.ts
deleted file mode 100644
index 5128ae7b195..00000000000
--- a/site/src/@types/mui.d.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import type { PaletteColor, PaletteColorOptions } from "@mui/material/styles";
-
-declare module "@mui/material/styles" {
- interface Palette {
- neutral: PaletteColor;
- dots: string;
- }
-
- interface PaletteOptions {
- neutral?: PaletteColorOptions;
- dots?: string;
- }
-}
-
-declare module "@mui/material/Checkbox" {
- interface CheckboxPropsSizeOverrides {
- xsmall: true;
- }
-}
diff --git a/site/src/components/Command/Command.tsx b/site/src/components/Command/Command.tsx
index e59377acbde..45bd67572c8 100644
--- a/site/src/components/Command/Command.tsx
+++ b/site/src/components/Command/Command.tsx
@@ -40,10 +40,7 @@ export const CommandList: React.FC<
> = ({ className, ...props }) => {
return (
);
diff --git a/site/src/components/DropdownMenu/DropdownMenu.tsx b/site/src/components/DropdownMenu/DropdownMenu.tsx
index e740cbe5924..34cbad41b68 100644
--- a/site/src/components/DropdownMenu/DropdownMenu.tsx
+++ b/site/src/components/DropdownMenu/DropdownMenu.tsx
@@ -70,7 +70,7 @@ export const DropdownMenuRadioItem: React.FC<
{...props}
>
{children}
-
+
diff --git a/site/src/components/Slider/Slider.tsx b/site/src/components/Slider/Slider.tsx
index c2e4704e10c..9b810faed6e 100644
--- a/site/src/components/Slider/Slider.tsx
+++ b/site/src/components/Slider/Slider.tsx
@@ -7,31 +7,37 @@ import { cn } from "#/utils/cn";
export const Slider: React.FC<
React.ComponentPropsWithRef
-> = ({ className, ...props }) => {
+> = ({ className, defaultValue, value, min = 0, max = 100, ...props }) => {
+ const thumbCount = Array.isArray(value)
+ ? value.length
+ : Array.isArray(defaultValue)
+ ? defaultValue.length
+ : 1;
+
return (
-
-
+ />
+ ))}
);
};
diff --git a/site/src/components/Switch/Switch.tsx b/site/src/components/Switch/Switch.tsx
index 03c9eea16ac..3a4d63e70f8 100644
--- a/site/src/components/Switch/Switch.tsx
+++ b/site/src/components/Switch/Switch.tsx
@@ -29,13 +29,12 @@ const switchVariants = cva(
);
const thumbVariants = cva(
- "pointer-events-none block rounded-full bg-surface-primary shadow-lg ring-0 transition-transform",
+ "pointer-events-none block rounded-full bg-surface-primary shadow-lg ring-0 transition-transform data-[state=unchecked]:translate-x-0",
{
variants: {
size: {
- default:
- "size-4 data-[state=checked]:translate-x-2.5 data-[state=unchecked]:-translate-x-1.5",
- sm: "size-3 data-[state=checked]:translate-x-1.5 data-[state=unchecked]:-translate-x-1.5",
+ default: "size-4 data-[state=checked]:translate-x-4",
+ sm: "size-3 data-[state=checked]:translate-x-3",
},
},
defaultVariants: {
diff --git a/site/src/components/SyntaxHighlighter/SyntaxHighlighter.tsx b/site/src/components/SyntaxHighlighter/SyntaxHighlighter.tsx
index 68d9e140ce5..ed072a89e5a 100644
--- a/site/src/components/SyntaxHighlighter/SyntaxHighlighter.tsx
+++ b/site/src/components/SyntaxHighlighter/SyntaxHighlighter.tsx
@@ -1,8 +1,8 @@
-import { useTheme } from "@emotion/react";
import Editor, { DiffEditor, loader } from "@monaco-editor/react";
import type * as Monaco from "monaco-editor";
import * as monaco from "monaco-editor";
import { type ComponentProps, type FC, useCallback } from "react";
+import { useTheme } from "#/theme/context";
import { useCoderTheme } from "./coderTheme";
loader.config({ monaco });
diff --git a/site/src/components/SyntaxHighlighter/coderTheme.ts b/site/src/components/SyntaxHighlighter/coderTheme.ts
index 0150ff3f1ab..caecbf2fe6f 100644
--- a/site/src/components/SyntaxHighlighter/coderTheme.ts
+++ b/site/src/components/SyntaxHighlighter/coderTheme.ts
@@ -1,6 +1,7 @@
-import { useTheme } from "@emotion/react";
import { useMonaco } from "@monaco-editor/react";
import { useEffect, useState } from "react";
+import { useTheme } from "#/theme/context";
+
export const useCoderTheme = (): { isLoading: boolean; name: string } => {
const [isLoading, setIsLoading] = useState(true);
const monaco = useMonaco();
diff --git a/site/src/contexts/ThemeProvider.tsx b/site/src/contexts/ThemeProvider.tsx
index c50882a6fa5..b8f8e44aff9 100644
--- a/site/src/contexts/ThemeProvider.tsx
+++ b/site/src/contexts/ThemeProvider.tsx
@@ -1,16 +1,3 @@
-import createCache from "@emotion/cache";
-/** @deprecated Emotion is deprecated. Migrate to Tailwind CSS. */
-import {
- CacheProvider,
- ThemeProvider as EmotionThemeProvider,
-} from "@emotion/react";
-/** @deprecated MUI CssBaseline is deprecated. Migrate to shadcn/ui components and Tailwind CSS. */
-import CssBaseline from "@mui/material/CssBaseline";
-/** @deprecated MUI components are deprecated. Migrate to shadcn/ui components and Tailwind CSS. */
-import {
- ThemeProvider as MuiThemeProvider,
- StyledEngineProvider,
-} from "@mui/material/styles";
import {
type FC,
type PropsWithChildren,
@@ -22,6 +9,7 @@ import { appearanceSettings } from "#/api/queries/users";
import { useEmbeddedMetadata } from "#/hooks/useEmbeddedMetadata";
import themes, { baseModeFor, CONCRETE_THEMES, type Theme } from "#/theme";
import { AppearanceProvider } from "#/theme/appearance";
+import { ThemeContextProvider } from "#/theme/context";
import {
migrateLegacyPreference,
resolveActiveThemeName,
@@ -58,19 +46,9 @@ export const ThemeProvider: FC = ({ children }) => {
const theme = themes[concreteName];
- return (
-
- {children}
-
- );
+ return {children};
};
-// This is being added to allow Tailwind classes to be used with MUI components. https://mui.com/material-ui/integrations/interoperability/#tailwind-css
-const cache = createCache({
- key: "css",
- prepend: true,
-});
-
interface ThemeOverrideProps {
theme: Theme;
children?: ReactNode;
@@ -78,15 +56,10 @@ interface ThemeOverrideProps {
export const ThemeOverride: FC = ({ theme, children }) => {
return (
-
-
-
-
-
- {children}
-
-
-
-
+
+
+ {children}
+
+
);
};
diff --git a/site/src/index.css b/site/src/index.css
index 7b8dbac66f2..5a7e29b313f 100644
--- a/site/src/index.css
+++ b/site/src/index.css
@@ -369,6 +369,10 @@
@apply h-full;
}
+ body {
+ @apply bg-surface-primary text-content-primary font-sans antialiased;
+ }
+
button,
input {
@apply font-sans;
@@ -423,17 +427,18 @@
}
}
- /*
- This is a temporary fix for MUI Modals/Popovers until they are removed.
- When html has scrollbar-gutter: stable, the browser reserves space for the scrollbar.
- MUI Modals/Popovers, when locking body scroll, add `overflow: hidden` and `padding-right`
- to the body to compensate for the scrollbar they are hiding. This added padding-right
- conflicts with the already reserved gutter space, causing a layout shift.
- This rule overrides MUI's added padding-right on the body specifically when MUI
- is likely to have set both overflow:hidden and padding-right.
- */
- body[style*="overflow: hidden"][style*="padding-right"] {
- padding-right: 0px;
+ h2 {
+ font-size: 1.5em;
+ font-weight: bold;
+ }
+
+ h3,
+ p {
+ margin-block: 1em;
+ }
+
+ h4 {
+ margin-block: 1.33em;
}
}
diff --git a/site/src/modules/workspaces/WorkspaceTiming/ResourcesChart.tsx b/site/src/modules/workspaces/WorkspaceTiming/ResourcesChart.tsx
index da936ef54e5..d543215d732 100644
--- a/site/src/modules/workspaces/WorkspaceTiming/ResourcesChart.tsx
+++ b/site/src/modules/workspaces/WorkspaceTiming/ResourcesChart.tsx
@@ -1,4 +1,3 @@
-import { type Theme, useTheme } from "@emotion/react";
import { ExternalLinkIcon } from "lucide-react";
import { type FC, useState } from "react";
import { Link } from "react-router";
@@ -7,6 +6,8 @@ import {
TooltipContent,
TooltipTrigger,
} from "#/components/Tooltip/Tooltip";
+import type { Theme } from "#/theme";
+import { useTheme } from "#/theme/context";
import { Bar } from "./Chart/Bar";
import {
Chart,
diff --git a/site/src/modules/workspaces/WorkspaceTiming/ScriptsChart.tsx b/site/src/modules/workspaces/WorkspaceTiming/ScriptsChart.tsx
index 1e51d025284..ec3d540b352 100644
--- a/site/src/modules/workspaces/WorkspaceTiming/ScriptsChart.tsx
+++ b/site/src/modules/workspaces/WorkspaceTiming/ScriptsChart.tsx
@@ -1,10 +1,11 @@
-import { type Theme, useTheme } from "@emotion/react";
import { type FC, useState } from "react";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "#/components/Tooltip/Tooltip";
+import type { Theme } from "#/theme";
+import { useTheme } from "#/theme/context";
import { Bar } from "./Chart/Bar";
import {
Chart,
diff --git a/site/src/pages/AgentsPage/components/ChatElements/Response.tsx b/site/src/pages/AgentsPage/components/ChatElements/Response.tsx
index b4325f27146..ddf932b0379 100644
--- a/site/src/pages/AgentsPage/components/ChatElements/Response.tsx
+++ b/site/src/pages/AgentsPage/components/ChatElements/Response.tsx
@@ -1,4 +1,3 @@
-import { useTheme } from "@emotion/react";
import {
File as FileViewer,
type SupportedLanguages,
@@ -11,6 +10,7 @@ import {
type UrlTransform,
} from "streamdown";
import { ScrollArea } from "#/components/ScrollArea/ScrollArea";
+import { useTheme } from "#/theme/context";
import { cn } from "#/utils/cn";
import { MarkdownImage } from "./MarkdownImage";
diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/EditFilesTool.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/EditFilesTool.tsx
index 015d9c65bfb..1af4bf6b8ac 100644
--- a/site/src/pages/AgentsPage/components/ChatElements/tools/EditFilesTool.tsx
+++ b/site/src/pages/AgentsPage/components/ChatElements/tools/EditFilesTool.tsx
@@ -1,9 +1,9 @@
-import { useTheme } from "@emotion/react";
import type { FileDiffMetadata } from "@pierre/diffs";
import { FileDiff } from "@pierre/diffs/react";
import type React from "react";
import type * as TypesGen from "#/api/typesGenerated";
import { ScrollArea } from "#/components/ScrollArea/ScrollArea";
+import { useTheme } from "#/theme/context";
import { getPathBasename } from "../../../utils/path";
import { DiffFileHeader } from "./DiffFileHeader";
import {
diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/ReadFileTool.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/ReadFileTool.tsx
index e9462fa7935..88d9132f92d 100644
--- a/site/src/pages/AgentsPage/components/ChatElements/tools/ReadFileTool.tsx
+++ b/site/src/pages/AgentsPage/components/ChatElements/tools/ReadFileTool.tsx
@@ -1,7 +1,7 @@
-import { useTheme } from "@emotion/react";
import { File as FileViewer } from "@pierre/diffs/react";
import type React from "react";
import { ScrollArea } from "#/components/ScrollArea/ScrollArea";
+import { useTheme } from "#/theme/context";
import { getPathBasename } from "../../../utils/path";
import { asRecord, asString } from "../runtimeTypeUtils";
import { ToolCall } from "./ToolCall";
diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/Tool.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/Tool.tsx
index 58e38f35d13..dc8f9e2757a 100644
--- a/site/src/pages/AgentsPage/components/ChatElements/tools/Tool.tsx
+++ b/site/src/pages/AgentsPage/components/ChatElements/tools/Tool.tsx
@@ -1,8 +1,8 @@
-import { useTheme } from "@emotion/react";
import { File as FileViewer } from "@pierre/diffs/react";
import { type ComponentPropsWithRef, type FC, memo } from "react";
import type * as TypesGen from "#/api/typesGenerated";
import { ScrollArea } from "#/components/ScrollArea/ScrollArea";
+import { useTheme } from "#/theme/context";
import { cn } from "#/utils/cn";
import { AdvisorTool, type AdvisorToolResultType } from "./AdvisorTool";
import {
diff --git a/site/src/pages/AgentsPage/components/ChatElements/tools/WriteFileTool.tsx b/site/src/pages/AgentsPage/components/ChatElements/tools/WriteFileTool.tsx
index 4c43eee4935..26c89503fca 100644
--- a/site/src/pages/AgentsPage/components/ChatElements/tools/WriteFileTool.tsx
+++ b/site/src/pages/AgentsPage/components/ChatElements/tools/WriteFileTool.tsx
@@ -1,9 +1,9 @@
-import { useTheme } from "@emotion/react";
import type { FileDiffMetadata } from "@pierre/diffs";
import { FileDiff } from "@pierre/diffs/react";
import type React from "react";
import type * as TypesGen from "#/api/typesGenerated";
import { ScrollArea } from "#/components/ScrollArea/ScrollArea";
+import { useTheme } from "#/theme/context";
import { getPathBasename } from "../../../utils/path";
import { DiffFileHeader } from "./DiffFileHeader";
import {
diff --git a/site/src/pages/AgentsPage/components/DiffViewer/DiffViewer.tsx b/site/src/pages/AgentsPage/components/DiffViewer/DiffViewer.tsx
index 1be56678479..3b6070e07fa 100644
--- a/site/src/pages/AgentsPage/components/DiffViewer/DiffViewer.tsx
+++ b/site/src/pages/AgentsPage/components/DiffViewer/DiffViewer.tsx
@@ -1,4 +1,3 @@
-import { useTheme } from "@emotion/react";
import type {
CodeViewHandle,
CodeViewItem,
@@ -22,6 +21,7 @@ import {
} from "react";
import { ErrorAlert } from "#/components/Alert/ErrorAlert";
import { Skeleton } from "#/components/Skeleton/Skeleton";
+import { useTheme } from "#/theme/context";
import { cn } from "#/utils/cn";
import { countChangedLines } from "../../utils/countChangedLines";
import { changeColor, changeLabel } from "../../utils/diffColors";
diff --git a/site/src/pages/DeploymentSettingsPage/AppearanceSettingsPage/AnnouncementBannerDialog.tsx b/site/src/pages/DeploymentSettingsPage/AppearanceSettingsPage/AnnouncementBannerDialog.tsx
index 4a6553b11d7..28e08a8f26d 100644
--- a/site/src/pages/DeploymentSettingsPage/AppearanceSettingsPage/AnnouncementBannerDialog.tsx
+++ b/site/src/pages/DeploymentSettingsPage/AppearanceSettingsPage/AnnouncementBannerDialog.tsx
@@ -1,4 +1,3 @@
-import { useTheme } from "@emotion/react";
import { useFormik } from "formik";
import { type FC, useState } from "react";
import { SliderPicker, TwitterPicker } from "react-color";
@@ -15,6 +14,7 @@ import {
import { Label } from "#/components/Label/Label";
import { Textarea } from "#/components/Textarea/Textarea";
import { AnnouncementBannerView } from "#/modules/dashboard/AnnouncementBanners/AnnouncementBannerView";
+import { useTheme } from "#/theme/context";
import { cn } from "#/utils/cn";
import { getFormHelpers } from "#/utils/formUtils";
diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx
index 60689401139..582e250de99 100644
--- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx
+++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx
@@ -1,4 +1,3 @@
-import { useTheme } from "@emotion/react";
import { PlusIcon, RotateCwIcon } from "lucide-react";
import type { FC } from "react";
import Confetti from "react-confetti";
@@ -20,6 +19,7 @@ import {
TooltipTrigger,
} from "#/components/Tooltip/Tooltip";
import { useWindowSize } from "#/hooks/useWindowSize";
+import { useTheme } from "#/theme/context";
import { AIGovernanceUsersConsumption } from "./AIGovernanceUsersConsumptionChart";
import { LicenseCard } from "./LicenseCard";
import { LicenseSeatConsumptionChart } from "./LicenseSeatConsumptionChart";
diff --git a/site/src/pages/TemplateBuilder/ModuleCard.tsx b/site/src/pages/TemplateBuilder/ModuleCard.tsx
index bf793b414f0..ddead840989 100644
--- a/site/src/pages/TemplateBuilder/ModuleCard.tsx
+++ b/site/src/pages/TemplateBuilder/ModuleCard.tsx
@@ -67,7 +67,7 @@ export const ModuleCard: React.FC = ({
{official && (
<>
{" "}
-
+
>
)}
diff --git a/site/src/pages/TemplateVersionEditorPage/MonacoEditor.tsx b/site/src/pages/TemplateVersionEditorPage/MonacoEditor.tsx
index 90106ab01e1..8bf8b4a6a7c 100644
--- a/site/src/pages/TemplateVersionEditorPage/MonacoEditor.tsx
+++ b/site/src/pages/TemplateVersionEditorPage/MonacoEditor.tsx
@@ -1,8 +1,8 @@
-import { useTheme } from "@emotion/react";
import Editor, { loader } from "@monaco-editor/react";
import * as monaco from "monaco-editor";
import { type FC, useEffect } from "react";
import { MONOSPACE_FONT_FAMILY } from "#/theme/constants";
+import { useTheme } from "#/theme/context";
loader.config({ monaco });
diff --git a/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditorPage.test.tsx b/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditorPage.test.tsx
index 2c660fcbaa1..64f042898f1 100644
--- a/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditorPage.test.tsx
+++ b/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditorPage.test.tsx
@@ -31,15 +31,6 @@ import TemplateVersionEditorPage, {
const { API } = apiModule;
-// For some reason this component in Jest is throwing a MUI style warning so,
-// since we don't need it for this test, we can mock it out
-vi.mock(
- "modules/templates/TemplateResourcesTable/TemplateResourcesTable",
- () => ({
- TemplateResourcesTable: () => ,
- }),
-);
-
// Monaco is a large and complicated codebase that slows tests down and we don't
// need to test.
vi.mock("#/pages/TemplateVersionEditorPage/MonacoEditor", () => ({
diff --git a/site/src/theme/appearance.tsx b/site/src/theme/appearance.tsx
index 40120856c7f..bc864cf2b8e 100644
--- a/site/src/theme/appearance.tsx
+++ b/site/src/theme/appearance.tsx
@@ -8,8 +8,7 @@ import {
import type { ExternalImageModeStyles } from "#/theme/externalImages";
/**
- * Publishes *user* appearance values derived from the active site theme so
- * components can consume them without depending on Emotion's `useTheme`.
+ * Publishes *user* appearance values derived from the active site theme.
*
* This is the client-side, theme-derived appearance surface (for example, how
* external images should be tinted for the active theme). It is intentionally
diff --git a/site/src/theme/constants.ts b/site/src/theme/constants.ts
index 8b54c8d1a63..e9d2d5c964e 100644
--- a/site/src/theme/constants.ts
+++ b/site/src/theme/constants.ts
@@ -1,12 +1,9 @@
import type { TerminalFontName } from "#/api/typesGenerated";
-export const borderRadius = 8;
-
const MONOSPACE_DEFAULT_FONT = "Geist Mono Variable";
const TERMINAL_SYMBOL_FONT = "'Coder Terminal Symbols'";
export const MONOSPACE_FONT_FAMILY =
"'Geist Mono Variable', 'IBM Plex Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'Liberation Mono', 'Monaco', 'Courier New', Courier, monospace";
-export const BODY_FONT_FAMILY = `"Geist Variable", system-ui, sans-serif`;
const withTerminalSymbolFallback = (fontFamily: string) =>
fontFamily.replace(", monospace", `, ${TERMINAL_SYMBOL_FONT}, monospace`);
@@ -42,7 +39,3 @@ export const navHeight = 62;
export const containerWidth = 1380;
export const containerWidthMedium = 1080;
export const sidePadding = 24;
-
-// MUI does not have aligned heights for buttons and inputs so we have to "hack" it a little bit
-export const BUTTON_LG_HEIGHT = 40;
-export const BUTTON_MD_HEIGHT = 36;
diff --git a/site/src/theme/context.tsx b/site/src/theme/context.tsx
new file mode 100644
index 00000000000..1dbfad5c1c0
--- /dev/null
+++ b/site/src/theme/context.tsx
@@ -0,0 +1,26 @@
+import { createContext, type FC, type ReactNode, useContext } from "react";
+import type { Theme } from "#/theme";
+
+const ThemeContext = createContext(undefined);
+
+interface ThemeContextProviderProps {
+ theme: Theme;
+ children: ReactNode;
+}
+
+export const ThemeContextProvider: FC = ({
+ theme,
+ children,
+}) => {
+ return (
+ {children}
+ );
+};
+
+export const useTheme = (): Theme => {
+ const theme = useContext(ThemeContext);
+ if (theme === undefined) {
+ throw new Error("useTheme must be used within a ThemeContextProvider");
+ }
+ return theme;
+};
diff --git a/site/src/theme/dark/index.ts b/site/src/theme/dark/index.ts
index 29cec249232..78668aa8f29 100644
--- a/site/src/theme/dark/index.ts
+++ b/site/src/theme/dark/index.ts
@@ -2,11 +2,11 @@ import { forDarkThemes } from "../externalImages";
import branding from "./branding";
import experimental from "./experimental";
import monaco from "./monaco";
-import muiTheme from "./mui";
+import palette from "./palette";
import roles from "./roles";
export default {
- ...muiTheme,
+ palette,
externalImages: forDarkThemes,
experimental,
branding,
diff --git a/site/src/theme/dark/monaco.ts b/site/src/theme/dark/monaco.ts
index 4c73d8b9918..a7c4e72732f 100644
--- a/site/src/theme/dark/monaco.ts
+++ b/site/src/theme/dark/monaco.ts
@@ -1,5 +1,5 @@
import type * as monaco from "monaco-editor";
-import muiTheme from "./mui";
+import palette from "./palette";
export default {
base: "vs-dark",
@@ -31,7 +31,7 @@ export default {
},
],
colors: {
- "editor.foreground": muiTheme.palette.text.primary,
- "editor.background": muiTheme.palette.background.paper,
+ "editor.foreground": palette.text.primary,
+ "editor.background": 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
deleted file mode 100644
index fd526e4bcc5..00000000000
--- a/site/src/theme/dark/mui.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * @deprecated MUI dark theme is deprecated. Migrate to Tailwind CSS theme system.
- * This file provides MUI theme configuration for legacy compatibility only.
- */
-
-/** @deprecated MUI createTheme is deprecated. Migrate to Tailwind CSS theme system. */
-import { createTheme } from "@mui/material/styles";
-import { BODY_FONT_FAMILY, borderRadius } from "../constants";
-import { components } from "../mui";
-import tw from "../tailwindColors";
-
-const muiTheme = createTheme({
- palette: {
- mode: "dark",
- primary: {
- main: tw.sky[500],
- contrastText: tw.white,
- light: tw.sky[400],
- dark: tw.sky[600],
- },
- secondary: {
- main: tw.zinc[500],
- contrastText: tw.zinc[200],
- dark: tw.zinc[400],
- },
- background: {
- default: tw.zinc[950],
- paper: tw.zinc[900],
- },
- text: {
- primary: tw.zinc[50],
- secondary: tw.zinc[400],
- disabled: tw.zinc[500],
- },
- divider: tw.zinc[700],
- 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[200],
- },
- action: {
- hover: tw.zinc[800],
- },
- neutral: {
- main: tw.zinc[50],
- },
- dots: tw.zinc[500],
- },
- 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,
- },
- components,
-});
-
-export default muiTheme;
diff --git a/site/src/theme/dark/palette.ts b/site/src/theme/dark/palette.ts
new file mode 100644
index 00000000000..160efeff137
--- /dev/null
+++ b/site/src/theme/dark/palette.ts
@@ -0,0 +1,21 @@
+import type { Palette } from "../palette";
+import tw from "../tailwindColors";
+
+const palette: Palette = {
+ mode: "dark",
+ primary: {
+ main: tw.sky[500],
+ },
+ secondary: {
+ main: tw.zinc[500],
+ },
+ background: {
+ default: tw.zinc[950],
+ paper: tw.zinc[900],
+ },
+ text: {
+ primary: tw.zinc[50],
+ },
+};
+
+export default palette;
diff --git a/site/src/theme/darkProtanDeuter/index.ts b/site/src/theme/darkProtanDeuter/index.ts
index 29cec249232..17b6544a3e2 100644
--- a/site/src/theme/darkProtanDeuter/index.ts
+++ b/site/src/theme/darkProtanDeuter/index.ts
@@ -1,12 +1,12 @@
+import palette from "../dark/palette";
import { forDarkThemes } from "../externalImages";
import branding from "./branding";
import experimental from "./experimental";
import monaco from "./monaco";
-import muiTheme from "./mui";
import roles from "./roles";
export default {
- ...muiTheme,
+ palette,
externalImages: forDarkThemes,
experimental,
branding,
diff --git a/site/src/theme/darkProtanDeuter/mui.ts b/site/src/theme/darkProtanDeuter/mui.ts
deleted file mode 100644
index b59dca2f3e4..00000000000
--- a/site/src/theme/darkProtanDeuter/mui.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * @deprecated MUI theme is deprecated. Migrate to Tailwind CSS theme system.
- *
- * MUI components are deprecated and the colorblind-friendly palette is
- * expressed through `roles.ts` and the CSS variables in
- * `site/src/index.css`, both of which drive the Tailwind-rendered UI that
- * the diff panel and semantic roles use. We re-export the base dark MUI
- * theme so `palette.mode === "dark"` stays correct for any remaining
- * legacy MUI component that inspects it (for example, the Shiki theme
- * selector in `DiffViewer.tsx`).
- */
-export { default } from "../dark/mui";
diff --git a/site/src/theme/darkTritan/index.ts b/site/src/theme/darkTritan/index.ts
index 29cec249232..17b6544a3e2 100644
--- a/site/src/theme/darkTritan/index.ts
+++ b/site/src/theme/darkTritan/index.ts
@@ -1,12 +1,12 @@
+import palette from "../dark/palette";
import { forDarkThemes } from "../externalImages";
import branding from "./branding";
import experimental from "./experimental";
import monaco from "./monaco";
-import muiTheme from "./mui";
import roles from "./roles";
export default {
- ...muiTheme,
+ palette,
externalImages: forDarkThemes,
experimental,
branding,
diff --git a/site/src/theme/darkTritan/mui.ts b/site/src/theme/darkTritan/mui.ts
deleted file mode 100644
index 80e0ddc6328..00000000000
--- a/site/src/theme/darkTritan/mui.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * @deprecated MUI theme is deprecated. Migrate to Tailwind CSS theme system.
- *
- * The colorblind-friendly palette is expressed through `roles.ts` and the
- * CSS variables in `site/src/index.css`. We re-export the base dark MUI
- * theme so `palette.mode === "dark"` stays correct for any remaining
- * legacy MUI component that inspects it.
- */
-export { default } from "../dark/mui";
diff --git a/site/src/theme/index.ts b/site/src/theme/index.ts
index 33f140cdaa9..311d045ab7d 100644
--- a/site/src/theme/index.ts
+++ b/site/src/theme/index.ts
@@ -1,5 +1,3 @@
-/** @deprecated MUI Theme type is deprecated. Migrate to Tailwind CSS theme system. */
-import type { Theme as MuiTheme } from "@mui/material/styles";
import type * as monaco from "monaco-editor";
import type { Branding } from "./branding";
import dark from "./dark";
@@ -10,11 +8,12 @@ import type { ExternalImageModeStyles } from "./externalImages";
import light from "./light";
import lightProtanDeuter from "./lightProtanDeuter";
import lightTritan from "./lightTritan";
+import type { Palette } from "./palette";
import type { Roles } from "./roles";
-export interface Theme extends Omit {
- /** @deprecated prefer `theme.roles` when possible */
- palette: MuiTheme["palette"];
+export interface Theme {
+ /** @deprecated prefer roles or CSS variables when possible */
+ palette: Palette;
/** Sets of colors that can be used based on the role that a UI element serves
* for the user.
diff --git a/site/src/theme/light/index.ts b/site/src/theme/light/index.ts
index fd50cbd9f96..d5c1ba556d6 100644
--- a/site/src/theme/light/index.ts
+++ b/site/src/theme/light/index.ts
@@ -2,11 +2,11 @@ import { forLightThemes } from "../externalImages";
import branding from "./branding";
import experimental from "./experimental";
import monaco from "./monaco";
-import muiTheme from "./mui";
+import palette from "./palette";
import roles from "./roles";
export default {
- ...muiTheme,
+ palette,
externalImages: forLightThemes,
experimental,
branding,
diff --git a/site/src/theme/light/monaco.ts b/site/src/theme/light/monaco.ts
index 2da6974033b..d325b06dc23 100644
--- a/site/src/theme/light/monaco.ts
+++ b/site/src/theme/light/monaco.ts
@@ -1,5 +1,5 @@
import type * as monaco from "monaco-editor";
-import muiTheme from "./mui";
+import palette from "./palette";
export default {
base: "vs",
@@ -31,7 +31,7 @@ export default {
},
],
colors: {
- "editor.foreground": muiTheme.palette.text.primary,
- "editor.background": muiTheme.palette.background.paper,
+ "editor.foreground": palette.text.primary,
+ "editor.background": 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
deleted file mode 100644
index de3f2c0a1aa..00000000000
--- a/site/src/theme/light/mui.ts
+++ /dev/null
@@ -1,185 +0,0 @@
-/**
- * @deprecated MUI light theme is deprecated. Migrate to Tailwind CSS theme system.
- * This file provides MUI theme configuration for legacy compatibility only.
- */
-
-/** @deprecated MUI createTheme is deprecated. Migrate to Tailwind CSS theme system. */
-import { createTheme } from "@mui/material/styles";
-import { BODY_FONT_FAMILY, borderRadius } from "../constants";
-import { components } from "../mui";
-import tw from "../tailwindColors";
-
-// biome-ignore lint/suspicious/noExplicitAny: needed for MUI overrides
-type MuiStyle = any;
-
-const 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[600],
- disabled: tw.zinc[500],
- },
- divider: tw.zinc[200],
- warning: {
- light: tw.amber[400],
- 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],
- },
- dots: tw.zinc[400],
- },
- 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,
- },
- components: {
- ...components,
- MuiCssBaseline: {
- styleOverrides: (theme) => `
- 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 ${theme.palette.background.default} inset !important;
- }
-
- ::placeholder {
- color: ${theme.palette.text.disabled};
- }
- `,
- },
- MuiAvatar: {
- styleOverrides: {
- root: components.MuiAvatar.styleOverrides.root,
- colorDefault: {
- backgroundColor: tw.zinc[700],
- },
- },
- },
- MuiChip: {
- styleOverrides: {
- root: {
- backgroundColor: tw.zinc[400],
- },
- },
- },
- MuiInputBase: {
- ...components.MuiInputBase,
- styleOverrides: {
- ...components.MuiInputBase.styleOverrides,
- ["colorPrimary" as MuiStyle]: {
- // 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],
- },
- },
- },
- },
- 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],
- },
- },
- },
- },
- MuiTooltip: {
- styleOverrides: {
- tooltip: ({ theme }) => ({
- lineHeight: "150%",
- borderRadius: 4,
- background: theme.palette.background.paper,
- color: theme.palette.secondary.contrastText,
- border: `1px solid ${theme.palette.divider}`,
- padding: "8px 16px",
- boxShadow: "0 1px 4px #0001",
- }),
- },
- },
- },
-});
-
-export default muiTheme;
diff --git a/site/src/theme/light/palette.ts b/site/src/theme/light/palette.ts
new file mode 100644
index 00000000000..75f6b9fa7e8
--- /dev/null
+++ b/site/src/theme/light/palette.ts
@@ -0,0 +1,21 @@
+import type { Palette } from "../palette";
+import tw from "../tailwindColors";
+
+const palette: Palette = {
+ mode: "light",
+ primary: {
+ main: tw.sky[600],
+ },
+ secondary: {
+ main: tw.zinc[500],
+ },
+ background: {
+ default: tw.zinc[50],
+ paper: tw.zinc[100],
+ },
+ text: {
+ primary: tw.zinc[950],
+ },
+};
+
+export default palette;
diff --git a/site/src/theme/lightProtanDeuter/index.ts b/site/src/theme/lightProtanDeuter/index.ts
index fd50cbd9f96..220f82eb903 100644
--- a/site/src/theme/lightProtanDeuter/index.ts
+++ b/site/src/theme/lightProtanDeuter/index.ts
@@ -1,12 +1,12 @@
import { forLightThemes } from "../externalImages";
+import palette from "../light/palette";
import branding from "./branding";
import experimental from "./experimental";
import monaco from "./monaco";
-import muiTheme from "./mui";
import roles from "./roles";
export default {
- ...muiTheme,
+ palette,
externalImages: forLightThemes,
experimental,
branding,
diff --git a/site/src/theme/lightProtanDeuter/mui.ts b/site/src/theme/lightProtanDeuter/mui.ts
deleted file mode 100644
index 7f75c070c19..00000000000
--- a/site/src/theme/lightProtanDeuter/mui.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- * @deprecated MUI theme is deprecated. Migrate to Tailwind CSS theme system.
- *
- * The colorblind-friendly palette is expressed through `roles.ts` and the
- * CSS variables in `site/src/index.css`. We re-export the base light MUI
- * theme so `palette.mode === "light"` stays correct for any remaining
- * legacy MUI component that inspects it, including the Shiki theme
- * selector in `DiffViewer.tsx`.
- */
-export { default } from "../light/mui";
diff --git a/site/src/theme/lightTritan/index.ts b/site/src/theme/lightTritan/index.ts
index fd50cbd9f96..220f82eb903 100644
--- a/site/src/theme/lightTritan/index.ts
+++ b/site/src/theme/lightTritan/index.ts
@@ -1,12 +1,12 @@
import { forLightThemes } from "../externalImages";
+import palette from "../light/palette";
import branding from "./branding";
import experimental from "./experimental";
import monaco from "./monaco";
-import muiTheme from "./mui";
import roles from "./roles";
export default {
- ...muiTheme,
+ palette,
externalImages: forLightThemes,
experimental,
branding,
diff --git a/site/src/theme/lightTritan/mui.ts b/site/src/theme/lightTritan/mui.ts
deleted file mode 100644
index 718b6aa2b71..00000000000
--- a/site/src/theme/lightTritan/mui.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * @deprecated MUI theme is deprecated. Migrate to Tailwind CSS theme system.
- *
- * Re-exports the base light MUI theme so `palette.mode === "light"` stays
- * correct for legacy MUI components. Colorblind palette overrides live in
- * `roles.ts` and the CSS variables block in `site/src/index.css`.
- */
-export { default } from "../light/mui";
diff --git a/site/src/theme/mui.ts b/site/src/theme/mui.ts
deleted file mode 100644
index 11e93bf9be6..00000000000
--- a/site/src/theme/mui.ts
+++ /dev/null
@@ -1,222 +0,0 @@
-/**
- * @deprecated MUI theme configuration is deprecated. Migrate to Tailwind CSS theme system.
- * This file provides MUI theme overrides for legacy compatibility only.
- */
-
-/** @deprecated MUI ThemeOptions is deprecated. Migrate to Tailwind CSS theme system. */
-import type { ThemeOptions } from "@mui/material/styles";
-import { BUTTON_LG_HEIGHT, BUTTON_MD_HEIGHT } from "./constants";
-import tw from "./tailwindColors";
-
-// biome-ignore lint/suspicious/noExplicitAny: needed for MUI overrides
-type MuiStyle = any;
-
-export const components = {
- MuiAvatar: {
- styleOverrides: {
- root: {
- width: 36,
- height: 36,
- fontSize: 18,
-
- "& .MuiSvgIcon-root": {
- width: "50%",
- },
- },
- colorDefault: ({ theme }) => ({
- backgroundColor: theme.palette.primary.light,
- }),
- },
- },
- MuiLink: {
- defaultProps: {
- underline: "hover",
- },
- },
- MuiSkeleton: {
- styleOverrides: {
- root: ({ theme }) => ({
- backgroundColor: theme.palette.divider,
- }),
- },
- },
- MuiLinearProgress: {
- styleOverrides: {
- root: {
- borderRadius: 999,
- },
- },
- },
- 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" as MuiStyle]: {
- // Same as button
- "& .MuiOutlinedInput-notchedOutline": {
- borderColor: tw.zinc[600],
- },
- // 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,
- "&::first-letter": {
- // Server errors are returned in all lowercase. To display them as
- // field errors in the UI, we capitalize the first letter.
- textTransform: "uppercase",
- },
- },
- },
- },
- 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[400]}`,
- },
-
- "&.Mui-disabled": {
- color: tw.zinc[500],
- },
-
- "& .MuiSvgIcon-fontSizeXsmall": {
- fontSize: "1rem",
- },
- },
- },
- },
- MuiAutocomplete: {
- styleOverrides: {
- root: {
- // Not sure why but since the input has padding we don't need it here
- "& .MuiInputBase-root": {
- padding: "0px 0px 0px 8px",
- },
- },
- },
- },
- MuiList: {
- defaultProps: {
- disablePadding: true,
- },
- },
- MuiTabs: {
- defaultProps: {
- textColor: "primary",
- indicatorColor: "primary",
- },
- },
- MuiTooltip: {
- styleOverrides: {
- tooltip: ({ theme }) => ({
- lineHeight: "150%",
- borderRadius: 4,
- background: theme.palette.divider,
- padding: "8px 16px",
- }),
- arrow: ({ theme }) => ({
- color: theme.palette.divider,
- }),
- },
- },
-} satisfies ThemeOptions["components"];
diff --git a/site/src/theme/palette.ts b/site/src/theme/palette.ts
new file mode 100644
index 00000000000..f7ba7902c62
--- /dev/null
+++ b/site/src/theme/palette.ts
@@ -0,0 +1,20 @@
+/**
+ * Minimal palette used by remaining non-Tailwind consumers (Monaco, charts,
+ * confetti, color pickers). Prefer semantic CSS variables and roles when possible.
+ */
+export interface Palette {
+ mode: "dark" | "light";
+ primary: {
+ main: string;
+ };
+ secondary: {
+ main: string;
+ };
+ background: {
+ default: string;
+ paper: string;
+ };
+ text: {
+ primary: string;
+ };
+}
diff --git a/site/tailwind.config.js b/site/tailwind.config.js
index 839299b1d3e..14f66470128 100644
--- a/site/tailwind.config.js
+++ b/site/tailwind.config.js
@@ -1,8 +1,5 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
- corePlugins: {
- preflight: false,
- },
darkMode: ["selector"],
content: [
"./index.html",
diff --git a/site/tsconfig.json b/site/tsconfig.json
index 4b5dc19dbe4..c2df2443a31 100644
--- a/site/tsconfig.json
+++ b/site/tsconfig.json
@@ -5,7 +5,6 @@
"incremental": true,
"isolatedModules": true,
"jsx": "react-jsx",
- "jsxImportSource": "@emotion/react",
"lib": ["dom", "esnext"],
"module": "preserve",
"moduleResolution": "bundler",
diff --git a/site/vite.config.mts b/site/vite.config.mts
index d739b4b6d77..4b6c9f1476a 100644
--- a/site/vite.config.mts
+++ b/site/vite.config.mts
@@ -62,8 +62,6 @@ export default defineConfig({
},
codeSplitting: {
groups: [
- { name: "mui", test: /@mui/ },
- { name: "emotion", test: /@emotion/ },
{ name: "monaco", test: /monaco-editor/ },
{ name: "xterm", test: /@xterm/ },
{ name: "emoji-mart", test: /emoji-mart/ },
@@ -157,58 +155,11 @@ export default defineConfig({
},
allowedHosts: [".coder", ".dev.coder.com"],
},
- // Pre-bundle deps that Vite tends to discover late (deep MUI
- // imports, Emotion). Without this, Vite re-optimizes mid-session
- // which returns 504 "Outdated Optimize Dep" for every previously
- // served chunk, cascading into dynamic import failures.
+ // Pre-bundle deps that Vite tends to discover late. Without this, Vite
+ // re-optimizes mid-session which returns 504 "Outdated Optimize Dep" for
+ // every previously served chunk, cascading into dynamic import failures.
optimizeDeps: {
include: [
- "@emotion/cache",
- "@emotion/css",
- "@emotion/react",
- "@emotion/react/jsx-runtime",
- "@emotion/styled",
- "@mui/material/Autocomplete",
- "@mui/material/Card",
- "@mui/material/CardActionArea",
- "@mui/material/CardContent",
- "@mui/material/Checkbox",
- "@mui/material/Collapse",
- "@mui/material/CssBaseline",
- "@mui/material/Dialog",
- "@mui/material/DialogActions",
- "@mui/material/DialogContent",
- "@mui/material/DialogContentText",
- "@mui/material/DialogTitle",
- "@mui/material/Divider",
- "@mui/material/Drawer",
- "@mui/material/FormControl",
- "@mui/material/FormControlLabel",
- "@mui/material/FormGroup",
- "@mui/material/FormHelperText",
- "@mui/material/FormLabel",
- "@mui/material/InputAdornment",
- "@mui/material/InputBase",
- "@mui/material/Link",
- "@mui/material/List",
- "@mui/material/ListItem",
- "@mui/material/ListItemText",
- "@mui/material/Menu",
- "@mui/material/MenuItem",
- "@mui/material/MenuList",
- "@mui/material/Radio",
- "@mui/material/RadioGroup",
- "@mui/material/Select",
- "@mui/material/Skeleton",
- "@mui/material/Snackbar",
- "@mui/material/Stack",
- "@mui/material/TableRow",
- "@mui/material/TextField",
- "@mui/material/ToggleButton",
- "@mui/material/ToggleButtonGroup",
- "@mui/material/styles",
- "@mui/system/createTheme",
- "@mui/system/useTheme",
// Discovered at runtime without this entry, triggering
// a mid-run dep re-optimization that breaks imports.
"@tanstack/react-query-devtools",