diff --git a/apps/studio/components/interfaces/App/AppBannerWrapper.tsx b/apps/studio/components/interfaces/App/AppBannerWrapper.tsx index df824bb697f..d54189d2d38 100644 --- a/apps/studio/components/interfaces/App/AppBannerWrapper.tsx +++ b/apps/studio/components/interfaces/App/AppBannerWrapper.tsx @@ -1,33 +1,19 @@ -import { useMonaco } from '@monaco-editor/react' -import { useTheme } from 'next-themes' -import { PropsWithChildren, useMemo } from 'react' +import { PropsWithChildren } from 'react' import { ClockSkewBanner } from 'components/layouts/AppLayout/ClockSkewBanner' import IncidentBanner from 'components/layouts/AppLayout/IncidentBanner' import { NoticeBanner } from 'components/layouts/AppLayout/NoticeBanner' import { RestrictionBanner } from 'components/layouts/AppLayout/RestrictionBanner' -import { getTheme } from 'components/ui/CodeEditor/CodeEditor.utils' import { useFlag } from 'hooks/ui/useFlag' import { useProfile } from 'lib/profile' const AppBannerWrapper = ({ children }: PropsWithChildren<{}>) => { - const monaco = useMonaco() const { profile } = useProfile() - const { resolvedTheme } = useTheme() const ongoingIncident = useFlag('ongoingIncident') const showNoticeBanner = useFlag('showNoticeBanner') const clockSkewBanner = useFlag('clockSkewBanner') - // Define the supabase theme for Monaco before anything is rendered. Using useEffect would sometime load the theme - // after the editor was loaded, so it looked off. useMemo will always be run before rendering - useMemo(() => { - if (monaco && resolvedTheme) { - const mode: any = getTheme(resolvedTheme) - monaco.editor.defineTheme('supabase', mode) - } - }, [resolvedTheme, monaco]) - return (
diff --git a/apps/studio/components/interfaces/App/MonacoThemeProvider.tsx b/apps/studio/components/interfaces/App/MonacoThemeProvider.tsx new file mode 100644 index 00000000000..92b9fb6e0f8 --- /dev/null +++ b/apps/studio/components/interfaces/App/MonacoThemeProvider.tsx @@ -0,0 +1,44 @@ +import { useMonaco } from '@monaco-editor/react' +import { useTheme } from 'next-themes' +import { useMemo } from 'react' + +const getTheme = (theme: string) => { + const isDarkMode = theme.includes('dark') + // [TODO] Probably need better theming for light mode + return { + base: isDarkMode ? ('vs-dark' as const) : ('vs' as const), // can also be vs-dark or hc-black + inherit: true, // can also be false to completely replace the builtin rules + rules: [ + { token: '', background: isDarkMode ? '1f1f1f' : 'f0f0f0' }, + { + token: '', + background: isDarkMode ? '1f1f1f' : 'f0f0f0', + foreground: isDarkMode ? 'd4d4d4' : '444444', + }, + { token: 'string.sql', foreground: '24b47e' }, + { token: 'comment', foreground: '666666' }, + { token: 'predefined.sql', foreground: isDarkMode ? 'D4D4D4' : '444444' }, + ], + colors: { 'editor.background': isDarkMode ? '#1f1f1f' : '#f0f0f0' }, + } +} + +/** + * This component is used to set the theme for the Monaco editor. This would be a hook but it needs to be placed between + * ThemeProvider and the layout page so a component is the most convenient way to do this. + */ +export const MonacoThemeProvider = () => { + const monaco = useMonaco() + const { resolvedTheme } = useTheme() + + // Define the supabase theme for Monaco before anything is rendered. Using useEffect would sometime load the theme + // after the editor was loaded, so it looked off. useMemo will always be run before rendering + useMemo(() => { + if (monaco && resolvedTheme) { + const mode = getTheme(resolvedTheme) + monaco.editor.defineTheme('supabase', mode) + } + }, [resolvedTheme, monaco]) + + return null +} diff --git a/apps/studio/components/ui/CodeEditor/CodeEditor.utils.ts b/apps/studio/components/ui/CodeEditor/CodeEditor.utils.ts index e8e14e7ab49..5540d9d1456 100644 --- a/apps/studio/components/ui/CodeEditor/CodeEditor.utils.ts +++ b/apps/studio/components/ui/CodeEditor/CodeEditor.utils.ts @@ -8,24 +8,3 @@ export const alignEditor = (editor: any) => { }) }) } - -export const getTheme = (theme: string) => { - const isDarkMode = theme.includes('dark') - // [TODO] Probably need better theming for light mode - return { - base: isDarkMode ? 'vs-dark' : 'vs', // can also be vs-dark or hc-black - inherit: true, // can also be false to completely replace the builtin rules - rules: [ - { background: isDarkMode ? '1f1f1f' : 'f0f0f0' }, - { - token: '', - background: isDarkMode ? '1f1f1f' : 'f0f0f0', - foreground: isDarkMode ? 'd4d4d4' : '444444', - }, - { token: 'string.sql', foreground: '24b47e' }, - { token: 'comment', foreground: '666666' }, - { token: 'predefined.sql', foreground: isDarkMode ? 'D4D4D4' : '444444' }, - ], - colors: { 'editor.background': isDarkMode ? '#1f1f1f' : '#f0f0f0' }, - } -} diff --git a/apps/studio/pages/_app.tsx b/apps/studio/pages/_app.tsx index 8ae9da848ad..9560ed5aaab 100644 --- a/apps/studio/pages/_app.tsx +++ b/apps/studio/pages/_app.tsx @@ -32,11 +32,12 @@ import { ErrorBoundary } from 'react-error-boundary' import { FeatureFlagProvider, PageTelemetry, ThemeProvider, useThemeSandbox } from 'common' import MetaFaviconsPagesRouter from 'common/MetaFavicons/pages-router' -import { AppBannerWrapper, RouteValidationWrapper } from 'components/interfaces/App' +import { RouteValidationWrapper } from 'components/interfaces/App' import { AppBannerContextProvider } from 'components/interfaces/App/AppBannerWrapperContext' import { StudioCommandMenu } from 'components/interfaces/App/CommandMenu' import { FeaturePreviewContextProvider } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' import FeaturePreviewModal from 'components/interfaces/App/FeaturePreview/FeaturePreviewModal' +import { MonacoThemeProvider } from 'components/interfaces/App/MonacoThemeProvider' import { GenerateSql } from 'components/interfaces/SqlGenerator/SqlGenerator' import { ErrorBoundaryState } from 'components/ui/ErrorBoundaryState' import GroupsTelemetry from 'components/ui/GroupsTelemetry' @@ -130,6 +131,7 @@ function CustomApp({ Component, pageProps }: AppPropsWithLayout) { +