Feat(Theme): Support dark mode

This commit is contained in:
2024-10-23 10:17:45 +08:00
parent b7c3fb8524
commit dbce6b9cf2
180 changed files with 3478 additions and 3199 deletions

View File

@@ -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);
}
});
}
}

View 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`
}
}))

View File

@@ -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>
</>
)

View File

@@ -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 ? (

View File

@@ -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;
}
}

View File

@@ -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
}
}))

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -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
}
}
}))

View File

@@ -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;
}
}

View 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
}
}))

View File

@@ -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
}