Clarify about page image controls in admin

This commit is contained in:
nmemmert
2026-05-12 09:27:29 -04:00
parent becc1b5b27
commit 853e56bd91
2 changed files with 52 additions and 3 deletions
+19 -3
View File
@@ -225,12 +225,12 @@ const FIELDS: Array<{ key: StringField; label: string; multiline?: boolean; sect
{ key: 'aboutShowP1', label: 'About Show — Paragraph 1', multiline: true, section: 'about' }, { key: 'aboutShowP1', label: 'About Show — Paragraph 1', multiline: true, section: 'about' },
{ key: 'aboutShowP2', label: 'About Show — Paragraph 2', multiline: true, section: 'about' }, { key: 'aboutShowP2', label: 'About Show — Paragraph 2', multiline: true, section: 'about' },
{ key: 'aboutNate', label: 'About Nate', multiline: true, section: 'about' }, { key: 'aboutNate', label: 'About Nate', multiline: true, section: 'about' },
{ key: 'aboutPhotoUrl', label: 'About Section Photo URL', section: 'about' }, { key: 'aboutPhotoUrl', label: 'About — Nate Portrait Image URL', section: 'about' },
{ key: 'aboutVerseArtUrl', label: 'About Verse Art Image URL', section: 'about' }, { key: 'aboutVerseArtUrl', label: 'About — Scripture Artwork Image URL', section: 'about' },
{ key: 'aboutEyebrow', label: 'About — "About Nate" Eyebrow', section: 'about' }, { key: 'aboutEyebrow', label: 'About — "About Nate" Eyebrow', section: 'about' },
{ key: 'aboutListenBtnLabel', label: 'About — Listen Button Label', section: 'about' }, { key: 'aboutListenBtnLabel', label: 'About — Listen Button Label', section: 'about' },
{ key: 'aboutShowEyebrow', label: 'About — "About the Show" Eyebrow', section: 'about' }, { key: 'aboutShowEyebrow', label: 'About — "About the Show" Eyebrow', section: 'about' },
{ key: 'contactPhotoUrl', label: 'Contact Profile Photo URL', section: 'contact' }, { key: 'contactPhotoUrl', label: 'Contact Profile Photo URL', section: 'contact' },
{ key: 'contactEyebrow', label: 'Contact — Section Eyebrow', section: 'contact' }, { key: 'contactEyebrow', label: 'Contact — Section Eyebrow', section: 'contact' },
{ key: 'contactHeading', label: 'Contact — Heading', section: 'contact' }, { key: 'contactHeading', label: 'Contact — Heading', section: 'contact' },
{ key: 'contactName', label: 'Contact — Profile Name', section: 'contact' }, { key: 'contactName', label: 'Contact — Profile Name', section: 'contact' },
@@ -1034,6 +1034,18 @@ export default function AdminPage({ content, onSave, onLogout }: Props) {
) )
} }
function renderImagePreview(value: string | null | undefined, alt: string) {
const src = value?.trim() ?? ''
if (!src) return null
return (
<div className="admin-field-image-preview">
<span className="admin-field-image-preview-label">Preview</span>
<img src={src} alt={alt} className="admin-field-image-preview-img" />
</div>
)
}
function renderFileAssetSelector(value: string | null | undefined, onChange: (value: string) => void, fieldId: string) { function renderFileAssetSelector(value: string | null | undefined, onChange: (value: string) => void, fieldId: string) {
const assetOptions = [...assets.map(asset => ({ label: asset.filename, value: asset.url }))] const assetOptions = [...assets.map(asset => ({ label: asset.filename, value: asset.url }))]
const currentValue = value?.trim() ?? '' const currentValue = value?.trim() ?? ''
@@ -2139,6 +2151,10 @@ export default function AdminPage({ content, onSave, onLogout }: Props) {
<> <>
<input id={`field-${key}`} type="text" value={form[key] as string} onChange={e => handleChange(key, e.target.value)} /> <input id={`field-${key}`} type="text" value={form[key] as string} onChange={e => handleChange(key, e.target.value)} />
{(key.includes('ImageUrl') || key.includes('PhotoUrl') || key.includes('ArtUrl')) && renderImageAssetSelector(form[key] as string, value => handleChange(key, value), `field-${key}-asset`)} {(key.includes('ImageUrl') || key.includes('PhotoUrl') || key.includes('ArtUrl')) && renderImageAssetSelector(form[key] as string, value => handleChange(key, value), `field-${key}-asset`)}
{key === 'aboutPhotoUrl' && <p className="admin-field-note">This controls the portrait shown on the left side of the About page.</p>}
{key === 'aboutVerseArtUrl' && <p className="admin-field-note">This controls the scripture artwork shown under the About the Show text. It is separate from the Contact page image.</p>}
{key === 'aboutPhotoUrl' && renderImagePreview(form[key] as string, 'About page portrait preview')}
{key === 'aboutVerseArtUrl' && renderImagePreview(form[key] as string, 'About page scripture artwork preview')}
</> </>
)} )}
</div> </div>
+33
View File
@@ -2772,6 +2772,39 @@
border-color: rgba(201, 168, 76, 0.75); border-color: rgba(201, 168, 76, 0.75);
} }
.admin-field-note {
margin: 0.65rem 0 0;
font-size: 0.84rem;
color: var(--brand-muted);
}
.admin-field-image-preview {
margin-top: 0.75rem;
padding: 0.85rem 0.9rem;
border: 1px solid rgba(201, 168, 76, 0.16);
border-radius: 10px;
background: rgba(255, 255, 255, 0.02);
}
.admin-field-image-preview-label {
display: block;
margin-bottom: 0.55rem;
font-size: 0.78rem;
color: var(--brand-gold);
letter-spacing: 0.14em;
text-transform: uppercase;
}
.admin-field-image-preview-img {
display: block;
width: 100%;
max-width: 320px;
height: auto;
border-radius: 8px;
border: 1px solid rgba(201, 168, 76, 0.18);
background: rgba(0, 0, 0, 0.25);
}
/* ── Admin: section divider ── */ /* ── Admin: section divider ── */
.admin-section-header { .admin-section-header {
border-top: 1px solid rgba(201, 168, 76, 0.18); border-top: 1px solid rgba(201, 168, 76, 0.18);