MonacoThemeProvider.tsx88 lines · main
| 1 | import { useMonaco } from '@monaco-editor/react' |
| 2 | import { useTheme } from 'next-themes' |
| 3 | import { useMemo } from 'react' |
| 4 | |
| 5 | /* |
| 6 | * Briven Monaco theme — Phase 5 screen 4 of BACKEND_FORK_BRIEF.md. |
| 7 | * Palette sourced from packages/config/tailwind/theme.css: |
| 8 | * bg #0a0b0d |
| 9 | * text #f5f7fa |
| 10 | * primary #00e87a (cursor, selection accent) |
| 11 | * code-comment #6b7280 |
| 12 | * code-keyword #ff7a9f |
| 13 | * code-string #9dffa8 |
| 14 | * code-number #ffb86b |
| 15 | * code-fn #5b9fff |
| 16 | */ |
| 17 | const BRIVEN_DARK = { |
| 18 | bg: '0a0b0d', |
| 19 | text: 'f5f7fa', |
| 20 | primary: '00e87a', |
| 21 | comment: '6b7280', |
| 22 | keyword: 'ff7a9f', |
| 23 | string: '9dffa8', |
| 24 | number: 'ffb86b', |
| 25 | fn: '5b9fff', |
| 26 | } |
| 27 | |
| 28 | const BRIVEN_LIGHT = { |
| 29 | bg: 'f5f7fa', |
| 30 | text: '0a0b0d', |
| 31 | primary: '00c968', |
| 32 | comment: '6b7280', |
| 33 | keyword: 'd1265f', |
| 34 | string: '0a8b3a', |
| 35 | number: 'b85a00', |
| 36 | fn: '2e5fbf', |
| 37 | } |
| 38 | |
| 39 | export const getTheme = (theme: string) => { |
| 40 | const isDarkMode = theme.includes('dark') |
| 41 | const p = isDarkMode ? BRIVEN_DARK : BRIVEN_LIGHT |
| 42 | return { |
| 43 | base: isDarkMode ? ('vs-dark' as const) : ('vs' as const), |
| 44 | inherit: true, |
| 45 | rules: [ |
| 46 | { token: '', background: p.bg, foreground: p.text }, |
| 47 | { token: 'comment', foreground: p.comment, fontStyle: 'italic' }, |
| 48 | { token: 'string', foreground: p.string }, |
| 49 | { token: 'string.sql', foreground: p.string }, |
| 50 | { token: 'number', foreground: p.number }, |
| 51 | { token: 'keyword', foreground: p.keyword }, |
| 52 | { token: 'keyword.sql', foreground: p.keyword }, |
| 53 | { token: 'predefined.sql', foreground: p.fn }, |
| 54 | { token: 'operator.sql', foreground: p.primary }, |
| 55 | { token: 'identifier', foreground: p.text }, |
| 56 | { token: 'delimiter', foreground: p.text }, |
| 57 | ], |
| 58 | colors: { |
| 59 | 'editor.background': `#${p.bg}`, |
| 60 | 'editor.foreground': `#${p.text}`, |
| 61 | 'editorCursor.foreground': `#${p.primary}`, |
| 62 | 'editorLineNumber.foreground': `#${p.comment}`, |
| 63 | 'editorLineNumber.activeForeground': `#${p.text}`, |
| 64 | 'editor.selectionBackground': `#${p.primary}33`, |
| 65 | 'editor.lineHighlightBackground': isDarkMode ? '#13151a' : '#e8eaef', |
| 66 | }, |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | /** |
| 71 | * This component is used to set the theme for the Monaco editor. This would be a hook but it needs to be placed between |
| 72 | * ThemeProvider and the layout page so a component is the most convenient way to do this. |
| 73 | */ |
| 74 | export const MonacoThemeProvider = () => { |
| 75 | const monaco = useMonaco() |
| 76 | const { resolvedTheme } = useTheme() |
| 77 | |
| 78 | // Define the briven theme for Monaco before anything is rendered. Using useEffect would sometime load the theme |
| 79 | // after the editor was loaded, so it looked off. useMemo will always be run before rendering |
| 80 | useMemo(() => { |
| 81 | if (monaco && resolvedTheme) { |
| 82 | const mode = getTheme(resolvedTheme) |
| 83 | monaco.editor.defineTheme('briven', mode) |
| 84 | } |
| 85 | }, [resolvedTheme, monaco]) |
| 86 | |
| 87 | return null |
| 88 | } |