회원탈퇴 팝업 UI 개선 및 관련 JS 이벤트 처리 추가
This commit is contained in:
@@ -329,6 +329,149 @@ src/main/java/com/eactive/apim/portal/
|
||||
- `elink-portal-common`: 공통 유틸리티 (../elink-portal-common)
|
||||
- `kjb-safedb`: SafeDB 암호화 라이브러리 (../kjb-safedb)
|
||||
|
||||
## SASS / CSS 스타일 개발
|
||||
|
||||
### 개요
|
||||
|
||||
이 프로젝트는 **Dart Sass**를 사용하여 CSS를 관리합니다.
|
||||
`src/main/resources/static/css/main.css`는 SASS에서 컴파일된 결과물이므로 **직접 수정하면 안 됩니다.**
|
||||
스타일 변경은 반드시 `src/main/resources/static/sass/` 하위 파일을 수정하세요.
|
||||
|
||||
### 설치
|
||||
|
||||
```bash
|
||||
# Node.js가 설치된 상태에서
|
||||
npm install
|
||||
```
|
||||
|
||||
### 빌드 명령어
|
||||
|
||||
```bash
|
||||
# 1회 컴파일 (개발용, 들여쓰기 유지)
|
||||
npm run sass:build
|
||||
|
||||
# 1회 컴파일 (배포용, minified)
|
||||
npm run sass:build:minified
|
||||
|
||||
# 파일 변경 감지 후 자동 컴파일 (개발 중 권장)
|
||||
npm run sass:watch
|
||||
|
||||
# 빌드 + minified 동시 생성
|
||||
npm run build
|
||||
|
||||
# 단축 스크립트 (npm 없이 sass 직접 실행)
|
||||
./sass-build.sh
|
||||
```
|
||||
|
||||
### SASS 파일 구조
|
||||
|
||||
```
|
||||
src/main/resources/static/sass/
|
||||
├── main.scss # 진입점 - 모든 파일을 @use로 조합
|
||||
│
|
||||
├── abstracts/ # CSS 출력 없는 헬퍼 (변수, 믹스인 등)
|
||||
│ ├── _variables.scss # 색상, 타이포그래피, 그림자 변수
|
||||
│ ├── _mixins.scss # 재사용 믹스인
|
||||
│ └── _color-functions.scss # Dart Sass 3.0 color 유틸리티
|
||||
│
|
||||
├── base/ # 전역 기본 스타일
|
||||
│ ├── _reset.scss
|
||||
│ ├── _typography.scss
|
||||
│ ├── _animations.scss
|
||||
│ ├── _kjb-font.scss # 광주은행 전용 폰트
|
||||
│ └── _utilities.scss # 유틸리티 클래스
|
||||
│
|
||||
├── layout/ # 페이지 레이아웃 구조
|
||||
│ ├── _header.scss
|
||||
│ ├── _footer.scss
|
||||
│ ├── _grid.scss
|
||||
│ └── _container.scss
|
||||
│
|
||||
├── components/ # 재사용 UI 컴포넌트
|
||||
│ ├── _buttons.scss
|
||||
│ ├── _forms.scss
|
||||
│ ├── _modals.scss # customPopup 모달 스타일
|
||||
│ ├── _tables.scss
|
||||
│ ├── _badges.scss
|
||||
│ ├── _cards.scss
|
||||
│ ├── _navigation.scss
|
||||
│ ├── _pagination.scss
|
||||
│ └── ...
|
||||
│
|
||||
├── pages/ # 페이지별 스타일
|
||||
│ ├── _mypage.scss
|
||||
│ ├── _login.scss
|
||||
│ ├── _apikey-list.scss
|
||||
│ └── ...
|
||||
│
|
||||
├── themes/
|
||||
│ └── _dark.scss # 다크 테마 (예약)
|
||||
│
|
||||
└── vendors/
|
||||
└── _overrides.scss # 외부 라이브러리 스타일 덮어쓰기
|
||||
```
|
||||
|
||||
### 새 스타일 추가하는 방법
|
||||
|
||||
#### 1. 기존 컴포넌트/페이지 파일에 추가
|
||||
해당 `_*.scss` 파일을 직접 수정합니다.
|
||||
|
||||
```scss
|
||||
// components/_buttons.scss 예시
|
||||
.btn-withdrawal {
|
||||
color: $text-gray;
|
||||
border: 1px solid $border-gray;
|
||||
|
||||
&:hover {
|
||||
color: $accent-orange;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 새 페이지 스타일 파일 추가
|
||||
|
||||
```bash
|
||||
# 1. 파일 생성 (언더스코어 접두사 필수)
|
||||
touch src/main/resources/static/sass/pages/_new-page.scss
|
||||
|
||||
# 2. main.scss 에 @use 추가
|
||||
```
|
||||
|
||||
```scss
|
||||
// main.scss 에 추가
|
||||
@use 'pages/new-page' as *;
|
||||
```
|
||||
|
||||
#### 3. 변수 활용 예시
|
||||
|
||||
```scss
|
||||
// abstracts/_variables.scss 에 정의된 변수 사용
|
||||
.my-component {
|
||||
color: $primary-blue; // #0049b4 (광주은행 블루)
|
||||
background: $gray-bg; // #F8FAFC
|
||||
border: 1px solid $border-gray; // #E2E8F0
|
||||
box-shadow: $shadow-md;
|
||||
font-family: $font-family-primary;
|
||||
}
|
||||
```
|
||||
|
||||
### 컴파일 결과 확인
|
||||
|
||||
```bash
|
||||
# 컴파일 후 출력 파일 확인
|
||||
ls -lh src/main/resources/static/css/main.css
|
||||
ls -lh src/main/resources/static/css/main.min.css # minified
|
||||
```
|
||||
|
||||
### 주의사항
|
||||
|
||||
- `src/main/resources/static/css/main.css` **직접 수정 금지** — SASS 재컴파일 시 덮어씌워짐
|
||||
- `style2.css` 는 레거시 파일(구 디자인 시스템)이며 `main.css` 와 **별도로 관리됨**
|
||||
- `@import` 대신 **`@use`** 사용 (Dart Sass 3.0 호환)
|
||||
- 파일명 앞에 언더스코어(`_`) 필수 — `_filename.scss` 형식이어야 단독 컴파일되지 않음
|
||||
|
||||
---
|
||||
|
||||
## AI 코딩 어시스턴트 지침 파일
|
||||
|
||||
이 프로젝트는 여러 AI 코딩 어시스턴트를 지원합니다. 각 도구는 다음 파일을 참조합니다:
|
||||
|
||||
@@ -576,6 +576,51 @@ const customPopups = {
|
||||
$(document).off('keydown.changeRole');
|
||||
},
|
||||
|
||||
showWithdrawal: function () {
|
||||
$('#withdrawalPopup').show();
|
||||
setTimeout(function() {
|
||||
$('#withdrawalModalBackdrop').addClass('show');
|
||||
$('#withdrawalModal').addClass('show');
|
||||
}, 10);
|
||||
|
||||
$('body').css('overflow', 'hidden');
|
||||
|
||||
$('#withdrawalPopupConfirmButton').off('click').on('click', function () {
|
||||
customPopups.hideWithdrawal();
|
||||
$('#withdrawalForm').submit();
|
||||
});
|
||||
|
||||
$('#withdrawalPopupCancelButton').off('click').on('click', function () {
|
||||
customPopups.hideWithdrawal();
|
||||
});
|
||||
|
||||
$('#withdrawalPopupCloseButton').off('click').on('click', function () {
|
||||
customPopups.hideWithdrawal();
|
||||
});
|
||||
|
||||
$(document).off('keydown.withdrawal').on('keydown.withdrawal', function (e) {
|
||||
if (e.key === 'Escape') {
|
||||
customPopups.hideWithdrawal();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
hideWithdrawal: function () {
|
||||
$('#withdrawalModalBackdrop').removeClass('show');
|
||||
$('#withdrawalModal').removeClass('show');
|
||||
|
||||
setTimeout(function() {
|
||||
$('#withdrawalPopup').hide();
|
||||
}, 300);
|
||||
|
||||
$('body').css('overflow', '');
|
||||
|
||||
$('#withdrawalPopupConfirmButton').off('click');
|
||||
$('#withdrawalPopupCancelButton').off('click');
|
||||
$('#withdrawalPopupCloseButton').off('click');
|
||||
$(document).off('keydown.withdrawal');
|
||||
},
|
||||
|
||||
init: function () {
|
||||
// emailValidationPopup 팝업의 닫기 버튼에 이벤트 리스너 추가
|
||||
$('#emailValidationPopupCloseButton').on('click', function () {
|
||||
|
||||
@@ -225,6 +225,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script th:if="${error}" th:inline="javascript">
|
||||
@@ -686,8 +687,20 @@
|
||||
|
||||
updateHiddenFields();
|
||||
initializePhoneNumbers();
|
||||
|
||||
// 회원탈퇴 버튼 이벤트
|
||||
const withdrawalBtn = document.querySelector('.withdrawal-link');
|
||||
if (withdrawalBtn) {
|
||||
withdrawalBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
customPopups.showWithdrawal();
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
<section layout:fragment="pagePopups">
|
||||
<th:block th:replace="~{fragment/popup/withdrawalPopup :: withdrawalPopup}"></th:block>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script th:if="${error}" th:inline="javascript">
|
||||
@@ -151,11 +152,14 @@
|
||||
if (withdrawalBtn) {
|
||||
withdrawalBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
document.getElementById('withdrawalPopup').style.display = 'block';
|
||||
customPopups.showWithdrawal();
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
<section layout:fragment="pagePopups">
|
||||
<th:block th:replace="~{fragment/popup/withdrawalPopup :: withdrawalPopup}"></th:block>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script th:if="${error}" th:inline="javascript">
|
||||
@@ -184,11 +185,14 @@
|
||||
if (withdrawalBtn) {
|
||||
withdrawalBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
document.getElementById('withdrawalPopup').style.display = 'block';
|
||||
customPopups.showWithdrawal();
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
<section layout:fragment="pagePopups">
|
||||
<th:block th:replace="~{fragment/popup/withdrawalPopup :: withdrawalPopup}"></th:block>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,65 +1,40 @@
|
||||
<section class="content pop" th:fragment="withdrawalPopup">
|
||||
<!-- 회원탈퇴 팝업 -->
|
||||
<div class="popup_total" id="withdrawalPopup" style="display:none; z-index: 1000;">
|
||||
<div class="pop_dim">
|
||||
<div class="inner">
|
||||
<div class="popup-content">
|
||||
<div class="inner_txt">
|
||||
<div class="title">
|
||||
<h2>API Portal 회원탈퇴</h2>
|
||||
</div>
|
||||
</div>
|
||||
<form id="withdrawalForm" th:action="@{/withdraw}" method="POST">
|
||||
<div class="pop_grid">
|
||||
<div class="list-dot list">
|
||||
<p>회원 탈퇴는 API Portal 사이트의 회원 탈퇴입니다.</p>
|
||||
<p>사용중인 API 서비스의 중지는 제휴 담당자를 통해 문의 주시기 바랍니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pop_btnbox">
|
||||
<button class="popup_button_gray btn_cancel">취소</button>
|
||||
<button class="popup_button_blue btn_withdraw">탈퇴신청</button>
|
||||
</div>
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
||||
</form>
|
||||
<a class="btn_close">
|
||||
<img th:src="@{/img/icon/icon_close2.png}" alt="닫기">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- views/fragment/popup/withdrawalPopup.html -->
|
||||
<div th:fragment="withdrawalPopup" id="withdrawalPopup" style="display: none;">
|
||||
<!-- Modal Backdrop -->
|
||||
<div class="modal-backdrop" id="withdrawalModalBackdrop"></div>
|
||||
|
||||
<!-- Modal Wrapper -->
|
||||
<div class="modal" id="withdrawalModal">
|
||||
<div class="modal-dialog">
|
||||
|
||||
<!-- Modal Header -->
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">API Portal 회원탈퇴</h3>
|
||||
<button type="button" class="modal-close" id="withdrawalPopupCloseButton">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Modal Body -->
|
||||
<div class="modal-body">
|
||||
<ul style="margin: 0; padding-left: 20px; color: #64748B; font-size: 14px; line-height: 1.8;">
|
||||
<li>회원 탈퇴는 API Portal 사이트의 회원 탈퇴입니다.</li>
|
||||
<li>사용중인 API 서비스의 중지는 제휴 담당자를 통해 문의 주시기 바랍니다.</li>
|
||||
</ul>
|
||||
<form id="withdrawalForm" th:action="@{/withdraw}" method="POST" style="display:none;">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer -->
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" id="withdrawalPopupCancelButton">취소</button>
|
||||
<button type="button" class="btn btn-primary" id="withdrawalPopupConfirmButton">탈퇴신청</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
const withdrawalPopup = {
|
||||
init: function() {
|
||||
this.bindEvents();
|
||||
},
|
||||
|
||||
bindEvents: function() {
|
||||
$('.withdrawal a').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$('#withdrawalPopup').show();
|
||||
});
|
||||
|
||||
// 팝업 닫기 - 닫기 버튼과 취소 버튼
|
||||
$('#withdrawalPopup .btn_close, #withdrawalPopup .btn_cancel').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$('#withdrawalPopup').hide();
|
||||
});
|
||||
|
||||
$('#withdrawalPopup .btn_withdraw').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
withdrawalPopup.handleWithdrawal();
|
||||
});
|
||||
},
|
||||
|
||||
handleWithdrawal: function() {
|
||||
$('#withdrawalForm').submit();
|
||||
}
|
||||
};
|
||||
|
||||
withdrawalPopup.init();
|
||||
});
|
||||
</script>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user