fix(birthdays): match profile picture editor pattern

This commit is contained in:
Rafael Foster
2026-04-29 07:09:37 -03:00
parent 6eafe80395
commit 3e0549524e
2 changed files with 91 additions and 26 deletions
+21 -17
View File
@@ -275,7 +275,11 @@ function openBirthdayModal({ mode, birthday = null }) {
title: isEdit ? t('birthdays.editTitle') : t('birthdays.newTitle'),
content: `
<div class="birthday-modal">
<div class="birthday-preview" id="birthday-preview">${birthdayPreviewHtml(birthday?.name || '', photoData)}</div>
<div class="birthday-modal__identity">
<button type="button" class="birthday-avatar-editor" id="birthday-preview" aria-label="${t('birthdays.photoLabel')}">
${birthdayPreviewHtml(birthday?.name || '', photoData)}
</button>
<div class="birthday-modal__fields">
<div class="form-group">
<label class="form-label" for="bd-name">${t('birthdays.nameLabel')}</label>
<input class="form-input" id="bd-name" type="text" value="${esc(birthday?.name || '')}" autocomplete="name">
@@ -284,14 +288,17 @@ function openBirthdayModal({ mode, birthday = null }) {
<label class="form-label" for="bd-birth-date">${t('birthdays.birthDateLabel')}</label>
<input class="form-input" id="bd-birth-date" type="date" value="${esc(birthday?.birth_date || '')}">
</div>
<div class="form-group">
<label class="form-label" for="bd-photo">${t('birthdays.photoLabel')}</label>
<input class="form-input" id="bd-photo" type="file" accept="image/png,image/jpeg,image/webp,image/gif">
<div class="form-help">${t('birthdays.photoOptional')}</div>
<div class="birthday-modal__photo-actions">
<button type="button" class="btn btn--secondary" id="bd-remove-photo">${t('birthdays.removePhoto')}</button>
</div>
</div>
<input class="sr-only" id="bd-photo" type="file" accept="image/png,image/jpeg,image/webp,image/gif">
<div class="birthday-modal__photo-actions">
<button type="button" class="birthday-modal__photo-action" id="bd-photo-edit" aria-label="${t('birthdays.photoLabel')}" title="${t('birthdays.photoLabel')}">
<i data-lucide="pencil" aria-hidden="true"></i>
</button>
<button type="button" class="birthday-modal__photo-action birthday-modal__photo-action--danger" id="bd-remove-photo" aria-label="${t('birthdays.removePhoto')}" title="${t('birthdays.removePhoto')}">
<i data-lucide="trash-2" aria-hidden="true"></i>
</button>
</div>
<div class="form-group">
<label class="form-label" for="bd-notes">${t('birthdays.notesLabel')}</label>
<textarea class="form-input" id="bd-notes" rows="3" placeholder="${t('birthdays.notesPlaceholder')}">${esc(birthday?.notes || '')}</textarea>
@@ -310,18 +317,15 @@ function openBirthdayModal({ mode, birthday = null }) {
onSave(panel) {
const nameInput = panel.querySelector('#bd-name');
const preview = panel.querySelector('#birthday-preview');
const fileInput = panel.querySelector('#bd-photo');
const photoEdit = panel.querySelector('#bd-photo-edit');
const renderPreview = () => {
preview.replaceChildren();
preview.insertAdjacentHTML('beforeend', birthdayPreviewHtml(nameInput.value.trim(), photoData));
preview.innerHTML = birthdayPreviewHtml(nameInput.value.trim(), photoData);
};
nameInput.addEventListener('input', renderPreview);
panel.querySelectorAll('.js-date-input').forEach((input) => {
input.addEventListener('blur', () => {
const parsed = parseDateInput(input.value);
if (parsed) input.value = formatDateInput(parsed);
});
});
panel.querySelector('#bd-photo').addEventListener('change', async (e) => {
preview.addEventListener('click', () => fileInput?.click());
photoEdit?.addEventListener('click', () => fileInput?.click());
fileInput?.addEventListener('change', async (e) => {
const file = e.target.files?.[0];
if (!file) return;
try {
@@ -333,7 +337,7 @@ function openBirthdayModal({ mode, birthday = null }) {
});
panel.querySelector('#bd-remove-photo').addEventListener('click', () => {
photoData = null;
panel.querySelector('#bd-photo').value = '';
if (fileInput) fileInput.value = '';
renderPreview();
});
panel.querySelector('#bd-cancel').addEventListener('click', closeModal);
+62 -1
View File
@@ -287,6 +287,21 @@
background: color-mix(in srgb, var(--module-accent) 16%, white);
}
.birthday-avatar-editor {
width: 84px;
height: 84px;
margin: 0 auto var(--space-3);
padding: 0;
border: none;
border-radius: var(--radius-full);
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: color-mix(in srgb, var(--module-accent) 16%, white);
cursor: pointer;
}
.birthday-preview__image {
width: 100%;
height: 100%;
@@ -300,7 +315,43 @@
}
.birthday-modal__photo-actions {
margin-top: var(--space-2);
display: flex;
gap: var(--space-2);
justify-content: center;
margin-top: calc(var(--space-1) * -1);
margin-bottom: var(--space-2);
}
.birthday-modal__photo-action {
width: 30px;
height: 30px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-full);
border: 1px solid var(--color-border);
background: var(--color-surface);
color: var(--color-text-secondary);
}
.birthday-modal__photo-action svg {
width: 14px;
height: 14px;
}
.birthday-modal__photo-action--danger {
color: var(--color-danger);
}
.birthday-modal__identity {
display: flex;
align-items: flex-start;
gap: var(--space-4);
}
.birthday-modal__fields {
flex: 1;
min-width: 0;
}
.birthday-modal__hint {
@@ -308,6 +359,16 @@
font-size: var(--text-sm);
}
@media (max-width: 640px) {
.birthday-modal__identity {
flex-direction: column;
}
.birthday-modal__photo-actions {
justify-content: flex-start;
}
}
@media (max-width: 960px) {
.birthdays-grid {
grid-template-columns: 1fr;