Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Show diff files with monaco
  • Loading branch information
BrunoQuaresma committed Dec 6, 2022
commit fc414bc0840df01d337f05ff48ca299b969a4a4e
1 change: 1 addition & 0 deletions site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@material-ui/core": "4.12.1",
"@material-ui/icons": "4.5.1",
"@material-ui/lab": "4.0.0-alpha.42",
"@monaco-editor/react": "^4.4.6",
"@testing-library/react-hooks": "8.0.1",
"@vitejs/plugin-react": "2.1.0",
"@xstate/inspect": "0.6.5",
Expand Down
86 changes: 32 additions & 54 deletions site/src/components/SyntaxHighlighter/SyntaxHighlighter.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,36 @@
import { makeStyles } from "@material-ui/core/styles"
import { ComponentProps, FC } from "react"
import { Prism } from "react-syntax-highlighter"
import { colors } from "theme/colors"
import darcula from "react-syntax-highlighter/dist/cjs/styles/prism/darcula"
import { combineClasses } from "util/combineClasses"

export const SyntaxHighlighter: FC<ComponentProps<typeof Prism>> = ({
className,
...props
}) => {
const styles = useStyles()

return (
<Prism
style={darcula}
useInlineStyles={false}
// Use inline styles does not work correctly
// https://github.com/react-syntax-highlighter/react-syntax-highlighter/issues/329
codeTagProps={{ style: {} }}
className={combineClasses([styles.prism, className])}
{...props}
/>
)
}

