From a6f0c39c35e9d9d4b2dc919060a435ff58ce5282 Mon Sep 17 00:00:00 2001 From: nmemmert Date: Wed, 17 Jun 2026 13:48:49 -0400 Subject: [PATCH] Simplify episodes page and upgrade podcast highlights to card layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Episodes page now shows Spotify show embed only (no episode list) - Podcast highlights section replaced plain links with episode-card style (gold border, episode number, title, summary, Listen → CTA) Co-Authored-By: Claude Sonnet 4.6 --- src/App.tsx | 209 +++++++++------------------------------------------- 1 file changed, 35 insertions(+), 174 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index e43ff30..a8419e5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -14,8 +14,7 @@ import { GlobalSearch } from './components/GlobalSearch' import { EpisodeAudioPlayer } from './components/EpisodeAudioPlayer' import './App.css' -const SPOTIFY_EMBED_URL = - 'https://open.spotify.com/embed/show/0Gq1TzoJOdReSZ1gYQi8Xl?utm_source=generator&theme=0' + const CONSENT_KEY = 'vbn_analytics_consent_choice' const HEADLINER_WIDGET_ID = 'WI_cmou3b4q7000701p0o9qmmcfj' @@ -764,7 +763,7 @@ function PodcastHighlightsSection({ content }: { content: SiteContent }) { Podcast Highlights{' '} -
+
{links.map(link => { const hasRichContent = !!( link.embedUrl @@ -772,19 +771,31 @@ function PodcastHighlightsSection({ content }: { content: SiteContent }) { || (link.discussionQuestions ?? []).length > 0 || link.showNotes ) - const label = <>{link.episodeNumber ? `Ep. ${link.episodeNumber}: ` : ''}{link.title || link.url} - // Use external link only when there's a url AND no rich detail-page content - if (!hasRichContent && link.url) { + const dest = (!hasRichContent && link.url) + ? { external: link.url } + : { internal: `/episodes/${link.id}` } + + const inner = ( + <> +
+ {link.episodeNumber && Ep. {link.episodeNumber}} +
+

{link.title || link.url}

+ {link.summary &&

{link.summary}

} + Listen → + + ) + + if ('external' in dest) { return ( - - {label} + + {inner} ) } - // Otherwise always route to the internal detail page return ( - - {label} + + {inner} ) })} @@ -1613,106 +1624,12 @@ function EpisodeDetailPage({ content }: { content: SiteContent }) { } function EpisodesPage({ content }: { content: SiteContent }) { - const [allEpisodes, setAllEpisodes] = useState([]) - const [loading, setLoading] = useState(true) - const [failed, setFailed] = useState(false) const siteTitle = content.seo?.title || DEFAULTS.seo.title usePageMeta( `Episodes | ${siteTitle}`, content.episodesSeoIntro || 'Browse all episodes of Verse by Verse with Nate — expository Bible teaching, one verse at a time.', ) - useEffect(() => { - fetch('/api/episodes/all') - .then(r => (r.ok ? r.json() : Promise.reject(new Error('fetch failed')))) - .then((data: { episodes: Episode[] }) => { - if (data.episodes.length === 0) setFailed(true) - else setAllEpisodes(data.episodes) - setLoading(false) - }) - .catch(() => { - setFailed(true) - setLoading(false) - }) - }, []) - - const archivedSeries = content.archivedSeries ?? [] - - const archivedEpisodeNums = new Set( - archivedSeries.flatMap(s => { - if (!s.episodeRange) return [] - const nums: number[] = [] - for (let i = s.episodeRange.from; i <= s.episodeRange.to; i++) nums.push(i) - return nums - }) - ) - - const currentEpisodes = allEpisodes.filter(ep => { - const num = parseInt(ep.episode, 10) - return isNaN(num) || !archivedEpisodeNums.has(num) - }) - - function episodesForSeries(series: ArchivedSeries) { - if (!series.episodeRange) return [] - const { from, to } = series.episodeRange - return allEpisodes.filter(ep => { - const num = parseInt(ep.episode, 10) - return !isNaN(num) && num >= from && num <= to - }) - } - - function renderEpisodeCards(episodes: Episode[]) { - return ( - - ) - } - - const spotifyFallback = ( -
-