Rename Downloads→Resources throughout, fix audit bugs, add /subscribe to footer; v1.1.49
Publish Container / docker (push) Successful in 14m2s
Publish Container / docker (push) Successful in 14m2s
- Rename all user-facing "Downloads" text to "Resources" (nav, page eyebrows, buttons, admin labels, page title, content defaults)
- Add usePageMeta to ContactPage, EpisodeDetailPage, DownloadDetailPage, StartHerePage for correct social share previews
- Wire contactEyebrow and aboutShowEyebrow fields to the UI (were editable in admin but never rendered)
- Wrap StartHerePage in full site chrome (header, search, footer); fix Step 2 link from /#qa to /questions
- Fix admin "View All Contacts" link (was 404); now navigates to Contact admin panel
- Remove broken "Previous Studies" jump nav entry (no matching anchor)
- Remove /studys typo route
- Make dashboard "Top Resource Downloads" stat dynamic instead of hardcoded to titus-study key
- Add Newsletter link (/subscribe) to footer legal nav
- Fix server.js startup log ("Portfolio app" → "Siteforge")
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
0d2e68ae11
commit
a072076818
7 files changed
+123
-65
No files matched your search
+16
-17
@@ -728,7 +728,7 @@ const ADMIN_VIEW_OPTIONS: Array<{ group: string; options: Array<{ value: AdminVi
|
||||
options: [
|
||||
{ value: 'podcast', label: 'Podcast Hub' },
|
||||
{ value: 'colossians-study', label: 'Studies' },
|
||||
{ value: 'downloads', label: 'Downloads' },
|
||||
{ value: 'downloads', label: 'Resources' },
|
||||
{ value: 'custom-links', label: 'Custom Links' },
|
||||
{ value: 'content-blocks', label: 'Content Blocks' },
|
||||
{ value: 'books', label: 'Books' },
|
||||
@@ -798,7 +798,6 @@ const ADMIN_SECTION_LINKS: Partial<Record<AdminView, AdminSectionLink[]>> = {
|
||||
downloads: [
|
||||
{ id: 'downloads-study-guide', label: 'Study Guide' },
|
||||
{ id: 'downloads-library', label: 'Download Library' },
|
||||
{ id: 'downloads-previous-studies', label: 'Previous Studies' },
|
||||
],
|
||||
global: [
|
||||
{ id: 'global-footer', label: 'Footer' },
|
||||
@@ -903,7 +902,7 @@ const FIELDS: Array<{ key: StringField; label: string; multiline?: boolean; sect
|
||||
{ key: 'seriesImageUrl', label: 'Series Cover Image URL', section: 'series' },
|
||||
{ key: 'seriesListenUrl', label: 'Series Listen URL', section: 'series' },
|
||||
{ key: 'seriesListenBtnLabel', label: 'Series — Listen Button Label', section: 'series' },
|
||||
{ key: 'seriesDownloadsBtnLabel', label: 'Series — Downloads Button Label', section: 'series' },
|
||||
{ key: 'seriesDownloadsBtnLabel', label: 'Series — Resources Button Label', section: 'series' },
|
||||
{ key: 'studyGuideTitle', label: 'Study Guide Title', section: 'series' },
|
||||
{ key: 'studyGuideDescription', label: 'Study Guide Description', multiline: true, section: 'series' },
|
||||
{ key: 'studyGuideUrl', label: 'Study Guide URL (Amazon link)', section: 'series' },
|
||||
@@ -2000,9 +1999,9 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
if (placement === 'footer') return 'Footer navigation links'
|
||||
if (placement === 'otherSites') return 'Other site links in footer dropdown'
|
||||
if (placement === 'externalSites') return 'Homepage external site links'
|
||||
if (placement === 'books') return 'Downloads page (Reading List)'
|
||||
if (placement === 'recommended') return 'Downloads page (Recommended Resources)'
|
||||
return 'Downloads page (More Resources)'
|
||||
if (placement === 'books') return 'Resources page (Reading List)'
|
||||
if (placement === 'recommended') return 'Resources page (Recommended Resources)'
|
||||
return 'Resources page (More Resources)'
|
||||
}
|
||||
|
||||
function getCustomLinkPreviewPath(placement: CustomLink['placement']) {
|
||||
@@ -2016,7 +2015,7 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
if (page === 'homepage') return 'Homepage'
|
||||
if (page === 'start-here') return 'Start Here'
|
||||
if (page === 'episodes') return 'Episodes'
|
||||
if (page === 'downloads') return 'Downloads'
|
||||
if (page === 'downloads') return 'Resources'
|
||||
if (page === 'about') return 'About'
|
||||
if (page === 'contact') return 'Contact'
|
||||
return 'Q&A'
|
||||
@@ -2832,8 +2831,8 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
</div>
|
||||
</div>
|
||||
<div className="admin-dashboard-card">
|
||||
<div className="admin-dashboard-card-value">{downloadStats['titus-study'] ?? 0}</div>
|
||||
<div className="admin-dashboard-card-label">Titus Study Downloads</div>
|
||||
<div className="admin-dashboard-card-value">{Math.max(0, ...Object.values(downloadStats))}</div>
|
||||
<div className="admin-dashboard-card-label">Top Resource Downloads</div>
|
||||
<div className="admin-dashboard-card-sub">
|
||||
{Object.values(downloadStats).reduce((a, b) => a + b, 0)} total resource downloads
|
||||
</div>
|
||||
@@ -2864,7 +2863,7 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
{c.message && <div className="admin-dashboard-feed-preview">{c.message.slice(0, 100)}{c.message.length > 100 ? '…' : ''}</div>}
|
||||
</div>
|
||||
))}
|
||||
<Link to="/contacts" className="admin-dashboard-card-action" style={{ marginTop: '0.5rem', display: 'inline-block' }}>View All Contacts →</Link>
|
||||
<button type="button" className="admin-dashboard-card-action" style={{ marginTop: '0.5rem', background: 'none', border: 'none', cursor: 'pointer', padding: 0 }} onClick={() => setAdminView('contact')}>View All Contacts →</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -3341,7 +3340,7 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<p className="admin-stats-note">Companion study guide title, description, and Amazon link are now managed in Downloads.</p>
|
||||
<p className="admin-stats-note">Companion study guide title, description, and Amazon link are now managed in Resources.</p>
|
||||
{renderSaveStatus()}
|
||||
<div className="admin-end-series-wrap">
|
||||
<hr style={{ border: 'none', borderTop: '1px solid #2a2518', margin: '2rem 0 1.5rem' }} />
|
||||
@@ -3520,7 +3519,7 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
{adminView === 'downloads' && (
|
||||
<section className="admin-panel-section">
|
||||
<div className="admin-panel-head">
|
||||
<h2>Downloads</h2>
|
||||
<h2>Resources</h2>
|
||||
<p>Manage the featured study guide, current download library, and previous series downloads.</p>
|
||||
</div>
|
||||
|
||||
@@ -3533,7 +3532,7 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
|
||||
<div className="admin-section-header" id="downloads-study-guide">
|
||||
<h3>Companion Study Guide</h3>
|
||||
<p>This is the featured primary download at the top of the Downloads page.</p>
|
||||
<p>This is the featured primary download at the top of the Resources page.</p>
|
||||
</div>
|
||||
<div className="admin-array-row">
|
||||
<div className="admin-array-fields">
|
||||
@@ -3782,7 +3781,7 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
|
||||
<div className="admin-panel-subhead">
|
||||
<h3>More Resources Links</h3>
|
||||
<p>These create cards in Downloads → More guides, worksheets, and past study downloads.</p>
|
||||
<p>These create cards in Resources → More guides, worksheets, and past study downloads.</p>
|
||||
</div>
|
||||
{(form.customLinks ?? []).filter(link => link.placement === 'resources').length === 0 && (
|
||||
<p className="admin-stats-note">No resource links yet.</p>
|
||||
@@ -3863,7 +3862,7 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
<option value="homepage">Homepage</option>
|
||||
<option value="start-here">Start Here</option>
|
||||
<option value="episodes">Episodes</option>
|
||||
<option value="downloads">Downloads</option>
|
||||
<option value="downloads">Resources</option>
|
||||
<option value="about">About</option>
|
||||
<option value="contact">Contact</option>
|
||||
<option value="questions">Q&A</option>
|
||||
@@ -3901,7 +3900,7 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
<section className="admin-panel-section">
|
||||
<div className="admin-panel-head">
|
||||
<h2>Books</h2>
|
||||
<p>Amazon books shown in the Reading List section on the Downloads page. Add a cover image, description, and Amazon link for each book.</p>
|
||||
<p>Amazon books shown in the Reading List section on the Resources page. Add a cover image, description, and Amazon link for each book.</p>
|
||||
</div>
|
||||
{(form.customLinks ?? []).filter(l => l.placement === 'books').length === 0 && <p className="admin-stats-note">No books yet.</p>}
|
||||
{(form.customLinks ?? []).filter(l => l.placement === 'books').map(book => (
|
||||
@@ -3955,7 +3954,7 @@ async function handleAssetUpload(event: ChangeEvent<HTMLInputElement>) {
|
||||
<section className="admin-panel-section">
|
||||
<div className="admin-panel-head">
|
||||
<h2>Recommended Resources</h2>
|
||||
<p>Curated resources shown at the bottom of the Downloads page. When at least one is added, it replaces the default Truth For Life widget. Add a title, image, link, and description for each resource.</p>
|
||||
<p>Curated resources shown at the bottom of the Resources page. When at least one is added, it replaces the default Truth For Life widget. Add a title, image, link, and description for each resource.</p>
|
||||
</div>
|
||||
{(form.customLinks ?? []).filter(l => l.placement === 'recommended').length === 0 && (
|
||||
<p className="admin-stats-note">No custom recommended resources yet — the Truth For Life widget shows by default.</p>
|
||||
|
||||
Reference in new issue
Block a user