Skip to content

Commit 59e9762

Browse files
committed
코드방송 라이브 화면 UI 구현
1 parent bdc4587 commit 59e9762

File tree

10 files changed

+404
-0
lines changed

10 files changed

+404
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
.code-editor {
2+
flex: 1;
3+
display: flex;
4+
flex-direction: column;
5+
background-color: #0f0f1a;
6+
padding: 20px;
7+
overflow-y: auto;
8+
color: white;
9+
font-family: 'Courier New', monospace;
10+
font-size: 15px;
11+
}
12+
13+
.editor-header {
14+
display: flex;
15+
justify-content: space-between;
16+
align-items: center;
17+
margin-bottom: 10px;
18+
}
19+
20+
.current-user-badge {
21+
background-color: #222;
22+
color: #fff;
23+
padding: 6px 12px;
24+
border-radius: 12px;
25+
font-weight: 600;
26+
font-size: 14px;
27+
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
28+
}
29+
30+
31+
.run-button {
32+
background-color: #6a0dad;
33+
color: white;
34+
border: none;
35+
padding: 6px 12px;
36+
border-radius: 6px;
37+
cursor: pointer;
38+
font-size: 14px;
39+
display: flex;
40+
align-items: center;
41+
gap: 6px;
42+
transition: background-color 0.2s ease;
43+
}
44+
45+
.run-button:hover {
46+
background-color: #8844dd;
47+
}
48+
49+
.code-block {
50+
background-color: #0f0f1a;
51+
padding: 10px;
52+
white-space: pre-wrap;
53+
line-height: 1.5;
54+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React from 'react';
2+
import './CodeEditor.css';
3+
import { FaPlay } from 'react-icons/fa';
4+
5+
const currentUser = {
6+
name: '김코딩',
7+
role: 'host',
8+
code: `# 버블 정렬 구현
9+
def bubble_sort(arr):
10+
n = len(arr)
11+
12+
for i in range(n):
13+
for j in range(0, n - i - 1):
14+
if arr[j] > arr[j + 1]:
15+
# 두 요소 교환
16+
arr[j], arr[j + 1] = arr[j + 1], arr[j]
17+
18+
return arr
19+
20+
# 예제 배열
21+
array = [64, 34, 25, 12, 22, 11, 90]
22+
print("정렬 전:", array)
23+
print("정렬 후:", bubble_sort(array.copy()))`
24+
};
25+
26+
const getIcon = (role) => {
27+
switch (role) {
28+
case 'host':
29+
return '👑';
30+
case 'editing':
31+
return '✍️';
32+
default:
33+
return '';
34+
}
35+
};
36+
37+
const CodeEditor = () => {
38+
const handleRun = () => {
39+
alert("코드 실행 기능은 아직 미구현입니다.");
40+
};
41+
42+
return (
43+
<section className="code-editor">
44+
<div className="editor-header">
45+
<div className="current-user-badge">
46+
{getIcon(currentUser.role)} {currentUser.name}
47+
</div>
48+
<button className="run-button" onClick={handleRun}>
49+
<FaPlay/> 실행
50+
</button>
51+
</div>
52+
<pre className="code-block">
53+
<code>{currentUser.code}</code>
54+
</pre>
55+
</section>
56+
);
57+
};
58+
59+
export default CodeEditor;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
.code-preview-list {
2+
background-color: #191919;
3+
padding: 12px 16px;
4+
display: flex;
5+
gap: 16px;
6+
overflow-x: auto;
7+
border-top: 1px solid #333;
8+
}
9+
10+
.code-preview-card {
11+
background-color: #1f1f2e;
12+
border-radius: 10px;
13+
min-width: 240px;
14+
max-width: 240px;
15+
flex-shrink: 0;
16+
color: white;
17+
font-size: 13px;
18+
font-family: 'Courier New', monospace;
19+
display: flex;
20+
flex-direction: column;
21+
border: 1px solid #333;
22+
overflow: hidden;
23+
}
24+
25+
.card-header {
26+
background-color: #2c2c2c;
27+
padding: 8px 12px;
28+
display: flex;
29+
justify-content: space-between;
30+
align-items: center;
31+
font-weight: bold;
32+
font-size: 14px;
33+
border-bottom: 1px solid #444;
34+
height: 30px;
35+
}
36+
37+
.card-name {
38+
color: #fff;
39+
}
40+
41+
.card-role {
42+
font-size: 16px;
43+
}
44+
45+
.preview-language {
46+
font-size: 12px;
47+
color: #aaa;
48+
margin-bottom: 8px;
49+
}
50+
51+
.preview-code {
52+
padding: 12px;
53+
white-space: pre-wrap;
54+
line-height: 1.5;
55+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from 'react';
2+
import './CodePreviewList.css';
3+
4+
const previews = [
5+
{
6+
name: '김코딩',
7+
// language: 'Python',
8+
code: `# 버블 정렬 구현\ndef bubble_sort(arr):\n n = len(arr)\n`,
9+
isHost: true
10+
},
11+
{
12+
name: '이알고',
13+
// language: 'JavaScript',
14+
code: `// 퀵 정렬 구현\nfunction quickSort(arr) {\n if (arr.length <= 1) {\n return arr;`,
15+
isHost: false
16+
},
17+
{
18+
name: '박개발',
19+
// language: 'JavaScript',
20+
code: `// 병합 정렬 구현\nfunction mergeSort(arr) {\n if (arr.length <= 1) {\n return arr;`,
21+
isHost: false
22+
}
23+
];
24+
25+
const CodePreviewList = () => {
26+
return (
27+
<section className="code-preview-list">
28+
{previews.map((p, idx) => (
29+
<div key={idx} className="code-preview-card">
30+
<div className="card-header">
31+
<span className="card-name">{p.name}</span>
32+
{p.isHost && <span className="card-role">👑</span>}
33+
</div>
34+
{/*<div className="preview-language">{p.language}</div>*/}
35+
<pre className="preview-code">{p.code}</pre>
36+
</div>
37+
))}
38+
</section>
39+
);
40+
};
41+
42+
export default CodePreviewList;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
.broadcast-header {
2+
display: flex;
3+
justify-content: space-between;
4+
align-items: center;
5+
background-color: #1a1a1a;
6+
padding: 16px 24px;
7+
border-bottom: 1px solid #333;
8+
color: white;
9+
margin-bottom: 0;
10+
}
11+
12+
.header-left {
13+
display: flex;
14+
align-items: center;
15+
}
16+
17+
.broadcast-title {
18+
font-size: 20px;
19+
font-weight: bold;
20+
margin: 0;
21+
}
22+
23+
.header-right {
24+
display: flex;
25+
align-items: center;
26+
gap: 12px;
27+
}
28+
29+
.exit-button {
30+
background-color: #333;
31+
color: red;
32+
border: none;
33+
padding: 6px 12px;
34+
border-radius: 6px;
35+
cursor: pointer;
36+
font-size: 14px;
37+
transition: background-color 0.2s;
38+
}
39+
40+
.exit-button:hover {
41+
background-color: #555;
42+
}
43+
44+
.language-tag {
45+
background-color: #4b8bbe;
46+
color: white;
47+
font-size: 12px;
48+
padding: 4px 10px;
49+
border-radius: 20px;
50+
font-weight: 500;
51+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from 'react';
2+
import './CodecastHeader.css';
3+
4+
const CodecastHeader = () => {
5+
const handleExit = () => {
6+
// 실제 방송 종료 처리 로직이 들어갈 수 있음
7+
alert('방송을 종료하고 나갑니다.');
8+
};
9+
10+
return (
11+
<header className="broadcast-header">
12+
<div className="header-left">
13+
<h1 className="broadcast-title">정렬 알고리즘 라이브 코딩</h1>
14+
</div>
15+
16+
<div className="header-right">
17+
<span className="language-tag">Python</span>
18+
<button className="exit-button" onClick={handleExit}>
19+
나가기
20+
</button>
21+
</div>
22+
</header>
23+
);
24+
};
25+
26+
export default CodecastHeader;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.broadcast-wrapper {
2+
display: flex;
3+
flex-direction: column;
4+
height: 100vh;
5+
background-color: #111;
6+
color: white;
7+
}
8+
9+
.main-section {
10+
flex: 1;
11+
display: flex;
12+
overflow: hidden;
13+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import './CodecastLive.css';
3+
4+
import Header from './CodecastHeader';
5+
import Sidebar from './CodecastSidebar';
6+
import CodeEditor from './CodeEditor';
7+
import CodePreviewList from './CodePreviewList';
8+
9+
const CodeBroadcastPage = () => {
10+
return (
11+
<div className="broadcast-wrapper">
12+
<Header />
13+
<div className="main-section">
14+
<Sidebar />
15+
<CodeEditor />
16+
</div>
17+
<CodePreviewList />
18+
</div>
19+
);
20+
};
21+
22+
export default CodeBroadcastPage;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.sidebar {
2+
width: 200px;
3+
background-color: #1c1c1c;
4+
padding: 16px;
5+
border-right: 1px solid #333;
6+
color: white;
7+
}
8+
9+
.sidebar-title {
10+
font-size: 16px;
11+
margin-bottom: 12px;
12+
}
13+
14+
.participant-list {
15+
list-style: none;
16+
padding: 0;
17+
margin: 0;
18+
}
19+
20+
.participant-item {
21+
display: flex;
22+
align-items: center;
23+
margin-bottom: 10px;
24+
font-size: 14px;
25+
gap: 8px;
26+
}
27+
28+
.participant-icon {
29+
font-size: 14px;
30+
}
31+
32+
.participant-icon.gold {
33+
color: gold;
34+
}
35+
36+
.participant-icon.green {
37+
color: #00c853;
38+
}
39+
40+
.participant-icon.gray {
41+
color: #777;
42+
}

0 commit comments

Comments
 (0)