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 731055af5c962..07a3056c14fb1 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 5d554465f08a3..a3873be2f85aa 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 915674b3c20a2..6640567b485c1 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 7c256e374cdb1..f2c88be0c87bf 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 36e1eb8bcb884..10f6177fca805 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 6724c41e40891..0000000000000
--- 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 5128ae7b1953a..0000000000000
--- 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 e59377acbde0d..45bd67572c8f1 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 e740cbe59249e..34cbad41b683f 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 c2e4704e10cb7..9b810faed6ef7 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 03c9eea16ac6e..3a4d63e70f8cf 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 68d9e140ce528..ed072a89e5a59 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 0150ff3f1ab15..caecbf2fe6fa1 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 c50882a6fa5a7..b8f8e44aff960 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 7b8dbac66f2e4..5a7e29b313f89 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 da936ef54e50d..d543215d73211 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 1e51d025284c4..ec3d540b352f3 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 b4325f2714699..ddf932b0379c3 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 015d9c65bfb5a..1af4bf6b8acbd 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 e9462fa79350e..88d9132f92dc7 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 58e38f35d1373..dc8f9e2757a05 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 4c43eee49354a..26c89503fca29 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 1be56678479fc..3b6070e07fae1 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 4a6553b11d787..28e08a8f26dd5 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 60689401139a3..582e250de9917 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 bf793b414f091..ddead840989a7 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 90106ab01e187..8bf8b4a6a7c44 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 2c660fcbaa103..64f042898f17d 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 40120856c7fe7..bc864cf2b8ec2 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 8b54c8d1a6389..e9d2d5c964ece 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 0000000000000..1dbfad5c1c050
--- /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 29cec249232c6..78668aa8f2967 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 4c73d8b9918e8..a7c4e72732f11 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 fd526e4bcc584..0000000000000
--- 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 0000000000000..160efeff13740
--- /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 29cec249232c6..17b6544a3e2e0 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 b59dca2f3e430..0000000000000
--- 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 29cec249232c6..17b6544a3e2e0 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 80e0ddc63284a..0000000000000
--- 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 33f140cdaa96b..311d045ab7d83 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 fd50cbd9f9638..d5c1ba556d653 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 2da6974033b3b..d325b06dc23df 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 de3f2c0a1aaed..0000000000000
--- 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 0000000000000..75f6b9fa7e8f8
--- /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 fd50cbd9f9638..220f82eb9033b 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 7f75c070c190b..0000000000000
--- 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 fd50cbd9f9638..220f82eb9033b 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 718b6aa2b71a0..0000000000000
--- 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 11e93bf9be686..0000000000000
--- 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 0000000000000..f7ba7902c62c9
--- /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 839299b1d3e35..14f66470128e2 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 4b5dc19dbe4e7..c2df2443a3174 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 d739b4b6d774a..4b6c9f1476a67 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",