diff --git a/package.json b/package.json index 8f1b0bd..9735041 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@catppuccin/palette": "^1.7.1", "@monaco-editor/react": "^4.6.0", "copy-to-clipboard": "^3.3.3", "history": "^5.3.0", diff --git a/src/style/themes.ts b/src/style/themes.ts index e328a35..6c76f72 100644 --- a/src/style/themes.ts +++ b/src/style/themes.ts @@ -1,11 +1,13 @@ import type { editor } from 'monaco-editor'; +import { CatppuccinFlavor, ColorFormat, flavors } from '@catppuccin/palette'; 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}`; +type ColorRecord = Record; export interface Theme { id: string; @@ -28,6 +30,10 @@ export interface Themes { 'monokai': Theme; 'solarized': Theme; 'solarized-light': Theme; + 'latte': Theme; + 'frappe': Theme; + 'macchiato': Theme; + 'mocha': Theme; } const themes: Themes = { @@ -44,31 +50,34 @@ const themes: Themes = { 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', - logInfo: '#3fb950', // green.3 - logError: '#f85149', // red.4 - logWarning: '#d29922', // yellow.3 - logDate: '#33B3AE', // teal.3 - logException: '#f8e3a1', // yellow.0 - diffMeta: '#33B3AE', // teal.3 - diffAddition: '#3fb950', // green.3 - diffDeletion: '#f85149', // red.4 + 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', + logInfo: '#3fb950', // green.3 + logError: '#f85149', // red.4 + logWarning: '#d29922', // yellow.3 + logDate: '#33B3AE', // teal.3 + logException: '#f8e3a1', // yellow.0 + diffMeta: '#33B3AE', // teal.3 + diffAddition: '#3fb950', // green.3 + diffDeletion: '#f85149', // red.4 + }, }, - }), + {} + ), }, 'light': { id: 'light', @@ -83,31 +92,34 @@ const themes: Themes = { 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', - logInfo: '#2da44e', // green.4 - logError: '#cf222e', // red.5 - logWarning: '#d4a72c', // yellow.3 - logDate: '#136061', // teal.6 - logException: '#7d4e00', // yellow.6 - diffMeta: '#136061', // teal.6 - diffAddition: '#2da44e', // green.4 - diffDeletion: '#cf222e', // red.5 + 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', + logInfo: '#2da44e', // green.4 + logError: '#cf222e', // red.5 + logWarning: '#d4a72c', // yellow.3 + logDate: '#136061', // teal.6 + logException: '#7d4e00', // yellow.6 + diffMeta: '#136061', // teal.6 + diffAddition: '#2da44e', // green.4 + diffDeletion: '#cf222e', // red.5 + }, }, - }), + {} + ), }, 'dracula': { id: 'dracula', @@ -197,6 +209,10 @@ const themes: Themes = { diffDeletion: '#dc322f', // red }), }, + 'latte': createCatppuccinTheme(flavors.latte), + 'frappe': createCatppuccinTheme(flavors.frappe), + 'macchiato': createCatppuccinTheme(flavors.macchiato), + 'mocha': createCatppuccinTheme(flavors.mocha), }; export default themes; @@ -231,7 +247,8 @@ interface MonacoThemeProps { } export function makeMonacoTheme( - props: MonacoThemeProps + props: MonacoThemeProps, + extraColors: ColorRecord ): editor.IStandaloneThemeData { const colors = Object.fromEntries( Object.entries(props.colors).map(([key, color]) => [ @@ -240,6 +257,11 @@ export function makeMonacoTheme( ]) ) as Record; + const editorColors: ColorRecord = { + 'editor.background': `#${colors.background}`, + 'editor.foreground': `#${colors.primary}`, + }; + return { base: props.base, inherit: true, @@ -274,10 +296,7 @@ export function makeMonacoTheme( { token: 'addition.diff', foreground: colors.diffAddition }, { token: 'deletion.diff', foreground: colors.diffDeletion }, ], - colors: { - 'editor.background': `#${colors.background}`, - 'editor.foreground': `#${colors.primary}`, - }, + colors: { ...editorColors, ...extraColors }, }; } @@ -302,3 +321,65 @@ export function addExtraColors( ); return theme; } + +export function createCatppuccinTheme(flavor: CatppuccinFlavor): Theme { + const color = (color: ColorFormat) => color.hex as Color; + const nameToId: Record = { + [flavors.latte.name]: 'latte', + [flavors.frappe.name]: 'frappe', + [flavors.macchiato.name]: 'macchiato', + [flavors.mocha.name]: 'mocha', + }; + + const editorTheme = makeMonacoTheme( + { + base: flavor.dark ? 'vs-dark' : 'vs', + colors: { + // Monaco + primary: color(flavor.colors.text), + background: color(flavor.colors.mantle), + string: color(flavor.colors.green), + comment: color(flavor.colors.overlay2), + delimiter: color(flavor.colors.overlay2), + annotation: color(flavor.colors.yellow), + constant: color(flavor.colors.peach), + number: color(flavor.colors.peach), + operator: color(flavor.colors.sky), + keyword: color(flavor.colors.mauve), + type: color(flavor.colors.yellow), + variable: color(flavor.colors.text), + + // Log Files + logDate: color(flavor.colors.mauve), + logInfo: color(flavor.colors.green), + logWarning: color(flavor.colors.yellow), + logError: color(flavor.colors.red), + logException: color(flavor.colors.yellow), + + // Diff Files + diffMeta: color(flavor.colors.sky), + diffAddition: color(flavor.colors.green), + diffDeletion: color(flavor.colors.red), + }, + }, + { + 'editorBracketHighlight.foreground1': color(flavor.colors.overlay2), + 'editorBracketHighlight.foreground2': color(flavor.colors.overlay2), + 'editorBracketHighlight.foreground3': color(flavor.colors.overlay2), + } + ); + + return { + id: nameToId[flavor.name], + lightOrDark: flavor.dark ? 'dark' : 'light', + primary: color(flavor.colors.text), + secondary: color(flavor.colors.base), + highlight: color(flavor.colors.surface0), + background: color(flavor.colors.mantle), + highlightedLine: { + color: color(flavor.colors.rosewater), + backgroundColor: color(flavor.colors.surface2), + }, + editor: editorTheme, + }; +} diff --git a/yarn.lock b/yarn.lock index 3eec2a4..5235a42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1086,6 +1086,11 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@catppuccin/palette@^1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@catppuccin/palette/-/palette-1.7.1.tgz#c7cd165dcc1fc025a05ac138a4749b2279cf115e" + integrity sha512-aRc1tbzrevOTV7nFTT9SRdF26w/MIwT4Jwt4fDMc9itRZUDXCuEDBLyz4TQMlqO9ZP8mf5Hu4Jr6D03NLFc6Gw== + "@csstools/normalize.css@*": version "12.1.1" resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-12.1.1.tgz#f0ad221b7280f3fc814689786fd9ee092776ef8f" @@ -8727,7 +8732,16 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -8831,7 +8845,14 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -9907,7 +9928,16 @@ workbox-window@6.6.1: "@types/trusted-types" "^2.0.2" workbox-core "6.6.1" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==