Home page redesign: latest-episode player beside current series, ways-in cards, finished-books shelf, shortened PRISM, newsletter + share band, quieter 'more from us' group; v2.32.0
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d1c84aec6b
commit
729cf94c12
4 files changed
+263
-150
No files matched your search
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "siteforge",
|
||||
"version": "2.31.1",
|
||||
"version": "2.32.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "siteforge",
|
||||
"version": "2.31.1",
|
||||
"version": "2.32.0",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.1135.0",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "siteforge",
|
||||
"private": true,
|
||||
"version": "2.31.1",
|
||||
"version": "2.32.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
+48
@@ -13825,3 +13825,51 @@ a.study-track-card:hover {
|
||||
.finished-book-card--featured .finished-book-card-img { aspect-ratio: 16 / 9; height: auto; }
|
||||
}
|
||||
.ep-hero-player { margin-bottom: 0.5rem; }
|
||||
|
||||
/* ── Home page redesign ── */
|
||||
.hero-stats { margin: 1.1rem 0 0; font-size: 0.85rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--brand-gold); opacity: 0.85; }
|
||||
|
||||
.section-home-now { background: #080808; border-top: 1px solid rgba(201, 168, 76, 0.18); border-bottom: 1px solid rgba(201, 168, 76, 0.18); padding: 3.5rem 0; }
|
||||
.home-now-grid { max-width: 1100px; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: 2.5rem; align-items: start; }
|
||||
.home-now-player .eyebrow, .home-now-series .eyebrow { margin-bottom: 0.9rem; }
|
||||
.home-now-all { display: inline-block; margin-top: 0.9rem; font-size: 0.88rem; color: var(--brand-gold); text-decoration: none; letter-spacing: 0.04em; }
|
||||
.home-now-series { display: flex; flex-direction: column; gap: 1rem; }
|
||||
.home-now-series .eyebrow { margin-bottom: 0; }
|
||||
.home-series-card { display: grid; grid-template-columns: 120px 1fr; gap: 1.25rem; align-items: start; background: #131313; border: 1px solid rgba(201, 168, 76, 0.22); border-radius: 14px; padding: 1.1rem; }
|
||||
.home-series-art { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 8px; }
|
||||
.home-series-info h3 { font-family: var(--brand-font-heading); font-size: 1.3rem; color: var(--brand-warm-white); margin: 0 0 0.4rem; }
|
||||
.home-series-desc { color: var(--brand-muted); font-size: 0.95rem; line-height: 1.55; margin: 0 0 0.9rem; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
|
||||
.home-series-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
|
||||
.section-home-shelf { padding: 3rem 0 2.5rem; background: var(--brand-black); }
|
||||
.home-shelf-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: 1.25rem; }
|
||||
.home-shelf-row { display: flex; gap: 1rem; overflow-x: auto; padding-bottom: 0.75rem; scroll-snap-type: x proximity; scrollbar-width: thin; }
|
||||
.home-shelf-book { flex: 0 0 130px; scroll-snap-align: start; text-decoration: none; color: #e8d9b5; font-size: 0.88rem; text-align: center; display: flex; flex-direction: column; gap: 0.5rem; }
|
||||
.home-shelf-book img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 8px; border: 1px solid rgba(201, 168, 76, 0.25); transition: transform 180ms, border-color 180ms; }
|
||||
.home-shelf-book:hover img { transform: translateY(-3px); border-color: rgba(201, 168, 76, 0.6); }
|
||||
|
||||
.prism-steps--chips { display: flex; flex-wrap: wrap; gap: 0.45rem; margin: 1rem 0; }
|
||||
.prism-steps--chips p { padding: 0.4rem 0.8rem; border-radius: 999px; font-size: 0.82rem; }
|
||||
.prism-more { background: transparent; border: 0; padding: 0; color: var(--brand-gold); font-family: var(--brand-font-body); font-size: 0.9rem; letter-spacing: 0.04em; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
|
||||
.section-prism { padding: 3.5rem 0; }
|
||||
|
||||
.section-home-connect { background: #0c0c08; border-top: 1px solid rgba(201, 168, 76, 0.15); border-bottom: 1px solid rgba(201, 168, 76, 0.15); padding: 3.5rem 0; }
|
||||
.home-connect-grid { max-width: 1100px; display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
|
||||
.home-connect-card { background: rgba(26, 26, 21, 0.7); border: 1px solid rgba(201, 168, 76, 0.18); border-radius: 14px; padding: 2rem; }
|
||||
.home-connect-card--newsletter { text-align: center; }
|
||||
.home-connect-card--newsletter .newsletter-inner { max-width: none; }
|
||||
.home-connect-card .section-heading { font-size: 1.5rem; }
|
||||
.home-connect-card .share-p { margin-bottom: 1.1rem; }
|
||||
.home-connect-share-row { display: flex; align-items: center; justify-content: space-between; gap: 1.25rem; flex-wrap: wrap; }
|
||||
.home-connect-share-row .share-qr { width: 110px; height: 110px; }
|
||||
|
||||
.home-more .section-qa-callout, .home-more .section-tfl, .home-more .section-external-sites { padding-top: 3rem; padding-bottom: 3rem; }
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.home-now-grid, .home-connect-grid { grid-template-columns: 1fr; gap: 2rem; }
|
||||
}
|
||||
@media (max-width: 520px) {
|
||||
.home-series-card { grid-template-columns: 84px 1fr; gap: 0.9rem; padding: 0.9rem; }
|
||||
.home-series-info h3 { font-size: 1.1rem; }
|
||||
.home-connect-card { padding: 1.4rem; }
|
||||
}
|
||||
+212
-147
@@ -1052,7 +1052,7 @@ function ExternalSitesSection({ content }: { content: SiteContent }) {
|
||||
)
|
||||
}
|
||||
|
||||
function HomepageNewsletterSection() {
|
||||
function HomepageNewsletterSection({ embedded = false }: { embedded?: boolean }) {
|
||||
const [email, setEmail] = useState('')
|
||||
const [firstName, setFirstName] = useState('')
|
||||
const [honey, setHoney] = useState('')
|
||||
@@ -1074,44 +1074,52 @@ function HomepageNewsletterSection() {
|
||||
}
|
||||
}
|
||||
|
||||
const content = (
|
||||
<>
|
||||
<p className="eyebrow">Stay in the Word</p>
|
||||
<h2 className="section-heading">Get episode updates by email</h2>
|
||||
<p className="newsletter-sub">New episodes, study resources, and ministry updates — delivered to your inbox.</p>
|
||||
{status === 'done' ? (
|
||||
<p className="newsletter-thanks">You're subscribed! Thank you for signing up.</p>
|
||||
) : (
|
||||
<form className="newsletter-form" onSubmit={handleSubmit} noValidate>
|
||||
<input type="text" className="contact-honeypot" tabIndex={-1} autoComplete="off" aria-hidden="true" value={honey} onChange={e => setHoney(e.target.value)} />
|
||||
<div className="newsletter-fields">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="First name"
|
||||
required
|
||||
autoComplete="given-name"
|
||||
value={firstName}
|
||||
onChange={e => setFirstName(e.target.value)}
|
||||
className="newsletter-input"
|
||||
/>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email address"
|
||||
required
|
||||
autoComplete="email"
|
||||
value={email}
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
className="newsletter-input"
|
||||
/>
|
||||
<button type="submit" className="btn-primary" disabled={status === 'submitting'}>
|
||||
{status === 'submitting' ? 'Subscribing…' : 'Subscribe'}
|
||||
</button>
|
||||
</div>
|
||||
{status === 'error' && <p className="newsletter-error">Something went wrong. Please try again.</p>}
|
||||
</form>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
// `embedded` drops the full-width band so the signup can sit inside another section (homepage connect row).
|
||||
if (embedded) {
|
||||
return <div className="home-connect-card home-connect-card--newsletter" aria-label="Newsletter sign-up">{content}</div>
|
||||
}
|
||||
return (
|
||||
<section className="section-newsletter" aria-label="Newsletter sign-up">
|
||||
<div className="section-inner newsletter-inner">
|
||||
<p className="eyebrow">Stay in the Word</p>
|
||||
<h2 className="section-heading">Get episode updates by email</h2>
|
||||
<p className="newsletter-sub">New episodes, study resources, and ministry updates — delivered to your inbox.</p>
|
||||
{status === 'done' ? (
|
||||
<p className="newsletter-thanks">You're subscribed! Thank you for signing up.</p>
|
||||
) : (
|
||||
<form className="newsletter-form" onSubmit={handleSubmit} noValidate>
|
||||
<input type="text" className="contact-honeypot" tabIndex={-1} autoComplete="off" aria-hidden="true" value={honey} onChange={e => setHoney(e.target.value)} />
|
||||
<div className="newsletter-fields">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="First name"
|
||||
required
|
||||
autoComplete="given-name"
|
||||
value={firstName}
|
||||
onChange={e => setFirstName(e.target.value)}
|
||||
className="newsletter-input"
|
||||
/>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email address"
|
||||
required
|
||||
autoComplete="email"
|
||||
value={email}
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
className="newsletter-input"
|
||||
/>
|
||||
<button type="submit" className="btn-primary" disabled={status === 'submitting'}>
|
||||
{status === 'submitting' ? 'Subscribing…' : 'Subscribe'}
|
||||
</button>
|
||||
</div>
|
||||
{status === 'error' && <p className="newsletter-error">Something went wrong. Please try again.</p>}
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
<div className="section-inner newsletter-inner">{content}</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1224,6 +1232,44 @@ function TestimonialsSection({ testimonials }: { testimonials: Testimonial[] })
|
||||
|
||||
function LandingPage({ content }: { content: SiteContent }) {
|
||||
const featuredStudy = getHomepageFeaturedStudy(content)
|
||||
const { episodes } = useAllEpisodes()
|
||||
const [prismOpen, setPrismOpen] = useState(false)
|
||||
const finishedBooks = [...(content.finishedBooks ?? [])].sort((a, b) => b.season - a.season)
|
||||
const episodesInSeason = (season?: number) => (season ? episodes.filter(ep => ep.season === String(season)).length : 0)
|
||||
|
||||
const liveSeries = [
|
||||
{
|
||||
key: 'primary',
|
||||
imageUrl: content.seriesImageUrl,
|
||||
title: content.seriesTitle,
|
||||
label: content.seriesLabel,
|
||||
description: content.seriesDescription,
|
||||
listenUrl: content.seriesListenUrl,
|
||||
listenBtnLabel: content.seriesListenBtnLabel,
|
||||
studySlug: content.seriesStudySlug,
|
||||
season: content.seriesSeason,
|
||||
},
|
||||
...(content.secondSeries?.title?.trim()
|
||||
? [{
|
||||
key: 'second',
|
||||
imageUrl: content.secondSeries.imageUrl,
|
||||
title: content.secondSeries.title,
|
||||
label: content.secondSeries.label,
|
||||
description: content.secondSeries.description,
|
||||
listenUrl: content.secondSeries.listenUrl,
|
||||
listenBtnLabel: content.secondSeries.listenBtnLabel,
|
||||
studySlug: content.secondSeries.studySlug,
|
||||
season: content.secondSeries.season,
|
||||
}]
|
||||
: []),
|
||||
]
|
||||
|
||||
// Fixed "ways in" cards go first; the admin-managed cards follow, skipping any that point to the same page.
|
||||
const adminCards = content.whereToNextCards ?? []
|
||||
const fixedCards = [
|
||||
{ id: 'start', path: '/start-here', title: 'Start here', description: 'New to the show? A short path through the best first episodes.' },
|
||||
{ id: 'verse', path: '/scripture', title: 'Find a verse', description: 'Look up any passage and jump to the episode or lesson that covers it.' },
|
||||
].filter(card => !adminCards.some(c => c.path === card.path))
|
||||
|
||||
return (
|
||||
<div className="site">
|
||||
@@ -1259,12 +1305,108 @@ function LandingPage({ content }: { content: SiteContent }) {
|
||||
<SpotifyIcon />
|
||||
{content.heroBtnSpotify || 'Listen on Spotify'}
|
||||
</a>
|
||||
<Link to="/episodes" className="btn-secondary">{content.heroBtnEpisodes || 'Explore Episodes ↓'}</Link>
|
||||
<Link to="/start-here" className="btn-secondary btn-start-here">{content.heroBtnStartHere || 'New here? Start here →'}</Link>
|
||||
<Link to="/episodes" className="btn-secondary">{content.heroBtnEpisodes || 'Explore Episodes ↓'}</Link>
|
||||
</div>
|
||||
{episodes.length > 0 && (
|
||||
<p className="hero-stats">
|
||||
{episodes.length} episodes
|
||||
{finishedBooks.length > 0 && <> · {finishedBooks.length} {finishedBooks.length === 1 ? 'book' : 'books'} completed</>}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── LISTEN NOW: latest episode + current series ── */}
|
||||
<section className="section-home-now" id="series" aria-label="Listen now">
|
||||
<div className="section-inner home-now-grid">
|
||||
<div className="home-now-player">
|
||||
<p className="eyebrow">Latest Episode</p>
|
||||
<LatestEpisodePlayer content={content} />
|
||||
<Link to="/episodes" className="home-now-all">Browse all episodes →</Link>
|
||||
</div>
|
||||
<div className="home-now-series">
|
||||
<p className="eyebrow">Current Series</p>
|
||||
{liveSeries.map(series => {
|
||||
const count = episodesInSeason(series.season)
|
||||
return (
|
||||
<article className="home-series-card" key={series.key}>
|
||||
<img src={series.imageUrl} alt={series.title} className="home-series-art" />
|
||||
<div className="home-series-info">
|
||||
<p className="series-label">{series.label}{count > 0 ? ` · ${count} episodes so far` : ''}</p>
|
||||
<h3>{series.title}</h3>
|
||||
<p className="home-series-desc">{series.description}</p>
|
||||
<div className="home-series-actions">
|
||||
<a
|
||||
href={series.listenUrl || content.platformSpotifyUrl || '/spotify'}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="btn-primary"
|
||||
>
|
||||
<SpotifyIcon />
|
||||
{series.listenBtnLabel || content.seriesListenBtnLabel || 'Listen to Series'}
|
||||
</a>
|
||||
{series.studySlug
|
||||
? <Link to={`/study/${series.studySlug}`} className="btn-secondary">Study Along</Link>
|
||||
: <Link to="/resources" className="btn-secondary">{content.seriesDownloadsBtnLabel || 'View Resources'}</Link>}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── WAYS IN ── */}
|
||||
<section className="section-home-jump" aria-label="Homepage navigation">
|
||||
<div className="section-inner">
|
||||
<div className="home-jump-head">
|
||||
<p className="eyebrow">{content.whereToNextEyebrow || 'Where to Next'}</p>
|
||||
<h2 className="section-heading">{content.whereToNextHeading || 'Choose the page you need.'}</h2>
|
||||
</div>
|
||||
<div className="home-jump-grid">
|
||||
{[...fixedCards, ...adminCards].map(card => (
|
||||
<Link key={card.id} to={card.path} className="home-jump-card">
|
||||
<h3>{card.title}</h3>
|
||||
<p>{card.description}</p>
|
||||
</Link>
|
||||
))}
|
||||
{featuredStudy && (
|
||||
<Link to={`/study/${featuredStudy.slug || ''}`} className="home-jump-card home-jump-card--featured">
|
||||
<div className="home-jump-featured-head">
|
||||
<p className="eyebrow">{featuredStudy.homepageEyebrow || 'Study'}</p>
|
||||
{featuredStudy.showNewTag && <span className="home-jump-new-tag">{featuredStudy.newTagLabel || 'NEW'}</span>}
|
||||
</div>
|
||||
<h3>{featuredStudy.title}</h3>
|
||||
<p>{featuredStudy.description || 'Explore this study track with lesson notes, commentary, and guided questions.'}</p>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── FINISHED BOOKS SHELF ── */}
|
||||
{finishedBooks.length > 0 && (
|
||||
<section className="section-home-shelf" aria-label="Finished books">
|
||||
<div className="section-inner">
|
||||
<div className="home-shelf-head">
|
||||
<h2 className="section-heading" style={{ textAlign: 'left', marginBottom: 0 }}>Books We've Finished</h2>
|
||||
<Link to="/finished" className="home-now-all">See all →</Link>
|
||||
</div>
|
||||
<div className="home-shelf-row">
|
||||
{finishedBooks.map(book => (
|
||||
<Link key={book.id} to={`/finished/${book.id}`} className="home-shelf-book">
|
||||
{book.imageUrl && <img src={book.imageUrl} alt={book.title} loading="lazy" />}
|
||||
<span>{book.title}</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* ── PRISM ── */}
|
||||
<section className="section-prism" aria-label="PRISM featured video">
|
||||
<div className="section-inner prism-feature">
|
||||
<div className="prism-video-shell">
|
||||
@@ -1288,136 +1430,59 @@ function LandingPage({ content }: { content: SiteContent }) {
|
||||
<p className="prism-description">
|
||||
{content.prismIntro || 'What if every time you opened your Bible, you had a clear, repeatable method to actually dig in?'}
|
||||
</p>
|
||||
<p className="prism-description">
|
||||
{content.prismPatternIntro || 'In this bonus episode, I walk you through P.R.I.S.M. — a five-step daily Bible study pattern designed to help you slow down, go deep, and let the Word do its work.'}
|
||||
</p>
|
||||
<div className="prism-steps" aria-label="P.R.I.S.M. steps">
|
||||
<div className="prism-steps prism-steps--chips" aria-label="P.R.I.S.M. steps">
|
||||
<p>{content.prismStep1 || 'P — Pray before you read'}</p>
|
||||
<p>{content.prismStep2 || 'R — Read slowly and observe'}</p>
|
||||
<p>{content.prismStep3 || 'I — Interpret with context'}</p>
|
||||
<p>{content.prismStep4 || 'S — Study and apply specifically'}</p>
|
||||
<p>{content.prismStep5 || 'M — Memorize one verse at a time'}</p>
|
||||
</div>
|
||||
<p className="prism-description">
|
||||
{content.prismOutro || "Whether you're brand new to daily Bible reading or you've been at it for years, P.R.I.S.M. gives you a consistent framework for every passage, every day."}
|
||||
</p>
|
||||
<p className="prism-description prism-emphasis">
|
||||
{content.prismClosing || "The goal isn't to get through the text — it's to let the text get through to you."}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<HomepageNewsletterSection />
|
||||
|
||||
<section className="section-series" id="series" aria-label="Current series">
|
||||
<div className="section-inner">
|
||||
<h2 className="section-heading">
|
||||
<span className="ornament">✦</span> Current Series{' '}
|
||||
<span className="ornament">✦</span>
|
||||
</h2>
|
||||
<div className={`series-grid${content.secondSeries?.title?.trim() ? ' series-grid--two' : ''}`}>
|
||||
{[
|
||||
{
|
||||
key: 'primary',
|
||||
imageUrl: content.seriesImageUrl,
|
||||
title: content.seriesTitle,
|
||||
label: content.seriesLabel,
|
||||
description: content.seriesDescription,
|
||||
listenUrl: content.seriesListenUrl,
|
||||
listenBtnLabel: content.seriesListenBtnLabel,
|
||||
studySlug: content.seriesStudySlug,
|
||||
},
|
||||
...(content.secondSeries?.title?.trim()
|
||||
? [{
|
||||
key: 'second',
|
||||
imageUrl: content.secondSeries.imageUrl,
|
||||
title: content.secondSeries.title,
|
||||
label: content.secondSeries.label,
|
||||
description: content.secondSeries.description,
|
||||
listenUrl: content.secondSeries.listenUrl,
|
||||
listenBtnLabel: content.secondSeries.listenBtnLabel,
|
||||
studySlug: content.secondSeries.studySlug,
|
||||
}]
|
||||
: []),
|
||||
].map(series => (
|
||||
<article className="series-card" key={series.key}>
|
||||
<img
|
||||
src={series.imageUrl}
|
||||
alt={series.title}
|
||||
className="series-art"
|
||||
/>
|
||||
<div className="series-info">
|
||||
<p className="series-label">{series.label}</p>
|
||||
<h3>{series.title}</h3>
|
||||
<p>{series.description}</p>
|
||||
<a
|
||||
href={series.listenUrl || content.platformSpotifyUrl || '/spotify'}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="btn-primary"
|
||||
>
|
||||
<SpotifyIcon />
|
||||
{series.listenBtnLabel || content.seriesListenBtnLabel || 'Listen to Series'}
|
||||
</a>
|
||||
{series.studySlug
|
||||
? <Link to={`/study/${series.studySlug}`} className="btn-secondary">Study Along</Link>
|
||||
: <Link to="/resources" className="btn-secondary">{content.seriesDownloadsBtnLabel || 'View Resources'}</Link>}
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<TruthForLifeWidget type="audiodevo" />
|
||||
|
||||
<ExternalSitesSection content={content} />
|
||||
|
||||
<section className="section-home-jump" aria-label="Homepage navigation">
|
||||
<div className="section-inner">
|
||||
<div className="home-jump-head">
|
||||
<p className="eyebrow">{content.whereToNextEyebrow || 'Where to Next'}</p>
|
||||
<h2 className="section-heading">{content.whereToNextHeading || 'Choose the page you need.'}</h2>
|
||||
</div>
|
||||
<div className="home-jump-grid">
|
||||
{(content.whereToNextCards ?? []).map(card => (
|
||||
<Link key={card.id} to={card.path} className="home-jump-card">
|
||||
<h3>{card.title}</h3>
|
||||
<p>{card.description}</p>
|
||||
</Link>
|
||||
))}
|
||||
{featuredStudy && (
|
||||
<Link to={`/study/${featuredStudy.slug || ''}`} className="home-jump-card home-jump-card--featured">
|
||||
<div className="home-jump-featured-head">
|
||||
<p className="eyebrow">{featuredStudy.homepageEyebrow || 'Study'}</p>
|
||||
{featuredStudy.showNewTag && <span className="home-jump-new-tag">{featuredStudy.newTagLabel || 'NEW'}</span>}
|
||||
</div>
|
||||
<h3>{featuredStudy.title}</h3>
|
||||
<p>{featuredStudy.description || 'Explore this study track with lesson notes, commentary, and guided questions.'}</p>
|
||||
</Link>
|
||||
{prismOpen && (
|
||||
<>
|
||||
<p className="prism-description">
|
||||
{content.prismPatternIntro || 'In this bonus episode, I walk you through P.R.I.S.M. — a five-step daily Bible study pattern designed to help you slow down, go deep, and let the Word do its work.'}
|
||||
</p>
|
||||
<p className="prism-description">
|
||||
{content.prismOutro || "Whether you're brand new to daily Bible reading or you've been at it for years, P.R.I.S.M. gives you a consistent framework for every passage, every day."}
|
||||
</p>
|
||||
<p className="prism-description prism-emphasis">
|
||||
{content.prismClosing || "The goal isn't to get through the text — it's to let the text get through to you."}
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
<button type="button" className="prism-more" aria-expanded={prismOpen} onClick={() => setPrismOpen(v => !v)}>
|
||||
{prismOpen ? 'Show less' : 'Read more about PRISM'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<HomepageQACallout />
|
||||
|
||||
<TestimonialsSection testimonials={content.testimonials ?? []} />
|
||||
|
||||
<section className="section-share" aria-label="Share the show">
|
||||
<div className="section-inner section-share-inner">
|
||||
<div className="share-text">
|
||||
{/* ── CONNECT: newsletter + share ── */}
|
||||
<section className="section-home-connect" aria-label="Stay connected">
|
||||
<div className="section-inner home-connect-grid">
|
||||
<HomepageNewsletterSection embedded />
|
||||
<div className="home-connect-card home-connect-card--share">
|
||||
<h2 className="section-heading" style={{ textAlign: 'left', marginBottom: '0.75rem' }}>
|
||||
{content.shareHeading || 'Help one more person hear the Word this week.'}
|
||||
</h2>
|
||||
<p className="share-p">{content.shareP || 'Scan the QR code or text the show link to a friend who needs encouragement today.'}</p>
|
||||
<ShareShowButton />
|
||||
<div className="home-connect-share-row">
|
||||
<ShareShowButton />
|
||||
<img src={content.shareQrImageUrl || '/images/qr-code.jpg'} alt="QR code to share the show" className="share-qr" />
|
||||
</div>
|
||||
</div>
|
||||
<img src={content.shareQrImageUrl || '/images/qr-code.jpg'} alt="QR code to share the show" className="share-qr" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── MORE FROM US ── */}
|
||||
<div className="home-more">
|
||||
<HomepageQACallout />
|
||||
<TruthForLifeWidget type="audiodevo" />
|
||||
<ExternalSitesSection content={content} />
|
||||
</div>
|
||||
|
||||
<SiteFooter content={content} />
|
||||
|
||||
<AnalyticsConsentBanner content={content} />
|
||||
|
||||
Reference in new issue
Block a user