|
import { Compartment, type Extension } from '@codemirror/state'; |
|
import { EditorView } from '@codemirror/view'; |
|
import { vscodeDark, vscodeLight } from '@uiw/codemirror-theme-vscode'; |
|
import type { Theme } from '~/types/theme.js'; |
|
import type { EditorSettings } from './CodeMirrorEditor.js'; |
|
|
|
export const darkTheme = EditorView.theme({}, { dark: true }); |
|
export const themeSelection = new Compartment(); |
|
|
|
export function getTheme(theme: Theme, settings: EditorSettings = {}): Extension { |
|
return [ |
|
getEditorTheme(settings), |
|
theme === 'dark' ? themeSelection.of([getDarkTheme()]) : themeSelection.of([getLightTheme()]), |
|
]; |
|
} |
|
|
|
export function reconfigureTheme(theme: Theme) { |
|
return themeSelection.reconfigure(theme === 'dark' ? getDarkTheme() : getLightTheme()); |
|
} |
|
|
|
function getEditorTheme(settings: EditorSettings) { |
|
return EditorView.theme({ |
|
'&': { |
|
fontSize: settings.fontSize ?? '12px', |
|
}, |
|
'&.cm-editor': { |
|
height: '100%', |
|
background: 'var(--cm-backgroundColor)', |
|
color: 'var(--cm-textColor)', |
|
}, |
|
'.cm-cursor': { |
|
borderLeft: 'var(--cm-cursor-width) solid var(--cm-cursor-backgroundColor)', |
|
}, |
|
'.cm-scroller': { |
|
lineHeight: '1.5', |
|
'&:focus-visible': { |
|
outline: 'none', |
|
}, |
|
}, |
|
'.cm-line': { |
|
padding: '0 0 0 4px', |
|
}, |
|
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': { |
|
backgroundColor: 'var(--cm-selection-backgroundColorFocused) !important', |
|
opacity: 'var(--cm-selection-backgroundOpacityFocused, 0.3)', |
|
}, |
|
'&:not(.cm-focused) > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': { |
|
backgroundColor: 'var(--cm-selection-backgroundColorBlured)', |
|
opacity: 'var(--cm-selection-backgroundOpacityBlured, 0.3)', |
|
}, |
|
'&.cm-focused > .cm-scroller .cm-matchingBracket': { |
|
backgroundColor: 'var(--cm-matching-bracket)', |
|
}, |
|
'.cm-activeLine': { |
|
background: 'var(--cm-activeLineBackgroundColor)', |
|
}, |
|
'.cm-gutters': { |
|
background: 'var(--cm-gutter-backgroundColor)', |
|
borderRight: 0, |
|
color: 'var(--cm-gutter-textColor)', |
|
}, |
|
'.cm-gutter': { |
|
'&.cm-lineNumbers': { |
|
fontFamily: 'Roboto Mono, monospace', |
|
fontSize: settings.gutterFontSize ?? settings.fontSize ?? '12px', |
|
minWidth: '40px', |
|
}, |
|
'& .cm-activeLineGutter': { |
|
background: 'transparent', |
|
color: 'var(--cm-gutter-activeLineTextColor)', |
|
}, |
|
'&.cm-foldGutter .cm-gutterElement > .fold-icon': { |
|
cursor: 'pointer', |
|
color: 'var(--cm-foldGutter-textColor)', |
|
transform: 'translateY(2px)', |
|
'&:hover': { |
|
color: 'var(--cm-foldGutter-textColorHover)', |
|
}, |
|
}, |
|
}, |
|
'.cm-foldGutter .cm-gutterElement': { |
|
padding: '0 4px', |
|
}, |
|
'.cm-tooltip-autocomplete > ul > li': { |
|
minHeight: '18px', |
|
}, |
|
'.cm-panel.cm-search label': { |
|
marginLeft: '2px', |
|
fontSize: '12px', |
|
}, |
|
'.cm-panel.cm-search .cm-button': { |
|
fontSize: '12px', |
|
}, |
|
'.cm-panel.cm-search .cm-textfield': { |
|
fontSize: '12px', |
|
}, |
|
'.cm-panel.cm-search input[type=checkbox]': { |
|
position: 'relative', |
|
transform: 'translateY(2px)', |
|
marginRight: '4px', |
|
}, |
|
'.cm-panels': { |
|
borderColor: 'var(--cm-panels-borderColor)', |
|
}, |
|
'.cm-panels-bottom': { |
|
borderTop: '1px solid var(--cm-panels-borderColor)', |
|
backgroundColor: 'transparent', |
|
}, |
|
'.cm-panel.cm-search': { |
|
background: 'var(--cm-search-backgroundColor)', |
|
color: 'var(--cm-search-textColor)', |
|
padding: '8px', |
|
}, |
|
'.cm-search .cm-button': { |
|
background: 'var(--cm-search-button-backgroundColor)', |
|
borderColor: 'var(--cm-search-button-borderColor)', |
|
color: 'var(--cm-search-button-textColor)', |
|
borderRadius: '4px', |
|
'&:hover': { |
|
color: 'var(--cm-search-button-textColorHover)', |
|
}, |
|
'&:focus-visible': { |
|
outline: 'none', |
|
borderColor: 'var(--cm-search-button-borderColorFocused)', |
|
}, |
|
'&:hover:not(:focus-visible)': { |
|
background: 'var(--cm-search-button-backgroundColorHover)', |
|
borderColor: 'var(--cm-search-button-borderColorHover)', |
|
}, |
|
'&:hover:focus-visible': { |
|
background: 'var(--cm-search-button-backgroundColorHover)', |
|
borderColor: 'var(--cm-search-button-borderColorFocused)', |
|
}, |
|
}, |
|
'.cm-panel.cm-search [name=close]': { |
|
top: '6px', |
|
right: '6px', |
|
padding: '0 6px', |
|
fontSize: '1rem', |
|
backgroundColor: 'var(--cm-search-closeButton-backgroundColor)', |
|
color: 'var(--cm-search-closeButton-textColor)', |
|
'&:hover': { |
|
'border-radius': '6px', |
|
color: 'var(--cm-search-closeButton-textColorHover)', |
|
backgroundColor: 'var(--cm-search-closeButton-backgroundColorHover)', |
|
}, |
|
}, |
|
'.cm-search input': { |
|
background: 'var(--cm-search-input-backgroundColor)', |
|
borderColor: 'var(--cm-search-input-borderColor)', |
|
color: 'var(--cm-search-input-textColor)', |
|
outline: 'none', |
|
borderRadius: '4px', |
|
'&:focus-visible': { |
|
borderColor: 'var(--cm-search-input-borderColorFocused)', |
|
}, |
|
}, |
|
'.cm-tooltip': { |
|
background: 'var(--cm-tooltip-backgroundColor)', |
|
border: '1px solid transparent', |
|
borderColor: 'var(--cm-tooltip-borderColor)', |
|
color: 'var(--cm-tooltip-textColor)', |
|
}, |
|
'.cm-tooltip.cm-tooltip-autocomplete ul li[aria-selected]': { |
|
background: 'var(--cm-tooltip-backgroundColorSelected)', |
|
color: 'var(--cm-tooltip-textColorSelected)', |
|
}, |
|
'.cm-searchMatch': { |
|
backgroundColor: 'var(--cm-searchMatch-backgroundColor)', |
|
}, |
|
'.cm-tooltip.cm-readonly-tooltip': { |
|
padding: '4px', |
|
whiteSpace: 'nowrap', |
|
backgroundColor: 'var(--bolt-elements-bg-depth-2)', |
|
borderColor: 'var(--bolt-elements-borderColorActive)', |
|
'& .cm-tooltip-arrow:before': { |
|
borderTopColor: 'var(--bolt-elements-borderColorActive)', |
|
}, |
|
'& .cm-tooltip-arrow:after': { |
|
borderTopColor: 'transparent', |
|
}, |
|
}, |
|
}); |
|
} |
|
|
|
function getLightTheme() { |
|
return vscodeLight; |
|
} |
|
|
|
function getDarkTheme() { |
|
return vscodeDark; |
|
} |
|
|