11---
22import ' ../styles/global.css'
33import Main from ' ../layouts/Main.astro'
4- import IconShowPassword from ' ../assets/icon/eye .svg'
4+ import IconCheck from ' ../assets/icon/check .svg'
55import IconHidePassword from ' ../assets/icon/eye-off.svg'
6+ import IconShowPassword from ' ../assets/icon/eye.svg'
7+ import IconX from ' ../assets/icon/x.svg'
68---
79
810<Main title =" Authentication" >
@@ -11,23 +13,13 @@ import IconHidePassword from '../assets/icon/eye-off.svg'
1113 <h2 >Login</h2 >
1214 <form action =" #" >
1315 <div class =" form-field" >
14- <input
15- type =" email"
16- id =" login-email"
17- name =" login-email"
18- required
19- />
16+ <input type =" email" id =" login-email" name =" login-email" required />
2017 <label for =" login-email" >E-mail</label >
2118 </div >
2219
2320 <div class =" form-field" >
2421 <div class =" input-with-icon" >
25- <input
26- type =" password"
27- id =" login-password"
28- name =" login-password"
29- required
30- />
22+ <input type =" password" id =" login-password" name =" login-password" required />
3123 <label for =" login-password" >Password</label >
3224 <div class =" icons" title =" Toggle password visibility" >
3325 <IconShowPassword class =" show-password" />
@@ -47,22 +39,12 @@ import IconHidePassword from '../assets/icon/eye-off.svg'
4739 <h2 >Register</h2 >
4840 <form action =" #" >
4941 <div class =" form-field" >
50- <input
51- type =" text"
52- id =" register-username"
53- name =" register-username"
54- required
55- />
42+ <input type =" text" id =" register-username" name =" register-username" required />
5643 <label for =" register-username" >Username</label >
5744 </div >
5845
5946 <div class =" form-field" >
60- <input
61- type =" email"
62- id =" register-email"
63- name =" register-email"
64- required
65- />
47+ <input type =" email" id =" register-email" name =" register-email" required />
6648 <label for =" register-email" >E-mail</label >
6749 </div >
6850
@@ -86,18 +68,52 @@ import IconHidePassword from '../assets/icon/eye-off.svg'
8668 <div class =" input-with-icon" >
8769 <input
8870 type =" password"
89- id =" register-password-password "
90- name =" register-password-password "
71+ id =" register-password-confirm "
72+ name =" register-password-confirm "
9173 required
9274 />
93- <label for =" register-password-password " >Password</label >
75+ <label for =" register-password-confirm " >Password confirmation </label >
9476 <div class =" icons" title =" Toggle password visibility" >
9577 <IconShowPassword class =" show-password" />
9678 <IconHidePassword class =" hide-password" />
9779 </div >
9880 </div >
9981 </div >
10082
83+ <div id =" password-requirements" >
84+ <h3 >Password requirements</h3 >
85+ <ul >
86+ <li >
87+ <IconCheck class =" password-requirement-check" />
88+ <IconX class =" password-requirement-x" />
89+ <span >At least 12 characters long.</span >
90+ </li >
91+ <li >
92+ <IconCheck class =" password-requirement-check" />
93+ <IconX class =" password-requirement-x" />
94+ <span > Contains at least one uppercase letter (A-Z). </span >
95+ </li >
96+ <li >
97+ <IconCheck class =" password-requirement-check" />
98+ <IconX class =" password-requirement-x" />
99+ <span > Contains at least one lowercase letter (a-z). </span >
100+ </li >
101+ <li >
102+ <IconCheck class =" password-requirement-check" />
103+ <IconX class =" password-requirement-x" />
104+ <span >Contains at least one digit (0-9).</span >
105+ </li >
106+ <li >
107+ <IconCheck class =" password-requirement-check" />
108+ <IconX class =" password-requirement-x" />
109+ <span >
110+ Contains at least one special character (any non-alphanumeric
111+ character).
112+ </span >
113+ </li >
114+ </ul >
115+ </div >
116+
101117 <button type =" submit" >Register</button >
102118 </form >
103119
@@ -139,6 +155,16 @@ import IconHidePassword from '../assets/icon/eye-off.svg'
139155 width: clamp(320px, 100%, 500px);
140156 }
141157
158+ ul {
159+ list-style: none;
160+ }
161+
162+ ul > li {
163+ display: flex;
164+ gap: var(--spacing-small);
165+ align-items: center;
166+ }
167+
142168 .flip-link {
143169 font-weight: bold;
144170 }
@@ -181,7 +207,8 @@ import IconHidePassword from '../assets/icon/eye-off.svg'
181207 border-bottom-color: var(--color-secondary);
182208 }
183209
184- .hide-password {
210+ .hide-password,
211+ .password-requirement-check {
185212 display: none;
186213 }
187214
@@ -197,6 +224,20 @@ import IconHidePassword from '../assets/icon/eye-off.svg'
197224 display: flex;
198225 }
199226
227+ .password-requirement-check,
228+ .password-requirement-x {
229+ width: 1.75rem;
230+ min-width: 1.75rem;
231+ }
232+
233+ .password-requirement-check {
234+ color: var(--color-success);
235+ }
236+
237+ .password-requirement-x {
238+ color: var(--color-error);
239+ }
240+
200241 #authentication {
201242 align-items: center;
202243 display: flex;
@@ -223,6 +264,7 @@ import IconHidePassword from '../assets/icon/eye-off.svg'
223264 const registerSection = document.getElementById('register')
224265 const loginLink = document.getElementById('register-link')
225266 const registerLink = document.getElementById('login-link')
267+ const passwordInput = document.getElementById('register-password')
226268
227269 // Maintain label position on filled inputs
228270 document.querySelectorAll('.form-field input').forEach((input) => {
@@ -259,9 +301,7 @@ import IconHidePassword from '../assets/icon/eye-off.svg'
259301 const hideIcons = section.querySelectorAll('.hide-password')
260302
261303 const toggle = () => {
262- const isHidden = [...passwordInputs].some(
263- (input) => input.type === 'password'
264- )
304+ const isHidden = [...passwordInputs].some((input) => input.type === 'password')
265305 passwordInputs.forEach((input) => {
266306 input.type = isHidden ? 'text' : 'password'
267307 })
@@ -275,4 +315,24 @@ import IconHidePassword from '../assets/icon/eye-off.svg'
275315
276316 iconContainer.addEventListener('click', toggle)
277317 })
318+
319+ passwordInput.addEventListener('input', () => {
320+ const password = passwordInput.value
321+ const requirements = [
322+ { regex: /.{12,}/, index: 0 },
323+ { regex: /[A-Z]/, index: 1 },
324+ { regex: /[a-z]/, index: 2 },
325+ { regex: /\d/, index: 3 },
326+ { regex: /[^a-zA-Z0-9]/, index: 4 },
327+ ]
328+
329+ requirements.forEach(({ regex, index }) => {
330+ const isValid = regex.test(password)
331+ const checkIcon = document.querySelectorAll('.password-requirement-check')[index]
332+ const xIcon = document.querySelectorAll('.password-requirement-x')[index]
333+
334+ checkIcon.style.display = isValid ? 'inline' : 'none'
335+ xIcon.style.display = isValid ? 'none' : 'inline'
336+ })
337+ })
278338</script >
0 commit comments