From 52a0fbf6a9b0143c78985c556887be1d3040b571 Mon Sep 17 00:00:00 2001 From: Luck Date: Mon, 8 May 2023 21:18:58 +0100 Subject: [PATCH] Add some more themes --- package.json | 4 +- src/components/EditorGlobalStyle.tsx | 2 +- src/components/EditorTextArea.tsx | 10 +- src/style/themes.ts | 360 +++++++++++++-------------- yarn.lock | 18 +- 5 files changed, 202 insertions(+), 192 deletions(-) diff --git a/package.json b/package.json index 75998ac..4b45ce1 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "copy-to-clipboard": "^3.3.1", "history": "^5.0.0", "local-storage": "^2.0.0", + "monaco-themes": "^0.4.4", "pako": "^2.0.3", "react": "^18.2.0", "react-device-detect": "^2.1.2", @@ -36,7 +37,8 @@ "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", - "format": "prettier --write '**/*.ts' '**/*.tsx' '**/*.css'" + "format": "prettier --write '**/*.ts' '**/*.tsx' '**/*.css'", + "compile": "tsc" }, "eslintConfig": { "extends": [ diff --git a/src/components/EditorGlobalStyle.tsx b/src/components/EditorGlobalStyle.tsx index cb19cac..bc4ce33 100644 --- a/src/components/EditorGlobalStyle.tsx +++ b/src/components/EditorGlobalStyle.tsx @@ -5,7 +5,7 @@ const EditorGlobalStyle = createGlobalStyle>` html, body { color-scheme: ${props => props.theme.lightOrDark}; scrollbar-color: ${props => props.theme.lightOrDark}; - background-color: ${props => props.theme.editor.background}; + background-color: ${props => props.theme.background}; } `; diff --git a/src/components/EditorTextArea.tsx b/src/components/EditorTextArea.tsx index 3875ade..4a7630a 100644 --- a/src/components/EditorTextArea.tsx +++ b/src/components/EditorTextArea.tsx @@ -13,7 +13,7 @@ import React, { useState, } from 'react'; import styled from 'styled-components'; -import themes, { makeMonacoTheme, Theme } from '../style/themes'; +import themes, { Theme } from '../style/themes'; import type { editor } from 'monaco-editor'; import { ResetFunction } from './Editor'; @@ -56,8 +56,8 @@ export default function EditorTextArea({ usePlaceholderText(actualContent, editor, monaco); const beforeMount: BeforeMount = monaco => { - for (const [id, theme] of Object.entries(themes)) { - monaco.editor.defineTheme(id, makeMonacoTheme(theme)); + for (const theme of Object.values(themes) as Theme[]) { + monaco.editor.defineTheme(theme.id, theme.editor); } monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({ @@ -149,8 +149,8 @@ const EditorArea = styled.main` } .highlighted-line + div { - color: ${props => props.theme.editor.lineNumberHl}; - background-color: ${props => props.theme.editor.lineNumberHlBackground}; + color: ${props => props.theme.highlightedLine.color}; + background-color: ${props => props.theme.highlightedLine.backgroundColor}; font-weight: bold; } diff --git a/src/style/themes.ts b/src/style/themes.ts index e47f54c..d390066 100644 --- a/src/style/themes.ts +++ b/src/style/themes.ts @@ -1,215 +1,211 @@ import type { editor } from 'monaco-editor'; +import dracula from 'monaco-themes/themes/Dracula.json'; +import monokai from 'monaco-themes/themes/Monokai.json'; +import solarizedDark from 'monaco-themes/themes/Solarized-dark.json'; +import solarizedLight from 'monaco-themes/themes/Solarized-light.json'; + +type Color = `#${string}`; + export interface Theme { id: string; - primary: string; - secondary: string; - highlight: string; - lightOrDark: string; - - editor: { - background: string; - lineNumber: string; - lineNumberHl: string; - lineNumberHlBackground: string; - primary: string; - selection: string; - comment: string; - commentTag: string; - punctuation: string; - annotation: string; - namespace: string; - property: string; - constant: string; - number: string; - selector: string; - operator: string; - keyword: string; - function: string; - className: string; - variable: string; + primary: Color; + secondary: Color; + highlight: Color; + background: Color; + lightOrDark: 'light' | 'dark'; + highlightedLine: { + color: Color; + backgroundColor: Color; }; + editor: editor.IStandaloneThemeData; } export interface Themes { - light: Theme; - blue: Theme; - dark: Theme; + 'dark': Theme; + 'light': Theme; + 'dracula': Theme; + 'monokai': Theme; + 'solarized': Theme; + 'solarized-light': Theme; } const themes: Themes = { - light: { - id: 'light', - primary: '#aaddff', - secondary: '#022550', - highlight: '#36368c', - lightOrDark: 'light', - - editor: { - background: '#ffffff', - lineNumber: '#cccccc', - lineNumberHl: '#000000', - lineNumberHlBackground: '#e0f6ff', - primary: '#000000', - selection: '#b3d4fc', - comment: '#708090', - commentTag: '#A082BD', - punctuation: '#999999', - annotation: '#999999', - namespace: '#708090', - property: '#ee9900', - constant: '#990055', - number: '#990055', - selector: '#669900', - operator: '#9a6e3a', - keyword: '#0077aa', - function: '#DD4A68', - className: '#DD4A68', - variable: '#ee9900', - }, - }, - blue: { - id: 'blue', - primary: '#022550', - secondary: '#aaddff', - highlight: '#77c8f9', - lightOrDark: 'dark', - - editor: { - background: '#041f29', - lineNumber: '#81969A', - lineNumberHl: '#ffffff', - lineNumberHlBackground: '#0e303e', - primary: '#E0E2E4', - selection: '#E0E2E4', - comment: '#7D8C93', - commentTag: '#A082BD', - punctuation: '#E8E2B7', - annotation: '#00FFF8', - namespace: '#7CA8CF', - property: '#ee9900', - constant: '#F77669', - number: '#FFCD22', - selector: '#E2B671', - operator: '#E8E2B7', - keyword: '#1CCBEF', - function: '#BCBCBC', - className: '#82CF75', - variable: '#ee9900', - }, - }, - dark: { + 'dark': { id: 'dark', primary: '#c9d1d9', // fg.default secondary: '#010409', // canvas.inset highlight: '#161b22', // canvas.overlay + background: '#0d1117', // canvas.default lightOrDark: 'dark', - editor: { - background: '#0d1117', // canvas.default - lineNumber: '#484f58', // fg.subtle - lineNumberHl: '#f0f6fc', // fg.onEmphasis - lineNumberHlBackground: '#161b22', // canvas.overlay - primary: '#c9d1d9', // fg.default - selection: '#c9d1d9', // fg.default - comment: '#8b949e', - commentTag: '#79c0ff', - punctuation: '#d2a8ff', - annotation: '#a5d6ff', - namespace: '#c9d1d9', - property: '#7ee787', - constant: '#ff7b72', - number: '#f2cc60', - selector: '#79c0ff', - operator: '#ff7b72', - keyword: '#ff7b72', - function: '#e2c5ff', - className: '#ffa657', - variable: '#ffa657', + highlightedLine: { + color: '#f0f6fc', // fg.onEmphasis + backgroundColor: '#161b22', // canvas.overlay }, + + editor: makeMonacoTheme({ + base: 'vs-dark', + colors: { + primary: '#c9d1d9', // fg.default + background: '#0d1117', // canvas.default + comment: '#8b949e', + delimiter: '#d2a8ff', + annotation: '#a5d6ff', + constant: '#ff7b72', + number: '#f2cc60', + string: '#79c0ff', + operator: '#ff7b72', + keyword: '#ff7b72', + type: '#ffa657', + variable: '#ffa657', + }, + }), + }, + 'light': { + id: 'light', + primary: '#aaddff', + secondary: '#022550', + highlight: '#36368c', + background: '#ffffff', + lightOrDark: 'light', + + highlightedLine: { + color: '#000000', + backgroundColor: '#e0f6ff', + }, + + editor: makeMonacoTheme({ + base: 'vs', + colors: { + primary: '#000000', + background: '#ffffff', + comment: '#708090', + delimiter: '#999999', + annotation: '#999999', + constant: '#990055', + number: '#990055', + string: '#669900', + operator: '#9a6e3a', + keyword: '#0077aa', + type: '#DD4A68', + variable: '#ee9900', + }, + }), + }, + 'dracula': { + id: 'dracula', + primary: '#f8f8f2', + secondary: '#383a59', + highlight: '#44475a', + background: '#282a36', + lightOrDark: 'dark', + highlightedLine: { + color: '#586e75', + backgroundColor: '#44475a', + }, + editor: dracula as editor.IStandaloneThemeData, + }, + 'monokai': { + id: 'monokai', + primary: '#F8F8F2', + secondary: '#222218', + highlight: '#49483E', + background: '#272822', + lightOrDark: 'dark', + highlightedLine: { + color: '#49483E', + backgroundColor: '#3E3D32', + }, + editor: monokai as editor.IStandaloneThemeData, + }, + 'solarized': { + id: 'solarized', + primary: '#839496', // base0 + secondary: '#073642', // base02 + highlight: '#002b36', // base03 + background: '#002B36', // base03 + lightOrDark: 'dark', + highlightedLine: { + color: '#93a1a1', // base1 + backgroundColor: '#073642', // base02 + }, + editor: solarizedDark as editor.IStandaloneThemeData, + }, + 'solarized-light': { + id: 'solarized-light', + primary: '#586E75', // base01 + secondary: '#eee8d5', // base2 + highlight: '#FDF6E3', // base3 + background: '#FDF6E3', // base3 + lightOrDark: 'light', + highlightedLine: { + color: '#586e75', // base01 + backgroundColor: '#eee8d5', // base2 + }, + editor: solarizedLight as editor.IStandaloneThemeData, }, }; export default themes; -export function makeMonacoTheme(theme: Theme): editor.IStandaloneThemeData { +interface MonacoThemeProps { + base: 'vs' | 'vs-dark'; + colors: { + primary: Color; + background: Color; + string: Color; + comment: Color; + delimiter: Color; + annotation: Color; + constant: Color; + number: Color; + operator: Color; + keyword: Color; + type: Color; + variable: Color; + }; +} + +export function makeMonacoTheme( + props: MonacoThemeProps +): editor.IStandaloneThemeData { + const colors = Object.fromEntries( + Object.entries(props.colors).map(([key, color]) => [ + key, + color.substring(1), + ]) + ) as Record; + return { - base: theme.lightOrDark === 'light' ? 'vs' : 'vs-dark', + base: props.base, inherit: true, rules: [ { - token: '', // minimap - foreground: theme.editor.primary.substring(1), - background: theme.editor.background.substring(1), - }, - { - token: 'string', - foreground: theme.editor.selector.substring(1), - }, - { - token: 'keyword', - foreground: theme.editor.keyword.substring(1), - }, - { - token: 'constant', - foreground: theme.editor.constant.substring(1), - }, - { - token: 'number', - foreground: theme.editor.number.substring(1), - }, - { - token: 'annotation', - foreground: theme.editor.annotation.substring(1), - }, - { - token: 'variable', - foreground: theme.editor.variable.substring(1), - }, - { - token: 'operator', - foreground: theme.editor.operator.substring(1), - }, - { - token: 'operators', - foreground: theme.editor.operator.substring(1), - }, - { - token: 'punctuation', - foreground: theme.editor.operator.substring(1), - }, - { - token: 'delimiter', - foreground: theme.editor.punctuation.substring(1), - }, - { - token: 'delimiter.square', - foreground: theme.editor.punctuation.substring(1), - }, - { - token: 'delimiter.bracket', - foreground: theme.editor.punctuation.substring(1), - }, - { - token: 'delimiter.parenthesis', - foreground: theme.editor.punctuation.substring(1), - }, - { - token: 'identifier', - foreground: theme.editor.primary.substring(1), - }, - { - token: 'type', - foreground: theme.editor.className.substring(1), - }, - { - token: 'comment', - foreground: theme.editor.comment.substring(1), + token: '' /* minimap */, + foreground: colors.primary, + background: colors.background, }, + { token: 'string', foreground: colors.string }, + { token: 'keyword', foreground: colors.keyword }, + { token: 'constant', foreground: colors.constant }, + { token: 'number', foreground: colors.number }, + { token: 'annotation', foreground: colors.annotation }, + { token: 'variable', foreground: colors.variable }, + { token: 'operator', foreground: colors.operator }, + { token: 'operators', foreground: colors.operator }, + { token: 'punctuation', foreground: colors.operator }, + { token: 'delimiter', foreground: colors.delimiter }, + { token: 'delimiter.square', foreground: colors.delimiter }, + { token: 'delimiter.bracket', foreground: colors.delimiter }, + { token: 'delimiter.parenthesis', foreground: colors.delimiter }, + { token: 'identifier', foreground: colors.primary }, + { token: 'type', foreground: colors.type }, + { token: 'comment', foreground: colors.comment }, ], colors: { - 'editor.background': theme.editor.background, - 'editor.foreground': theme.editor.primary, + 'editor.background': `#${colors.background}`, + 'editor.foreground': `#${colors.primary}`, }, }; } diff --git a/yarn.lock b/yarn.lock index c149258..9513e47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3163,9 +3163,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001370, caniuse-lite@^1.0.30001373: - version "1.0.30001388" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001388.tgz#88e01f4591cbd81f9f665f3f078c66b509fbe55d" - integrity sha512-znVbq4OUjqgLxMxoNX2ZeeLR0d7lcDiE5uJ4eUiWdml1J1EkxbnQq6opT9jb9SMfJxB0XA16/ziHwni4u1I3GQ== + version "1.0.30001486" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001486.tgz" + integrity sha512-uv7/gXuHi10Whlj0pp5q/tsK/32J2QSqVRKQhs2j8VsDCjgyruAh/eEXHF822VqO9yT6iZKw3nRwZRSPBE9OQg== case-sensitive-paths-webpack-plugin@^2.4.0: version "2.4.0" @@ -4554,6 +4554,11 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-plist@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/fast-plist/-/fast-plist-0.1.3.tgz#328cd9335e93a2479ac90814a1302437574ea925" + integrity sha512-d9cEfo/WcOezgPLAC/8t8wGb6YOD6JTCPMw2QcG2nAdFmyY+9rTUizCTaGjIZAloWENTEUMAPpkUAIJJJ0i96A== + fastq@^1.6.0: version "1.13.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" @@ -6519,6 +6524,13 @@ monaco-editor@^0.34.1: resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.34.1.tgz#1b75c4ad6bc4c1f9da656d740d98e0b850a22f87" integrity sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ== +monaco-themes@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/monaco-themes/-/monaco-themes-0.4.4.tgz#28ab13e538c4867a9bc89dc67f15dfaf3fc69de1" + integrity sha512-Hbb9pvRrpSi0rZezcB/IOdQnpx10o55Lx4zFdRAAVpFMa1HP7FgaqEZdKffb4ovd90fETCixeFO9JPYFMAq+TQ== + dependencies: + fast-plist "^0.1.3" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"