feat(chat): redesign chat UI with structured rendering and interactive action buttons

This commit is contained in:
2026-03-07 21:08:08 +09:00
parent 4b855c9e57
commit 507324f78e
5 changed files with 826 additions and 107 deletions

View File

@@ -44,9 +44,16 @@
}
/* ─── Reset ──────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
html,
body {
height: 100%;
font-family: var(--font-sans);
font-size: 14px;
@@ -57,13 +64,22 @@ html, body {
}
/* ─── Scrollbar ──────────────────────────────────────── */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--bg-active);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
/* ─── Header ─────────────────────────────────────────── */
.header {
@@ -77,7 +93,11 @@ html, body {
z-index: 100;
}
.header-left { display: flex; align-items: center; gap: 12px; }
.header-left {
display: flex;
align-items: center;
gap: 12px;
}
.logo {
display: flex;
@@ -94,7 +114,11 @@ html, body {
-webkit-text-fill-color: transparent;
}
.header-right { display: flex; align-items: center; gap: 16px; }
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.connection-status {
display: flex;
@@ -112,8 +136,14 @@ html, body {
transition: background var(--transition-normal);
}
.status-dot.connected { background: var(--success); box-shadow: 0 0 6px var(--success); }
.status-dot.error { background: var(--error); }
.status-dot.connected {
background: var(--success);
box-shadow: 0 0 6px var(--success);
}
.status-dot.error {
background: var(--error);
}
/* ─── Main Layout ────────────────────────────────────── */
.main-layout {
@@ -181,14 +211,34 @@ html, body {
flex-shrink: 0;
}
.session-indicator.connected { background: var(--success); box-shadow: 0 0 4px rgba(52, 211, 153, 0.4); }
.session-indicator.connecting { background: var(--warning); animation: pulse 1.5s infinite; }
.session-indicator.disconnected { background: var(--text-muted); }
.session-indicator.error { background: var(--error); }
.session-indicator.connected {
background: var(--success);
box-shadow: 0 0 4px rgba(52, 211, 153, 0.4);
}
.session-indicator.connecting {
background: var(--warning);
animation: pulse 1.5s infinite;
}
.session-indicator.disconnected {
background: var(--text-muted);
}
.session-indicator.error {
background: var(--error);
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.4;
}
}
.session-info {
@@ -223,8 +273,14 @@ html, body {
font-size: 14px;
}
.session-card:hover .session-remove { opacity: 1; }
.session-remove:hover { color: var(--error); background: rgba(248, 113, 113, 0.1); }
.session-card:hover .session-remove {
opacity: 1;
}
.session-remove:hover {
color: var(--error);
background: rgba(248, 113, 113, 0.1);
}
/* ─── Chat Area ──────────────────────────────────────── */
.chat-area {
@@ -317,32 +373,265 @@ html, body {
font-size: 13px;
}
/* Antigravity 에서 가져온 HTML을 표시하는 컨테이너 */
.chat-messages .ag-content {
font-family: var(--font-sans);
line-height: 1.6;
/* Antigravity 에서 가져온 구조화 메시지를 렌더링하는 컴포넌트 */
/* --- 메시지 공통 --- */
.chat-messages>* {
margin-bottom: 8px;
}
/* --- 작업 카드 (Task boundary) --- */
.msg-card {
border: 1px solid var(--border-subtle);
border-radius: 10px;
overflow: hidden;
background: var(--bg-secondary);
transition: border-color var(--transition-fast);
}
.msg-card:hover {
border-color: var(--border-medium);
}
.msg-card-header {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
padding: 10px 14px;
}
.msg-toggle {
font-size: 11px;
color: var(--text-muted);
width: 14px;
text-align: center;
flex-shrink: 0;
transition: color var(--transition-fast);
}
.msg-card-header:hover .msg-toggle {
color: var(--text-primary);
}
.chat-messages .ag-content pre,
.chat-messages .ag-content code {
font-family: var(--font-mono);
.msg-card-title {
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
}
.chat-messages .ag-content pre {
.msg-card-summary {
width: 100%;
font-size: 12px;
color: var(--text-secondary);
line-height: 1.5;
padding-left: 22px;
}
.msg-card-body {
border-top: 1px solid var(--border-subtle);
padding: 8px 14px 10px;
}
.msg-step {
display: flex;
align-items: flex-start;
gap: 8px;
padding: 3px 0;
font-size: 12px;
color: var(--text-secondary);
line-height: 1.4;
}
.msg-step-icon {
width: 16px;
text-align: center;
flex-shrink: 0;
font-size: 11px;
}
.msg-step-text {
flex: 1;
min-width: 0;
word-break: break-word;
}
/* --- 텍스트 메시지 --- */
.msg-text {
font-size: 13px;
line-height: 1.6;
color: var(--text-primary);
padding: 4px 0;
word-break: break-word;
}
.msg-text p {
margin: 4px 0;
}
.msg-text ul,
.msg-text ol {
padding-left: 18px;
margin: 4px 0;
}
.msg-text li {
margin: 2px 0;
}
.msg-text strong {
font-weight: 600;
}
.msg-text a {
color: var(--text-accent);
text-decoration: none;
}
.msg-text a:hover {
text-decoration: underline;
}
.msg-text code:not(pre code) {
font-family: var(--font-mono);
font-size: 12px;
background: var(--bg-tertiary);
padding: 1px 5px;
border-radius: 4px;
color: var(--text-accent);
}
.msg-text pre {
background: var(--bg-tertiary);
border: 1px solid var(--border-subtle);
border-radius: 8px;
padding: 14px;
padding: 10px 12px;
overflow-x: auto;
margin: 10px 0;
margin: 6px 0;
font-family: var(--font-mono);
font-size: 12px;
line-height: 1.5;
}
.chat-messages .ag-content code {
.msg-text img {
max-width: 320px;
max-height: 200px;
border-radius: 8px;
margin: 4px 0;
}
/* --- Thought Process --- */
.msg-thought {
margin: 4px 0;
}
.msg-thought-btn {
display: flex;
align-items: center;
gap: 6px;
width: 100%;
padding: 6px 10px;
background: none;
border: none;
border-radius: 6px;
color: var(--text-muted);
font-family: var(--font-sans);
font-size: 12px;
cursor: pointer;
transition: all var(--transition-fast);
text-align: left;
}
.msg-thought-btn:hover {
background: var(--bg-hover);
color: var(--text-secondary);
}
.msg-thought-icon {
font-size: 14px;
}
/* --- 코드 블록 --- */
.msg-code-block {
border: 1px solid var(--border-subtle);
border-radius: 8px;
overflow: hidden;
margin: 4px 0;
}
.msg-code-lang {
padding: 4px 12px;
background: var(--bg-tertiary);
padding: 2px 6px;
border-radius: 4px;
border-bottom: 1px solid var(--border-subtle);
font-family: var(--font-mono);
font-size: 11px;
color: var(--text-muted);
text-transform: lowercase;
}
.msg-code-block pre {
margin: 0;
padding: 10px 12px;
background: var(--bg-primary);
overflow-x: auto;
font-size: 12px;
line-height: 1.5;
}
.msg-code-block code {
font-family: var(--font-mono);
font-size: 12px;
color: var(--text-primary);
}
/* --- 이미지 --- */
.msg-image {
margin: 4px 0;
}
.msg-image img {
max-width: 320px;
max-height: 200px;
border-radius: 8px;
border: 1px solid var(--border-subtle);
object-fit: contain;
}
/* --- 액션 버튼 --- */
.msg-actions {
display: flex;
gap: 6px;
padding: 4px 0;
flex-wrap: wrap;
}
.msg-action-btn {
padding: 4px 12px;
background: var(--bg-tertiary);
border: 1px solid var(--border-subtle);
border-radius: 6px;
color: var(--text-secondary);
font-family: var(--font-sans);
font-size: 12px;
cursor: default;
transition: all var(--transition-fast);
}
.msg-action-btn[style*="cursor: pointer"]:hover {
background: var(--bg-hover);
border-color: var(--border-medium);
color: var(--text-primary);
}
.msg-action-btn.msg-action-primary {
background: var(--accent-primary);
color: white;
border-color: var(--accent-primary);
}
.msg-action-btn.msg-action-primary:hover {
background: var(--accent-secondary);
transform: scale(1.02);
}
/* Chat Input */
@@ -371,8 +660,13 @@ html, body {
transition: border-color var(--transition-fast);
}
.chat-input-area textarea::placeholder { color: var(--text-muted); }
.chat-input-area textarea:focus { border-color: var(--accent-primary); }
.chat-input-area textarea::placeholder {
color: var(--text-muted);
}
.chat-input-area textarea:focus {
border-color: var(--accent-primary);
}
/* ─── Buttons ────────────────────────────────────────── */
.btn-icon {
@@ -430,7 +724,9 @@ html, body {
transform: scale(1.05);
}
.btn-send:active { transform: scale(0.95); }
.btn-send:active {
transform: scale(0.95);
}
.btn {
padding: 8px 16px;
@@ -448,7 +744,9 @@ html, body {
color: white;
}
.btn-primary:hover { background: var(--accent-secondary); }
.btn-primary:hover {
background: var(--accent-secondary);
}
.btn-secondary {
background: var(--bg-tertiary);
@@ -456,7 +754,9 @@ html, body {
border: 1px solid var(--border-subtle);
}
.btn-secondary:hover { background: var(--bg-hover); }
.btn-secondary:hover {
background: var(--bg-hover);
}
/* ─── Modal ──────────────────────────────────────────── */
.modal-backdrop {
@@ -471,7 +771,15 @@ html, body {
animation: fadeIn 0.15s ease;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.modal {
background: var(--bg-elevated);
@@ -483,7 +791,17 @@ html, body {
animation: slideUp 0.2s ease;
}
@keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes slideUp {
from {
transform: translateY(20px);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
.modal-header {
display: flex;
@@ -533,7 +851,9 @@ html, body {
transition: border-color var(--transition-fast);
}
.form-group input:focus { border-color: var(--accent-primary); }
.form-group input:focus {
border-color: var(--accent-primary);
}
.form-hint {
font-size: 11px;
@@ -605,11 +925,32 @@ html, body {
animation-fill-mode: forwards;
}
@keyframes slideInRight { from { transform: translateX(100px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes fadeOut { to { opacity: 0; transform: translateY(10px); } }
@keyframes slideInRight {
from {
transform: translateX(100px);
opacity: 0;
}
.toast.error { border-color: var(--error); }
.toast.success { border-color: var(--success); }
to {
transform: none;
opacity: 1;
}
}
@keyframes fadeOut {
to {
opacity: 0;
transform: translateY(10px);
}
}
.toast.error {
border-color: var(--error);
}
.toast.success {
border-color: var(--success);
}
/* ─── View Tabs (Chat ↔ Mirror) ──────────────────────── */
.view-tabs {
@@ -677,5 +1018,4 @@ html, body {
font-size: 14px;
pointer-events: none;
animation: pulse 1.5s infinite;
}
}