From 31fc2dfb0d2f0a8120fa1c95cf3030684d267c69 Mon Sep 17 00:00:00 2001 From: gahusb Date: Mon, 27 Apr 2026 08:38:15 +0900 Subject: [PATCH] refactor(agent-office): rewrite CSS for full-screen canvas layout with mobile bottom sheet Co-Authored-By: Claude Sonnet 4.6 --- src/pages/agent-office/AgentOffice.css | 785 ++++++++++++++----------- 1 file changed, 431 insertions(+), 354 deletions(-) diff --git a/src/pages/agent-office/AgentOffice.css b/src/pages/agent-office/AgentOffice.css index fb7d82f..f85453a 100644 --- a/src/pages/agent-office/AgentOffice.css +++ b/src/pages/agent-office/AgentOffice.css @@ -1,400 +1,477 @@ -.ao-page { +/* src/pages/agent-office/AgentOffice.css */ + +/* ===== Root Layout ===== */ +.ao-root { display: flex; flex-direction: column; height: 100vh; background: #0d0d1a; - color: #e0e0e0; + color: #ffffff; font-family: 'Courier New', monospace; + overflow: hidden; } -.ao-header { +/* ===== Top Bar ===== */ +.ao-topbar { display: flex; align-items: center; justify-content: space-between; - padding: 8px 20px; + height: 44px; + padding: 0 16px; background: #1a1a2e; - border-bottom: 1px solid #2a2a4a; + border-bottom: 1px solid #333; flex-shrink: 0; } - -.ao-title { - font-size: 1.2rem; - color: #8b5cf6; - margin: 0; - letter-spacing: 2px; -} - -.ao-status { +.ao-topbar-left { display: flex; align-items: center; - gap: 8px; - font-size: 0.8rem; + gap: 12px; +} +.ao-topbar-title { + font-weight: bold; + font-size: 15px; + color: #8b5cf6; +} +.ao-topbar-status { + font-size: 11px; +} +.ao-topbar-status.connected { color: #22c55e; } +.ao-topbar-status.disconnected { color: #ef4444; } +.ao-topbar-right { + display: flex; + align-items: center; + gap: 10px; +} +.ao-topbar-select { + background: #2a2a3e; + color: #aaa; + border: 1px solid #444; + padding: 3px 8px; + border-radius: 4px; + font-size: 12px; + font-family: inherit; +} +.ao-topbar-zoom { + display: flex; + align-items: center; + gap: 4px; +} +.ao-topbar-zoom button { + background: #2a2a3e; + color: #aaa; + border: 1px solid #444; + width: 24px; + height: 24px; + border-radius: 4px; + cursor: pointer; + font-size: 14px; +} +.ao-topbar-zoom button:disabled { + opacity: 0.3; + cursor: default; +} +.ao-topbar-zoom span { color: #888; + font-size: 12px; + min-width: 28px; + text-align: center; } -.ao-dot { +/* ===== Main Area ===== */ +.ao-main { + flex: 1; + display: flex; + position: relative; + overflow: hidden; +} +.ao-canvas { + flex: 1; + cursor: grab; + display: block; +} +.ao-canvas:active { + cursor: grabbing; +} + +/* ===== Side Panel ===== */ +.ao-sidepanel { + width: 320px; + background: #111; + border-left: 1px solid #333; + display: flex; + flex-direction: column; + flex-shrink: 0; + animation: slideIn 0.2s ease-out; +} +@keyframes slideIn { + from { transform: translateX(100%); } + to { transform: translateX(0); } +} +.ao-sidepanel-header { + padding: 12px; + border-bottom: 1px solid #333; + display: flex; + align-items: center; + justify-content: space-between; +} +.ao-sidepanel-agent { + display: flex; + align-items: center; + gap: 10px; +} +.ao-sidepanel-icon { + width: 36px; + height: 36px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; +} +.ao-sidepanel-name { + font-weight: bold; + font-size: 14px; +} +.ao-sidepanel-state { + font-size: 11px; + color: #22c55e; +} +.ao-sidepanel-close { + background: none; + border: none; + color: #666; + font-size: 24px; + cursor: pointer; + padding: 0 4px; +} +.ao-sidepanel-close:hover { + color: #fff; +} + +/* Tabs */ +.ao-sidepanel-tabs { + display: flex; + border-bottom: 1px solid #333; +} +.ao-sidepanel-tab { + flex: 1; + padding: 8px 4px; + text-align: center; + font-size: 12px; + font-family: inherit; + background: none; + border: none; + border-bottom: 2px solid transparent; + color: #666; + cursor: pointer; +} +.ao-sidepanel-tab.active { + color: #8b5cf6; + border-bottom-color: #8b5cf6; + font-weight: bold; +} +.ao-sidepanel-tab:hover { + color: #aaa; +} +.ao-sidepanel-content { + flex: 1; + overflow-y: auto; + padding: 12px; +} + +/* ===== Command Tab ===== */ +.ao-command-tab { display: flex; flex-direction: column; gap: 12px; } +.ao-section { margin-bottom: 4px; } +.ao-section-label { + color: #888; + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 6px; +} +.ao-quick-actions { + display: flex; + flex-wrap: wrap; + gap: 6px; +} +.ao-btn-quick { + background: #2a2a4e; + color: #8b5cf6; + border: 1px solid #4c1d95; + padding: 5px 12px; + border-radius: 4px; + font-size: 11px; + font-family: inherit; + cursor: pointer; +} +.ao-btn-quick:hover { background: #3a3a5e; } +.ao-btn-quick:disabled { opacity: 0.4; } + +.ao-param-row { + display: flex; + gap: 6px; +} +.ao-input { + flex: 1; + background: #1a1a2e; + border: 1px solid #333; + color: #fff; + padding: 7px 10px; + border-radius: 4px; + font-size: 12px; + font-family: inherit; +} +.ao-input::placeholder { color: #555; } +.ao-btn-send { + background: #4c1d95; + color: #fff; + border: none; + padding: 7px 14px; + border-radius: 4px; + font-size: 12px; + font-family: inherit; + cursor: pointer; + white-space: nowrap; +} +.ao-btn-send:hover { background: #5b21b6; } +.ao-btn-send:disabled { opacity: 0.4; } + +/* Approval */ +.ao-approval-card { + background: rgba(146,64,14,0.15); + border: 1px solid #92400e; + border-radius: 6px; + padding: 10px; +} +.ao-approval-title { + color: #fbbf24; + font-size: 12px; + font-weight: bold; + margin-bottom: 4px; +} +.ao-approval-desc { + color: #ddd; + font-size: 11px; + margin-bottom: 8px; + word-break: break-all; +} +.ao-approval-actions { + display: flex; + gap: 6px; +} +.ao-btn-approve { + flex: 1; + background: #065f46; + color: #fff; + border: none; + padding: 7px; + border-radius: 4px; + font-size: 12px; + cursor: pointer; +} +.ao-btn-reject { + flex: 1; + background: #7f1d1d; + color: #fff; + border: none; + padding: 7px; + border-radius: 4px; + font-size: 12px; + cursor: pointer; +} + +/* ===== Task Tab ===== */ +.ao-task-tab { display: flex; flex-direction: column; gap: 4px; } +.ao-task-item { + background: #1a1a2e; + border-radius: 4px; + padding: 8px; + cursor: pointer; +} +.ao-task-item:hover { background: #222240; } +.ao-task-header { + display: flex; + align-items: center; + gap: 6px; + font-size: 12px; +} +.ao-task-type { color: #ccc; font-weight: bold; flex: 1; } +.ao-task-badge { + padding: 1px 6px; + border-radius: 3px; + font-size: 10px; +} +.ao-task-time { color: #666; font-size: 10px; } +.ao-task-result { + margin-top: 6px; + background: #0d0d1a; + padding: 6px; + border-radius: 3px; + font-size: 10px; + color: #aaa; + max-height: 200px; + overflow-y: auto; + white-space: pre-wrap; + word-break: break-all; +} + +/* ===== Token Tab ===== */ +.ao-token-tab { display: flex; flex-direction: column; gap: 12px; } +.ao-token-period { + display: flex; + gap: 4px; +} +.ao-btn-period { + flex: 1; + background: #1a1a2e; + color: #888; + border: 1px solid #333; + padding: 5px; + border-radius: 4px; + font-size: 11px; + font-family: inherit; + cursor: pointer; +} +.ao-btn-period.active { + background: #4c1d95; + color: #fff; + border-color: #4c1d95; +} +.ao-token-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; +} +.ao-token-card { + background: #1a1a2e; + border-radius: 6px; + padding: 10px; + text-align: center; +} +.ao-token-label { + font-size: 10px; + color: #888; + text-transform: uppercase; + margin-bottom: 4px; +} +.ao-token-value { + font-size: 18px; + font-weight: bold; + color: #fff; +} +.ao-token-bar { margin-top: 4px; } +.ao-token-bar-label { font-size: 10px; color: #888; margin-bottom: 4px; } +.ao-token-bar-track { + display: flex; + height: 8px; + border-radius: 4px; + overflow: hidden; + background: #1a1a2e; +} +.ao-token-bar-fill.input { background: #3b82f6; } +.ao-token-bar-fill.output { background: #8b5cf6; } +.ao-token-bar-legend { + display: flex; + gap: 12px; + font-size: 10px; + color: #888; + margin-top: 4px; +} +.ao-token-bar-legend .dot { + display: inline-block; width: 8px; height: 8px; border-radius: 50%; + margin-right: 4px; } -.ao-dot--on { background: #34d399; } -.ao-dot--off { background: #f87171; } - -/* Dashboard */ -.ao-dashboard { - display: flex; - gap: 1px; - background: #2a2a4a; - flex: 1; - min-height: 0; - overflow: hidden; -} - -/* Agent Column */ -.ao-col { - flex: 1; - display: flex; - flex-direction: column; - background: #0d0d1a; - min-width: 0; - overflow-y: auto; -} - -.ao-col-header { - display: flex; - align-items: center; - gap: 8px; - padding: 10px 12px; - border-top: 3px solid; - background: #1a1a2e; - flex-shrink: 0; -} - -.ao-col-chevron { - display: none; - color: #666; - font-size: 0.8rem; - margin-left: 4px; -} - -.ao-col-body { - display: flex; - flex-direction: column; - flex: 1; - min-height: 0; - overflow: hidden; -} - -.ao-col-name { - font-weight: bold; - font-size: 0.9rem; -} - -.ao-col-state { - font-size: 0.7rem; - padding: 2px 8px; - border-radius: 8px; - text-transform: uppercase; - margin-left: auto; -} -.ao-col-state--idle { background: #333; color: #888; } -.ao-col-state--working { background: #3730a3; color: #a5b4fc; } -.ao-col-state--waiting { background: #92400e; color: #fbbf24; } -.ao-col-state--reporting { background: #065f46; color: #34d399; } -.ao-col-state--break { background: #4c1d95; color: #c4b5fd; } -.ao-col-state--offline { background: #1f1f1f; color: #555; } - -.ao-col-tokens { - font-size: 0.7rem; - color: #8b5cf6; - background: rgba(139, 92, 246, 0.12); - padding: 2px 8px; - border-radius: 8px; - margin-left: 6px; - cursor: help; - font-family: 'Courier New', monospace; - white-space: nowrap; -} - -.ao-col-badge { - background: #f43f5e; - color: #fff; - font-size: 0.65rem; - padding: 1px 5px; - border-radius: 6px; - font-weight: bold; -} - -.ao-col-detail { - padding: 6px 12px; - font-size: 0.8rem; - color: #a78bfa; - background: rgba(139, 92, 246, 0.05); - border-bottom: 1px solid #2a2a4a; - flex-shrink: 0; -} - -.ao-col-approval { - display: flex; - align-items: center; - gap: 8px; - padding: 8px 12px; - background: rgba(251, 191, 36, 0.08); - border-bottom: 1px solid #2a2a4a; - font-size: 0.8rem; - color: #fbbf24; - flex-shrink: 0; -} - -.ao-col-commands { - display: flex; - flex-wrap: wrap; - gap: 4px; - padding: 8px 12px; - border-bottom: 1px solid #1a1a2e; - flex-shrink: 0; -} - -.ao-col-input { - display: flex; - gap: 6px; - padding: 6px 12px; - border-bottom: 1px solid #1a1a2e; - flex-shrink: 0; -} - -.ao-col-tasks { - flex: 1; - overflow-y: auto; - padding: 4px 0; -} - -.ao-col-tasks-title { - padding: 4px 12px; - font-size: 0.7rem; - color: #555; - text-transform: uppercase; - letter-spacing: 1px; -} - -.ao-col-empty { - padding: 12px; - text-align: center; - color: #444; - font-size: 0.8rem; -} - -.ao-col-task { - padding: 6px 12px; - border-bottom: 1px solid rgba(255,255,255,0.03); -} - -.ao-col-task-row { +.ao-token-bar-legend .dot.input { background: #3b82f6; } +.ao-token-bar-legend .dot.output { background: #8b5cf6; } +.ao-token-detail { display: flex; justify-content: space-between; - align-items: center; + font-size: 10px; + color: #666; } -.ao-col-task-type { - font-size: 0.8rem; - color: #ccc; -} - -.ao-col-task-badge { - font-size: 0.65rem; - padding: 1px 6px; - border-radius: 4px; - color: #fff; -} - -.ao-col-task-time { - font-size: 0.7rem; - color: #555; - margin-top: 2px; -} - -.ao-col-task-detail { - margin-top: 4px; - font-size: 0.7rem; -} -.ao-col-task-detail summary { - cursor: pointer; - color: #8b5cf6; -} -.ao-col-task-detail pre { - color: #888; - white-space: pre-wrap; - margin: 4px 0 0; - max-height: 120px; +/* ===== Log Tab ===== */ +.ao-log-tab { + max-height: 100%; overflow-y: auto; -} - -/* Command Column */ -.ao-cmd-form { display: flex; flex-direction: column; - gap: 6px; - padding: 8px 12px; - border-bottom: 1px solid #1a1a2e; - flex-shrink: 0; + gap: 2px; } - -.ao-cmd-row { +.ao-log-item { display: flex; gap: 6px; + font-size: 11px; + padding: 3px 0; + border-bottom: 1px solid #1a1a2e; +} +.ao-log-time { color: #555; min-width: 60px; } +.ao-log-level { min-width: 48px; font-weight: bold; } +.ao-log-msg { color: #ccc; word-break: break-all; } + +/* ===== Common ===== */ +.ao-empty { + color: #555; + text-align: center; + padding: 24px; + font-size: 13px; } -.ao-cmd-select { - flex: 1; - padding: 6px 8px; - background: #111; - border: 1px solid #333; - border-radius: 6px; - color: #e0e0e0; - font-size: 0.8rem; - font-family: inherit; -} -.ao-cmd-select:focus { border-color: #8b5cf6; outline: none; } - -.ao-cmd-send { - width: 100%; -} - -/* Office Section */ -.ao-office-section { - height: 280px; - flex-shrink: 0; - border-top: 2px solid #2a2a4a; - position: relative; -} - -.ao-canvas-container { - width: 100%; - height: 100%; -} - -/* Shared */ -.ao-btn { - padding: 4px 12px; - border: none; - border-radius: 6px; - font-size: 0.8rem; - cursor: pointer; - font-family: inherit; -} -.ao-btn--approve { background: #065f46; color: #34d399; } -.ao-btn--approve:hover { background: #047857; } -.ao-btn--reject { background: #7f1d1d; color: #f87171; } -.ao-btn--reject:hover { background: #991b1b; } -.ao-btn--send { background: #4c1d95; color: #c4b5fd; } -.ao-btn--send:hover { background: #5b21b6; } - -.ao-cmd-btn { - padding: 4px 10px; - border: 1px solid #333; - border-radius: 6px; - background: transparent; - color: #ccc; - font-size: 0.75rem; - cursor: pointer; - font-family: inherit; -} -.ao-cmd-btn:hover { border-color: #8b5cf6; background: rgba(139, 92, 246, 0.1); } - -.ao-chat-input { - flex: 1; - padding: 6px 10px; - background: #111; - border: 1px solid #333; - border-radius: 6px; - color: #e0e0e0; - font-size: 0.8rem; - font-family: inherit; - min-width: 0; -} -.ao-chat-input:focus { border-color: #8b5cf6; outline: none; } - -.ao-doc-tg-status { - font-size: 0.7rem; - margin-left: 4px; -} - -/* Mobile: vertical stack + accordion */ +/* ===== Mobile (< 768px) ===== */ @media (max-width: 768px) { - .ao-page { - height: auto; - min-height: 100vh; - } + .ao-topbar-right { gap: 6px; } + .ao-topbar-select { font-size: 11px; padding: 2px 6px; } - .ao-dashboard { + .ao-main { flex-direction: column; - gap: 1px; - overflow: visible; - flex: none; } - .ao-col { - flex: none; - overflow: visible; + .ao-canvas { + flex: 1; } - .ao-col-header { - cursor: pointer; - user-select: none; - padding: 12px 14px; - } - - .ao-col-chevron { - display: inline; - } - - .ao-col--collapsed .ao-col-body { - display: none; - } - - .ao-col--attention { - box-shadow: inset 3px 0 0 #fbbf24; - } - - .ao-col-tasks { - max-height: 260px; - } - - .ao-office-section { - height: 140px; - order: -1; - border-top: none; - border-bottom: 2px solid #2a2a4a; - } - - .ao-title { - font-size: 1rem; - letter-spacing: 1px; - } - - .ao-header { - padding: 8px 12px; - } - - .ao-col-commands { - gap: 6px; - } - - .ao-cmd-btn, - .ao-btn { - padding: 6px 12px; - font-size: 0.8rem; - } - - /* 명령 입력 하단 고정 */ - .ao-cmd-form { + /* Side panel → bottom sheet */ + .ao-sidepanel { position: fixed; - bottom: calc(var(--bottom-nav-h, 64px) + var(--safe-area-bottom, 0px)); + bottom: 0; left: 0; right: 0; - padding: 8px 16px; - background: var(--bg-secondary, #12122a); - border-top: 1px solid #2a2a4a; - z-index: 200; + width: 100%; + max-height: 55vh; + border-left: none; + border-top: 1px solid #333; + border-radius: 16px 16px 0 0; + animation: slideUp 0.25s ease-out; + z-index: 100; + } + @keyframes slideUp { + from { transform: translateY(100%); } + to { transform: translateY(0); } + } + + .ao-sidepanel-header { + padding: 8px 12px; + } + .ao-sidepanel-header::before { + content: ''; + display: block; + width: 32px; + height: 4px; + background: #555; + border-radius: 2px; + margin: 0 auto 8px; + } + + .ao-sidepanel-tab { + font-size: 11px; + padding: 6px 2px; + } + + .ao-sidepanel-content { + padding: 8px 12px; + padding-bottom: env(safe-area-inset-bottom, 16px); } }