Commit Graph
155 Commits
Author SHA1 Message Date
nmemmertandClaude Sonnet 4.6 a12a471c41 Add host welcome/reset emails, email field, and /host URL; v2.0.7
- Host accounts now have an optional email field
- Creating a host with an email sends a welcome email with the portal
  URL, username, and password via Resend
- Resetting a password also emails the new credentials if the host
  has an email on file; admin sees a confirmation either way
- Admin panel shows email column and confirmation messages
- Portal URL changed from /host-upload to /host

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-08 14:01:51 -04:00
nmemmertandClaude Sonnet 4.6 afdc00114a Add Nuggets host upload portal with Seafile integration; v2.0.4
- New /host-upload page: per-host login (username + password) with
  session cookie, drag-and-drop file upload to Seafile via server proxy
- Two upload targets: Episode Upload (audio) and Episode Info (docs)
- Server route: /api/nuggets-upload/* for host auth + file proxy,
  /api/admin/nuggets-upload/hosts for admin CRUD (create/disable/reset pw/delete)
- Admin panel: Nuggets → Upload Portal view to manage host accounts
- Seafile config via SEAFILE_URL / SEAFILE_TOKEN / SEAFILE_NUGGETS_REPO_ID env vars
- Directories default to /Episode Upload and /Episode Info (configurable)
- Uses multer for multipart uploads; 500 MB per-file limit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-08 13:38:57 -04:00
nmemmertandClaude Sonnet 4.6 29d2ace1b2 Fix cramped host card layout on Nuggets page; v2.0.3
Publish Container / docker (push) Successful in 12m59s
- Restructure host card: image+name/role in a row header, bio spans full card width below
- Widen hosts column from 300px max to 360px max
- Add nuggets-host-card-header and nuggets-host-card-meta CSS classes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-08 10:47:21 -04:00
nmemmertandClaude Sonnet 4.6 4378fad66f Fix 5 bugs: analytics range keys, stale visitor rows, NuggetsPage init state, episodes timer leak, unsanitized nuggets object; v2.0.1
Publish Container / docker (push) Successful in 14m54s
- analytics: union byDayReal+byDayBot keys so bot-only days aren't dropped from range totals
- analytics: exclude timestamp-less visitor rows from range filters (was unconditionally including them)
- App.tsx: init `configured` to false so a network failure doesn't show a misleading "no episodes" state; add r.ok guard before r.json()
- episodes.js: wrap fetch in try/catch so clearTimeout is called on network failure, matching the nuggets.js pattern
- helpers.js: add sanitizeNuggets + wire it into sanitizeSiteContent so corrupted hosts/urls can't crash NuggetsPage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-08 08:21:02 -04:00
nmemmertandClaude Sonnet 5 31e79ad542 Add Verse By Verse: Nuggets sub-show with editable hosts and RSS feed
Publish Container / docker (push) Successful in 14m16s
New /nuggets page for the companion show, linked from the Episodes nav
dropdown. Hosts (name, role, bio, photo) show in a left column with the
episode list on the right — latest episode featured, rest below.
Episodes are pulled from an admin-configurable RSS feed URL (empty by
default, shows "coming soon" until set) rather than hardcoded like the
main show's feed, since the show doesn't have one yet.

Everything is editable in /admin under a new Nuggets section: Show
Settings (title, tagline, description, podcast art, RSS/platform URLs)
and Hosts (add freely; removing a host archives them instead of
deleting — kept on record and restorable, never lost).

Extracted the RSS item-parsing logic shared with the main show's feed
(server/routes/episodes.js) into server/rss-helpers.js so both feeds
use the same parser instead of duplicating it.

Also fixes the local Vite dev server not proxying /uploads/* to the
backend — it was silently serving the SPA shell (200, text/html)
instead of the actual file, so any admin-uploaded image (podcast art,
host photos, etc.) appeared broken in local dev only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Yvx4rPVy2HWe7ubuk3X3J
2026-09-07 14:27:52 -04:00
nmemmertandClaude Sonnet 5 335a9cbe31 Consolidate the three duplicate Bible-book lookup tables into one shared registry
Publish Container / docker (push) Successful in 14m9s
src/App.tsx (Scripture Index book map) and server/routes/bible-passage.js
(BSB/bolls.life passage fetch) each hand-maintained their own independent
66-book list with a different key format (3-letter USFM id vs bolls.life's
numeric id), so a future alias/rename fix in one would silently not apply to
the other.

Add shared/bible-books.js as the single canonical list (name + aliases +
USFM id, in canonical order); the server derives its numeric bolls.life ids
from the array position instead of hand-maintaining a second table. Requires
allowJs + including shared/ in tsconfig.app.json so the client can import the
plain-JS module alongside its TypeScript sources.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Yvx4rPVy2HWe7ubuk3X3J
2026-09-07 09:49:52 -04:00
nmemmertandClaude Sonnet 5 c158fb6317 Fix contact form crash, analytics range filter, Scripture Index parsing, and unsafe-delete UI bugs
Publish Container / docker (push) Successful in 13m12s
- server/routes/contact.js: import fireWebhooks (was undefined, throwing on every submission)
- server/routes/analytics.js: filter admin-stats by row.at, the field recordVisitor actually sets, instead of the never-populated row.visitedAt
- src/App.tsx: parseSIRef now supports chapter-spanning verse ranges (e.g. "5:15-6:2"); SI_BOOK_MAP indexes both spaced and unspaced book names so multi-word Bible Book values from the admin field resolve correctly
- src/App.css / src/App.tsx: fix Episodes/Studies nav dropdown menus being unclickable — a positioning gap between the trigger and menu created a hover dead zone; menu is now flush with spacing moved into padding so hover carries through
- src/components/StudySectionComments.tsx: check response status before removing a comment locally, so a rejected delete no longer appears to succeed
- src/components/QASection.tsx: don't bail out of search scoring for 1-2 character queries, so short substrings like "OT" or "AI" can still match
- src/AdminPage.tsx: check response status in study-user, QR code, and episode-script delete handlers before updating local state

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Yvx4rPVy2HWe7ubuk3X3J
2026-09-07 09:39:37 -04:00
nmemmertandClaude Sonnet 5 6ed29ea527 Rebuild Scripture Index as a true cross-content reference index
Publish Container / docker (push) Successful in 15m2s
Previously it just grouped study lessons under each study (essentially
another list of lessons) and ignored podcast episodes entirely. Now it
parses every reference from studies and episode show notes, merges
entries that point at the same verse(s) into one row with links to all
sources, and groups rows by book in canonical Bible order. References
that don't parse (e.g. whole-chapter refs) fall into an "Other
References" section instead of being dropped.

Also fixes the reference passed to the index for studies without a
bibleBook set — it was falling back to the study's marketing title
instead of its slug, producing unparseable references.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Yvx4rPVy2HWe7ubuk3X3J
2026-09-07 09:20:12 -04:00
nmemmertandClaude Sonnet 4.6 5bc8245ed2 Add structured show notes form to Episode Highlights; v1.2.3
Replace single showNotes textarea with five guided fields: Episode Summary,
Key Themes, Scripture References, Key Quotes, and Resources & Links. Legacy
showNotes content is preserved as a backward-compatible fallback — it
auto-populates the Summary field in the admin editor and renders on the public
episode detail page until overwritten with structured data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-03 14:17:47 -04:00
nmemmertandClaude Sonnet 4.6 36dfa0c1d7 Redesign Scripture Index with BSB verse text and row layout; v1.2.1
Publish Container / docker (push) Successful in 13m38s
- Replace cramped auto-fill grid with full-width row layout (reference | verse text | arrow)
- Fetch BSB passage text from bible.helloao.org, grouped by chapter to minimize API calls
- Display 2-line italic excerpt of each passage beneath the lesson title
- Hover state reveals arrow and highlights row in gold
- Mobile-responsive collapse to single column

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-03 11:04:22 -04:00
nmemmertandClaude Sonnet 4.6 83d631608b Add Studies dropdown with Scripture Index link; split nav triggers into hover+click
Publish Container / docker (push) Successful in 14m4s
- Studies nav item is now a dropdown (same pattern as Episodes): hover to expand,
  click the label to navigate directly to /study
- Dropdown contains: All Studies (/study) and Scripture Index (/scripture)
- Episodes dropdown follows the same split pattern: label navigates, caret toggles
- Dropdown menus open on CSS :hover (desktop) and stay toggle-able on mobile
- v1.2.1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-03 10:34:17 -04:00
nmemmertandClaude Sonnet 4.6 63d4f9e316 v1.2.0: Broadcast emails, webhook admin UI, dynamic sitemap, scripture index
Publish Container / docker (push) Successful in 14m11s
- Admin > Audience > Broadcast Email: compose and send one-off HTML emails
  to all subscribers via Resend batch API; {{name}} personalization; confirm step
- Admin > Configure > Webhooks: CRUD UI for managing POST event webhooks;
  backend GET/POST/DELETE /api/admin-webhooks routes wired to existing state.webhooks
- Sitemap: dynamically appends released study lesson URLs (/study/:slug/:id)
  and episode highlight URLs (/episodes/:id) to /sitemap.xml
- Scripture Index: public /scripture page listing every released lesson grouped
  by study with passage reference links; served by /api/public/scripture-index

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-03 09:54:43 -04:00
nmemmertandClaude Sonnet 4.6 a072076818 Rename Downloads→Resources throughout, fix audit bugs, add /subscribe to footer; v1.1.49
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>
2026-09-03 08:37:23 -04:00
nmemmertandClaude Sonnet 4.6 07b2dc843f Add Ko-fi support section with QR code to About page; v1.1.47
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 11:58:34 -04:00
nmemmertandClaude Sonnet 4.6 d2829e610e Add Ko-fi integration: footer link, floating widget, and admin field; v1.1.46
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 11:57:09 -04:00
nmemmertandClaude Sonnet 4.6 1db0a919c2 Add optional Apple Books button to downloads and book cards; v1.1.42
Publish Container / docker (push) Successful in 15m16s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-27 11:34:55 -04:00
nmemmertandClaude Sonnet 4.6 0512d40fc6 Redesign resources page with PageBanner, featured download, and consistent page headers; v1.1.40
Publish Container / docker (push) Has been cancelled
- Replace hero study guide form with PageBanner + featured download card in library
- Add PageBanner component used consistently across all interior pages (Downloads, Episodes, About, Contact, Q&A, Finished Books)
- Remove duplicate headings/eyebrows that conflicted with banner titles on About, Contact, Q&A, Finished Books pages
- Compact download card sizing (padding, border-radius, image size)
- Add Books & Resources tabbed section with fallback to TruthForLife widget
- Fix server sanitizer to pass through 'resources' placement items without URL
- Add featured-badge and featured card styling for primary guide

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-26 11:03:43 -04:00
nmemmertandClaude Sonnet 4.6 005da43738 Default book button label to 'Learn More' when using url instead of amazonUrl; v1.1.38
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-26 08:47:25 -04:00
nmemmertandClaude Sonnet 4.6 24d7fd7cec Fix book card button to render when url is set but amazonUrl is not; v1.1.38
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-26 08:42:09 -04:00
nmemmertandClaude Sonnet 4.6 eb1d3ddd9c Add Books + editable Recommended Resources sections; improve content block links; v1.1.38
- CustomBlock: add linkUrl/linkLabel fields for a styled button below the body
- Body text auto-linkifies raw URLs into gold anchor tags
- New 'books' placement: Reading List grid on Downloads page (cover, desc, Amazon btn)
- New 'recommended' placement: editable Recommended Resources section on Downloads
  page; falls back to Truth For Life widget when empty
- Admin: Books and Recommended Resources panels added to Content nav

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-26 08:16:36 -04:00
nmemmertandClaude Sonnet 4.6 a35e04320a Remove production checklist and email/calendar/contacts app; v1.1.37
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-20 09:30:19 -04:00
nmemmertandClaude Sonnet 4.6 bf3154378b Track all link clicks (internal + external) in analytics; v1.1.33
Replaces outbound-only tracking with a useLinkClickTracking hook that
captures every <a> click on the site. Stores as link_click events keyed
by destination URL, with an internal flag. Admin analytics page gains a
Link Clicks table sorted by count, showing type (internal/external).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-10 09:11:53 -04:00
nmemmertandClaude Sonnet 4.6 441b907ae1 Fancy 404 page with book icon, action buttons, and broken-link report form; v1.1.32
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-10 08:56:10 -04:00
nmemmertandClaude Sonnet 4.6 f53dcdec4f Add admin control for hero podcast art image; v1.1.28
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-05 11:18:49 -04:00
nmemmertandClaude Sonnet 4.6 ce235ba9ef Add /contacts and /calendar pages; email signature settings; v1.1.12
- /contacts: standalone page with hybrid contact list (submissions + manual entry), inline edit, search, archive
- /calendar: monthly release scheduling calendar reading/writing podcast checklist episode dates
- /email settings: editable signature panel; signature persisted server-side and injected into outgoing emails
- Move contacts out of /admin panel (now links to /contacts route)
- Partial PATCH for contact submissions (name, notes, archived independently)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-28 10:12:52 -04:00
nmemmertandClaude Sonnet 4.6 7670b44d27 Add /email route as standalone web email client; v1.1.11
Extracts the email inbox from /admin and builds it as a full-viewport
email client at /email with the same admin auth. Key improvements over
the old embedded panel:

- Full-height split-pane layout (sidebar list + detail pane)
- Subject line extracted and shown separately for inbound emails
- Inline reply composer inside the detail pane (no more page-jump)
- Compose-new button for outbound messages to arbitrary addresses
- Search/filter across name, email, subject, and body
- Unread dot indicators with localStorage tracking (marks read on open)
- Keyboard navigation: ↑/↓ or j/k to move, r to reply, e to archive, Esc to close
- Source badges (contact-form / inbound-email) on list items
- Sent history and reply templates accessible via footer drawers
- 30-second polling for new messages
- New POST /api/admin-email/compose server endpoint for outbound sends
- Dashboard card "Open Inbox" now links to /email

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-28 09:34:39 -04:00
nmemmertandClaude Sonnet 4.6 ae179fb4e8 Remove Spotify iframe branch from episode detail pages; v1.1.9
Individual episode pages always use EpisodeAudioPlayer — the Spotify
iframe check is removed since all per-episode embeds use direct audio URLs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-22 14:46:03 -04:00
nmemmertandClaude Sonnet 4.6 021fe24c7e Separate /episodes player from per-episode player; v1.1.8
- EpisodeAudioPlayer restored to original horizontal layout (unchanged
  for individual episode detail pages chosen in /admin)
- LatestEpisodePlayer on /episodes page gets its own markup + CSS
  (.latest-episode-player__*) with the centered layout A — large gold
  play button, skip-back 15s / skip-forward 30s, full-width scrubber

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-22 14:42:08 -04:00
nmemmertandClaude Sonnet 4.6 939e7b9da4 Restore Spotify iframe on individual episode detail pages; v1.1.7
The per-episode player (chosen in /admin) reverts to the Spotify embed
iframe — only the /episodes listing page uses the new custom player.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-22 14:37:25 -04:00
nmemmertandClaude Sonnet 4.6 1e24eaa9af Replace Spotify show embed on /episodes with custom player; v1.1.6
LatestEpisodePlayer fetches the most recent episode from /api/episodes
(Anchor RSS) and renders it with the centered cinematic layout. The
Spotify show iframe is removed; platform buttons and HeadlinerWidget
remain below as before.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-22 14:36:41 -04:00
nmemmertandClaude Sonnet 4.6 5d4ba7e593 Replace Spotify iframe with custom centered player (layout A); v1.1.5
- EpisodeAudioPlayer full variant: centered title, large gold play button,
  skip-back 15s / skip-forward 30s flanking controls, full-width scrubber
- Compact variant (study sections) unchanged
- Episode detail page fetches direct Anchor MP3 URL from /api/episodes by
  title match; falls back to resolvedEmbedUrl while loading
- Plays stream from Anchor CDN so stats still count

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-22 14:32:05 -04:00
nmemmertandClaude Sonnet 4.6 b60604aa80 Add testimonials section and Q&A submit CTA; v1.0.8
- Testimonials: new Testimonial type, CMS field, admin UI under About,
  and TestimonialsSection rendered on homepage and About page (hidden when empty)
- Q&A: "Submit a Question →" CTA at bottom of Q&A page linking to /contact

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-22 12:37:46 -04:00
nmemmertandClaude Sonnet 4.6 595a2c3ec4 Reverse podcast highlights order; convert Q&A to full page; v1.0.6
- Podcast highlights now display newest-first (reversed array)
- Q&A page uses full site layout (header, nav, footer) instead of card/modal wrapper
- Remove redundant "Back to Site" link from QASection now that header is present

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-22 11:58:34 -04:00
nmemmertandClaude Sonnet 4.6 25fa24afdf Add Finished Books feature with episode playlists and nav dropdown
Public:
- /finished page with ornament heading, intro text, book grid, and styled empty state
- /finished/:id episode playlist page filtered by RSS season number
- Episodes nav becomes click-toggle dropdown (Current Series / Finished Books)
- Finished Books link in footer
- Dropdown font fixed to match other nav links

Admin:
- End Current Series & Start New Book wizard on Current Series tab
- Finished Books management tab with add/edit/remove and image asset picker

Data:
- FinishedBook type + finishedBooks[] field on SiteContent
- RSS parser extracts itunes:season per episode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 10:34:43 -04:00
nmemmertandClaude Sonnet 4.6 2eb98b66d0 Add Finished Books feature with episode playlists
- New FinishedBook type in content.ts + finishedBooks[] field on SiteContent
- RSS parser now extracts itunes:season into each episode object
- /finished grid page and /finished/:id playlist page (filters episodes by season)
- Episodes nav link replaced with dropdown: Current Series / Finished Books
- Finished Books link added to footer
- Admin: "End Current Series & Start New Book" wizard on Current Series tab
- Admin: Finished Books management tab (add/edit/remove entries)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 10:22:37 -04:00
nmemmertandClaude Sonnet 4.6 a8f6024234 Fix Truth For Life devotional widget not rendering
Replaced broken srcdoc iframe approach with direct script injection so
the TFL syndicate.js runs in page context with access to the DOM it needs.
Also added truthforlife.org and ajax.googleapis.com to CSP script-src,
which was silently blocking the widget and its jQuery dependency.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 09:26:00 -04:00
nmemmert dd43d0c3ea notes upgrade 2026-06-18 13:43:17 -04:00
nmemmert e0ed798741 easter egg 2026-06-18 10:03:32 -04:00
nmemmert 9174331d2d Bug fixes (real breakage):
Newsletter nudge — was calling /api/study-account/profile (wrong endpoint, ignored subscription). Now correctly calls /api/study-account/preferences with PATCH.
Security:

Email regex — replaced the permissive [^\s@]+@[^\s@]+ pattern with a proper RFC-compliant regex in contact.js and downloads.js
Avatar magic bytes — server now checks actual PNG/JPEG/GIF/WEBP header bytes, not just the data URL prefix
Certificate rate limit — public /api/public/certificate/:token now has a 30 req/15min limiter
Session absolute TTL — admin sessions now have a 30-day hard cap; a stolen token can no longer be kept alive indefinitely by passive reads
Account lockout — 5 failed logins locks a study account for 1 hour
CSP headers — Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, and Referrer-Policy headers added globally
Data integrity:

Cascade delete — deleting a study account now also removes their certificates, community posts, comments, and progress file
UX / reliability:

Escape key on modals — all 3 modal groups (study index, notes, account) now close on Escape
Display name min-length — empty spaces-only names rejected; if provided, must be ≥2 chars
Note save rate limit — 30 saves/minute per user max
Analytics fetch timeout — 5s AbortController so a hanging server doesn't block the browser indefinitely
Email validation on signup — frontend catches bad email formats before hitting the server
Cleanup:

Deduplicated download forms — StudyDownloadForm and ResourceDownloadForm now share a single DownloadForm base; both are now thin wrappers
2026-06-18 09:35:44 -04:00
nmemmertandClaude Sonnet 4.6 31426fccba Add comprehensive visitor engagement tracking and scroll-to-top on navigation
Tracks scroll depth (25/50/75/90%), time on page, UTM parameters, outbound
link clicks, search queries, audio pause/completion/listen time, and 404s.
Logged-in study users are now tied to their visitor record and surfaced in
the admin recent visits table. Scroll position resets on every route change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 14:06:21 -04:00
nmemmertandClaude Sonnet 4.6 a6f0c39c35 Simplify episodes page and upgrade podcast highlights to card layout
- 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 <noreply@anthropic.com>
2026-06-17 13:48:49 -04:00
nmemmertandClaude Sonnet 4.6 a1d5889711 Replace Spotify embeds with branded custom audio player backed by RSS
- Add /api/episode-audio route returning MP3 URLs from Anchor RSS feed
- Replace Spotify URL text inputs in admin with RSS episode dropdowns
- New EpisodeAudioPlayer component with podcast art, show name, progress
  bar, and Spotify icon link — full and compact sizes
- Backward-compatible: legacy Spotify embed URLs still render as iframes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 13:23:19 -04:00
nmemmertandClaude Sonnet 4.6 3d8f02d915 Scope external site link styles to homepage section only
The .section-resources CSS overrides were breaking the Downloads page
resource link layout. Added .section-external-sites class to the
ExternalSitesSection and scoped all image/layout overrides to it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 12:04:49 -04:00
nmemmertandClaude Sonnet 4.6 68fa1497a3 Remove helper text from external sites section on homepage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 11:35:13 -04:00
nmemmertandClaude Sonnet 4.6 d42c00d6dd Show image on external site link cards on homepage
Adds the configured imageUrl as a full-width banner at the top of each
External Sites card, above the link name and description.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 11:18:08 -04:00
nmemmertandClaude Sonnet 4.6 47887d7fbd Add admin-editable QR code image to homepage share section
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 10:03:21 -04:00
nmemmertandClaude Sonnet 4.6 1bc573147d Redesign Q&A for mobile and upgrade completion certificate
- Full mobile redesign of Q&A: edge-to-edge cards, full-width layout,
  wrapping action buttons, hidden sidebar, proper touch targets, and
  fixed double-padding from thanks-page/thanks-card wrapper
- Fancy certificate redesign: double gold border frame, corner ornaments,
  ornamental rules with diamond dividers, decorative seal, gold glow,
  and updated issuer to "Verse by Verse with Nate"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 13:40:31 -04:00
nmemmertandClaude Sonnet 4.6 c4645e3475 Add cross-site improvements across three phases
Phase 1 — Quick wins:
- Image lazy-loading on series/resource cards
- Newsletter signup added to Episodes page (before highlights)
- Per-route meta tags via usePageMeta hook (title, og:title, og:description)
- Breadcrumbs on study index, section, and notes pages
- SVG completion checkmark badges on study section list
- Analytics time-range filter (7d / 30d / 90d) in admin panel

Phase 2 — Medium features:
- Related episodes on archived series detail pages
- Resource library two-tier filter (type + tag chips)
- Global search (Fuse.js) moved below sticky header as full-width bar
- Q&A anonymous upvoting with localStorage dedup + admin pin/unpin
- Study enrollment funnel tracking (firstVisitAt, firstCompletionAt) with funnel chart in analytics

Phase 3 — Larger features:
- Study section comments (auto-approve for enrolled users, admin moderation panel)
- Study completion certificate (canvas render, PNG download, shareable public URL)
- Episode script full-text search (mammoth docx extraction, server-side search, admin upload UI)
- Reflection questions renamed from Discussion Questions; quiz answers can be shared to section discussion
- Public certificate route at /certificate/:token with og meta tags
- Comment moderation panel added to admin under Manage > Study Comments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 09:10:29 -04:00
nmemmert 66699270f5 Clean. Here's what's live now:
- **Tag filter bar** appears above the grid whenever any download has tags assigned. Chips for "All" + each unique tag, centered under the heading.
- **Clicking a tag** filters the grid to only matching downloads. Clicking the active tag again (or "All") clears the filter.
- **Empty state** — if a tag has no results it shows a friendly message instead of a blank grid.
- The filter only shows when tags exist — so it's invisible today (your 3 current downloads have no tags) and appears automatically once you start tagging items in the admin.

To use it: go to Admin → Downloads → edit a download item → add tags like `Colossians`, `Worksheet`, `Devotional`. Those tags will show up as filter chips on the public page instantly after publishing.
2026-06-05 09:23:55 -04:00
nmemmert bccd1cfa60 TFL Resources 2026-06-04 09:46:51 -04:00