fix #488: improve mobile responsive layout
This commit is contained in:
43
docs/design/488-ux-mobile-responsive/README.md
Normal file
43
docs/design/488-ux-mobile-responsive/README.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Redmine #488 - 모바일 VPD/권한 화면 반응형 개선 설계
|
||||||
|
|
||||||
|
## 프로젝트 개요
|
||||||
|
|
||||||
|
VPD Backoffice는 Oracle Database VPD/ORDS 기능을 백오피스 권한 테이블로 제어하기 위한 Spring Boot 관리 도구다. 사용자는 사용자, 그룹, 역할, TABLE/VIEW 권한, VPD policy/filter, Bearer Token, ORDS 검증, MCP Reasoning을 한 화면 흐름에서 운영한다.
|
||||||
|
|
||||||
|
## 목표
|
||||||
|
|
||||||
|
390px 모바일 viewport에서 `VPD 설정`과 `권한 관리` 화면이 가로로 밀리지 않고, 아키텍처 설명 카드와 테이블/폼이 읽을 수 있는 형태로 표시되게 한다.
|
||||||
|
|
||||||
|
## 문제
|
||||||
|
|
||||||
|
캡처 기준:
|
||||||
|
|
||||||
|
- `/tmp/vpd-ux-audit/screenshots/mobile-vpd-policies.png`
|
||||||
|
- `/tmp/vpd-ux-audit/screenshots/mobile-permissions.png`
|
||||||
|
|
||||||
|
확인된 문제:
|
||||||
|
|
||||||
|
- `architecture-strip` 모바일 override가 기본 grid 선언보다 앞에 있어 390px에서도 5열 grid가 유지된다.
|
||||||
|
- 일부 grid/table item이 `min-width:auto`로 계산되어 `.table-responsive` 바깥의 body 폭을 밀어낸다.
|
||||||
|
- 행 규칙 grid가 모바일에서도 4열을 유지해 입력 컨트롤이 좁아진다.
|
||||||
|
|
||||||
|
## 설계
|
||||||
|
|
||||||
|
- 공통 CSS에서 architecture strip의 모바일 override를 실제 선언 뒤쪽에 다시 배치한다.
|
||||||
|
- card, form, table wrapper에 `min-width: 0`을 부여해 내부 overflow가 body 폭을 밀지 않게 한다.
|
||||||
|
- 모바일에서 큰 table은 body가 아니라 wrapper 내부에서만 horizontal scroll 되게 한다.
|
||||||
|
- 모바일에서 `form-grid`, `rule-row`, `section-heading`은 1열 또는 wrap 형태로 전환한다.
|
||||||
|
|
||||||
|
## 완료 기준
|
||||||
|
|
||||||
|
- 390px viewport에서 `document.documentElement.scrollWidth <= window.innerWidth`가 성립한다.
|
||||||
|
- `VPD 설정`, `권한 관리` 모바일 캡처에서 architecture strip이 1열로 표시된다.
|
||||||
|
- 테이블은 화면 밖으로 body를 밀지 않고 wrapper 내부에서 스크롤된다.
|
||||||
|
- 1440px 데스크톱 화면의 정보 밀도는 유지된다.
|
||||||
|
|
||||||
|
## 검증
|
||||||
|
|
||||||
|
- `mvn test`
|
||||||
|
- Playwright 캡처 또는 DOM 검사:
|
||||||
|
- `/vpd-policies`
|
||||||
|
- `/permissions`
|
||||||
@@ -215,12 +215,14 @@ body {
|
|||||||
gap: .5rem;
|
gap: .5rem;
|
||||||
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr);
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.architecture-step {
|
.architecture-step {
|
||||||
background: var(--rw-surface);
|
background: var(--rw-surface);
|
||||||
border: 1px solid var(--rw-border);
|
border: 1px solid var(--rw-border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
min-width: 0;
|
||||||
padding: .85rem;
|
padding: .85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,6 +249,7 @@ body {
|
|||||||
color: var(--rw-muted);
|
color: var(--rw-muted);
|
||||||
font-size: .82rem;
|
font-size: .82rem;
|
||||||
margin: .25rem 0 0;
|
margin: .25rem 0 0;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
}
|
}
|
||||||
|
|
||||||
.architecture-arrow {
|
.architecture-arrow {
|
||||||
@@ -298,6 +301,7 @@ body {
|
|||||||
|
|
||||||
.content-band {
|
.content-band {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
min-width: 0;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,6 +315,7 @@ body {
|
|||||||
.section-heading {
|
.section-heading {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
@@ -325,8 +330,9 @@ body {
|
|||||||
.form-grid {
|
.form-grid {
|
||||||
align-items: end;
|
align-items: end;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-grid label {
|
.form-grid label {
|
||||||
@@ -394,12 +400,14 @@ body {
|
|||||||
.rule-row {
|
.rule-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: .5rem;
|
gap: .5rem;
|
||||||
grid-template-columns: 1fr 1fr 1fr auto;
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.permission-wizard {
|
.permission-wizard {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-progress {
|
.wizard-progress {
|
||||||
@@ -428,7 +436,8 @@ body {
|
|||||||
.wizard-summary {
|
.wizard-summary {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: .75rem;
|
gap: .75rem;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr));
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-summary > div,
|
.wizard-summary > div,
|
||||||
@@ -458,6 +467,7 @@ body {
|
|||||||
border: 1px solid var(--rw-border);
|
border: 1px solid var(--rw-border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
display: none;
|
display: none;
|
||||||
|
min-width: 0;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1042,18 +1052,119 @@ body {
|
|||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-responsive {
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-responsive > .table {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th,
|
||||||
|
.table td {
|
||||||
|
min-width: 0;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-responsive > .table th,
|
||||||
|
.table-responsive > .table td {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table code,
|
||||||
|
.table-responsive > .table code {
|
||||||
|
overflow-wrap: normal;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-break: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-pre {
|
||||||
|
max-height: 8rem;
|
||||||
|
overflow: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 920px) {
|
||||||
|
.architecture-strip {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.architecture-arrow {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
|
main.container {
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
padding-left: .75rem;
|
||||||
|
padding-right: .75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title h1 {
|
||||||
|
font-size: 1.45rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-band {
|
||||||
|
padding: .85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-heading {
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.form-grid .span-2 {
|
.form-grid .span-2 {
|
||||||
grid-column: span 1;
|
grid-column: span 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rule-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rule-row .btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-panel {
|
||||||
|
padding: .85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-actions {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizard-actions .btn {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-responsive > .table {
|
||||||
|
min-width: 960px;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar .container {
|
.navbar .container {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: .75rem;
|
gap: .75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-nav {
|
.rw-menu {
|
||||||
flex-wrap: wrap;
|
width: 100%;
|
||||||
gap: .25rem;
|
}
|
||||||
|
|
||||||
|
.rw-menu-group {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rw-menu-trigger {
|
||||||
|
padding-left: .65rem;
|
||||||
|
padding-right: .65rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user