Episodes page: show both series lanes (A and B) in the hero with lane-aware series chips; v2.31.1
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f1577e9d8a
commit
d1c84aec6b
4 files changed
+33
-22
No files matched your search
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "siteforge",
|
"name": "siteforge",
|
||||||
"version": "2.31.0",
|
"version": "2.31.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "siteforge",
|
"name": "siteforge",
|
||||||
"version": "2.31.0",
|
"version": "2.31.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.1135.0",
|
"@aws-sdk/client-s3": "^3.1135.0",
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "siteforge",
|
"name": "siteforge",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.31.0",
|
"version": "2.31.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
+9
-12
@@ -13788,17 +13788,13 @@ a.study-track-card:hover {
|
|||||||
|
|
||||||
|
|
||||||
/* ── Episodes hub & Finished Books library ── */
|
/* ── Episodes hub & Finished Books library ── */
|
||||||
.ep-hero {
|
.ep-hero { max-width: 1000px; display: flex; flex-direction: column; gap: 1.5rem; }
|
||||||
display: grid;
|
.ep-hero-series { display: block; }
|
||||||
grid-template-columns: 220px 1fr;
|
.ep-hero-series--two { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; }
|
||||||
grid-template-areas: "art body" "player player";
|
.ep-hero-series-card { display: grid; grid-template-columns: 220px 1fr; gap: 1.5rem 2rem; align-items: center; }
|
||||||
gap: 1.5rem 2rem;
|
.ep-hero-series--two .ep-hero-series-card { grid-template-columns: 110px 1fr; gap: 1rem; align-items: start; padding: 1rem; background: rgba(26, 26, 21, 0.7); border: 1px solid rgba(201, 168, 76, 0.18); border-radius: 12px; }
|
||||||
align-items: center;
|
.ep-hero-art { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 12px; border: 1px solid rgba(201, 168, 76, 0.25); }
|
||||||
max-width: 1000px;
|
.ep-hero-browse { display: inline-block; margin-top: 0.6rem; font-size: 0.85rem; color: var(--brand-gold); text-decoration: none; letter-spacing: 0.04em; }
|
||||||
}
|
|
||||||
.ep-hero-art { grid-area: art; width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 12px; border: 1px solid rgba(201, 168, 76, 0.25); }
|
|
||||||
.ep-hero-body { grid-area: body; }
|
|
||||||
.ep-hero-player { grid-area: player; }
|
|
||||||
.ep-hero-title { font-family: var(--brand-font-heading); font-size: 1.7rem; color: #e8d9b5; margin: 0.2rem 0 0.6rem; }
|
.ep-hero-title { font-family: var(--brand-font-heading); font-size: 1.7rem; color: #e8d9b5; margin: 0.2rem 0 0.6rem; }
|
||||||
.ep-hero-desc { color: var(--brand-muted); line-height: 1.6; margin: 0; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
|
.ep-hero-desc { color: var(--brand-muted); line-height: 1.6; margin: 0; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
|
||||||
.section-episode-browser { padding: 3rem 0 2rem; }
|
.section-episode-browser { padding: 3rem 0 2rem; }
|
||||||
@@ -13819,7 +13815,8 @@ a.study-track-card:hover {
|
|||||||
.finished-book-card--featured .finished-book-card-title { font-size: 1.8rem; }
|
.finished-book-card--featured .finished-book-card-title { font-size: 1.8rem; }
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.ep-hero { grid-template-columns: 96px 1fr; gap: 1rem; }
|
.ep-hero-series--two { grid-template-columns: 1fr; }
|
||||||
|
.ep-hero-series-card, .ep-hero-series--two .ep-hero-series-card { grid-template-columns: 96px 1fr; gap: 1rem; }
|
||||||
.ep-hero-title { font-size: 1.3rem; }
|
.ep-hero-title { font-size: 1.3rem; }
|
||||||
.ep-hero-desc { -webkit-line-clamp: 3; font-size: 0.9rem; }
|
.ep-hero-desc { -webkit-line-clamp: 3; font-size: 0.9rem; }
|
||||||
.ep-season-chips { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding-bottom: 0.2rem; }
|
.ep-season-chips { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding-bottom: 0.2rem; }
|
||||||
|
|||||||
+21
-7
@@ -2163,8 +2163,13 @@ function EpisodesPage({ content }: { content: SiteContent }) {
|
|||||||
const [openKey, setOpenKey] = useState<string | null>(null)
|
const [openKey, setOpenKey] = useState<string | null>(null)
|
||||||
|
|
||||||
const finishedBooks = [...(content.finishedBooks ?? [])].sort((a, b) => b.season - a.season)
|
const finishedBooks = [...(content.finishedBooks ?? [])].sort((a, b) => b.season - a.season)
|
||||||
|
const second = content.secondSeries?.title?.trim() ? content.secondSeries : null
|
||||||
|
const liveSeries = [
|
||||||
|
{ key: content.seriesSeason ? String(content.seriesSeason) : '', title: content.seriesTitle, label: second ? (content.seriesLabel || 'Series A') : 'Current series', description: content.seriesDescription, imageUrl: content.seriesImageUrl, season: content.seriesSeason },
|
||||||
|
...(second ? [{ key: second.season ? String(second.season) : '', title: second.title, label: second.label || 'Series B', description: second.description, imageUrl: second.imageUrl, season: second.season }] : []),
|
||||||
|
]
|
||||||
const seasonChips = [
|
const seasonChips = [
|
||||||
...(content.seriesSeason ? [{ key: String(content.seriesSeason), label: 'Current series' }] : []),
|
...liveSeries.filter(ls => ls.key).map(ls => ({ key: ls.key, label: second ? ls.title : 'Current series' })),
|
||||||
...finishedBooks.map(book => ({ key: String(book.season), label: book.title })),
|
...finishedBooks.map(book => ({ key: String(book.season), label: book.title })),
|
||||||
]
|
]
|
||||||
const countFor = (key: string) => episodes.filter(ep => ep.season === key).length
|
const countFor = (key: string) => episodes.filter(ep => ep.season === key).length
|
||||||
@@ -2190,11 +2195,20 @@ function EpisodesPage({ content }: { content: SiteContent }) {
|
|||||||
<p className="episode-seo-intro" aria-hidden="true">
|
<p className="episode-seo-intro" aria-hidden="true">
|
||||||
{content.episodesSeoIntro || 'Verse by Verse with Nate is an expository Bible teaching podcast where we go through Scripture one verse at a time. Each episode digs into the text carefully and practically, helping you understand what the Bible says, what it means, and how to live it out. New episodes released regularly — subscribe on Spotify or your favorite podcast platform.'}
|
{content.episodesSeoIntro || 'Verse by Verse with Nate is an expository Bible teaching podcast where we go through Scripture one verse at a time. Each episode digs into the text carefully and practically, helping you understand what the Bible says, what it means, and how to live it out. New episodes released regularly — subscribe on Spotify or your favorite podcast platform.'}
|
||||||
</p>
|
</p>
|
||||||
{content.seriesImageUrl && <img src={content.seriesImageUrl} alt={content.seriesTitle} className="ep-hero-art" />}
|
<div className={`ep-hero-series${second ? ' ep-hero-series--two' : ''}`}>
|
||||||
<div className="ep-hero-body">
|
{liveSeries.map((ls, i) => (
|
||||||
<p className="finished-book-card-season">Current series{content.seriesSeason ? ` · Season ${content.seriesSeason}` : ''}</p>
|
<div key={i} className="ep-hero-series-card">
|
||||||
<h2 className="ep-hero-title">{content.seriesTitle}</h2>
|
{ls.imageUrl && <img src={ls.imageUrl} alt={ls.title} className="ep-hero-art" />}
|
||||||
{content.seriesDescription && <p className="ep-hero-desc">{content.seriesDescription}</p>}
|
<div className="ep-hero-body">
|
||||||
|
<p className="finished-book-card-season">{ls.label}{ls.season ? ` · Season ${ls.season}` : ''}</p>
|
||||||
|
<h2 className="ep-hero-title">{ls.title}</h2>
|
||||||
|
{ls.description && <p className="ep-hero-desc">{ls.description}</p>}
|
||||||
|
{second && ls.key && (
|
||||||
|
<a href="#browse-episodes" className="ep-hero-browse" onClick={() => { setSeason(ls.key); setExpanded(false) }}>Browse these episodes ↓</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="ep-hero-player">
|
<div className="ep-hero-player">
|
||||||
<LatestEpisodePlayer content={content} />
|
<LatestEpisodePlayer content={content} />
|
||||||
@@ -2205,7 +2219,7 @@ function EpisodesPage({ content }: { content: SiteContent }) {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="section-episode-browser" aria-label="Browse episodes">
|
<section id="browse-episodes" className="section-episode-browser" aria-label="Browse episodes">
|
||||||
<div className="section-inner">
|
<div className="section-inner">
|
||||||
<h2 className="section-heading"><span className="ornament">✦</span> Browse Episodes <span className="ornament">✦</span></h2>
|
<h2 className="section-heading"><span className="ornament">✦</span> Browse Episodes <span className="ornament">✦</span></h2>
|
||||||
<input
|
<input
|
||||||
|
|||||||
Reference in new issue
Block a user