/* ═══════════════════════════════════════════════════════════════════════════ ★ 개발자 빌더 — IDE 스타일 프로페셔널 테마 코스믹 글래스모피즘 X → 깔끔한 IDE/Figma 스타일 mockup 09-developer.css 기반 React 포팅 ═══════════════════════════════════════════════════════════════════════════ */ /* ─── 개발자 전용 색상 (다크) ─── */ .dark .dev-shell { --d-bg: #121218; --d-bg2: #1a1a22; --d-bg3: #22222c; --d-surface: #2a2a36; --d-surface2: #32323f; --d-border: #3a3a48; --d-border2: #4a4a58; --d-text: #e8e8ee; --d-text2: #b0b0be; --d-text3: #78788a; --d-accent: #5b9ef5; --d-accent2: #4a8de6; --d-green: #4ade80; --d-cyan: #22d3ee; --d-orange: #fb923c; --d-pink: #f472b6; --d-red: #f87171; } /* ─── 개발자 전용 색상 (라이트) ─── */ :root:not(.dark) .dev-shell, html:not(.dark) .dev-shell { --d-bg: #f5f5f8; --d-bg2: #ededf2; --d-bg3: #e4e4ec; --d-surface: #fff; --d-surface2: #f8f8fb; --d-border: #d8d8e2; --d-border2: #c4c4d0; --d-text: #1a1a24; --d-text2: #5a5a6e; --d-text3: #8a8a9e; --d-accent: #3b7dd8; --d-accent2: #2d6bc4; --d-green: #16a34a; --d-cyan: #0891b2; --d-orange: #ea580c; --d-pink: #db2777; --d-red: #dc2626; } /* ═══ 셸 ═══ */ .dev-shell { display: flex; flex-direction: column; height: 100vh; position: relative; z-index: 1; background: var(--d-bg); color: var(--d-text); font-family: inherit; } /* ─── 헤더 ─── */ .dev-hdr { display: flex; align-items: center; justify-content: space-between; padding: 0 0.8rem; height: 42px; background: var(--d-bg2); border-bottom: 1px solid var(--d-border); z-index: 10; flex-shrink: 0; } .dev-hdr-l { display: flex; align-items: center; gap: 0.6rem; } .dev-logo { font-size: 0.72rem; font-weight: 800; letter-spacing: -0.02em; color: var(--d-accent); } .dev-badge { font-size: 0.48rem; font-weight: 700; padding: 0.12rem 0.4rem; border-radius: 4px; background: var(--d-accent); color: #fff; } .dev-hdr-r { display: flex; align-items: center; gap: 0.35rem; } /* ─── 도구모음 ─── */ .dev-toolbar { display: flex; align-items: center; gap: 0.4rem; padding: 0 0.8rem; background: var(--d-bg2); border-bottom: 1px solid var(--d-border); height: 34px; flex-shrink: 0; } .dev-tb-group { display: flex; align-items: center; gap: 0.25rem; padding-right: 0.5rem; border-right: 1px solid var(--d-border); margin-right: 0.15rem; } .dev-tb-group:last-child { border-right: none; } .dev-tb-label { font-size: 0.44rem; font-weight: 700; color: var(--d-text3); text-transform: uppercase; letter-spacing: 0.04em; margin-right: 0.15rem; } /* ─── 공통 버튼/셀렉트/인풋 ─── */ .dev-btn { padding: 0.22rem 0.55rem; border-radius: 5px; border: 1px solid var(--d-border); background: var(--d-bg3); color: var(--d-text2); font-size: 0.52rem; font-weight: 600; cursor: pointer; transition: all 0.12s; display: flex; align-items: center; gap: 0.25rem; } .dev-btn:hover { border-color: var(--d-accent); color: var(--d-text); background: var(--d-surface); } .dev-btn.primary { background: var(--d-accent); border-color: var(--d-accent); color: #fff; } .dev-btn.primary:hover { background: var(--d-accent2); } .dev-select { padding: 0.12rem 0.3rem; border-radius: 4px; border: 1px solid var(--d-border); background: var(--d-bg3); color: var(--d-text); font-size: 0.52rem; outline: none; } .dev-select:focus { border-color: var(--d-accent); } .dev-input { padding: 0.18rem 0.35rem; border-radius: 4px; border: 1px solid var(--d-border); background: var(--d-bg3); color: var(--d-text); font-size: 0.5rem; outline: none; width: 100%; box-sizing: border-box; } .dev-input:focus { border-color: var(--d-accent); } /* ─── 뷰 탭 ─── */ .dev-view-tab { padding: 0.12rem 0.4rem; border-radius: 4px; border: 1px solid transparent; background: transparent; color: var(--d-text3); font-size: 0.52rem; cursor: pointer; transition: all 0.1s; font-weight: 600; } .dev-view-tab:hover { background: var(--d-surface); color: var(--d-text); } .dev-view-tab.active { background: var(--d-accent); color: #fff; border-color: var(--d-accent); } /* ═══ 3패널 ═══ */ .dev-body { display: flex; flex: 1; overflow: hidden; } /* ─── 좌: 팔레트 ─── */ .dev-palette { width: 180px; min-width: 180px; border-right: 1px solid var(--d-border); background: var(--d-bg2); overflow-y: auto; flex-shrink: 0; } .dev-pal-header { padding: 0.4rem 0.55rem; font-size: 0.48rem; font-weight: 700; color: var(--d-text3); text-transform: uppercase; letter-spacing: 0.06em; border-bottom: 1px solid var(--d-border); } .dev-pal-sec { padding: 0.4rem 0.55rem 0.15rem; font-size: 0.42rem; font-weight: 700; color: var(--d-accent); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 0.2rem; } .dev-pal-item { display: flex; align-items: center; gap: 0.4rem; padding: 0.28rem 0.55rem; font-size: 0.56rem; font-weight: 500; color: var(--d-text2); cursor: grab; transition: all 0.1s; border-radius: 4px; margin: 1px 3px; } .dev-pal-item:hover { background: var(--d-surface); color: var(--d-text); } .dev-pal-item:active { cursor: grabbing; background: var(--d-surface2); } .dev-pal-icon { width: 18px; height: 18px; border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 0.65rem; flex-shrink: 0; } /* 카테고리별 아이콘 색상 */ .dev-pal-item[data-cat="data"] .dev-pal-icon { color: var(--d-accent); } .dev-pal-item[data-cat="input"] .dev-pal-icon { color: var(--d-green); } .dev-pal-item[data-cat="action"] .dev-pal-icon { color: var(--d-pink); } .dev-pal-item[data-cat="display"] .dev-pal-icon { color: var(--d-orange); } /* ─── 중: 캔버스 ─── */ .dev-canvas { flex: 1; overflow: auto; position: relative; background: var(--d-bg); } .dark .dev-canvas { background-image: radial-gradient(circle, rgba(255,255,255,0.03) 0.5px, transparent 0.5px); background-size: 20px 20px; } :root:not(.dark) .dev-canvas, html:not(.dark) .dev-canvas { background-image: radial-gradient(circle, rgba(0,0,0,0.06) 0.5px, transparent 0.5px); background-size: 20px 20px; } .dev-canvas-inner { position: relative; min-width: 1200px; min-height: 800px; padding: 16px; } /* 12-col grid 캔버스 (business kind) */ .dev-canvas-grid { position: relative; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 8px; padding: 16px; min-height: 600px; box-sizing: border-box; container-type: inline-size; container-name: card; background-image: linear-gradient(to right, var(--grid-line, rgba(var(--v5-primary-rgb),.08)) 1px, transparent 1px); background-size: calc((100% - 32px) / 12 + 8px) 100%; background-position: 16px 0; background-repeat: repeat-x; } .dev-canvas-grid.dragging { background-image: linear-gradient(to right, var(--grid-line-hover, rgba(var(--v5-primary-rgb),.2)) 1px, transparent 1px); } /* 빌더 팝업 프레임 안의 grid */ .dev-popup-grid { min-height: 320px; padding: 12px; } /* grid 경고 — 비-grid 블록 잔존 시 */ .dev-grid-warn { grid-column: 1 / -1; padding: .5rem .75rem; font-size: .5rem; color: var(--d-orange, #e29a45); background: rgba(255, 200, 60, .08); border: 1px dashed rgba(255, 200, 60, .35); border-radius: 6px; } /* 블록 — grid item */ .dev-block { position: relative; min-width: 0; min-height: 48px; border: 1.5px dashed var(--d-border2); border-radius: 6px; background: var(--d-bg2); cursor: move; transition: border-color 0.1s, box-shadow 0.1s; overflow: hidden; } .dev-block:hover { border-color: var(--d-accent); box-shadow: 0 0 0 1px var(--d-accent); } .dev-block.selected { border-color: var(--d-accent); border-style: solid; border-width: 2px; box-shadow: 0 0 0 3px rgba(91,158,245,0.15); } .dev-block-label { position: absolute; top: -1px; left: 6px; padding: 0 0.3rem; font-size: 0.4rem; font-weight: 700; color: var(--d-accent); background: var(--d-bg); letter-spacing: 0.02em; z-index: 1; } .dev-block.selected .dev-block-label { background: var(--d-accent); color: #fff; border-radius: 0 0 3px 3px; padding: 0.02rem 0.3rem; } .dev-block-content { padding: 0.4rem; font-size: 0.5rem; color: var(--d-text2); pointer-events: none; height: 100%; display: flex; flex-direction: column; padding-top: 0.7rem; } /* 리사이즈 핸들 */ .dev-resize-handle { position: absolute; bottom: 0; right: 0; width: 12px; height: 12px; cursor: nwse-resize; z-index: 2; } .dev-resize-handle::after { content: ''; position: absolute; bottom: 2px; right: 2px; width: 6px; height: 6px; border-right: 2px solid var(--d-border2); border-bottom: 2px solid var(--d-border2); } .dev-block.selected .dev-resize-handle::after { border-color: var(--d-accent); } /* ─── 우: 속성 패널 ─── */ .dev-props { width: 260px; min-width: 260px; border-left: 1px solid var(--d-border); background: var(--d-bg2); overflow-y: auto; flex-shrink: 0; } .dev-prop-header { padding: 0.4rem 0.6rem; font-size: 0.55rem; font-weight: 700; color: var(--d-text); border-bottom: 1px solid var(--d-border); display: flex; align-items: center; gap: 0.25rem; background: var(--d-bg3); } .dev-prop-sec { padding: 0.4rem 0.6rem 0.15rem; font-size: 0.42rem; font-weight: 700; color: var(--d-accent); text-transform: uppercase; letter-spacing: 0.04em; border-top: 1px solid var(--d-border); margin-top: 0.15rem; } .dev-prop-sec:first-of-type { border-top: none; margin-top: 0; } .dev-prop-row { padding: 0.2rem 0.6rem; display: flex; flex-direction: column; gap: 0.08rem; } .dev-prop-row.inline { flex-direction: row; align-items: center; justify-content: space-between; } .dev-prop-label { font-size: 0.46rem; font-weight: 600; color: var(--d-text3); } /* 위치 그리드 (col/span/row/rowSpan 4칸) */ .dev-pos-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.2rem; padding: 0.2rem 0.6rem; } /* 반응형 오버라이드 섹션 */ .dev-resp-row { border-top: 1px dashed var(--d-border); padding: 0.25rem 0 0.2rem; } .dev-resp-row:first-of-type { border-top: none; } .dev-resp-label { padding: 0.2rem 0.6rem 0.05rem; font-size: 0.42rem; font-weight: 700; color: var(--d-text3); text-transform: uppercase; letter-spacing: 0.04em; } .dev-pos-item { display: flex; align-items: center; gap: 0.2rem; } .dev-pos-item label { font-size: 0.42rem; font-weight: 700; color: var(--d-text3); width: 14px; } .dev-pos-item input { flex: 1; padding: 0.12rem 0.2rem; border-radius: 3px; border: 1px solid var(--d-border); background: var(--d-bg3); color: var(--d-text); font-size: 0.46rem; text-align: center; outline: none; width: 0; } .dev-pos-item input:focus { border-color: var(--d-accent); } /* 토글 */ .dev-toggle { width: 26px; height: 14px; border-radius: 7px; background: var(--d-border); position: relative; cursor: pointer; transition: background 0.12s; flex-shrink: 0; } .dev-toggle.on { background: var(--d-accent); } .dev-toggle::after { content: ''; position: absolute; width: 10px; height: 10px; border-radius: 50%; background: #fff; top: 2px; left: 2px; transition: left 0.12s; } .dev-toggle.on::after { left: 14px; } /* 필드 목록 */ .dev-field-list { padding: 0 0.6rem 0.2rem; max-height: 280px; overflow-y: auto; } .dev-field-item { display: flex; align-items: center; gap: 0.3rem; padding: 0.18rem 0; font-size: 0.48rem; color: var(--d-text2); border-bottom: 1px dashed var(--d-border); cursor: pointer; transition: background 0.08s; border-radius: 2px; } .dev-field-item:last-child { border-bottom: none; } .dev-field-item:hover { background: var(--d-surface); } .dev-field-check { width: 14px; height: 14px; border-radius: 3px; border: 1.5px solid var(--d-border2); display: flex; align-items: center; justify-content: center; font-size: 0.42rem; cursor: pointer; transition: all 0.1s; flex-shrink: 0; color: transparent; } .dev-field-check.on { background: var(--d-accent); border-color: var(--d-accent); color: #fff; } .dev-field-name { flex: 1; font-weight: 500; color: var(--d-text); font-size: 0.48rem; } .dev-field-type { font-size: 0.4rem; color: var(--d-text3); font-weight: 600; padding: 0.08rem 0.25rem; border-radius: 3px; background: var(--d-surface); } .dev-field-drag { color: var(--d-text3); cursor: grab; font-size: 0.5rem; } /* 필드 배지 */ .dev-fc-badge { font-size: 0.36rem; font-weight: 700; padding: 0.04rem 0.18rem; border-radius: 2px; letter-spacing: 0.02em; } .dev-fc-badge.pk { background: var(--d-accent); color: #fff; } .dev-fc-badge.req { background: var(--d-red); color: #fff; } .dev-fc-badge.sch { background: var(--d-green); color: #fff; } .dev-fc-badge.sys { background: var(--d-text3); color: #fff; } .dev-fc-badge.cmp { background: var(--d-orange); color: #fff; } /* ═══ 상태바 ═══ */ .dev-status { display: flex; align-items: center; justify-content: space-between; padding: 0 0.8rem; height: 22px; font-size: 0.42rem; color: var(--d-text3); background: var(--d-bg2); border-top: 1px solid var(--d-border); flex-shrink: 0; } /* ═══ 빈 캔버스 ═══ */ .dev-empty { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: var(--d-text3); } .dev-empty-icon { font-size: 2rem; margin-bottom: 0.4rem; opacity: 0.3; } .dev-empty-text { font-size: 0.6rem; font-weight: 500; } /* ═══ 프리뷰 테이블 ═══ */ .dev-pv-table { width: 100%; border-collapse: collapse; font-size: 0.48rem; } .dev-pv-table th { text-align: left; padding: 0.22rem 0.35rem; font-weight: 700; color: var(--d-text3); border-bottom: 1px solid var(--d-border); font-size: 0.42rem; text-transform: uppercase; } .dev-pv-table td { padding: 0.22rem 0.35rem; border-bottom: 1px dashed var(--d-border); color: var(--d-text2); } /* ═══ 프리뷰 폼 ═══ */ .dev-pv-field { display: flex; flex-direction: column; gap: 0.1rem; margin-bottom: 0.35rem; } .dev-pv-field-label { font-size: 0.42rem; font-weight: 700; color: var(--d-text3); } .dev-pv-field-input { padding: 0.22rem 0.35rem; border-radius: 4px; border: 1px solid var(--d-border); background: var(--d-bg3); font-size: 0.48rem; color: var(--d-text2); } /* ═══ 프리뷰 검색 ═══ */ .dev-pv-search { display: flex; gap: 0.25rem; flex-wrap: wrap; } .dev-pv-search-item { display: flex; flex-direction: column; gap: 0.06rem; } .dev-pv-search-label { font-size: 0.38rem; font-weight: 600; color: var(--d-text3); } .dev-pv-search-input { padding: 0.18rem 0.3rem; border-radius: 3px; border: 1px solid var(--d-border); background: var(--d-bg3); font-size: 0.44rem; color: var(--d-text2); min-width: 80px; } /* ═══ 프리뷰 버튼 ═══ */ .dev-pv-btn { display: inline-flex; align-items: center; gap: 0.2rem; padding: 0.18rem 0.45rem; border-radius: 4px; font-size: 0.46rem; font-weight: 600; border: 1px solid var(--d-border); color: var(--d-text2); } .dev-pv-btn.primary { background: var(--d-accent); border-color: var(--d-accent); color: #fff; } /* ═══ 팝업 오버레이 ═══ */ .dev-popup-overlay { position: absolute; inset: 0; background: rgba(0,0,0,0.3); display: flex; align-items: center; justify-content: center; z-index: 20; } .dev-popup-frame { width: 500px; min-height: 300px; border-radius: 8px; border: 1px solid var(--d-border); background: var(--d-bg2); position: relative; overflow: hidden; box-shadow: 0 20px 60px rgba(0,0,0,0.3); } .dev-popup-frame .dev-canvas-inner { min-width: unset; min-height: 300px; padding: 12px; } /* ═══ 힌트 텍스트 ═══ */ .dev-hint { font-size: 0.42rem; color: var(--d-text3); padding: 0.15rem 0.6rem; font-style: italic; } /* ═══ 삭제 버튼 ═══ */ .dev-delete-btn { width: 100%; padding: 0.25rem; border-radius: 4px; border: 1px solid var(--d-red); background: transparent; color: var(--d-red); font-size: 0.46rem; font-weight: 600; cursor: pointer; transition: all 0.12s; } .dev-delete-btn:hover { background: var(--d-red); color: #fff; }