Feat(Theme): Support dark mode
This commit is contained in:
@@ -1,89 +0,0 @@
|
||||
.keyframes(@animationName, @content) {
|
||||
animation-name: @animationName;
|
||||
@-webkit-keyframes @animationName {
|
||||
@content();
|
||||
}
|
||||
@-moz-keyframes @animationName {
|
||||
@content();
|
||||
}
|
||||
@-o-keyframes @animationName {
|
||||
@content();
|
||||
}
|
||||
@keyframes @animationName {
|
||||
@content();
|
||||
}
|
||||
}
|
||||
|
||||
.root {
|
||||
position: relative;
|
||||
height: 0;
|
||||
|
||||
:global .monaco-editor-light {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: var(--border);
|
||||
|
||||
.jsx-tag-angle-bracket {
|
||||
color: #800000;
|
||||
}
|
||||
|
||||
.jsx-text {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.jsx-tag-name {
|
||||
color: #800000;
|
||||
}
|
||||
|
||||
.jsx-tag-attribute-key {
|
||||
color: #f00;
|
||||
}
|
||||
}
|
||||
|
||||
:global .monaco-editor-vs-dark {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: var(--border);
|
||||
|
||||
.jsx-tag-angle-bracket {
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
.jsx-text {
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.jsx-tag-name {
|
||||
color: #569cd6;
|
||||
}
|
||||
|
||||
.jsx-tag-attribute-key {
|
||||
color: #9cdcfe;
|
||||
}
|
||||
}
|
||||
|
||||
.playgroundCodeEditorLoading {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 4px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
border-top: 2px #666 solid;
|
||||
border-right: 2px #ddd solid;
|
||||
border-bottom: 2px #ddd solid;
|
||||
border-left: 2px #ddd solid;
|
||||
animation: .6s linear infinite;
|
||||
|
||||
.keyframes(fUHD7o, {
|
||||
0% {
|
||||
transform: rotateZ(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotateZ(360deg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
53
src/components/Playground/CodeEditor/Editor/index.style.ts
Normal file
53
src/components/Playground/CodeEditor/Editor/index.style.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { createStyles, keyframes } from 'antd-style'
|
||||
|
||||
const rotate = keyframes`
|
||||
0% {
|
||||
transform: rotateZ(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotateZ(360deg);
|
||||
}
|
||||
`
|
||||
|
||||
export default createStyles(() => ({
|
||||
root: {
|
||||
position: 'relative',
|
||||
height: 0,
|
||||
|
||||
'.monaco-editor-light': {
|
||||
height: '100%',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: 'var(--border)',
|
||||
'.jsx-tag-angle-bracket': { color: '#800000' },
|
||||
'.jsx-text': { color: '#000' },
|
||||
'.jsx-tag-name': { color: '#800000' },
|
||||
'.jsx-tag-attribute-key': { color: '#f00' }
|
||||
},
|
||||
|
||||
'.monaco-editor-dark': {
|
||||
height: '100%',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: 'var(--border)',
|
||||
'.jsx-tag-angle-bracket': { color: '#808080' },
|
||||
'.jsx-text': { color: '#d4d4d4' },
|
||||
'.jsx-tag-name': { color: '#569cd6' },
|
||||
'.jsx-tag-attribute-key': { color: '#9cdcfe' }
|
||||
}
|
||||
},
|
||||
|
||||
loading: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
margin: 4,
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: '50%',
|
||||
borderTop: '2px #666 solid',
|
||||
borderRight: '2px #ddd solid',
|
||||
borderBottom: '2px #ddd solid',
|
||||
borderLeft: '2px #ddd solid',
|
||||
animation: `${rotate} .6s linear infinite`
|
||||
}
|
||||
}))
|
||||
@@ -1,8 +1,8 @@
|
||||
import { editor, Selection } from 'monaco-editor'
|
||||
import MonacoEditor, { Monaco } from '@monaco-editor/react'
|
||||
import styles from '@/components/Playground/CodeEditor/Editor/index.module.less'
|
||||
import useStyles from '@/components/Playground/CodeEditor/Editor/index.style'
|
||||
import '@/components/Playground/CodeEditor/Editor/loader'
|
||||
import { IEditorOptions, IFiles, ITheme, ITsconfig } from '@/components/Playground/shared'
|
||||
import { IEditorOptions, IFiles, ITsconfig } from '@/components/Playground/shared'
|
||||
import { fileNameToLanguage, tsconfigJsonDiagnosticsOptions } from '@/components/Playground/files'
|
||||
import { useEditor, useTypesProgress } from '@/components/Playground/CodeEditor/Editor/hooks'
|
||||
import { MonacoEditorConfig } from '@/components/Playground/CodeEditor/Editor/monacoConfig'
|
||||
@@ -13,28 +13,29 @@ export interface ExtraLib {
|
||||
}
|
||||
|
||||
interface EditorProps {
|
||||
isDarkMode?: boolean
|
||||
tsconfig?: ITsconfig
|
||||
files?: IFiles
|
||||
selectedFileName?: string
|
||||
readonly?: boolean
|
||||
onChange?: (code: string | undefined) => void
|
||||
options?: IEditorOptions
|
||||
theme?: ITheme
|
||||
onJumpFile?: (fileName: string) => void
|
||||
extraLibs?: ExtraLib[]
|
||||
}
|
||||
|
||||
const Editor = ({
|
||||
isDarkMode,
|
||||
tsconfig,
|
||||
files = {},
|
||||
selectedFileName = '',
|
||||
readonly,
|
||||
theme,
|
||||
onChange,
|
||||
options,
|
||||
onJumpFile,
|
||||
extraLibs = []
|
||||
}: EditorProps) => {
|
||||
const { styles } = useStyles()
|
||||
const editorRef = useRef<editor.IStandaloneCodeEditor>()
|
||||
const monacoRef = useRef<Monaco>()
|
||||
const { doOpenEditor, loadJsxSyntaxHighlight, autoLoadExtraLib } = useEditor()
|
||||
@@ -114,9 +115,9 @@ const Editor = ({
|
||||
<>
|
||||
<div className={styles.root}>
|
||||
<MonacoEditor
|
||||
theme={theme}
|
||||
theme={isDarkMode ? 'vs-dark' : 'light'}
|
||||
path={file.name}
|
||||
className={`monaco-editor-${theme ?? 'light'}`}
|
||||
className={`monaco-editor-${isDarkMode ? 'dark' : 'light'}`}
|
||||
language={file.language}
|
||||
value={file.value}
|
||||
onChange={onChange}
|
||||
@@ -129,7 +130,7 @@ const Editor = ({
|
||||
readOnly: readonly
|
||||
}}
|
||||
/>
|
||||
{total > 0 && !finished && <div className={styles.playgroundCodeEditorLoading} />}
|
||||
{total > 0 && !finished && <div className={styles.loading} />}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Dispatch, SetStateAction, KeyboardEvent, ChangeEvent, MouseEvent } from 'react'
|
||||
import styles from '@/components/Playground/CodeEditor/FileSelector/item.module.less'
|
||||
import useStyles from '@/components/Playground/CodeEditor/FileSelector/item.style'
|
||||
|
||||
interface ItemProps {
|
||||
className?: string
|
||||
@@ -30,6 +30,7 @@ const Item = ({
|
||||
onValidate,
|
||||
...prop
|
||||
}: ItemProps) => {
|
||||
const { styles, cx } = useStyles()
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const [fileName, setFileName] = useState(value)
|
||||
const [isCreating, setIsCreating] = useState(prop.creating)
|
||||
@@ -110,7 +111,7 @@ const Item = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${styles.root}${active ? ` ${styles.active}` : ''}${className ? ` ${className}` : ''}`}
|
||||
className={cx(styles.root, active ? styles.active : '', className)}
|
||||
onClick={handleOnClick}
|
||||
>
|
||||
{isCreating ? (
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
.root{
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
height: 40px;
|
||||
|
||||
.multiple {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
|
||||
.tabContent {
|
||||
height: 40px;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
margin-left: 10px;
|
||||
|
||||
.tabItemAdd {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.tabsMarginRight {
|
||||
height: 100%;
|
||||
|
||||
> * {
|
||||
height: 100%;
|
||||
width: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sticky {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: flex-end;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { createStyles } from 'antd-style'
|
||||
|
||||
export default createStyles(() => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flex: '0 0 auto',
|
||||
height: 40
|
||||
},
|
||||
|
||||
multiple: {
|
||||
flex: 1,
|
||||
width: 0
|
||||
},
|
||||
|
||||
tabContent: {
|
||||
height: 40,
|
||||
alignItems: 'flex-end',
|
||||
gap: 2,
|
||||
marginLeft: 10
|
||||
},
|
||||
|
||||
tabItemAdd: {
|
||||
padding: '0 12px'
|
||||
},
|
||||
|
||||
tabsMarginRight: {
|
||||
height: '100%',
|
||||
|
||||
'> *': {
|
||||
height: '100%',
|
||||
width: 10
|
||||
}
|
||||
},
|
||||
|
||||
sticky: {
|
||||
display: 'flex',
|
||||
flex: '0 0 auto',
|
||||
alignItems: 'flex-end',
|
||||
marginRight: 10
|
||||
}
|
||||
}))
|
||||
@@ -1,4 +1,4 @@
|
||||
import styles from '@/components/Playground/CodeEditor/FileSelector/index.module.less'
|
||||
import useStyles from '@/components/Playground/CodeEditor/FileSelector/index.style'
|
||||
import HideScrollbar, { HideScrollbarElement } from '@/components/common/HideScrollbar'
|
||||
import FlexBox from '@/components/common/FlexBox'
|
||||
import { IFiles } from '@/components/Playground/shared'
|
||||
@@ -32,6 +32,7 @@ const FileSelector = ({
|
||||
onUpdateFileName,
|
||||
selectedFileName = ''
|
||||
}: FileSelectorProps) => {
|
||||
const { styles } = useStyles()
|
||||
const hideScrollbarRef = useRef<HideScrollbarElement>(null)
|
||||
const [tabs, setTabs] = useState<string[]>([])
|
||||
const [isCreating, setIsCreating] = useState(false)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
.root {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 auto;
|
||||
height: 30px;
|
||||
padding: 0 20px;
|
||||
border: 1px solid #f0f0f0;
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
border-radius: 6px 6px 0 0;
|
||||
cursor: pointer;
|
||||
|
||||
.tabItemInput {
|
||||
position: relative;
|
||||
min-width: 40px;
|
||||
transform: translateY(1px);
|
||||
|
||||
.tabItemInputMask {
|
||||
display: inline-block;
|
||||
color: transparent;
|
||||
}
|
||||
input {
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
width: 100%;
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.tabItemClose {
|
||||
transform: translateX(10px);
|
||||
|
||||
:hover {
|
||||
fill: #888;
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 8px;
|
||||
fill: #666;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: white;
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { createStyles } from 'antd-style'
|
||||
|
||||
export default createStyles(({ token }) => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flex: '0 0 auto',
|
||||
height: 30,
|
||||
padding: '0 20px',
|
||||
color: token.colorText,
|
||||
border: `1px solid ${token.colorBorder}`,
|
||||
backgroundColor: token.colorBgLayout,
|
||||
borderRadius: '6px 6px 0 0',
|
||||
cursor: 'pointer'
|
||||
},
|
||||
|
||||
active: {
|
||||
backgroundColor: token.colorBgElevated,
|
||||
borderBottom: 'none'
|
||||
},
|
||||
|
||||
tabItemInput: {
|
||||
position: 'relative',
|
||||
minWidth: 40,
|
||||
transform: 'translateY(1px)',
|
||||
|
||||
input: {
|
||||
position: 'absolute',
|
||||
backgroundColor: 'transparent',
|
||||
width: '100%',
|
||||
color: token.colorText,
|
||||
fontSize: token.fontSizeSM
|
||||
}
|
||||
},
|
||||
|
||||
tabItemInputMask: {
|
||||
display: 'inline-block',
|
||||
color: 'transparent'
|
||||
},
|
||||
|
||||
tabItemClose: {
|
||||
transform: 'translateX(10px)',
|
||||
|
||||
svg: {
|
||||
height: token.sizeXS,
|
||||
fill: token.colorTextSecondary
|
||||
},
|
||||
|
||||
'>:hover': {
|
||||
fill: token.colorTextDescription
|
||||
}
|
||||
}
|
||||
}))
|
||||
@@ -1,15 +0,0 @@
|
||||
.root {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.errorMessage {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
color: white;
|
||||
background-color: #FF4D4FAA;
|
||||
padding: 5px 10px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
19
src/components/Playground/CodeEditor/index.style.ts
Normal file
19
src/components/Playground/CodeEditor/index.style.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { createStyles } from 'antd-style'
|
||||
|
||||
export default createStyles(({ token }) => ({
|
||||
root: {
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
},
|
||||
|
||||
errorMessage: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
color: token.colorErrorText,
|
||||
backgroundColor: token.colorErrorBg,
|
||||
padding: '5px 10px',
|
||||
fontSize: token.fontSize
|
||||
}
|
||||
}))
|
||||
@@ -1,7 +1,7 @@
|
||||
import _ from 'lodash'
|
||||
import styles from '@/components/Playground/CodeEditor/index.module.less'
|
||||
import useStyles from '@/components/Playground/CodeEditor/index.style'
|
||||
import FlexBox from '@/components/common/FlexBox'
|
||||
import { IEditorOptions, IFiles, ITheme, ITsconfig } from '@/components/Playground/shared'
|
||||
import { IEditorOptions, IFiles, ITsconfig } from '@/components/Playground/shared'
|
||||
import {
|
||||
fileNameToLanguage,
|
||||
getFileNameList,
|
||||
@@ -12,7 +12,7 @@ import FileSelector from '@/components/Playground/CodeEditor/FileSelector'
|
||||
import Editor, { ExtraLib } from '@/components/Playground/CodeEditor/Editor'
|
||||
|
||||
interface CodeEditorProps {
|
||||
theme?: ITheme
|
||||
isDarkMode?: boolean
|
||||
showFileSelector?: boolean
|
||||
tsconfig?: ITsconfig
|
||||
files: IFiles
|
||||
@@ -31,7 +31,7 @@ interface CodeEditorProps {
|
||||
}
|
||||
|
||||
const CodeEditor = ({
|
||||
theme,
|
||||
isDarkMode,
|
||||
showFileSelector = true,
|
||||
tsconfig,
|
||||
files,
|
||||
@@ -48,6 +48,7 @@ const CodeEditor = ({
|
||||
extraLibs,
|
||||
...props
|
||||
}: CodeEditorProps) => {
|
||||
const { styles } = useStyles()
|
||||
const filteredFilesName = getFileNameList(files).filter(
|
||||
(item) => ![IMPORT_MAP_FILE_NAME, TS_CONFIG_FILE_NAME].includes(item) && !files[item].hidden
|
||||
)
|
||||
@@ -139,8 +140,8 @@ const CodeEditor = ({
|
||||
/>
|
||||
)}
|
||||
<Editor
|
||||
isDarkMode={isDarkMode}
|
||||
tsconfig={tsconfig}
|
||||
theme={theme}
|
||||
selectedFileName={
|
||||
onSelectedFileChange ? propsSelectedFileName : selectedFileName
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user