feat(ui): improve modal footer layout and enhance mobile form styling

This commit is contained in:
Daniel Volz
2025-12-28 11:56:55 +01:00
parent fb1732bd4a
commit 415dd87117
2 changed files with 84 additions and 30 deletions
+19 -18
View File
@@ -2226,7 +2226,7 @@ function AppContent() {
</div>
<div className="med-detail-footer">
<button className="danger" onClick={() => { setSelectedMed(null); setShowImageLightbox(false); }}>
<button onClick={() => { setSelectedMed(null); setShowImageLightbox(false); }}>
{t('common.close')}
</button>
<div className="footer-actions">
@@ -2297,7 +2297,7 @@ function AppContent() {
</div>
<div className="user-meds-footer">
<button className="ghost" onClick={() => setSelectedUser(null)}>{t('common.close')}</button>
<button onClick={() => setSelectedUser(null)}>{t('common.close')}</button>
</div>
</div>
</div>
@@ -2388,15 +2388,15 @@ function AppContent() {
<h2>{editingId ? t('form.editEntry') : t('form.newEntry')}</h2>
</div>
<form className="form-grid mobile-edit-form" onSubmit={(e) => { saveMedication(e); setShowEditModal(false); }}>
<label>
<label className="full">
{t('form.commercialName')}
<input value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} placeholder={t('form.placeholders.commercial')} required />
</label>
<label>
<label className="full">
{t('form.genericName')}
<input value={form.genericName} onChange={(e) => setForm({ ...form, genericName: e.target.value })} placeholder={t('form.placeholders.generic')} />
</label>
<label>
<label className="full">
{t('form.takenBy')}
<input value={form.takenBy} onChange={(e) => setForm({ ...form, takenBy: e.target.value })} placeholder={t('form.placeholders.takenBy')} />
</label>
@@ -2416,21 +2416,21 @@ function AppContent() {
{t('form.loosePills')}
<input type="number" min="0" value={form.looseTablets} onChange={(e) => handleValueChange("looseTablets", e.target.value)} />
</label>
<label>
<div className="full">
<p className="sub"><strong>{t('form.total')}:</strong> {deriveTotal(form)} {t('common.pills')}</p>
</div>
<label className="full">
{t('form.pillWeight')}
<input type="number" min="0" step="0.1" value={form.pillWeightMg} onChange={(e) => setForm({ ...form, pillWeightMg: e.target.value })} placeholder={t('form.placeholders.pillWeight')} />
<input type="number" min="0" step="0.1" value={form.pillWeightMg} onChange={(e) => setForm({ ...form, pillWeightMg: e.target.value })} placeholder={t('form.placeholders.weight')} />
</label>
<label>
{t('form.expiry')}
<label className="full">
{t('form.expiryDate')}
<input type="date" value={form.expiryDate} onChange={(e) => setForm({ ...form, expiryDate: e.target.value })} />
</label>
<label className="full">
{t('form.notes')}
<textarea value={form.notes} onChange={(e) => setForm({ ...form, notes: e.target.value })} placeholder={t('form.placeholders.notes')} rows={2} />
</label>
<div className="full">
<p className="sub"><strong>{t('form.total')}:</strong> {deriveTotal(form)} {t('common.pills')}</p>
</div>
{editingId && (() => {
const currentMed = meds.find(m => m.id === editingId);
@@ -2472,12 +2472,13 @@ function AppContent() {
<span>{t('form.blisters.everyDays')}</span>
<input type="number" min="1" value={b.every} onChange={(e) => setBlisterValue(idx, "every", e.target.value)} />
</label>
<label className="compact">
<label className="compact full-row">
<span>{t('form.blisters.startDate')}</span>
<div className="datetime-inputs">
<input type="date" value={b.startDate} onChange={(e) => setBlisterValue(idx, "startDate", e.target.value)} />
<input type="time" value={b.startTime} onChange={(e) => setBlisterValue(idx, "startTime", e.target.value)} />
</div>
<input type="date" value={b.startDate} onChange={(e) => setBlisterValue(idx, "startDate", e.target.value)} />
</label>
<label className="compact time-label">
<span>{t('form.blisters.startTime')}</span>
<input type="time" value={b.startTime} onChange={(e) => setBlisterValue(idx, "startTime", e.target.value)} />
</label>
{form.blisters.length > 1 && <button type="button" className="ghost danger remove-blister-btn" onClick={() => removeBlister(idx)} title={t('common.delete')}>🗑</button>}
</div>
@@ -2485,7 +2486,7 @@ function AppContent() {
<button type="button" className="ghost add-blister" onClick={addBlister}>+ {t('form.blisters.addIntake')}</button>
</fieldset>
<div className="full align-end gap">
<div className="modal-footer">
<button type="button" className="ghost" onClick={() => { setShowEditModal(false); resetForm(); }}>
{t('common.cancel')}
</button>
+65 -12
View File
@@ -2025,12 +2025,14 @@ textarea {
height: 2rem;
min-width: 2rem;
min-height: 2rem;
aspect-ratio: 1;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: all 0.2s ease;
flex-shrink: 0;
padding: 0;
}
.modal-close:hover {
@@ -2040,6 +2042,28 @@ textarea {
transform: scale(1.1);
}
/* Universal Modal Footer */
.modal-footer {
padding: 1rem 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid var(--border-primary);
gap: 0.75rem;
}
.modal-footer .footer-left,
.modal-footer .footer-right {
display: flex;
gap: 0.5rem;
align-items: center;
}
.modal-footer button.icon-only {
padding: 0.5rem 0.75rem;
min-width: auto;
}
/* Medication Detail Modal */
.med-detail-modal {
padding: 0;
@@ -2204,7 +2228,7 @@ textarea {
padding: 1rem 1.5rem;
border-top: 1px solid var(--border-primary);
display: flex;
justify-content: flex-end;
justify-content: flex-start;
}
.med-detail-header .med-avatar-lg {
@@ -3156,7 +3180,18 @@ h3 .reminder-icon.info-tooltip {
display: flex;
gap: 0.75rem;
margin-top: 1.5rem;
justify-content: flex-end;
justify-content: space-between;
align-items: center;
}
.share-dialog-footer .footer-left {
display: flex;
gap: 0.5rem;
}
.share-dialog-footer .footer-right {
display: flex;
gap: 0.5rem;
}
.share-dialog-result {
@@ -3337,18 +3372,23 @@ h3 .reminder-icon.info-tooltip {
margin: 0;
}
.mobile-edit-form {
gap: 0.75rem;
.mobile-edit-form.form-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: 0.75rem 1rem;
}
.mobile-edit-form label {
font-size: 0.9rem;
.mobile-edit-form.form-grid > label {
font-size: 0.8rem;
min-width: 0 !important;
width: 100%;
}
.mobile-edit-form input,
.mobile-edit-form textarea,
.mobile-edit-form select {
font-size: 16px; /* Prevents zoom on iOS */
.mobile-edit-form.form-grid input,
.mobile-edit-form.form-grid textarea,
.mobile-edit-form.form-grid select {
font-size: 16px !important;
width: 100%;
}
/* Mobile Blister/Intake Schedule Section */
@@ -3377,7 +3417,7 @@ h3 .reminder-icon.info-tooltip {
.mobile-edit-form .blister-row {
display: grid;
grid-template-columns: 1fr 1fr auto;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
padding: 0.75rem;
background: var(--bg-secondary);
@@ -3398,10 +3438,23 @@ h3 .reminder-icon.info-tooltip {
font-weight: 500;
}
.mobile-edit-form .blister-row label.compact:nth-child(3) {
.mobile-edit-form .blister-row label.compact.full-row {
grid-column: 1 / -1;
}
.mobile-edit-form .blister-row label.compact.time-label {
width: fit-content;
}
.mobile-edit-form .blister-row label.compact.time-label input[type="time"] {
width: auto;
}
.mobile-edit-form .blister-row .remove-blister-btn {
grid-column: 1 / -1;
justify-self: start;
}
.mobile-edit-form .blister-row .datetime-inputs {
display: flex;
gap: 0.5rem;