feat: xkeypad 보안 키패드 통합 및 비밀번호 변경 기능 구현

- xkeypad 보안 키패드 라이브러리 추가
- 비밀번호 변경 페이지에 보안 키패드 적용
- RSA 암호화 기능 통합
- route 설정 및 Sentry 설정 업데이트

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jay Sheen
2025-10-21 14:59:07 +09:00
parent ab5bea6aeb
commit 1648a30844
41 changed files with 3426 additions and 11 deletions

View File

@@ -0,0 +1,206 @@
/**
* XKeypad Modal Styles
* 키패드 모달 스타일
*/
/* 모달 오버레이 - 전체화면 */
.xkeypad-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.75);
z-index: 9998;
display: none;
animation: fadeIn 0.2s ease;
}
.xkeypad-modal-overlay.active {
display: block;
}
/* 모달 컨테이너 */
.xkeypad-modal-container {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: transparent;
z-index: 9999;
transform: translateY(100%);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
/* Safe area 적용 */
padding-bottom: env(safe-area-inset-bottom, 0);
padding-bottom: constant(safe-area-inset-bottom, 0); /* iOS 11.0 */
}
.xkeypad-modal-container.active {
transform: translateY(0);
}
/* 키패드 래퍼 */
.xkeypad-wrapper {
position: relative;
background-color: #dbdde2;
overflow: hidden;
}
/* 키패드 컨텐츠 영역 */
.xkeypad-content {
position: relative;
background-color: #dbdde2;
}
/* XKeypad 컨테이너가 모달 내에서 보이도록 */
.xkeypad-content .xkp_ui_qwerty,
.xkeypad-content .xkp_ui_number {
position: relative !important;
z-index: 10001 !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
width: 100% !important;
height: auto !important;
}
/* 모든 키패드 자식 요소들이 보이도록 */
.xkeypad-content .xkp_ui_qwerty *,
.xkeypad-content .xkp_ui_number * {
visibility: visible !important;
opacity: 1 !important;
}
/* 키패드 DIV가 모달 내에서 보이도록 */
.xkeypad-content > div {
position: relative !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
/* 키패드 버튼들이 보이도록 */
.xkeypad-content ul,
.xkeypad-content li,
.xkeypad-content a {
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
/* 애니메이션 */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
/* 반응형 대응 */
@media (max-width: 768px) {
.xkeypad-modal-container {
/* 모바일에서는 전체 너비 */
left: 0;
right: 0;
}
}
@media (min-width: 769px) {
/* 데스크톱에서는 중앙 정렬 */
.xkeypad-modal-container {
left: 50%;
transform: translateX(-50%) translateY(100%);
max-width: 600px;
width: 100%;
}
.xkeypad-modal-container.active {
transform: translateX(-50%) translateY(0);
}
}
/* iOS 노치 대응 */
@supports (padding: max(0px)) {
.xkeypad-modal-container {
padding-bottom: max(env(safe-area-inset-bottom, 0), 0px);
}
}
/* 키패드 타입별 높이는 자동 조정 - min-height 제거 */
/* 입력 필드 활성화 스타일 */
.xkeypad-input-active {
border-color: #4CAF50 !important;
box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1) !important;
}
/* 모달 열림/닫힘 시 body 스크롤 방지 */
body.xkeypad-modal-open {
position: fixed;
width: 100%;
overflow: hidden;
/* top 값은 JavaScript에서 동적으로 설정 */
}
/* iOS 바운스 스크롤 방지 */
.xkeypad-modal-container {
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
}
/* 터치 이벤트 최적화 */
.xkeypad-modal-overlay,
.xkeypad-modal-container {
touch-action: none;
}
.xkeypad-content {
touch-action: manipulation;
}
/* 다크모드 지원 */
@media (prefers-color-scheme: dark) {
.xkeypad-modal-overlay {
background-color: rgba(0, 0, 0, 0.7);
}
.xkeypad-wrapper {
background-color: #2c2c2e;
border-top-color: #48484a;
}
.xkeypad-modal-header {
background-color: #1c1c1e;
border-bottom-color: #48484a;
}
.xkeypad-drag-indicator {
background-color: #636366;
}
.xkeypad-close-btn {
background-color: rgba(255, 255, 255, 0.1);
}
.xkeypad-close-btn:hover {
background-color: rgba(255, 255, 255, 0.2);
}
.xkeypad-close-btn::before {
color: #f0f0f0;
}
}