const useStyles = makeStyles((theme) => ({
prism: {
margin: 0,
background: theme.palette.background.paperLight,
borderRadius: theme.shape.borderRadius,
padding: theme.spacing(2, 3),
// Line breaks are broken when used with line numbers on react-syntax-highlighter
// https://github.com/react-syntax-highlighter/react-syntax-highlighter/pull/483
overflowX: "auto",

"& code": {
color: theme.palette.text.secondary,
import { FC } from "react"
import Editor, { DiffEditor } from "@monaco-editor/react"
import { useCoderTheme } from "./coderTheme"

export const SyntaxHighlighter: FC<{
value: string
language: string
compareWith?: string
}> = ({ value, compareWith, language }) => {
const hasDiff = compareWith && value !== compareWith
const coderTheme = useCoderTheme()
const commonProps = {
language,
theme: coderTheme.name,
height: 560,
options: {
minimap: {
enabled: false,
},
renderSideBySide: false,
readOnly: true,
},
}

"& .key, & .property, & .code-snippet, & .keyword": {
color: colors.turquoise[7],
},
if (coderTheme.isLoading) {
return null
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a loading state?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, it is VERY fast. It is only a few milliseconds to monaco be loaded. From what I was able to inspect there is no networking involved so the "loading time" is "static"


"& .url": {
color: colors.blue[6],
},

"& .comment": {
color: theme.palette.text.disabled,
},
if (hasDiff) {
return (
<DiffEditor original={value} modified={compareWith} {...commonProps} />
)
}

"& .title": {
color: theme.palette.text.primary,
fontWeight: 600,
},
},
}))
return <Editor value={value} {...commonProps} />
}
238 changes: 238 additions & 0 deletions site/src/components/SyntaxHighlighter/coderTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import { Theme, useTheme } from "@material-ui/core/styles"
import { useMonaco } from "@monaco-editor/react"
import { useEffect, useState } from "react"
import { hslToHex } from "util/colors"

// eslint-disable-next-line @typescript-eslint/no-explicit-any -- The theme is not typed
export const coderTheme = (theme: Theme): Record<string, any> => ({
base: "vs-dark",
inherit: true,
rules: [
{
background: "282a36",
token: "",
},
{
foreground: "6272a4",
token: "comment",
},
{
foreground: "f1fa8c",
token: "string",
},
{
foreground: "bd93f9",
token: "constant.numeric",
},
{
foreground: "bd93f9",
token: "constant.language",
},
{
foreground: "bd93f9",
token: "constant.character",
},
{
foreground: "bd93f9",
token: "constant.other",
},
{
foreground: "ffb86c",
token: "variable.other.readwrite.instance",
},
{
foreground: "ff79c6",
token: "constant.character.escaped",
},
{
foreground: "ff79c6",
token: "constant.character.escape",
},
{
foreground: "ff79c6",
token: "string source",
},
{
foreground: "ff79c6",
token: "string source.ruby",
},
{
foreground: "ff79c6",
token: "keyword",
},
{
foreground: "ff79c6",
token: "storage",
},
{
foreground: "8be9fd",
fontStyle: "italic",
token: "storage.type",
},
{
foreground: "50fa7b",
fontStyle: "underline",
token: "entity.name.class",
},
{
foreground: "50fa7b",
fontStyle: "italic underline",
token: "entity.other.inherited-class",
},
{
foreground: "50fa7b",
token: "entity.name.function",
},
{
foreground: "ffb86c",
fontStyle: "italic",
token: "variable.parameter",
},
{
foreground: "ff79c6",
token: "entity.name.tag",
},
{
foreground: "50fa7b",
token: "entity.other.attribute-name",
},
{
foreground: "8be9fd",
token: "support.function",
},
{
foreground: "6be5fd",
token: "support.constant",
},
{
foreground: "66d9ef",
fontStyle: " italic",
token: "support.type",
},
{
foreground: "66d9ef",
fontStyle: " italic",
token: "support.class",
},
{
foreground: "f8f8f0",
background: "ff79c6",
token: "invalid",
},
{
foreground: "f8f8f0",
background: "bd93f9",
token: "invalid.deprecated",
},
{
foreground: "cfcfc2",
token: "meta.structure.dictionary.json string.quoted.double.json",
},
{
foreground: "6272a4",
token: "meta.diff",
},
{
foreground: "6272a4",
token: "meta.diff.header",
},
{
foreground: "ff79c6",
token: "markup.deleted",
},
{
foreground: "50fa7b",
token: "markup.inserted",
},
{
foreground: "e6db74",
token: "markup.changed",
},
{
foreground: "bd93f9",
token: "constant.numeric.line-number.find-in-files - match",
},
{
foreground: "e6db74",
token: "entity.name.filename",
},
{
foreground: "f83333",
token: "message.error",
},
{
foreground: "eeeeee",
token:
"punctuation.definition.string.begin.json - meta.structure.dictionary.value.json",
},
{
foreground: "eeeeee",
token:
"punctuation.definition.string.end.json - meta.structure.dictionary.value.json",
},
{
foreground: "8be9fd",
token: "meta.structure.dictionary.json string.quoted.double.json",
},
{
foreground: "f1fa8c",
token: "meta.structure.dictionary.value.json string.quoted.double.json",
},
{
foreground: "50fa7b",
token:
"meta meta meta meta meta meta meta.structure.dictionary.value string",
},
{
foreground: "ffb86c",
token: "meta meta meta meta meta meta.structure.dictionary.value string",
},
{
foreground: "ff79c6",
token: "meta meta meta meta meta.structure.dictionary.value string",
},
{
foreground: "bd93f9",
token: "meta meta meta meta.structure.dictionary.value string",
},
{
foreground: "50fa7b",
token: "meta meta meta.structure.dictionary.value string",
},
{
foreground: "ffb86c",
token: "meta meta.structure.dictionary.value string",
},
],
colors: {
"editor.foreground": hslToHex(theme.palette.text.secondary),
"editor.background": hslToHex(theme.palette.background.paper),
"editor.selectionBackground": hslToHex(theme.palette.action.hover),
"editor.lineHighlightBackground": hslToHex(
theme.palette.background.paperLight,
),
"editorCursor.foreground": "#f8f8f0",
"editorWhitespace.foreground": "#3B3A32",
"editorIndentGuide.activeBackground": "#9D550FB0",
"editor.selectionHighlightBorder": "#222218",
},
})

export const useCoderTheme = (): { isLoading: boolean; name: string } => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a comment here explaining what this hook/what its scope is might be helpful.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing!

const [isLoading, setIsLoading] = useState(true)
const monaco = useMonaco()
const theme = useTheme<Theme>()
const name = "coder"

useEffect(() => {
if (monaco) {
monaco.editor.defineTheme(name, coderTheme(theme))
setIsLoading(false)
}
}, [monaco, theme])

return {
isLoading,
name,
}
}
Loading