|
1 | | -import React, {useEffect, useState} from 'react'; |
| 1 | +import React, { useEffect, useMemo, useState } from 'react'; |
2 | 2 | import Editor from '@monaco-editor/react'; |
3 | 3 | import { FaPlay } from 'react-icons/fa'; |
4 | 4 | import './CodeEditor.css'; |
5 | 5 |
|
6 | | -const CodeEditor = ({ currentUser }) => { |
7 | | - const [code, setCode] = useState(currentUser.code); |
| 6 | +/** |
| 7 | + * Props |
| 8 | + * - file?: { name, language, content } |
| 9 | + * - readOnly?: boolean |
| 10 | + * - onChange?: (next: string) => void |
| 11 | + * - currentUser?: { name: string, role: 'host'|'edit'|'view', code?: string } // ✅ 뱃지 표시용 |
| 12 | + */ |
| 13 | +export default function CodeEditor({ file, readOnly = false, onChange, currentUser, isDark }) { |
| 14 | + const initialValue = useMemo(() => file?.content ?? '', [file?.content]); |
| 15 | + const [code, setCode] = useState(initialValue); |
8 | 16 |
|
9 | | - // ✅ currentUser가 바뀔 때마다 코드 상태를 새로 설정 |
10 | | - useEffect(() => { |
11 | | - setCode(currentUser.code); |
12 | | - }, [currentUser]); |
| 17 | + useEffect(() => setCode(initialValue), [initialValue]); |
13 | 18 |
|
14 | | - const handleRun = () => { |
15 | | - alert("코드 실행 기능은 아직 미구현입니다."); |
16 | | - }; |
| 19 | + const language = useMemo(() => file?.language || 'python', [file?.language]); |
| 20 | + |
| 21 | + const handleRun = () => alert('코드 실행 기능은 아직 미구현입니다.'); |
17 | 22 |
|
18 | | - const getIcon = (role) => { |
19 | | - switch (role) { |
20 | | - case 'host': |
21 | | - return '👑'; |
22 | | - case 'editing': |
23 | | - return '✍️'; |
24 | | - default: |
25 | | - return ''; |
26 | | - } |
| 23 | + const roleIcon = (role) => { |
| 24 | + if (role === 'host') return '👑'; |
| 25 | + if (role === 'edit') return '✏️'; |
| 26 | + if (role === 'view') return '👁️'; |
| 27 | + return ''; |
27 | 28 | }; |
28 | 29 |
|
| 30 | + // const theme = document.body.classList.contains('dark-mode') ? 'vs-light' : 'vs-dark'; |
| 31 | + const theme = isDark ? 'vs-dark' : 'vs-light'; // ✅ props 우선 |
29 | 32 | return ( |
30 | 33 | <section className="code-editor"> |
31 | 34 | <div className="editor-header"> |
32 | | - <div className="current-user-badge"> |
33 | | - {getIcon(currentUser.role)} {currentUser.name} |
34 | | - </div> |
| 35 | + {/* ✅ 사용자 뱃지 복원, 권한 뱃지 제거 */} |
| 36 | + {currentUser?.name && ( |
| 37 | + <div className="current-user-badge"> |
| 38 | + {roleIcon(currentUser.role)} {currentUser.name} |
| 39 | + </div> |
| 40 | + )} |
| 41 | + |
35 | 42 | <button className="run-button" onClick={handleRun}> |
36 | 43 | <FaPlay /> 실행 |
37 | 44 | </button> |
38 | 45 | </div> |
39 | 46 |
|
| 47 | + {/* 필요 시 height=100%로 바꿔도 됩니다 (부모 컨테이너가 flex:1이면) */} |
40 | 48 | <Editor |
41 | | - height="calc(100vh - 160px)" // 헤더와 버튼 고려 |
42 | | - defaultLanguage="python" |
43 | | - theme="vs-dark" |
| 49 | + height="90%" |
| 50 | + language={language} |
| 51 | + theme={theme} |
44 | 52 | value={code} |
45 | | - onChange={(newValue) => setCode(newValue)} |
| 53 | + onChange={(v) => { |
| 54 | + const next = v ?? ''; |
| 55 | + setCode(next); |
| 56 | + onChange && onChange(next); |
| 57 | + }} |
46 | 58 | options={{ |
| 59 | + readOnly, |
47 | 60 | fontSize: 14, |
48 | 61 | minimap: { enabled: false }, |
49 | 62 | padding: { top: 10 }, |
| 63 | + scrollBeyondLastLine: false, |
| 64 | + smoothScrolling: true, |
50 | 65 | }} |
51 | 66 | /> |
52 | 67 | </section> |
53 | 68 | ); |
54 | | -}; |
55 | | - |
56 | | -export default CodeEditor; |
| 69 | +} |
0 commit comments