diff --git a/client/components/users/passwordInput.jade b/client/components/users/passwordInput.jade new file mode 100644 index 000000000..98a918ade --- /dev/null +++ b/client/components/users/passwordInput.jade @@ -0,0 +1,14 @@ +template(name='passwordInput') + .at-input + label(for='at-field-{{_id}}') {{displayName}} + .password-input-container + input.password-field(type="{{type}}" placeholder="{{displayName}}" autocomplete="{{autocomplete}}" required="{{required}}") + button.password-toggle-btn(type="button" aria-label="Toggle password visibility" title="Toggle password visibility") + .eye-container + span.eye-text 👁️ + svg.eye-slash(width="20" height="20" viewBox="0 0 20 20" class="eye-slash-line") + line(x1="6" y1="14" x2="32" y2="-14" stroke="#000" stroke-width="2" stroke-linecap="round") + if errs + .at-error + each errs + div {{this}} \ No newline at end of file diff --git a/client/components/users/passwordInput.js b/client/components/users/passwordInput.js new file mode 100644 index 000000000..625e51193 --- /dev/null +++ b/client/components/users/passwordInput.js @@ -0,0 +1,46 @@ +import { TAPi18n } from '/imports/i18n'; + +Template.passwordInput.onRendered(function() { + const template = this; + const input = template.find('input.password-field'); + const label = template.find('label'); + + // Set the dynamic id and name based on the field _id + if (template.data && template.data._id) { + const fieldId = `at-field-${template.data._id}`; + input.id = fieldId; + input.name = fieldId; + label.setAttribute('for', fieldId); + + // Ensure the input starts as password type for password fields + input.type = 'password'; + + // Initially hide the slash line since password starts hidden + const slashLine = template.find('.eye-slash-line'); + if (slashLine) { + slashLine.style.display = 'none'; + } + } +}); + +Template.passwordInput.events({ + 'click .password-toggle-btn'(event, template) { + event.preventDefault(); + const input = template.find('input.password-field'); + const slashLine = template.find('.eye-slash-line'); + + if (input.type === 'password') { + input.type = 'text'; + // Show the slash line when password is visible + if (slashLine) { + slashLine.style.display = 'block'; + } + } else { + input.type = 'password'; + // Hide the slash line when password is hidden + if (slashLine) { + slashLine.style.display = 'none'; + } + } + }, +}); \ No newline at end of file diff --git a/client/components/users/userForm.css b/client/components/users/userForm.css index 89c572a4b..ae8392421 100644 --- a/client/components/users/userForm.css +++ b/client/components/users/userForm.css @@ -24,6 +24,63 @@ .auth-layout .auth-dialog .at-form input { width: 100%; } +.password-input-container { + position: relative; + display: flex; + align-items: center; +} +.password-input-container input { + flex: 1; + padding-right: 55px; /* More room for the bigger button */ + box-sizing: border-box; +} +.password-toggle-btn { + position: absolute; + right: 5px; /* Adjusted for larger button */ + top: calc(50% - 6px); /* Moved up by 6px total */ + transform: translateY(-50%); + background: #f8f8f8 !important; + border: 1px solid #ddd !important; + border-radius: 3px !important; + color: #000 !important; /* Black color for the icon */ + cursor: pointer; + padding: 8px 12px; /* 2x bigger padding */ + font-size: 16px; /* 2x bigger font size */ + width: auto !important; + height: auto !important; + line-height: 1; + display: flex !important; + align-items: center; + justify-content: center; + z-index: 10; + min-width: 40px; /* 2x bigger minimum width */ + min-height: 32px; /* 2x bigger minimum height */ +} +.password-toggle-btn .eye-text { + color: #000 !important; + font-size: 16px !important; + line-height: 1; + filter: grayscale(100%); + -webkit-filter: grayscale(100%); + opacity: 0.8; +} +.eye-slash-line { + position: absolute; + top: 10px; + left: 10px; + width: 20px; + height: 20px; + pointer-events: none; + stroke: #000; + stroke-width: 2; + fill: none; +} +.password-toggle-btn:hover .eye-text { + color: #000 !important; + filter: grayscale(100%); + -webkit-filter: grayscale(100%); + opacity: 0.8; +} .auth-layout .auth-dialog .at-form button { width: 100%; background: #216694; diff --git a/config/accounts.js b/config/accounts.js index 6ff1b83e9..2edb688de 100644 --- a/config/accounts.js +++ b/config/accounts.js @@ -3,6 +3,7 @@ import { FlowRouter } from 'meteor/ostrio:flow-router-extra'; const passwordField = AccountsTemplates.removeField('password'); passwordField.autocomplete = 'current-password'; +passwordField.template = 'passwordInput'; const emailField = AccountsTemplates.removeField('email'); let disableRegistration = false; let disableForgotPassword = false; @@ -70,6 +71,7 @@ AccountsTemplates.addFields([ required: true, minLength: 6, autocomplete: 'new-password', + template: 'passwordInput', }, { _id: 'invitationcode',