feat: Gravity Web Phase 1 - CDP remote control dashboard
This commit is contained in:
134
public/js/chat-panel.js
Normal file
134
public/js/chat-panel.js
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Chat Panel — 채팅 표시/입력 UI 관리
|
||||
*/
|
||||
|
||||
class ChatPanel {
|
||||
constructor() {
|
||||
this.containerEl = document.getElementById('chatContainer');
|
||||
this.emptyEl = document.getElementById('emptyState');
|
||||
this.messagesEl = document.getElementById('chatMessages');
|
||||
this.inputEl = document.getElementById('chatInput');
|
||||
this.sendBtn = document.getElementById('sendBtn');
|
||||
this.sessionNameEl = document.getElementById('chatSessionName');
|
||||
this.sessionStatusEl = document.getElementById('chatSessionStatus');
|
||||
|
||||
this.onSendMessage = null; // callback(text)
|
||||
this.activeSession = null;
|
||||
|
||||
this._setupInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력 이벤트 바인딩
|
||||
*/
|
||||
_setupInput() {
|
||||
// 자동 높이 조절
|
||||
this.inputEl.addEventListener('input', () => {
|
||||
this.inputEl.style.height = 'auto';
|
||||
this.inputEl.style.height = Math.min(this.inputEl.scrollHeight, 120) + 'px';
|
||||
});
|
||||
|
||||
// Enter로 전송 (Shift+Enter는 줄바꿈)
|
||||
this.inputEl.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
this._sendMessage();
|
||||
}
|
||||
});
|
||||
|
||||
this.sendBtn.addEventListener('click', () => {
|
||||
this._sendMessage();
|
||||
});
|
||||
}
|
||||
|
||||
_sendMessage() {
|
||||
const text = this.inputEl.value.trim();
|
||||
if (!text) return;
|
||||
|
||||
if (this.onSendMessage) {
|
||||
this.onSendMessage(text);
|
||||
}
|
||||
|
||||
// 입력창 초기화
|
||||
this.inputEl.value = '';
|
||||
this.inputEl.style.height = 'auto';
|
||||
}
|
||||
|
||||
/**
|
||||
* 세션 선택 시 UI 표시
|
||||
*/
|
||||
showSession(session) {
|
||||
this.activeSession = session;
|
||||
this.emptyEl.style.display = 'none';
|
||||
this.containerEl.style.display = 'flex';
|
||||
|
||||
this.sessionNameEl.textContent = session.name;
|
||||
this.sessionStatusEl.textContent = session.status === 'connected' ? '● 연결됨' : session.status;
|
||||
|
||||
this.messagesEl.innerHTML = `
|
||||
<div class="chat-welcome">
|
||||
<p>채팅 데이터를 불러오는 중...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
this.inputEl.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* 빈 상태 표시
|
||||
*/
|
||||
showEmpty() {
|
||||
this.activeSession = null;
|
||||
this.emptyEl.style.display = 'flex';
|
||||
this.containerEl.style.display = 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* 채팅 내용 업데이트 (Antigravity DOM HTML)
|
||||
*/
|
||||
updateChat(html) {
|
||||
if (!html || html.includes('chat container not found')) {
|
||||
this.messagesEl.innerHTML = `
|
||||
<div class="chat-welcome">
|
||||
<p>⚠️ 채팅 컨테이너를 찾을 수 없습니다.<br>
|
||||
Antigravity에서 채팅을 시작해주세요.</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
// HTML 삽입 (Antigravity에서 가져온 DOM)
|
||||
const wasAtBottom = this._isScrolledToBottom();
|
||||
|
||||
this.messagesEl.innerHTML = `<div class="ag-content">${html}</div>`;
|
||||
|
||||
// 스크롤 유지
|
||||
if (wasAtBottom) {
|
||||
this._scrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 세션 상태 업데이트
|
||||
*/
|
||||
updateSessionStatus(status) {
|
||||
if (!this.activeSession) return;
|
||||
|
||||
const statusText = {
|
||||
connected: '● 연결됨',
|
||||
disconnected: '○ 연결 끊김',
|
||||
error: '⚠ 오류',
|
||||
};
|
||||
|
||||
this.sessionStatusEl.textContent = statusText[status] || status;
|
||||
}
|
||||
|
||||
_isScrolledToBottom() {
|
||||
const el = this.messagesEl;
|
||||
return el.scrollTop + el.clientHeight >= el.scrollHeight - 50;
|
||||
}
|
||||
|
||||
_scrollToBottom() {
|
||||
this.messagesEl.scrollTop = this.messagesEl.scrollHeight;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user