feat: enhance file upload UI for avatar and header images with improved styling and error handling

This commit is contained in:
Christopher
2026-01-22 09:53:13 -08:00
parent 6cd74e1cc2
commit 64fbca7fbb
+65 -59
View File
@@ -491,37 +491,40 @@ export default function ProfilePage() {
</div> </div>
<div> <div>
<label style={{ fontSize: '12px', color: 'var(--foreground-tertiary)' }}>Avatar</label> <label style={{ fontSize: '12px', color: 'var(--foreground-tertiary)' }}>Avatar</label>
<div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}> <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>
<input <label className="btn btn-ghost btn-sm" style={{ cursor: 'pointer' }}>
type="file" {isSaving ? 'Uploading...' : 'Choose File'}
accept="image/*" <input
onChange={async (e) => { type="file"
const file = e.target.files?.[0]; accept="image/*"
if (!file) return; onChange={async (e) => {
setIsSaving(true); const file = e.target.files?.[0];
try { if (!file) return;
const formData = new FormData(); setIsSaving(true);
formData.append('file', file); try {
const res = await fetch('/api/uploads', { const formData = new FormData();
method: 'POST', formData.append('file', file);
body: formData, const res = await fetch('/api/uploads', {
}); method: 'POST',
const data = await res.json(); body: formData,
if (data.url) { });
setProfileForm(prev => ({ ...prev, avatarUrl: data.url })); const data = await res.json();
if (data.url) {
setProfileForm(prev => ({ ...prev, avatarUrl: data.url }));
}
} catch (err) {
console.error(err);
setSaveError('Upload failed');
} finally {
setIsSaving(false);
} }
} catch (err) { }}
console.error(err); disabled={isSaving}
setSaveError('Upload failed'); style={{ display: 'none' }}
} finally { />
setIsSaving(false); </label>
}
}}
disabled={isSaving}
style={{ fontSize: '13px' }}
/>
{profileForm.avatarUrl && ( {profileForm.avatarUrl && (
<div style={{ width: '32px', height: '32px', borderRadius: '50%', overflow: 'hidden' }}> <div style={{ width: '40px', height: '40px', borderRadius: '50%', overflow: 'hidden', border: '1px solid var(--border)' }}>
<img src={profileForm.avatarUrl} alt="Preview" style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> <img src={profileForm.avatarUrl} alt="Preview" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
</div> </div>
)} )}
@@ -529,37 +532,40 @@ export default function ProfilePage() {
</div> </div>
<div> <div>
<label style={{ fontSize: '12px', color: 'var(--foreground-tertiary)' }}>Header</label> <label style={{ fontSize: '12px', color: 'var(--foreground-tertiary)' }}>Header</label>
<div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}> <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>
<input <label className="btn btn-ghost btn-sm" style={{ cursor: 'pointer' }}>
type="file" {isSaving ? 'Uploading...' : 'Choose File'}
accept="image/*" <input
onChange={async (e) => { type="file"
const file = e.target.files?.[0]; accept="image/*"
if (!file) return; onChange={async (e) => {
setIsSaving(true); const file = e.target.files?.[0];
try { if (!file) return;
const formData = new FormData(); setIsSaving(true);
formData.append('file', file); try {
const res = await fetch('/api/uploads', { const formData = new FormData();
method: 'POST', formData.append('file', file);
body: formData, const res = await fetch('/api/uploads', {
}); method: 'POST',
const data = await res.json(); body: formData,
if (data.url) { });
setProfileForm(prev => ({ ...prev, headerUrl: data.url })); const data = await res.json();
if (data.url) {
setProfileForm(prev => ({ ...prev, headerUrl: data.url }));
}
} catch (err) {
console.error(err);
setSaveError('Upload failed');
} finally {
setIsSaving(false);
} }
} catch (err) { }}
console.error(err); disabled={isSaving}
setSaveError('Upload failed'); style={{ display: 'none' }}
} finally { />
setIsSaving(false); </label>
}
}}
disabled={isSaving}
style={{ fontSize: '13px' }}
/>
{profileForm.headerUrl && ( {profileForm.headerUrl && (
<div style={{ width: '48px', height: '32px', borderRadius: '4px', overflow: 'hidden' }}> <div style={{ width: '80px', height: '40px', borderRadius: '4px', overflow: 'hidden', border: '1px solid var(--border)' }}>
<img src={profileForm.headerUrl} alt="Preview" style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> <img src={profileForm.headerUrl} alt="Preview" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
</div> </div>
)} )}
@@ -568,7 +574,7 @@ export default function ProfilePage() {
{saveError && ( {saveError && (
<div style={{ color: 'var(--error)', fontSize: '13px' }}>{saveError}</div> <div style={{ color: 'var(--error)', fontSize: '13px' }}>{saveError}</div>
)} )}
<div style={{ display: 'flex', gap: '12px', justifyContent: 'flex-end' }}> <div style={{ display: 'flex', gap: '12px', justifyContent: 'flex-end', marginTop: '8px' }}>
<button className="btn btn-ghost" onClick={() => setIsEditing(false)} disabled={isSaving}> <button className="btn btn-ghost" onClick={() => setIsEditing(false)} disabled={isSaving}>
Cancel Cancel
</button> </button>