theme.ts 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import { EditorView } from '@codemirror/view'
  2. import { Compartment, TransactionSpec } from '@codemirror/state'
  3. export type FontFamily = 'monaco' | 'lucida'
  4. export type LineHeight = 'compact' | 'normal' | 'wide'
  5. export type Options = {
  6. fontSize: number
  7. fontFamily: FontFamily
  8. lineHeight: LineHeight
  9. }
  10. const optionsThemeConf = new Compartment()
  11. export const theme = (options: Options) => [
  12. baseTheme,
  13. optionsThemeConf.of(createThemeFromOptions(options)),
  14. ]
  15. export const lineHeights: Record<LineHeight, number> = {
  16. compact: 1.33,
  17. normal: 1.6,
  18. wide: 2,
  19. }
  20. const fontFamilies: Record<FontFamily, string[]> = {
  21. monaco: ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'monospace'],
  22. lucida: ['Lucida Console', 'Source Code Pro', 'monospace'],
  23. }
  24. const createThemeFromOptions = ({
  25. fontSize = 12,
  26. fontFamily = 'monaco',
  27. lineHeight = 'normal',
  28. }: Options) => {
  29. // Theme styles that depend on settings
  30. const fontFamilyValue = fontFamilies[fontFamily]?.join(', ')
  31. return [
  32. EditorView.editorAttributes.of({
  33. style: Object.entries({
  34. '--font-size': `${fontSize}px`,
  35. '--source-font-family': fontFamilyValue,
  36. '--line-height': lineHeights[lineHeight],
  37. })
  38. .map(([key, value]) => `${key}: ${value}`)
  39. .join(';'),
  40. }),
  41. // Set variables for tooltips, which are outside the editor
  42. // TODO: set these on document.body, or a new container element for the tooltips, without using a style mod
  43. EditorView.theme({
  44. '.cm-tooltip': {
  45. '--font-size': `${fontSize}px`,
  46. '--source-font-family': fontFamilyValue,
  47. },
  48. }),
  49. ]
  50. }
  51. const baseTheme = EditorView.theme({
  52. '.cm-content': {
  53. fontSize: 'var(--font-size)',
  54. fontFamily: 'var(--source-font-family)',
  55. lineHeight: 'var(--line-height)',
  56. color: '#000',
  57. },
  58. '.cm-gutters': {
  59. fontSize: 'var(--font-size)',
  60. lineHeight: 'var(--line-height)',
  61. },
  62. '.cm-lineNumbers': {
  63. fontFamily: 'var(--source-font-family)',
  64. },
  65. '.cm-tooltip': {
  66. // NOTE: fontFamily is not set here, as most tooltips use the UI font
  67. fontSize: 'var(--font-size)',
  68. },
  69. })
  70. export const setOptionsTheme = (options: Options): TransactionSpec => {
  71. return {
  72. effects: optionsThemeConf.reconfigure(createThemeFromOptions(options)),
  73. }
  74. }