/** * DB Console 스타일 */ /* ======================================== 레이아웃 ======================================== */ .dbconsole-container { display: flex; flex-direction: column; height: 100vh; overflow: hidden; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } .dbconsole-header { flex-shrink: 0; background: #f8f9fa; border-bottom: 1px solid #dee2e6; padding: 8px 16px; } .dbconsole-body { flex: 1; display: flex; overflow: hidden; } /* ======================================== 사이드바 (스키마 탐색기) ======================================== */ .dbconsole-sidebar { width: 280px; min-width: 200px; max-width: 400px; background: #fff; border-right: 1px solid #dee2e6; display: flex; flex-direction: column; overflow: hidden; } .dbconsole-sidebar-header { flex-shrink: 0; padding: 12px; background: #f8f9fa; border-bottom: 1px solid #dee2e6; } .dbconsole-sidebar-header h6 { margin: 0; font-size: 14px; font-weight: 600; color: #495057; } .dbconsole-sidebar-body { flex: 1; overflow-y: auto; padding: 8px; } /* 리사이저 */ .dbconsole-resizer { width: 4px; background: #e9ecef; cursor: col-resize; transition: background 0.2s; } .dbconsole-resizer:hover { background: #6c757d; } /* ======================================== 메인 영역 ======================================== */ .dbconsole-main { flex: 1; display: flex; flex-direction: column; overflow: hidden; } /* 에디터 영역 */ .dbconsole-editor-area { flex: 1; display: flex; flex-direction: column; min-height: 200px; } .dbconsole-editor-toolbar { flex-shrink: 0; padding: 8px 12px; background: #f8f9fa; border-bottom: 1px solid #dee2e6; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .dbconsole-editor-container { flex: 1; position: relative; min-height: 150px; } #sql-editor { width: 100%; height: 100%; position: absolute; top: 0; left: 0; } /* 결과 영역 */ .dbconsole-result-area { flex: 1; display: flex; flex-direction: column; min-height: 200px; border-top: 3px solid #dee2e6; } .dbconsole-result-header { flex-shrink: 0; display: flex; align-items: center; background: #f8f9fa; border-bottom: 1px solid #dee2e6; } .dbconsole-result-tabs { display: flex; gap: 0; } .dbconsole-result-tab { padding: 8px 16px; border: none; background: transparent; cursor: pointer; font-size: 13px; color: #6c757d; border-bottom: 2px solid transparent; transition: all 0.2s; } .dbconsole-result-tab:hover { color: #495057; background: #e9ecef; } .dbconsole-result-tab.active { color: #0d6efd; border-bottom-color: #0d6efd; font-weight: 500; } .dbconsole-result-actions { margin-left: auto; padding-right: 12px; display: flex; gap: 4px; } .dbconsole-result-body { flex: 1; overflow: hidden; position: relative; } .dbconsole-result-content { width: 100%; height: 100%; display: none; } .dbconsole-result-content.active { display: block; } #result-grid { width: 100%; height: 100%; } #sql-log { width: 100%; height: 100%; overflow-y: auto; padding: 12px; font-family: 'Consolas', 'Monaco', monospace; font-size: 12px; background: #1e1e1e; color: #d4d4d4; } .sql-log-entry { padding: 8px 12px; margin-bottom: 8px; background: #2d2d2d; border-radius: 4px; border-left: 3px solid #6c757d; } .sql-log-entry.success { border-left-color: #28a745; } .sql-log-entry.error { border-left-color: #dc3545; } .sql-log-time { color: #6c757d; font-size: 11px; } .sql-log-sql { color: #9cdcfe; margin: 4px 0; white-space: pre-wrap; word-break: break-all; } .sql-log-result { color: #ce9178; font-size: 11px; } /* ======================================== 스키마 트리 ======================================== */ .schema-tree { font-size: 13px; } .schema-item, .table-item, .column-item { padding: 4px 8px; cursor: pointer; display: flex; align-items: center; gap: 6px; border-radius: 4px; transition: background 0.15s; } .schema-item:hover, .table-item:hover { background: #e9ecef; } .schema-item.selected, .table-item.selected { background: #cfe2ff; } .column-item { padding-left: 32px; font-size: 12px; color: #6c757d; } .column-item:hover { background: #f8f9fa; } .tree-icon { width: 16px; text-align: center; color: #6c757d; } .tree-toggle { cursor: pointer; user-select: none; } .tree-children { display: none; padding-left: 16px; } .tree-children.expanded { display: block; } .table-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .table-type { font-size: 10px; padding: 1px 4px; border-radius: 3px; background: #e9ecef; color: #6c757d; } .table-type.view { background: #d1ecf1; color: #0c5460; } .column-name { flex: 1; } .column-type { font-size: 10px; color: #adb5bd; } .column-pk { color: #ffc107; font-size: 10px; } .column-fk { color: #17a2b8; font-size: 10px; } .column-idx { color: #6f42c1; font-size: 10px; } /* ======================================== 툴바 컨트롤 ======================================== */ .toolbar-group { display: flex; align-items: center; gap: 4px; } .toolbar-divider { width: 1px; height: 24px; background: #dee2e6; margin: 0 8px; } .toolbar-label { font-size: 12px; color: #6c757d; margin-right: 4px; } /* 버튼 스타일 */ .btn-toolbar { padding: 4px 12px; font-size: 13px; border-radius: 4px; } .btn-execute { background: #198754; border-color: #198754; color: #fff; } .btn-execute:hover { background: #157347; border-color: #146c43; } .btn-commit { background: #0d6efd; border-color: #0d6efd; color: #fff; } .btn-commit:hover { background: #0b5ed7; border-color: #0a58ca; } .btn-rollback { background: #dc3545; border-color: #dc3545; color: #fff; } .btn-rollback:hover { background: #bb2d3b; border-color: #b02a37; } /* 셀렉트 박스 */ .dbconsole-select { padding: 4px 8px; font-size: 13px; border: 1px solid #ced4da; border-radius: 4px; background: #fff; min-width: 150px; } .dbconsole-select:focus { border-color: #86b7fe; outline: 0; box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); } /* ======================================== 상태 표시 ======================================== */ .connection-status { display: flex; align-items: center; gap: 6px; padding: 4px 12px; background: #f8f9fa; border-radius: 4px; font-size: 12px; } .status-dot { width: 8px; height: 8px; border-radius: 50%; background: #6c757d; } .status-dot.connected { background: #28a745; } .status-dot.disconnected { background: #dc3545; } .status-dot.pending { background: #ffc107; animation: pulse 1s infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } .transaction-indicator { font-size: 11px; padding: 2px 8px; border-radius: 3px; background: #fff3cd; color: #856404; } .transaction-indicator.active { background: #d4edda; color: #155724; } /* ======================================== 모달 ======================================== */ .dbconsole-modal .modal-body { max-height: 70vh; overflow-y: auto; } .ddl-content { background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 4px; font-family: 'Consolas', 'Monaco', monospace; font-size: 12px; white-space: pre-wrap; word-break: break-all; max-height: 500px; overflow-y: auto; } /* ======================================== 로딩 오버레이 ======================================== */ .dbconsole-loading { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.8); display: none; justify-content: center; align-items: center; z-index: 1000; } .dbconsole-loading.show { display: flex; } /* ======================================== 반응형 ======================================== */ @media (max-width: 768px) { .dbconsole-sidebar { width: 100%; max-width: none; height: 200px; border-right: none; border-bottom: 1px solid #dee2e6; } .dbconsole-body { flex-direction: column; } .dbconsole-resizer { width: 100%; height: 4px; cursor: row-resize; } } /* ======================================== AG Grid 커스텀 스타일 ======================================== */ .ag-theme-alpine { --ag-header-height: 32px; --ag-row-height: 28px; --ag-font-size: 12px; } .ag-theme-alpine .ag-header-cell { font-weight: 600; } .ag-theme-alpine .ag-cell { line-height: 28px; } /* NULL 값 스타일 */ .cell-null { color: #adb5bd; font-style: italic; } /* LOB 값 스타일 */ .cell-lob { color: #6f42c1; } /* 행 번호 컬럼 스타일 */ .row-number-cell { background: #f8f9fa !important; color: #6c757d; font-size: 11px; text-align: center; font-weight: 500; border-right: 1px solid #dee2e6 !important; } /* AG Grid 텍스트 선택 방지 */ .ag-theme-alpine .ag-cell { user-select: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; } /* 편집 모드에서는 선택 가능 */ .ag-theme-alpine .ag-cell-edit-input { user-select: text; -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; } /* ======================================== 유틸리티 ======================================== */ .text-muted { color: #6c757d !important; } .small { font-size: 12px; } .gap-1 { gap: 0.25rem; } .gap-2 { gap: 0.5rem; } /* ======================================== 암호화/복호화 스타일 ======================================== */ .cell-encrypted { display: inline-flex; align-items: center; gap: 4px; color: #6f42c1; font-family: 'Consolas', 'Monaco', monospace; font-size: 11px; } .cell-encrypted .btn-decrypt { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; padding: 0; border: none; background: #6f42c1; color: #fff; border-radius: 3px; cursor: pointer; font-size: 10px; transition: background 0.2s; } .cell-encrypted .btn-decrypt:hover { background: #5a32a3; } .cell-encrypted .btn-decrypt:disabled { background: #adb5bd; cursor: not-allowed; } .cell-decrypted { display: inline-flex; align-items: center; gap: 4px; color: #198754; background: #d1e7dd; padding: 2px 6px; border-radius: 3px; font-size: 12px; } .cell-decrypted i { font-size: 12px; } /* ======================================== 컨텍스트 메뉴 ======================================== */ .dbconsole-context-menu { position: fixed; display: none; background: #fff; border: 1px solid #dee2e6; border-radius: 4px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15); z-index: 10000; min-width: 150px; padding: 4px 0; } .context-menu-item { padding: 8px 16px; cursor: pointer; font-size: 13px; display: flex; align-items: center; gap: 8px; } .context-menu-item:hover { background: #f8f9fa; } .context-menu-item i { width: 16px; text-align: center; color: #6c757d; } .context-menu-divider { height: 1px; background: #dee2e6; margin: 4px 0; } .context-menu-item.disabled { color: #adb5bd; cursor: not-allowed; } .context-menu-item.disabled:hover { background: transparent; }