feat(redesign): 로그인/회원가입 비주얼 마크업 이식

비번 보기 토글(.pw-field/.pw-toggle), 강도막대(.pw-meter),
일치표시(.form-ok), 에러 슬롯(.form-error) DOM/클래스 추가.
제출은 기존 AJAX(fetch /login·/signup)+CSRF 이중방어(_csrf hidden
+ BibimbapCsrf.headers) 그대로 보존, 필드 name·id 불변.
토글/강도/일치는 인라인 onclick/oninput 별도 스코프 — submit 무간섭.
/password/reset 링크는 라우트 미존재로 비노출.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
이정수 2026-06-30 16:18:19 +09:00
parent 5f0652edda
commit f266aeef9b
2 changed files with 69 additions and 3 deletions

View File

@ -202,6 +202,30 @@
gap: 0.625rem;
}
}
.pw-field {
position: relative;
display: flex;
align-items: center;
}
.pw-field .auth-field__input {
padding-right: 4rem;
flex: 1;
}
.pw-toggle {
position: absolute;
right: 0.75rem;
background: none;
border: none;
color: var(--text-muted);
font-size: 0.8125rem;
cursor: pointer;
padding: 0 0.25rem;
}
.form-error {
color: #d32f2f;
font-size: 0.8125rem;
margin: 0;
}
</style>
</head>
<body>
@ -228,7 +252,11 @@
</div>
<div class="auth-field">
<label class="auth-field__label" for="login-password">비밀번호</label>
<input class="auth-field__input" type="password" id="login-password" name="password" autocomplete="current-password" required />
<div class="pw-field">
<input class="auth-field__input" type="password" id="login-password" name="password" autocomplete="current-password" required />
<button type="button" class="pw-toggle"
onclick="var p=document.getElementById('login-password');p.type=p.type==='password'?'text':'password';this.textContent=p.type==='password'?'보기':'숨기기'">보기</button>
</div>
</div>
<div class="auth-row">
<label class="auth-check">
@ -236,6 +264,7 @@
<span>로그인 유지</span>
</label>
</div>
<div class="form-error" id="login-form-error" hidden></div>
<button class="auth-button auth-button--primary" type="submit">로그인</button>
</form>

View File

@ -200,6 +200,37 @@
grid-template-columns: 1fr;
}
}
.pw-meter {
display: flex;
gap: 4px;
height: 4px;
margin-top: 6px;
}
.pw-meter span {
flex: 1;
border-radius: 2px;
background: var(--border);
transition: background 0.2s;
}
.pw-meter[data-level="1"] span:nth-child(1) { background: #e53935; }
.pw-meter[data-level="2"] span:nth-child(1),
.pw-meter[data-level="2"] span:nth-child(2) { background: #fb8c00; }
.pw-meter[data-level="3"] span { background: #43a047; }
.form-ok {
color: #43a047;
font-size: 0.8125rem;
margin: 4px 0 0;
}
.form-error {
color: #d32f2f;
font-size: 0.8125rem;
margin: 0;
}
.help {
font-size: 0.8125rem;
color: var(--text-muted);
margin: 4px 0 0;
}
</style>
</head>
<body>
@ -233,11 +264,16 @@
<div class="auth-grid">
<div class="auth-field">
<label class="auth-field__label" for="signup-password">비밀번호</label>
<input class="auth-field__input" type="password" id="signup-password" name="password" autocomplete="new-password" minlength="8" required />
<input class="auth-field__input" type="password" id="signup-password" name="password" autocomplete="new-password" minlength="8" required
oninput="document.getElementById('signup-pw-meter').dataset.level=this.value.length>=10?3:this.value.length>=8?2:this.value?1:0" />
<div class="pw-meter" id="signup-pw-meter" data-level="0"><span></span><span></span><span></span></div>
<p class="help">8자 이상, 영문·숫자 조합을 권장합니다</p>
</div>
<div class="auth-field">
<label class="auth-field__label" for="signup-password-confirm">비밀번호 확인</label>
<input class="auth-field__input" type="password" id="signup-password-confirm" name="passwordConfirm" autocomplete="new-password" minlength="8" required />
<input class="auth-field__input" type="password" id="signup-password-confirm" name="passwordConfirm" autocomplete="new-password" minlength="8" required
oninput="document.getElementById('signup-pw-ok').hidden=!this.value||this.value!==document.getElementById('signup-password').value" />
<p class="form-ok" id="signup-pw-ok" hidden>✓ 비밀번호가 일치합니다</p>
</div>
</div>
<label class="auth-check">
@ -247,6 +283,7 @@
<a class="auth-link" href="<%= ctx %>/operation-policy" target="_blank" rel="noopener noreferrer">운영정책</a>에 동의합니다.
</span>
</label>
<div class="form-error" id="signup-form-error" hidden></div>
<button class="auth-button auth-button--primary" type="submit">회원가입</button>
</form>