From 58ea25047c79824eebb34e36f73ec27d129ae71f Mon Sep 17 00:00:00 2001 From: MYONG JAEWI <78201530+Jaymyong66@users.noreply.github.com> Date: Mon, 11 May 2026 21:08:13 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(layout):=20StepsScroll=EC=97=90=20min-h?= =?UTF-8?q?eight:0=20=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20=ED=8C=A8?= =?UTF-8?q?=EB=84=90=20=EB=82=B4=EB=B6=80=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit flex column 자식이 'flex: 1; overflow-y: auto;'로 정의되어 있어도 min-height 기본값(auto)이면 자식 컨텐츠의 내재 높이만큼 확장되어 overflow-y가 활성화되지 않는 flexbox 함정. Oracle 탭(OracleStepPanel)에서 OracleConsole + ClaimApproval 두 카드가 항상 함께 펼쳐져 컨테이너 높이를 초과하면서 잘려 보이고 스크롤도 되지 않던 문제를 해결. tab-contract는 StepCard accordion으로 활성 step만 펼쳐져 같은 함정에도 노출도가 낮았음. Co-Authored-By: Claude Opus 4.7 --- frontend/src/components/common/StepPanel.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/components/common/StepPanel.tsx b/frontend/src/components/common/StepPanel.tsx index c7ea84c9..199b27af 100644 --- a/frontend/src/components/common/StepPanel.tsx +++ b/frontend/src/components/common/StepPanel.tsx @@ -50,6 +50,9 @@ export const PanelStatusBadge = styled.span<{ variant?: 'warning' | 'accent' | ' export const StepsScroll = styled.div` flex: 1; + /* min-height: 0 — flex column 안에서 overflow-y: auto가 실제로 작동하려면 필수. + 없으면 자식 컨텐츠의 내재 높이만큼 확장되어 스크롤이 활성화되지 않는다. */ + min-height: 0; overflow-y: auto; padding: 8px; display: flex; From 4d3b90612490430ef7285caa4ac774dcbeda3ec7 Mon Sep 17 00:00:00 2001 From: MYONG JAEWI <78201530+Jaymyong66@users.noreply.github.com> Date: Mon, 11 May 2026 21:48:24 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix(layout):=20Oracle=20=ED=83=AD=20ActionP?= =?UTF-8?q?anel=20=EC=BB=A8=ED=85=90=EC=B8=A0=20=EC=9E=98=EB=A6=BC=20?= =?UTF-8?q?=E2=80=94=20Card=20flex-shrink=20=EC=B0=A8=EB=8B=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 진짜 원인: StepsScroll의 display:flex column 안에서 자식 Card들이 기본 flex-shrink:1 때문에 컨테이너 높이에 맞추기 위해 강제로 줄어들었고, 자기 자신만 작아진 Card의 overflow:hidden이 안의 CardBody 하단을 클립해 ClaimApproval의 Approve/Settle 버튼이 사라지던 현상. flex가 미리 자식을 줄여놓아서 scrollHeight === clientHeight가 되었고, overflow-y:auto가 작동할 'overflow'가 발생하지 않아 마우스 휠 스크롤도 무반응. computed style + 부모 chain dump로 Card height(181) vs CardBody height(221) 불일치를 확인하여 짚었다. 수정: - StepsScroll > * { flex-shrink: 0 } — 자식 Card가 자연 높이를 유지하게 하여 총합이 컨테이너를 초과하면 비로소 overflow-y:auto가 작동 - 함께 잡은 layout 보강: * Dashboard.tsx Body/TabContent에 min-height:0, min-width:0 * ActionPanel에 align-self:stretch + height:100% + max-height: calc(100vh - 140px) + min-height:0 — flex chain 안전 보강 + viewport 기준 hard ceiling * StepsScroll 스크롤바 가시성 향상 (3px → 8px, hover 색상) Co-Authored-By: Claude Opus 4.7 --- frontend/src/components/common/StepPanel.tsx | 28 ++++++++++++++++++-- frontend/src/pages/Dashboard.tsx | 7 +++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/common/StepPanel.tsx b/frontend/src/components/common/StepPanel.tsx index 199b27af..955a2954 100644 --- a/frontend/src/components/common/StepPanel.tsx +++ b/frontend/src/components/common/StepPanel.tsx @@ -11,6 +11,13 @@ export const ActionPanel = styled.div` flex-direction: column; overflow: hidden; background: ${p => p.theme.colors.bg}; + /* 높이 제약 — flex chain이 정상이면 height:100% 만으로 충분. 그래도 안전차원에서 + viewport 기준 max-height(헤더 ~140px 추정)도 같이 걸어둔다. align-self:stretch를 명시하여 + row flex 부모에서 cross-axis가 컨텐츠 크기로 부풀지 않게 한다. */ + align-self: stretch; + height: 100%; + max-height: calc(100vh - 140px); + min-height: 0; `; export const PanelHeader = styled.div` @@ -58,9 +65,26 @@ export const StepsScroll = styled.div` display: flex; flex-direction: column; gap: 5px; + /* 자식 Card들이 flex-shrink:1 기본값으로 줄어들어 컨텐츠를 잘라먹는 걸 방지. + 이게 빠지면 Card의 overflow:hidden이 CardBody 하단을 클립해 버튼이 사라진다. */ + > * { flex-shrink: 0; } + /* 스크롤 가능 여부를 사용자가 인지할 수 있도록 스크롤바를 충분히 보이게 */ + scrollbar-width: thin; + scrollbar-color: ${p => p.theme.colors.border2} transparent; - &::-webkit-scrollbar { width: 3px; } - &::-webkit-scrollbar-thumb { background: ${p => p.theme.colors.border2}; border-radius: 2px; } + &::-webkit-scrollbar { width: 8px; } + &::-webkit-scrollbar-track { background: transparent; } + &::-webkit-scrollbar-thumb { + background: ${p => p.theme.colors.border2}; + border-radius: 4px; + border: 2px solid transparent; + background-clip: padding-box; + } + &::-webkit-scrollbar-thumb:hover { + background: ${p => p.theme.colors.sub}; + background-clip: padding-box; + border: 2px solid transparent; + } `; export const ContentArea = styled.div` diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index df784e8b..721ad5e0 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -21,12 +21,19 @@ const DashboardRoot = styled.div` const Body = styled.div` display: flex; flex: 1; + /* min-height: 0 — column 부모(DashboardRoot)의 main축에서 컨텐츠보다 작게 줄어들 수 있도록. + 없으면 본인이 자식 컨텐츠의 내재 높이만큼 늘어 ActionPanel/StepsScroll의 높이 제약이 풀린다. */ + min-height: 0; overflow: hidden; `; const TabContent = styled.div<{ visible: boolean }>` display: ${p => (p.visible ? 'flex' : 'none')}; flex: 1; + /* TabContent는 row flex 컨테이너이지만 자체도 row(Body)의 자식. cross축(높이)은 Body 높이로 결정. + Body의 min-height:0 만으로 충분하지만 안전하게 자체에도 부여. */ + min-height: 0; + min-width: 0; overflow: hidden; `;