Skip to content

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) - #1598

Merged
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen
Apr 23, 2026
Merged

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549)#1598
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen

Conversation

@CraigBuckmaster

Copy link
Copy Markdown
Owner

What this does

Adds the surface-level entry point for the HWGTB epic — an Explore hero card and the full-screen landing page it routes to. The landing page surfaces three bundled features (Extra-Biblical Literature, Canon Comparison, Guided Journeys) in a single place, matching the "bundled-feature landing page" precedent used elsewhere in the app.

Closes

Closes#1549

Files added

  • app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC landing page
  • app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests

Files touched

  • app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry in the 'Scholarly Analysis' SECTION + new PREMIUM_SCREENS mapping (HowWeGotTheBibleLanding'How We Got The Bible')
  • app/src/navigation/types.tsHowWeGotTheBibleLanding route (undefined params) + CanonComparison route typed ahead of HWGTB-P3-01 ([HWGTB-P3-01] App: CanonComparisonScreen #1550)
  • app/src/navigation/ExploreStack.tsxStack.Screen registration via lazySuspense()
  • app/assets/explore-images.json + content/meta/explore-images.json — both updated with the new HowWeGotTheBible manifest key using the tool-level inline-images variant specified by the issue (count: null, contentType: null, images[] with url / caption / credit)

Landing screen

  • Header: ChevronLeft back button + title "How We Got The Bible"
  • Hero image via expo-image + useExploreImages() → the new manifest entry. Shows the artwork once uploaded to R2; renders nothing when absent (graceful)
  • Intro copy (2 paragraphs): what the bundle covers, evangelical framing, fair to other traditions, explicit rejection of conspiracy framing — per epic guardrails
  • Three navigation entries with icon + title + description:
    1. Extra-Biblical LiteratureExtraBiblicalIndex (HWGTB-P2-02 → PR feat(app): ExtraBiblicalIndexScreen (#1547) #1596)
    2. Canon Comparison → rendered as "Coming soon" (HWGTB-P3-01 not yet shipped; route typed ahead so flipping to live navigation is a one-line change when [HWGTB-P3-01] App: CanonComparisonScreen #1550 lands — canonComparisonReady = true)
    3. Guided JourneysJourneyBrowse with tab: 'featured'

Note on Guided Journeys navigation

The issue's suggested param shape was { filter: { ids: ['canon-formation', 'text-and-translation'] } }, but JourneyBrowseScreen's current ExploreStackParamList entry only supports { tab?, filterLens? }. Filter-by-journey-id is not yet supported in the browse screen. Per the issue's fallback guidance ("or whatever filter-param shape JourneyBrowseScreen already accepts"), landing on tab: 'featured' is the closest fit — once HWGTB-P3-02 (#1551) and HWGTB-P4-01 (#1552) author the two journeys, they'll surface via FEATURED_IDS.

Explore card

  • Title: "How We Got The Bible"
  • Subtitle: "Canon, manuscripts, translations, and the books Jude quoted"
  • Color: #c89858 — matches the st2 panel accent from feat(app): SecondTemplePanel component (#1546) #1595 for visual continuity across the bundle
  • Screen: HowWeGotTheBibleLanding
  • Premium: true — enforced via PREMIUM_SCREENS map; existing handleNavigate flow fires showUpgrade('feature', 'How We Got The Bible') for free users

Placed in the "Scholarly Analysis" section alongside Debates, Difficult Passages, and Content Library — conceptually closest neighbors.

Deferred: R2 hero artwork

The issue specifies placing artwork at _tools/art_staging/priority/explore_how_we_got_the_bible.png and running python _tools/upload_images_to_r2.py --priority. R2 write access is not available from this session — the manifest entry points at the planned URL (https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png) so uploading the asset to that path in a follow-up is enough to light up the hero image. Without the upload, the landing screen gracefully renders without the hero (the guarded-render path is exercised by the test suite's mocked hook).

How I verified

  • npx tsc --noEmit — clean ✅
  • npm run lint on touched files — 0 new warnings (4 pre-existing master warnings in unrelated files are out of scope) ✅
  • npx jest (full suite) — 470 suites / 3482 tests pass

Tests (8/8 passing)

 ✓ renders the page title
✓ renders the intro copy (evangelical-framed)
✓ renders all three landing entries
✓ Canon Comparison shows "Coming soon" label (HWGTB-P3-01 not yet shipped)
✓ tapping Extra-Biblical Literature navigates to ExtraBiblicalIndex
✓ tapping Guided Journeys navigates to JourneyBrowse with featured tab
✓ Canon Comparison entry has no onPress handler (no navigation fired)
✓ back button fires navigation.goBack

Merge order

Depends on: #1547 (PR #1596ExtraBiblicalIndexScreen) for the primary nav target. Works standalone on master when #1596 hasn't merged — the Extra-Biblical tap will navigate to a non-registered route until #1596 lands, at which point it works automatically.

Follow-up activation tasks:

Rollback

Revert this PR. Landing screen deleted, Explore card entry removed, manifest entries dropped. CanonComparison + HowWeGotTheBibleLanding routes leave the param list. Other routes (ExtraBiblicalIndex, ExtraBiblicalDetail) remain intact (they're owned by #1596 / #1597).


Generated by Claude Code

Adds the surface-level entry point for the HWGTB epic — an Explore
hero card and the full-screen landing page it routes to. The landing
page surfaces three bundled features (Extra-Biblical Literature, Canon
Comparison, Guided Journeys) in a single place, matching the
"bundled-feature landing page" precedent used elsewhere.
Files added
app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC
app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests
Files touched
app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry
in the 'Scholarly Analysis' SECTION; new PREMIUM_SCREENS mapping
('HowWeGotTheBibleLanding' → 'How We Got The Bible')
app/src/navigation/types.ts — HowWeGotTheBibleLanding
route (undefined params) + CanonComparison route typed ahead of
HWGTB-P3-01 (#1550)
app/src/navigation/ExploreStack.tsx — Stack.Screen registration
via lazySuspense()
app/assets/explore-images.json
content/meta/explore-images.json — both updated with the new
'HowWeGotTheBible' manifest key using the tool-level inline-images
variant specified by the issue (count: null, contentType: null,
images[] with url/caption/credit)
Landing screen
- Header row: ChevronLeft back + title 'How We Got The Bible'
- Hero image (expo-image) driven by useExploreImages() → the new
manifest entry — shows the artwork once uploaded to R2, renders
nothing when absent
- Intro copy (2 paragraphs): what the bundle covers, evangelical
framing, fair to other traditions, explicit rejection of
conspiracy framing per the epic guardrails
- Three nav entries with icon + title + description:
1. Extra-Biblical Literature → ExtraBiblicalIndex (HWGTB-P2-02)
2. Canon Comparison → rendered 'Coming soon' (HWGTB-P3-01 not
yet shipped; route typed ahead so flipping to live navigation
is a one-line change when #1550 lands)
3. Guided Journeys → JourneyBrowse with tab: 'featured'
(journey-id filter support is out of scope; canon-formation
and text-and-translation journeys will surface via
FEATURED_IDS once HWGTB-P3-02 / #1551 and HWGTB-P4-01 / #1552
land)
Explore card
- Title: 'How We Got The Bible'
- Subtitle: 'Canon, manuscripts, translations, and the books
Jude quoted'
- color: '#c89858' — matches the st2 panel accent for visual
continuity across the bundle
- screen: 'HowWeGotTheBibleLanding'
- premium: true — enforced via PREMIUM_SCREENS map; existing
handleNavigate flow fires showUpgrade('feature', 'How We Got
The Bible') for free users
Deferred — R2 hero artwork
The issue specifies placing the artwork at
_tools/art_staging/priority/explore_how_we_got_the_bible.png and
running python _tools/upload_images_to_r2.py --priority. R2 write
access is not available from this session — the manifest entry
points at the planned URL (
https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png
) so uploading the asset to that path in a follow-up is enough to
light up the hero image. Without the upload the landing screen
gracefully renders without the hero (the guarded-render path is
exercised by the loading-flag branch in the hero lookup).
How verified
npx tsc --noEmit — clean
npm run lint (src/) — 0 new warnings on touched files
npx jest (full suite) — 470 suites / 3482 tests pass
8 new tests cover: page title render, intro copy render, 3 landing
entries render, 'Coming soon' pill on Canon Comparison entry, tap →
ExtraBiblicalIndex, tap → JourneyBrowse with featured tab, 'Canon
Comparison' entry has no onPress (so tap is a no-op, not a nav),
back button fires goBack.
Merge order
Depends on #1547 (ExtraBiblicalIndexScreen — PR #1596) for the
primary nav target; the other two entries are safe to merge any
time. Works standalone on master when #1547 hasn't merged: the
Extra-Biblical tap will navigate to a non-registered route until
#1596 lands, at which point it works automatically.
Closes#1549
@github-actions

Copy link
Copy Markdown

Content Pipeline Results

✅ All pipeline checks passed

StepStatusDetails
Schema Validation136482 passed, 77 failed
Build DB
DB Integrity93 passed, 0 failed

Content Pipeline — Quality & Accuracy Report

All content checks passed

Scope: 0 chapter(s) across 0 book(s)


Generated by ci_content_check.py

@github-actions

Copy link
Copy Markdown

Test Results

✅ All tests passed

PassedFailedTotal
Tests✅ 3482❌ 03482
Suites✅ 470❌ 0470

Coverage

StatementsBranchesFunctionsLines

⏱️ Duration: 84.6s

@CraigBuckmaster
CraigBuckmaster merged commit 7e56f96 into masterApr 23, 2026
7 checks passed
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
@CraigBuckmaster
CraigBuckmaster deleted the feature/hwgtb-p2-04-landing-screen branch April 23, 2026 20:35
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster added a commit that referenced this pull request Apr 23, 2026
* feat(app): CanonComparisonScreen (#1550)
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
* fix(types): add BookIntro to ExploreStackParamList
The CanonComparison screen registered BookIntroScreen on ExploreStack
but the param list didn't declare it, causing TS2322 on navigate calls
from CanonComparisonScreen.
Adds the route to ExploreStackParamList alongside the existing
CanonComparison entry. BookIntro also exists on RootStack; same route
on two stacks is fine for React Navigation.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude (for Craig) <claude@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HWGTB-P2-04] App: Explore hero card for "How We Got The Bible"

2 participants

@CraigBuckmaster@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) by CraigBuckmaster · Pull Request #1598 · CraigBuckmaster/ScriptureDeepDive · GitHub
Skip to content

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) - #1598

Merged
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen
Apr 23, 2026
Merged

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549)#1598
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen

Conversation

@CraigBuckmaster

Copy link
Copy Markdown
Owner

What this does

Adds the surface-level entry point for the HWGTB epic — an Explore hero card and the full-screen landing page it routes to. The landing page surfaces three bundled features (Extra-Biblical Literature, Canon Comparison, Guided Journeys) in a single place, matching the "bundled-feature landing page" precedent used elsewhere in the app.

Closes

Closes#1549

Files added

  • app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC landing page
  • app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests

Files touched

  • app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry in the 'Scholarly Analysis' SECTION + new PREMIUM_SCREENS mapping (HowWeGotTheBibleLanding'How We Got The Bible')
  • app/src/navigation/types.tsHowWeGotTheBibleLanding route (undefined params) + CanonComparison route typed ahead of HWGTB-P3-01 ([HWGTB-P3-01] App: CanonComparisonScreen #1550)
  • app/src/navigation/ExploreStack.tsxStack.Screen registration via lazySuspense()
  • app/assets/explore-images.json + content/meta/explore-images.json — both updated with the new HowWeGotTheBible manifest key using the tool-level inline-images variant specified by the issue (count: null, contentType: null, images[] with url / caption / credit)

Landing screen

  • Header: ChevronLeft back button + title "How We Got The Bible"
  • Hero image via expo-image + useExploreImages() → the new manifest entry. Shows the artwork once uploaded to R2; renders nothing when absent (graceful)
  • Intro copy (2 paragraphs): what the bundle covers, evangelical framing, fair to other traditions, explicit rejection of conspiracy framing — per epic guardrails
  • Three navigation entries with icon + title + description:
    1. Extra-Biblical LiteratureExtraBiblicalIndex (HWGTB-P2-02 → PR feat(app): ExtraBiblicalIndexScreen (#1547) #1596)
    2. Canon Comparison → rendered as "Coming soon" (HWGTB-P3-01 not yet shipped; route typed ahead so flipping to live navigation is a one-line change when [HWGTB-P3-01] App: CanonComparisonScreen #1550 lands — canonComparisonReady = true)
    3. Guided JourneysJourneyBrowse with tab: 'featured'

Note on Guided Journeys navigation

The issue's suggested param shape was { filter: { ids: ['canon-formation', 'text-and-translation'] } }, but JourneyBrowseScreen's current ExploreStackParamList entry only supports { tab?, filterLens? }. Filter-by-journey-id is not yet supported in the browse screen. Per the issue's fallback guidance ("or whatever filter-param shape JourneyBrowseScreen already accepts"), landing on tab: 'featured' is the closest fit — once HWGTB-P3-02 (#1551) and HWGTB-P4-01 (#1552) author the two journeys, they'll surface via FEATURED_IDS.

Explore card

  • Title: "How We Got The Bible"
  • Subtitle: "Canon, manuscripts, translations, and the books Jude quoted"
  • Color: #c89858 — matches the st2 panel accent from feat(app): SecondTemplePanel component (#1546) #1595 for visual continuity across the bundle
  • Screen: HowWeGotTheBibleLanding
  • Premium: true — enforced via PREMIUM_SCREENS map; existing handleNavigate flow fires showUpgrade('feature', 'How We Got The Bible') for free users

Placed in the "Scholarly Analysis" section alongside Debates, Difficult Passages, and Content Library — conceptually closest neighbors.

Deferred: R2 hero artwork

The issue specifies placing artwork at _tools/art_staging/priority/explore_how_we_got_the_bible.png and running python _tools/upload_images_to_r2.py --priority. R2 write access is not available from this session — the manifest entry points at the planned URL (https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png) so uploading the asset to that path in a follow-up is enough to light up the hero image. Without the upload, the landing screen gracefully renders without the hero (the guarded-render path is exercised by the test suite's mocked hook).

How I verified

  • npx tsc --noEmit — clean ✅
  • npm run lint on touched files — 0 new warnings (4 pre-existing master warnings in unrelated files are out of scope) ✅
  • npx jest (full suite) — 470 suites / 3482 tests pass

Tests (8/8 passing)

 ✓ renders the page title
✓ renders the intro copy (evangelical-framed)
✓ renders all three landing entries
✓ Canon Comparison shows "Coming soon" label (HWGTB-P3-01 not yet shipped)
✓ tapping Extra-Biblical Literature navigates to ExtraBiblicalIndex
✓ tapping Guided Journeys navigates to JourneyBrowse with featured tab
✓ Canon Comparison entry has no onPress handler (no navigation fired)
✓ back button fires navigation.goBack

Merge order

Depends on: #1547 (PR #1596ExtraBiblicalIndexScreen) for the primary nav target. Works standalone on master when #1596 hasn't merged — the Extra-Biblical tap will navigate to a non-registered route until #1596 lands, at which point it works automatically.

Follow-up activation tasks:

Rollback

Revert this PR. Landing screen deleted, Explore card entry removed, manifest entries dropped. CanonComparison + HowWeGotTheBibleLanding routes leave the param list. Other routes (ExtraBiblicalIndex, ExtraBiblicalDetail) remain intact (they're owned by #1596 / #1597).


Generated by Claude Code

Adds the surface-level entry point for the HWGTB epic — an Explore
hero card and the full-screen landing page it routes to. The landing
page surfaces three bundled features (Extra-Biblical Literature, Canon
Comparison, Guided Journeys) in a single place, matching the
"bundled-feature landing page" precedent used elsewhere.
Files added
app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC
app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests
Files touched
app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry
in the 'Scholarly Analysis' SECTION; new PREMIUM_SCREENS mapping
('HowWeGotTheBibleLanding' → 'How We Got The Bible')
app/src/navigation/types.ts — HowWeGotTheBibleLanding
route (undefined params) + CanonComparison route typed ahead of
HWGTB-P3-01 (#1550)
app/src/navigation/ExploreStack.tsx — Stack.Screen registration
via lazySuspense()
app/assets/explore-images.json
content/meta/explore-images.json — both updated with the new
'HowWeGotTheBible' manifest key using the tool-level inline-images
variant specified by the issue (count: null, contentType: null,
images[] with url/caption/credit)
Landing screen
- Header row: ChevronLeft back + title 'How We Got The Bible'
- Hero image (expo-image) driven by useExploreImages() → the new
manifest entry — shows the artwork once uploaded to R2, renders
nothing when absent
- Intro copy (2 paragraphs): what the bundle covers, evangelical
framing, fair to other traditions, explicit rejection of
conspiracy framing per the epic guardrails
- Three nav entries with icon + title + description:
1. Extra-Biblical Literature → ExtraBiblicalIndex (HWGTB-P2-02)
2. Canon Comparison → rendered 'Coming soon' (HWGTB-P3-01 not
yet shipped; route typed ahead so flipping to live navigation
is a one-line change when #1550 lands)
3. Guided Journeys → JourneyBrowse with tab: 'featured'
(journey-id filter support is out of scope; canon-formation
and text-and-translation journeys will surface via
FEATURED_IDS once HWGTB-P3-02 / #1551 and HWGTB-P4-01 / #1552
land)
Explore card
- Title: 'How We Got The Bible'
- Subtitle: 'Canon, manuscripts, translations, and the books
Jude quoted'
- color: '#c89858' — matches the st2 panel accent for visual
continuity across the bundle
- screen: 'HowWeGotTheBibleLanding'
- premium: true — enforced via PREMIUM_SCREENS map; existing
handleNavigate flow fires showUpgrade('feature', 'How We Got
The Bible') for free users
Deferred — R2 hero artwork
The issue specifies placing the artwork at
_tools/art_staging/priority/explore_how_we_got_the_bible.png and
running python _tools/upload_images_to_r2.py --priority. R2 write
access is not available from this session — the manifest entry
points at the planned URL (
https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png
) so uploading the asset to that path in a follow-up is enough to
light up the hero image. Without the upload the landing screen
gracefully renders without the hero (the guarded-render path is
exercised by the loading-flag branch in the hero lookup).
How verified
npx tsc --noEmit — clean
npm run lint (src/) — 0 new warnings on touched files
npx jest (full suite) — 470 suites / 3482 tests pass
8 new tests cover: page title render, intro copy render, 3 landing
entries render, 'Coming soon' pill on Canon Comparison entry, tap →
ExtraBiblicalIndex, tap → JourneyBrowse with featured tab, 'Canon
Comparison' entry has no onPress (so tap is a no-op, not a nav),
back button fires goBack.
Merge order
Depends on #1547 (ExtraBiblicalIndexScreen — PR #1596) for the
primary nav target; the other two entries are safe to merge any
time. Works standalone on master when #1547 hasn't merged: the
Extra-Biblical tap will navigate to a non-registered route until
#1596 lands, at which point it works automatically.
Closes#1549
@github-actions

Copy link
Copy Markdown

Content Pipeline Results

✅ All pipeline checks passed

StepStatusDetails
Schema Validation136482 passed, 77 failed
Build DB
DB Integrity93 passed, 0 failed

Content Pipeline — Quality & Accuracy Report

All content checks passed

Scope: 0 chapter(s) across 0 book(s)


Generated by ci_content_check.py

@github-actions

Copy link
Copy Markdown

Test Results

✅ All tests passed

PassedFailedTotal
Tests✅ 3482❌ 03482
Suites✅ 470❌ 0470

Coverage

StatementsBranchesFunctionsLines

⏱️ Duration: 84.6s

@CraigBuckmaster
CraigBuckmaster merged commit 7e56f96 into masterApr 23, 2026
7 checks passed
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
@CraigBuckmaster
CraigBuckmaster deleted the feature/hwgtb-p2-04-landing-screen branch April 23, 2026 20:35
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster added a commit that referenced this pull request Apr 23, 2026
* feat(app): CanonComparisonScreen (#1550)
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
* fix(types): add BookIntro to ExploreStackParamList
The CanonComparison screen registered BookIntroScreen on ExploreStack
but the param list didn't declare it, causing TS2322 on navigate calls
from CanonComparisonScreen.
Adds the route to ExploreStackParamList alongside the existing
CanonComparison entry. BookIntro also exists on RootStack; same route
on two stacks is fine for React Navigation.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude (for Craig) <claude@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HWGTB-P2-04] App: Explore hero card for "How We Got The Bible"

2 participants

@CraigBuckmaster@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) by CraigBuckmaster · Pull Request #1598 · CraigBuckmaster/ScriptureDeepDive · GitHub
Skip to content

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) - #1598

Merged
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen
Apr 23, 2026
Merged

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549)#1598
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen

Conversation

@CraigBuckmaster

Copy link
Copy Markdown
Owner

What this does

Adds the surface-level entry point for the HWGTB epic — an Explore hero card and the full-screen landing page it routes to. The landing page surfaces three bundled features (Extra-Biblical Literature, Canon Comparison, Guided Journeys) in a single place, matching the "bundled-feature landing page" precedent used elsewhere in the app.

Closes

Closes#1549

Files added

  • app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC landing page
  • app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests

Files touched

  • app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry in the 'Scholarly Analysis' SECTION + new PREMIUM_SCREENS mapping (HowWeGotTheBibleLanding'How We Got The Bible')
  • app/src/navigation/types.tsHowWeGotTheBibleLanding route (undefined params) + CanonComparison route typed ahead of HWGTB-P3-01 ([HWGTB-P3-01] App: CanonComparisonScreen #1550)
  • app/src/navigation/ExploreStack.tsxStack.Screen registration via lazySuspense()
  • app/assets/explore-images.json + content/meta/explore-images.json — both updated with the new HowWeGotTheBible manifest key using the tool-level inline-images variant specified by the issue (count: null, contentType: null, images[] with url / caption / credit)

Landing screen

  • Header: ChevronLeft back button + title "How We Got The Bible"
  • Hero image via expo-image + useExploreImages() → the new manifest entry. Shows the artwork once uploaded to R2; renders nothing when absent (graceful)
  • Intro copy (2 paragraphs): what the bundle covers, evangelical framing, fair to other traditions, explicit rejection of conspiracy framing — per epic guardrails
  • Three navigation entries with icon + title + description:
    1. Extra-Biblical LiteratureExtraBiblicalIndex (HWGTB-P2-02 → PR feat(app): ExtraBiblicalIndexScreen (#1547) #1596)
    2. Canon Comparison → rendered as "Coming soon" (HWGTB-P3-01 not yet shipped; route typed ahead so flipping to live navigation is a one-line change when [HWGTB-P3-01] App: CanonComparisonScreen #1550 lands — canonComparisonReady = true)
    3. Guided JourneysJourneyBrowse with tab: 'featured'

Note on Guided Journeys navigation

The issue's suggested param shape was { filter: { ids: ['canon-formation', 'text-and-translation'] } }, but JourneyBrowseScreen's current ExploreStackParamList entry only supports { tab?, filterLens? }. Filter-by-journey-id is not yet supported in the browse screen. Per the issue's fallback guidance ("or whatever filter-param shape JourneyBrowseScreen already accepts"), landing on tab: 'featured' is the closest fit — once HWGTB-P3-02 (#1551) and HWGTB-P4-01 (#1552) author the two journeys, they'll surface via FEATURED_IDS.

Explore card

  • Title: "How We Got The Bible"
  • Subtitle: "Canon, manuscripts, translations, and the books Jude quoted"
  • Color: #c89858 — matches the st2 panel accent from feat(app): SecondTemplePanel component (#1546) #1595 for visual continuity across the bundle
  • Screen: HowWeGotTheBibleLanding
  • Premium: true — enforced via PREMIUM_SCREENS map; existing handleNavigate flow fires showUpgrade('feature', 'How We Got The Bible') for free users

Placed in the "Scholarly Analysis" section alongside Debates, Difficult Passages, and Content Library — conceptually closest neighbors.

Deferred: R2 hero artwork

The issue specifies placing artwork at _tools/art_staging/priority/explore_how_we_got_the_bible.png and running python _tools/upload_images_to_r2.py --priority. R2 write access is not available from this session — the manifest entry points at the planned URL (https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png) so uploading the asset to that path in a follow-up is enough to light up the hero image. Without the upload, the landing screen gracefully renders without the hero (the guarded-render path is exercised by the test suite's mocked hook).

How I verified

  • npx tsc --noEmit — clean ✅
  • npm run lint on touched files — 0 new warnings (4 pre-existing master warnings in unrelated files are out of scope) ✅
  • npx jest (full suite) — 470 suites / 3482 tests pass

Tests (8/8 passing)

 ✓ renders the page title
✓ renders the intro copy (evangelical-framed)
✓ renders all three landing entries
✓ Canon Comparison shows "Coming soon" label (HWGTB-P3-01 not yet shipped)
✓ tapping Extra-Biblical Literature navigates to ExtraBiblicalIndex
✓ tapping Guided Journeys navigates to JourneyBrowse with featured tab
✓ Canon Comparison entry has no onPress handler (no navigation fired)
✓ back button fires navigation.goBack

Merge order

Depends on: #1547 (PR #1596ExtraBiblicalIndexScreen) for the primary nav target. Works standalone on master when #1596 hasn't merged — the Extra-Biblical tap will navigate to a non-registered route until #1596 lands, at which point it works automatically.

Follow-up activation tasks:

Rollback

Revert this PR. Landing screen deleted, Explore card entry removed, manifest entries dropped. CanonComparison + HowWeGotTheBibleLanding routes leave the param list. Other routes (ExtraBiblicalIndex, ExtraBiblicalDetail) remain intact (they're owned by #1596 / #1597).


Generated by Claude Code

Adds the surface-level entry point for the HWGTB epic — an Explore
hero card and the full-screen landing page it routes to. The landing
page surfaces three bundled features (Extra-Biblical Literature, Canon
Comparison, Guided Journeys) in a single place, matching the
"bundled-feature landing page" precedent used elsewhere.
Files added
app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC
app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests
Files touched
app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry
in the 'Scholarly Analysis' SECTION; new PREMIUM_SCREENS mapping
('HowWeGotTheBibleLanding' → 'How We Got The Bible')
app/src/navigation/types.ts — HowWeGotTheBibleLanding
route (undefined params) + CanonComparison route typed ahead of
HWGTB-P3-01 (#1550)
app/src/navigation/ExploreStack.tsx — Stack.Screen registration
via lazySuspense()
app/assets/explore-images.json
content/meta/explore-images.json — both updated with the new
'HowWeGotTheBible' manifest key using the tool-level inline-images
variant specified by the issue (count: null, contentType: null,
images[] with url/caption/credit)
Landing screen
- Header row: ChevronLeft back + title 'How We Got The Bible'
- Hero image (expo-image) driven by useExploreImages() → the new
manifest entry — shows the artwork once uploaded to R2, renders
nothing when absent
- Intro copy (2 paragraphs): what the bundle covers, evangelical
framing, fair to other traditions, explicit rejection of
conspiracy framing per the epic guardrails
- Three nav entries with icon + title + description:
1. Extra-Biblical Literature → ExtraBiblicalIndex (HWGTB-P2-02)
2. Canon Comparison → rendered 'Coming soon' (HWGTB-P3-01 not
yet shipped; route typed ahead so flipping to live navigation
is a one-line change when #1550 lands)
3. Guided Journeys → JourneyBrowse with tab: 'featured'
(journey-id filter support is out of scope; canon-formation
and text-and-translation journeys will surface via
FEATURED_IDS once HWGTB-P3-02 / #1551 and HWGTB-P4-01 / #1552
land)
Explore card
- Title: 'How We Got The Bible'
- Subtitle: 'Canon, manuscripts, translations, and the books
Jude quoted'
- color: '#c89858' — matches the st2 panel accent for visual
continuity across the bundle
- screen: 'HowWeGotTheBibleLanding'
- premium: true — enforced via PREMIUM_SCREENS map; existing
handleNavigate flow fires showUpgrade('feature', 'How We Got
The Bible') for free users
Deferred — R2 hero artwork
The issue specifies placing the artwork at
_tools/art_staging/priority/explore_how_we_got_the_bible.png and
running python _tools/upload_images_to_r2.py --priority. R2 write
access is not available from this session — the manifest entry
points at the planned URL (
https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png
) so uploading the asset to that path in a follow-up is enough to
light up the hero image. Without the upload the landing screen
gracefully renders without the hero (the guarded-render path is
exercised by the loading-flag branch in the hero lookup).
How verified
npx tsc --noEmit — clean
npm run lint (src/) — 0 new warnings on touched files
npx jest (full suite) — 470 suites / 3482 tests pass
8 new tests cover: page title render, intro copy render, 3 landing
entries render, 'Coming soon' pill on Canon Comparison entry, tap →
ExtraBiblicalIndex, tap → JourneyBrowse with featured tab, 'Canon
Comparison' entry has no onPress (so tap is a no-op, not a nav),
back button fires goBack.
Merge order
Depends on #1547 (ExtraBiblicalIndexScreen — PR #1596) for the
primary nav target; the other two entries are safe to merge any
time. Works standalone on master when #1547 hasn't merged: the
Extra-Biblical tap will navigate to a non-registered route until
#1596 lands, at which point it works automatically.
Closes#1549
@github-actions

Copy link
Copy Markdown

Content Pipeline Results

✅ All pipeline checks passed

StepStatusDetails
Schema Validation136482 passed, 77 failed
Build DB
DB Integrity93 passed, 0 failed

Content Pipeline — Quality & Accuracy Report

All content checks passed

Scope: 0 chapter(s) across 0 book(s)


Generated by ci_content_check.py

@github-actions

Copy link
Copy Markdown

Test Results

✅ All tests passed

PassedFailedTotal
Tests✅ 3482❌ 03482
Suites✅ 470❌ 0470

Coverage

StatementsBranchesFunctionsLines

⏱️ Duration: 84.6s

@CraigBuckmaster
CraigBuckmaster merged commit 7e56f96 into masterApr 23, 2026
7 checks passed
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
@CraigBuckmaster
CraigBuckmaster deleted the feature/hwgtb-p2-04-landing-screen branch April 23, 2026 20:35
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster added a commit that referenced this pull request Apr 23, 2026
* feat(app): CanonComparisonScreen (#1550)
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
* fix(types): add BookIntro to ExploreStackParamList
The CanonComparison screen registered BookIntroScreen on ExploreStack
but the param list didn't declare it, causing TS2322 on navigate calls
from CanonComparisonScreen.
Adds the route to ExploreStackParamList alongside the existing
CanonComparison entry. BookIntro also exists on RootStack; same route
on two stacks is fine for React Navigation.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude (for Craig) <claude@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HWGTB-P2-04] App: Explore hero card for "How We Got The Bible"

2 participants

@CraigBuckmaster@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) by CraigBuckmaster · Pull Request #1598 · CraigBuckmaster/ScriptureDeepDive · GitHub
Skip to content

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) - #1598

Merged
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen
Apr 23, 2026
Merged

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549)#1598
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen

Conversation

@CraigBuckmaster

Copy link
Copy Markdown
Owner

What this does

Adds the surface-level entry point for the HWGTB epic — an Explore hero card and the full-screen landing page it routes to. The landing page surfaces three bundled features (Extra-Biblical Literature, Canon Comparison, Guided Journeys) in a single place, matching the "bundled-feature landing page" precedent used elsewhere in the app.

Closes

Closes#1549

Files added

  • app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC landing page
  • app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests

Files touched

  • app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry in the 'Scholarly Analysis' SECTION + new PREMIUM_SCREENS mapping (HowWeGotTheBibleLanding'How We Got The Bible')
  • app/src/navigation/types.tsHowWeGotTheBibleLanding route (undefined params) + CanonComparison route typed ahead of HWGTB-P3-01 ([HWGTB-P3-01] App: CanonComparisonScreen #1550)
  • app/src/navigation/ExploreStack.tsxStack.Screen registration via lazySuspense()
  • app/assets/explore-images.json + content/meta/explore-images.json — both updated with the new HowWeGotTheBible manifest key using the tool-level inline-images variant specified by the issue (count: null, contentType: null, images[] with url / caption / credit)

Landing screen

  • Header: ChevronLeft back button + title "How We Got The Bible"
  • Hero image via expo-image + useExploreImages() → the new manifest entry. Shows the artwork once uploaded to R2; renders nothing when absent (graceful)
  • Intro copy (2 paragraphs): what the bundle covers, evangelical framing, fair to other traditions, explicit rejection of conspiracy framing — per epic guardrails
  • Three navigation entries with icon + title + description:
    1. Extra-Biblical LiteratureExtraBiblicalIndex (HWGTB-P2-02 → PR feat(app): ExtraBiblicalIndexScreen (#1547) #1596)
    2. Canon Comparison → rendered as "Coming soon" (HWGTB-P3-01 not yet shipped; route typed ahead so flipping to live navigation is a one-line change when [HWGTB-P3-01] App: CanonComparisonScreen #1550 lands — canonComparisonReady = true)
    3. Guided JourneysJourneyBrowse with tab: 'featured'

Note on Guided Journeys navigation

The issue's suggested param shape was { filter: { ids: ['canon-formation', 'text-and-translation'] } }, but JourneyBrowseScreen's current ExploreStackParamList entry only supports { tab?, filterLens? }. Filter-by-journey-id is not yet supported in the browse screen. Per the issue's fallback guidance ("or whatever filter-param shape JourneyBrowseScreen already accepts"), landing on tab: 'featured' is the closest fit — once HWGTB-P3-02 (#1551) and HWGTB-P4-01 (#1552) author the two journeys, they'll surface via FEATURED_IDS.

Explore card

  • Title: "How We Got The Bible"
  • Subtitle: "Canon, manuscripts, translations, and the books Jude quoted"
  • Color: #c89858 — matches the st2 panel accent from feat(app): SecondTemplePanel component (#1546) #1595 for visual continuity across the bundle
  • Screen: HowWeGotTheBibleLanding
  • Premium: true — enforced via PREMIUM_SCREENS map; existing handleNavigate flow fires showUpgrade('feature', 'How We Got The Bible') for free users

Placed in the "Scholarly Analysis" section alongside Debates, Difficult Passages, and Content Library — conceptually closest neighbors.

Deferred: R2 hero artwork

The issue specifies placing artwork at _tools/art_staging/priority/explore_how_we_got_the_bible.png and running python _tools/upload_images_to_r2.py --priority. R2 write access is not available from this session — the manifest entry points at the planned URL (https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png) so uploading the asset to that path in a follow-up is enough to light up the hero image. Without the upload, the landing screen gracefully renders without the hero (the guarded-render path is exercised by the test suite's mocked hook).

How I verified

  • npx tsc --noEmit — clean ✅
  • npm run lint on touched files — 0 new warnings (4 pre-existing master warnings in unrelated files are out of scope) ✅
  • npx jest (full suite) — 470 suites / 3482 tests pass

Tests (8/8 passing)

 ✓ renders the page title
✓ renders the intro copy (evangelical-framed)
✓ renders all three landing entries
✓ Canon Comparison shows "Coming soon" label (HWGTB-P3-01 not yet shipped)
✓ tapping Extra-Biblical Literature navigates to ExtraBiblicalIndex
✓ tapping Guided Journeys navigates to JourneyBrowse with featured tab
✓ Canon Comparison entry has no onPress handler (no navigation fired)
✓ back button fires navigation.goBack

Merge order

Depends on: #1547 (PR #1596ExtraBiblicalIndexScreen) for the primary nav target. Works standalone on master when #1596 hasn't merged — the Extra-Biblical tap will navigate to a non-registered route until #1596 lands, at which point it works automatically.

Follow-up activation tasks:

Rollback

Revert this PR. Landing screen deleted, Explore card entry removed, manifest entries dropped. CanonComparison + HowWeGotTheBibleLanding routes leave the param list. Other routes (ExtraBiblicalIndex, ExtraBiblicalDetail) remain intact (they're owned by #1596 / #1597).


Generated by Claude Code

Adds the surface-level entry point for the HWGTB epic — an Explore
hero card and the full-screen landing page it routes to. The landing
page surfaces three bundled features (Extra-Biblical Literature, Canon
Comparison, Guided Journeys) in a single place, matching the
"bundled-feature landing page" precedent used elsewhere.
Files added
app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC
app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests
Files touched
app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry
in the 'Scholarly Analysis' SECTION; new PREMIUM_SCREENS mapping
('HowWeGotTheBibleLanding' → 'How We Got The Bible')
app/src/navigation/types.ts — HowWeGotTheBibleLanding
route (undefined params) + CanonComparison route typed ahead of
HWGTB-P3-01 (#1550)
app/src/navigation/ExploreStack.tsx — Stack.Screen registration
via lazySuspense()
app/assets/explore-images.json
content/meta/explore-images.json — both updated with the new
'HowWeGotTheBible' manifest key using the tool-level inline-images
variant specified by the issue (count: null, contentType: null,
images[] with url/caption/credit)
Landing screen
- Header row: ChevronLeft back + title 'How We Got The Bible'
- Hero image (expo-image) driven by useExploreImages() → the new
manifest entry — shows the artwork once uploaded to R2, renders
nothing when absent
- Intro copy (2 paragraphs): what the bundle covers, evangelical
framing, fair to other traditions, explicit rejection of
conspiracy framing per the epic guardrails
- Three nav entries with icon + title + description:
1. Extra-Biblical Literature → ExtraBiblicalIndex (HWGTB-P2-02)
2. Canon Comparison → rendered 'Coming soon' (HWGTB-P3-01 not
yet shipped; route typed ahead so flipping to live navigation
is a one-line change when #1550 lands)
3. Guided Journeys → JourneyBrowse with tab: 'featured'
(journey-id filter support is out of scope; canon-formation
and text-and-translation journeys will surface via
FEATURED_IDS once HWGTB-P3-02 / #1551 and HWGTB-P4-01 / #1552
land)
Explore card
- Title: 'How We Got The Bible'
- Subtitle: 'Canon, manuscripts, translations, and the books
Jude quoted'
- color: '#c89858' — matches the st2 panel accent for visual
continuity across the bundle
- screen: 'HowWeGotTheBibleLanding'
- premium: true — enforced via PREMIUM_SCREENS map; existing
handleNavigate flow fires showUpgrade('feature', 'How We Got
The Bible') for free users
Deferred — R2 hero artwork
The issue specifies placing the artwork at
_tools/art_staging/priority/explore_how_we_got_the_bible.png and
running python _tools/upload_images_to_r2.py --priority. R2 write
access is not available from this session — the manifest entry
points at the planned URL (
https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png
) so uploading the asset to that path in a follow-up is enough to
light up the hero image. Without the upload the landing screen
gracefully renders without the hero (the guarded-render path is
exercised by the loading-flag branch in the hero lookup).
How verified
npx tsc --noEmit — clean
npm run lint (src/) — 0 new warnings on touched files
npx jest (full suite) — 470 suites / 3482 tests pass
8 new tests cover: page title render, intro copy render, 3 landing
entries render, 'Coming soon' pill on Canon Comparison entry, tap →
ExtraBiblicalIndex, tap → JourneyBrowse with featured tab, 'Canon
Comparison' entry has no onPress (so tap is a no-op, not a nav),
back button fires goBack.
Merge order
Depends on #1547 (ExtraBiblicalIndexScreen — PR #1596) for the
primary nav target; the other two entries are safe to merge any
time. Works standalone on master when #1547 hasn't merged: the
Extra-Biblical tap will navigate to a non-registered route until
#1596 lands, at which point it works automatically.
Closes#1549
@github-actions

Copy link
Copy Markdown

Content Pipeline Results

✅ All pipeline checks passed

StepStatusDetails
Schema Validation136482 passed, 77 failed
Build DB
DB Integrity93 passed, 0 failed

Content Pipeline — Quality & Accuracy Report

All content checks passed

Scope: 0 chapter(s) across 0 book(s)


Generated by ci_content_check.py

@github-actions

Copy link
Copy Markdown

Test Results

✅ All tests passed

PassedFailedTotal
Tests✅ 3482❌ 03482
Suites✅ 470❌ 0470

Coverage

StatementsBranchesFunctionsLines

⏱️ Duration: 84.6s

@CraigBuckmaster
CraigBuckmaster merged commit 7e56f96 into masterApr 23, 2026
7 checks passed
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
@CraigBuckmaster
CraigBuckmaster deleted the feature/hwgtb-p2-04-landing-screen branch April 23, 2026 20:35
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster added a commit that referenced this pull request Apr 23, 2026
* feat(app): CanonComparisonScreen (#1550)
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
* fix(types): add BookIntro to ExploreStackParamList
The CanonComparison screen registered BookIntroScreen on ExploreStack
but the param list didn't declare it, causing TS2322 on navigate calls
from CanonComparisonScreen.
Adds the route to ExploreStackParamList alongside the existing
CanonComparison entry. BookIntro also exists on RootStack; same route
on two stacks is fine for React Navigation.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude (for Craig) <claude@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HWGTB-P2-04] App: Explore hero card for "How We Got The Bible"

2 participants

@CraigBuckmaster@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) by CraigBuckmaster · Pull Request #1598 · CraigBuckmaster/ScriptureDeepDive · GitHub
Skip to content

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) - #1598

Merged
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen
Apr 23, 2026
Merged

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549)#1598
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen

Conversation

@CraigBuckmaster

Copy link
Copy Markdown
Owner

What this does

Adds the surface-level entry point for the HWGTB epic — an Explore hero card and the full-screen landing page it routes to. The landing page surfaces three bundled features (Extra-Biblical Literature, Canon Comparison, Guided Journeys) in a single place, matching the "bundled-feature landing page" precedent used elsewhere in the app.

Closes

Closes#1549

Files added

  • app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC landing page
  • app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests

Files touched

  • app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry in the 'Scholarly Analysis' SECTION + new PREMIUM_SCREENS mapping (HowWeGotTheBibleLanding'How We Got The Bible')
  • app/src/navigation/types.tsHowWeGotTheBibleLanding route (undefined params) + CanonComparison route typed ahead of HWGTB-P3-01 ([HWGTB-P3-01] App: CanonComparisonScreen #1550)
  • app/src/navigation/ExploreStack.tsxStack.Screen registration via lazySuspense()
  • app/assets/explore-images.json + content/meta/explore-images.json — both updated with the new HowWeGotTheBible manifest key using the tool-level inline-images variant specified by the issue (count: null, contentType: null, images[] with url / caption / credit)

Landing screen

  • Header: ChevronLeft back button + title "How We Got The Bible"
  • Hero image via expo-image + useExploreImages() → the new manifest entry. Shows the artwork once uploaded to R2; renders nothing when absent (graceful)
  • Intro copy (2 paragraphs): what the bundle covers, evangelical framing, fair to other traditions, explicit rejection of conspiracy framing — per epic guardrails
  • Three navigation entries with icon + title + description:
    1. Extra-Biblical LiteratureExtraBiblicalIndex (HWGTB-P2-02 → PR feat(app): ExtraBiblicalIndexScreen (#1547) #1596)
    2. Canon Comparison → rendered as "Coming soon" (HWGTB-P3-01 not yet shipped; route typed ahead so flipping to live navigation is a one-line change when [HWGTB-P3-01] App: CanonComparisonScreen #1550 lands — canonComparisonReady = true)
    3. Guided JourneysJourneyBrowse with tab: 'featured'

Note on Guided Journeys navigation

The issue's suggested param shape was { filter: { ids: ['canon-formation', 'text-and-translation'] } }, but JourneyBrowseScreen's current ExploreStackParamList entry only supports { tab?, filterLens? }. Filter-by-journey-id is not yet supported in the browse screen. Per the issue's fallback guidance ("or whatever filter-param shape JourneyBrowseScreen already accepts"), landing on tab: 'featured' is the closest fit — once HWGTB-P3-02 (#1551) and HWGTB-P4-01 (#1552) author the two journeys, they'll surface via FEATURED_IDS.

Explore card

  • Title: "How We Got The Bible"
  • Subtitle: "Canon, manuscripts, translations, and the books Jude quoted"
  • Color: #c89858 — matches the st2 panel accent from feat(app): SecondTemplePanel component (#1546) #1595 for visual continuity across the bundle
  • Screen: HowWeGotTheBibleLanding
  • Premium: true — enforced via PREMIUM_SCREENS map; existing handleNavigate flow fires showUpgrade('feature', 'How We Got The Bible') for free users

Placed in the "Scholarly Analysis" section alongside Debates, Difficult Passages, and Content Library — conceptually closest neighbors.

Deferred: R2 hero artwork

The issue specifies placing artwork at _tools/art_staging/priority/explore_how_we_got_the_bible.png and running python _tools/upload_images_to_r2.py --priority. R2 write access is not available from this session — the manifest entry points at the planned URL (https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png) so uploading the asset to that path in a follow-up is enough to light up the hero image. Without the upload, the landing screen gracefully renders without the hero (the guarded-render path is exercised by the test suite's mocked hook).

How I verified

  • npx tsc --noEmit — clean ✅
  • npm run lint on touched files — 0 new warnings (4 pre-existing master warnings in unrelated files are out of scope) ✅
  • npx jest (full suite) — 470 suites / 3482 tests pass

Tests (8/8 passing)

 ✓ renders the page title
✓ renders the intro copy (evangelical-framed)
✓ renders all three landing entries
✓ Canon Comparison shows "Coming soon" label (HWGTB-P3-01 not yet shipped)
✓ tapping Extra-Biblical Literature navigates to ExtraBiblicalIndex
✓ tapping Guided Journeys navigates to JourneyBrowse with featured tab
✓ Canon Comparison entry has no onPress handler (no navigation fired)
✓ back button fires navigation.goBack

Merge order

Depends on: #1547 (PR #1596ExtraBiblicalIndexScreen) for the primary nav target. Works standalone on master when #1596 hasn't merged — the Extra-Biblical tap will navigate to a non-registered route until #1596 lands, at which point it works automatically.

Follow-up activation tasks:

Rollback

Revert this PR. Landing screen deleted, Explore card entry removed, manifest entries dropped. CanonComparison + HowWeGotTheBibleLanding routes leave the param list. Other routes (ExtraBiblicalIndex, ExtraBiblicalDetail) remain intact (they're owned by #1596 / #1597).


Generated by Claude Code

Adds the surface-level entry point for the HWGTB epic — an Explore
hero card and the full-screen landing page it routes to. The landing
page surfaces three bundled features (Extra-Biblical Literature, Canon
Comparison, Guided Journeys) in a single place, matching the
"bundled-feature landing page" precedent used elsewhere.
Files added
app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC
app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests
Files touched
app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry
in the 'Scholarly Analysis' SECTION; new PREMIUM_SCREENS mapping
('HowWeGotTheBibleLanding' → 'How We Got The Bible')
app/src/navigation/types.ts — HowWeGotTheBibleLanding
route (undefined params) + CanonComparison route typed ahead of
HWGTB-P3-01 (#1550)
app/src/navigation/ExploreStack.tsx — Stack.Screen registration
via lazySuspense()
app/assets/explore-images.json
content/meta/explore-images.json — both updated with the new
'HowWeGotTheBible' manifest key using the tool-level inline-images
variant specified by the issue (count: null, contentType: null,
images[] with url/caption/credit)
Landing screen
- Header row: ChevronLeft back + title 'How We Got The Bible'
- Hero image (expo-image) driven by useExploreImages() → the new
manifest entry — shows the artwork once uploaded to R2, renders
nothing when absent
- Intro copy (2 paragraphs): what the bundle covers, evangelical
framing, fair to other traditions, explicit rejection of
conspiracy framing per the epic guardrails
- Three nav entries with icon + title + description:
1. Extra-Biblical Literature → ExtraBiblicalIndex (HWGTB-P2-02)
2. Canon Comparison → rendered 'Coming soon' (HWGTB-P3-01 not
yet shipped; route typed ahead so flipping to live navigation
is a one-line change when #1550 lands)
3. Guided Journeys → JourneyBrowse with tab: 'featured'
(journey-id filter support is out of scope; canon-formation
and text-and-translation journeys will surface via
FEATURED_IDS once HWGTB-P3-02 / #1551 and HWGTB-P4-01 / #1552
land)
Explore card
- Title: 'How We Got The Bible'
- Subtitle: 'Canon, manuscripts, translations, and the books
Jude quoted'
- color: '#c89858' — matches the st2 panel accent for visual
continuity across the bundle
- screen: 'HowWeGotTheBibleLanding'
- premium: true — enforced via PREMIUM_SCREENS map; existing
handleNavigate flow fires showUpgrade('feature', 'How We Got
The Bible') for free users
Deferred — R2 hero artwork
The issue specifies placing the artwork at
_tools/art_staging/priority/explore_how_we_got_the_bible.png and
running python _tools/upload_images_to_r2.py --priority. R2 write
access is not available from this session — the manifest entry
points at the planned URL (
https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png
) so uploading the asset to that path in a follow-up is enough to
light up the hero image. Without the upload the landing screen
gracefully renders without the hero (the guarded-render path is
exercised by the loading-flag branch in the hero lookup).
How verified
npx tsc --noEmit — clean
npm run lint (src/) — 0 new warnings on touched files
npx jest (full suite) — 470 suites / 3482 tests pass
8 new tests cover: page title render, intro copy render, 3 landing
entries render, 'Coming soon' pill on Canon Comparison entry, tap →
ExtraBiblicalIndex, tap → JourneyBrowse with featured tab, 'Canon
Comparison' entry has no onPress (so tap is a no-op, not a nav),
back button fires goBack.
Merge order
Depends on #1547 (ExtraBiblicalIndexScreen — PR #1596) for the
primary nav target; the other two entries are safe to merge any
time. Works standalone on master when #1547 hasn't merged: the
Extra-Biblical tap will navigate to a non-registered route until
#1596 lands, at which point it works automatically.
Closes#1549
@github-actions

Copy link
Copy Markdown

Content Pipeline Results

✅ All pipeline checks passed

StepStatusDetails
Schema Validation136482 passed, 77 failed
Build DB
DB Integrity93 passed, 0 failed

Content Pipeline — Quality & Accuracy Report

All content checks passed

Scope: 0 chapter(s) across 0 book(s)


Generated by ci_content_check.py

@github-actions

Copy link
Copy Markdown

Test Results

✅ All tests passed

PassedFailedTotal
Tests✅ 3482❌ 03482
Suites✅ 470❌ 0470

Coverage

StatementsBranchesFunctionsLines

⏱️ Duration: 84.6s

@CraigBuckmaster
CraigBuckmaster merged commit 7e56f96 into masterApr 23, 2026
7 checks passed
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
@CraigBuckmaster
CraigBuckmaster deleted the feature/hwgtb-p2-04-landing-screen branch April 23, 2026 20:35
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster added a commit that referenced this pull request Apr 23, 2026
* feat(app): CanonComparisonScreen (#1550)
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
* fix(types): add BookIntro to ExploreStackParamList
The CanonComparison screen registered BookIntroScreen on ExploreStack
but the param list didn't declare it, causing TS2322 on navigate calls
from CanonComparisonScreen.
Adds the route to ExploreStackParamList alongside the existing
CanonComparison entry. BookIntro also exists on RootStack; same route
on two stacks is fine for React Navigation.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude (for Craig) <claude@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HWGTB-P2-04] App: Explore hero card for "How We Got The Bible"

2 participants

@CraigBuckmaster@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) by CraigBuckmaster · Pull Request #1598 · CraigBuckmaster/ScriptureDeepDive · GitHub
Skip to content

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) - #1598

Merged
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen
Apr 23, 2026
Merged

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549)#1598
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen

Conversation

@CraigBuckmaster

Copy link
Copy Markdown
Owner

What this does

Adds the surface-level entry point for the HWGTB epic — an Explore hero card and the full-screen landing page it routes to. The landing page surfaces three bundled features (Extra-Biblical Literature, Canon Comparison, Guided Journeys) in a single place, matching the "bundled-feature landing page" precedent used elsewhere in the app.

Closes

Closes#1549

Files added

  • app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC landing page
  • app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests

Files touched

  • app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry in the 'Scholarly Analysis' SECTION + new PREMIUM_SCREENS mapping (HowWeGotTheBibleLanding'How We Got The Bible')
  • app/src/navigation/types.tsHowWeGotTheBibleLanding route (undefined params) + CanonComparison route typed ahead of HWGTB-P3-01 ([HWGTB-P3-01] App: CanonComparisonScreen #1550)
  • app/src/navigation/ExploreStack.tsxStack.Screen registration via lazySuspense()
  • app/assets/explore-images.json + content/meta/explore-images.json — both updated with the new HowWeGotTheBible manifest key using the tool-level inline-images variant specified by the issue (count: null, contentType: null, images[] with url / caption / credit)

Landing screen

  • Header: ChevronLeft back button + title "How We Got The Bible"
  • Hero image via expo-image + useExploreImages() → the new manifest entry. Shows the artwork once uploaded to R2; renders nothing when absent (graceful)
  • Intro copy (2 paragraphs): what the bundle covers, evangelical framing, fair to other traditions, explicit rejection of conspiracy framing — per epic guardrails
  • Three navigation entries with icon + title + description:
    1. Extra-Biblical LiteratureExtraBiblicalIndex (HWGTB-P2-02 → PR feat(app): ExtraBiblicalIndexScreen (#1547) #1596)
    2. Canon Comparison → rendered as "Coming soon" (HWGTB-P3-01 not yet shipped; route typed ahead so flipping to live navigation is a one-line change when [HWGTB-P3-01] App: CanonComparisonScreen #1550 lands — canonComparisonReady = true)
    3. Guided JourneysJourneyBrowse with tab: 'featured'

Note on Guided Journeys navigation

The issue's suggested param shape was { filter: { ids: ['canon-formation', 'text-and-translation'] } }, but JourneyBrowseScreen's current ExploreStackParamList entry only supports { tab?, filterLens? }. Filter-by-journey-id is not yet supported in the browse screen. Per the issue's fallback guidance ("or whatever filter-param shape JourneyBrowseScreen already accepts"), landing on tab: 'featured' is the closest fit — once HWGTB-P3-02 (#1551) and HWGTB-P4-01 (#1552) author the two journeys, they'll surface via FEATURED_IDS.

Explore card

  • Title: "How We Got The Bible"
  • Subtitle: "Canon, manuscripts, translations, and the books Jude quoted"
  • Color: #c89858 — matches the st2 panel accent from feat(app): SecondTemplePanel component (#1546) #1595 for visual continuity across the bundle
  • Screen: HowWeGotTheBibleLanding
  • Premium: true — enforced via PREMIUM_SCREENS map; existing handleNavigate flow fires showUpgrade('feature', 'How We Got The Bible') for free users

Placed in the "Scholarly Analysis" section alongside Debates, Difficult Passages, and Content Library — conceptually closest neighbors.

Deferred: R2 hero artwork

The issue specifies placing artwork at _tools/art_staging/priority/explore_how_we_got_the_bible.png and running python _tools/upload_images_to_r2.py --priority. R2 write access is not available from this session — the manifest entry points at the planned URL (https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png) so uploading the asset to that path in a follow-up is enough to light up the hero image. Without the upload, the landing screen gracefully renders without the hero (the guarded-render path is exercised by the test suite's mocked hook).

How I verified

  • npx tsc --noEmit — clean ✅
  • npm run lint on touched files — 0 new warnings (4 pre-existing master warnings in unrelated files are out of scope) ✅
  • npx jest (full suite) — 470 suites / 3482 tests pass

Tests (8/8 passing)

 ✓ renders the page title
✓ renders the intro copy (evangelical-framed)
✓ renders all three landing entries
✓ Canon Comparison shows "Coming soon" label (HWGTB-P3-01 not yet shipped)
✓ tapping Extra-Biblical Literature navigates to ExtraBiblicalIndex
✓ tapping Guided Journeys navigates to JourneyBrowse with featured tab
✓ Canon Comparison entry has no onPress handler (no navigation fired)
✓ back button fires navigation.goBack

Merge order

Depends on: #1547 (PR #1596ExtraBiblicalIndexScreen) for the primary nav target. Works standalone on master when #1596 hasn't merged — the Extra-Biblical tap will navigate to a non-registered route until #1596 lands, at which point it works automatically.

Follow-up activation tasks:

Rollback

Revert this PR. Landing screen deleted, Explore card entry removed, manifest entries dropped. CanonComparison + HowWeGotTheBibleLanding routes leave the param list. Other routes (ExtraBiblicalIndex, ExtraBiblicalDetail) remain intact (they're owned by #1596 / #1597).


Generated by Claude Code

Adds the surface-level entry point for the HWGTB epic — an Explore
hero card and the full-screen landing page it routes to. The landing
page surfaces three bundled features (Extra-Biblical Literature, Canon
Comparison, Guided Journeys) in a single place, matching the
"bundled-feature landing page" precedent used elsewhere.
Files added
app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC
app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests
Files touched
app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry
in the 'Scholarly Analysis' SECTION; new PREMIUM_SCREENS mapping
('HowWeGotTheBibleLanding' → 'How We Got The Bible')
app/src/navigation/types.ts — HowWeGotTheBibleLanding
route (undefined params) + CanonComparison route typed ahead of
HWGTB-P3-01 (#1550)
app/src/navigation/ExploreStack.tsx — Stack.Screen registration
via lazySuspense()
app/assets/explore-images.json
content/meta/explore-images.json — both updated with the new
'HowWeGotTheBible' manifest key using the tool-level inline-images
variant specified by the issue (count: null, contentType: null,
images[] with url/caption/credit)
Landing screen
- Header row: ChevronLeft back + title 'How We Got The Bible'
- Hero image (expo-image) driven by useExploreImages() → the new
manifest entry — shows the artwork once uploaded to R2, renders
nothing when absent
- Intro copy (2 paragraphs): what the bundle covers, evangelical
framing, fair to other traditions, explicit rejection of
conspiracy framing per the epic guardrails
- Three nav entries with icon + title + description:
1. Extra-Biblical Literature → ExtraBiblicalIndex (HWGTB-P2-02)
2. Canon Comparison → rendered 'Coming soon' (HWGTB-P3-01 not
yet shipped; route typed ahead so flipping to live navigation
is a one-line change when #1550 lands)
3. Guided Journeys → JourneyBrowse with tab: 'featured'
(journey-id filter support is out of scope; canon-formation
and text-and-translation journeys will surface via
FEATURED_IDS once HWGTB-P3-02 / #1551 and HWGTB-P4-01 / #1552
land)
Explore card
- Title: 'How We Got The Bible'
- Subtitle: 'Canon, manuscripts, translations, and the books
Jude quoted'
- color: '#c89858' — matches the st2 panel accent for visual
continuity across the bundle
- screen: 'HowWeGotTheBibleLanding'
- premium: true — enforced via PREMIUM_SCREENS map; existing
handleNavigate flow fires showUpgrade('feature', 'How We Got
The Bible') for free users
Deferred — R2 hero artwork
The issue specifies placing the artwork at
_tools/art_staging/priority/explore_how_we_got_the_bible.png and
running python _tools/upload_images_to_r2.py --priority. R2 write
access is not available from this session — the manifest entry
points at the planned URL (
https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png
) so uploading the asset to that path in a follow-up is enough to
light up the hero image. Without the upload the landing screen
gracefully renders without the hero (the guarded-render path is
exercised by the loading-flag branch in the hero lookup).
How verified
npx tsc --noEmit — clean
npm run lint (src/) — 0 new warnings on touched files
npx jest (full suite) — 470 suites / 3482 tests pass
8 new tests cover: page title render, intro copy render, 3 landing
entries render, 'Coming soon' pill on Canon Comparison entry, tap →
ExtraBiblicalIndex, tap → JourneyBrowse with featured tab, 'Canon
Comparison' entry has no onPress (so tap is a no-op, not a nav),
back button fires goBack.
Merge order
Depends on #1547 (ExtraBiblicalIndexScreen — PR #1596) for the
primary nav target; the other two entries are safe to merge any
time. Works standalone on master when #1547 hasn't merged: the
Extra-Biblical tap will navigate to a non-registered route until
#1596 lands, at which point it works automatically.
Closes#1549
@github-actions

Copy link
Copy Markdown

Content Pipeline Results

✅ All pipeline checks passed

StepStatusDetails
Schema Validation136482 passed, 77 failed
Build DB
DB Integrity93 passed, 0 failed

Content Pipeline — Quality & Accuracy Report

All content checks passed

Scope: 0 chapter(s) across 0 book(s)


Generated by ci_content_check.py

@github-actions

Copy link
Copy Markdown

Test Results

✅ All tests passed

PassedFailedTotal
Tests✅ 3482❌ 03482
Suites✅ 470❌ 0470

Coverage

StatementsBranchesFunctionsLines

⏱️ Duration: 84.6s

@CraigBuckmaster
CraigBuckmaster merged commit 7e56f96 into masterApr 23, 2026
7 checks passed
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
@CraigBuckmaster
CraigBuckmaster deleted the feature/hwgtb-p2-04-landing-screen branch April 23, 2026 20:35
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster added a commit that referenced this pull request Apr 23, 2026
* feat(app): CanonComparisonScreen (#1550)
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
* fix(types): add BookIntro to ExploreStackParamList
The CanonComparison screen registered BookIntroScreen on ExploreStack
but the param list didn't declare it, causing TS2322 on navigate calls
from CanonComparisonScreen.
Adds the route to ExploreStackParamList alongside the existing
CanonComparison entry. BookIntro also exists on RootStack; same route
on two stacks is fine for React Navigation.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude (for Craig) <claude@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HWGTB-P2-04] App: Explore hero card for "How We Got The Bible"

2 participants

@CraigBuckmaster@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) by CraigBuckmaster · Pull Request #1598 · CraigBuckmaster/ScriptureDeepDive · GitHub
Skip to content

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) - #1598

Merged
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen
Apr 23, 2026
Merged

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549)#1598
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen

Conversation

@CraigBuckmaster

Copy link
Copy Markdown
Owner

What this does

Adds the surface-level entry point for the HWGTB epic — an Explore hero card and the full-screen landing page it routes to. The landing page surfaces three bundled features (Extra-Biblical Literature, Canon Comparison, Guided Journeys) in a single place, matching the "bundled-feature landing page" precedent used elsewhere in the app.

Closes

Closes#1549

Files added

  • app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC landing page
  • app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests

Files touched

  • app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry in the 'Scholarly Analysis' SECTION + new PREMIUM_SCREENS mapping (HowWeGotTheBibleLanding'How We Got The Bible')
  • app/src/navigation/types.tsHowWeGotTheBibleLanding route (undefined params) + CanonComparison route typed ahead of HWGTB-P3-01 ([HWGTB-P3-01] App: CanonComparisonScreen #1550)
  • app/src/navigation/ExploreStack.tsxStack.Screen registration via lazySuspense()
  • app/assets/explore-images.json + content/meta/explore-images.json — both updated with the new HowWeGotTheBible manifest key using the tool-level inline-images variant specified by the issue (count: null, contentType: null, images[] with url / caption / credit)

Landing screen

  • Header: ChevronLeft back button + title "How We Got The Bible"
  • Hero image via expo-image + useExploreImages() → the new manifest entry. Shows the artwork once uploaded to R2; renders nothing when absent (graceful)
  • Intro copy (2 paragraphs): what the bundle covers, evangelical framing, fair to other traditions, explicit rejection of conspiracy framing — per epic guardrails
  • Three navigation entries with icon + title + description:
    1. Extra-Biblical LiteratureExtraBiblicalIndex (HWGTB-P2-02 → PR feat(app): ExtraBiblicalIndexScreen (#1547) #1596)
    2. Canon Comparison → rendered as "Coming soon" (HWGTB-P3-01 not yet shipped; route typed ahead so flipping to live navigation is a one-line change when [HWGTB-P3-01] App: CanonComparisonScreen #1550 lands — canonComparisonReady = true)
    3. Guided JourneysJourneyBrowse with tab: 'featured'

Note on Guided Journeys navigation

The issue's suggested param shape was { filter: { ids: ['canon-formation', 'text-and-translation'] } }, but JourneyBrowseScreen's current ExploreStackParamList entry only supports { tab?, filterLens? }. Filter-by-journey-id is not yet supported in the browse screen. Per the issue's fallback guidance ("or whatever filter-param shape JourneyBrowseScreen already accepts"), landing on tab: 'featured' is the closest fit — once HWGTB-P3-02 (#1551) and HWGTB-P4-01 (#1552) author the two journeys, they'll surface via FEATURED_IDS.

Explore card

  • Title: "How We Got The Bible"
  • Subtitle: "Canon, manuscripts, translations, and the books Jude quoted"
  • Color: #c89858 — matches the st2 panel accent from feat(app): SecondTemplePanel component (#1546) #1595 for visual continuity across the bundle
  • Screen: HowWeGotTheBibleLanding
  • Premium: true — enforced via PREMIUM_SCREENS map; existing handleNavigate flow fires showUpgrade('feature', 'How We Got The Bible') for free users

Placed in the "Scholarly Analysis" section alongside Debates, Difficult Passages, and Content Library — conceptually closest neighbors.

Deferred: R2 hero artwork

The issue specifies placing artwork at _tools/art_staging/priority/explore_how_we_got_the_bible.png and running python _tools/upload_images_to_r2.py --priority. R2 write access is not available from this session — the manifest entry points at the planned URL (https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png) so uploading the asset to that path in a follow-up is enough to light up the hero image. Without the upload, the landing screen gracefully renders without the hero (the guarded-render path is exercised by the test suite's mocked hook).

How I verified

  • npx tsc --noEmit — clean ✅
  • npm run lint on touched files — 0 new warnings (4 pre-existing master warnings in unrelated files are out of scope) ✅
  • npx jest (full suite) — 470 suites / 3482 tests pass

Tests (8/8 passing)

 ✓ renders the page title
✓ renders the intro copy (evangelical-framed)
✓ renders all three landing entries
✓ Canon Comparison shows "Coming soon" label (HWGTB-P3-01 not yet shipped)
✓ tapping Extra-Biblical Literature navigates to ExtraBiblicalIndex
✓ tapping Guided Journeys navigates to JourneyBrowse with featured tab
✓ Canon Comparison entry has no onPress handler (no navigation fired)
✓ back button fires navigation.goBack

Merge order

Depends on: #1547 (PR #1596ExtraBiblicalIndexScreen) for the primary nav target. Works standalone on master when #1596 hasn't merged — the Extra-Biblical tap will navigate to a non-registered route until #1596 lands, at which point it works automatically.

Follow-up activation tasks:

Rollback

Revert this PR. Landing screen deleted, Explore card entry removed, manifest entries dropped. CanonComparison + HowWeGotTheBibleLanding routes leave the param list. Other routes (ExtraBiblicalIndex, ExtraBiblicalDetail) remain intact (they're owned by #1596 / #1597).


Generated by Claude Code

Adds the surface-level entry point for the HWGTB epic — an Explore
hero card and the full-screen landing page it routes to. The landing
page surfaces three bundled features (Extra-Biblical Literature, Canon
Comparison, Guided Journeys) in a single place, matching the
"bundled-feature landing page" precedent used elsewhere.
Files added
app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC
app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests
Files touched
app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry
in the 'Scholarly Analysis' SECTION; new PREMIUM_SCREENS mapping
('HowWeGotTheBibleLanding' → 'How We Got The Bible')
app/src/navigation/types.ts — HowWeGotTheBibleLanding
route (undefined params) + CanonComparison route typed ahead of
HWGTB-P3-01 (#1550)
app/src/navigation/ExploreStack.tsx — Stack.Screen registration
via lazySuspense()
app/assets/explore-images.json
content/meta/explore-images.json — both updated with the new
'HowWeGotTheBible' manifest key using the tool-level inline-images
variant specified by the issue (count: null, contentType: null,
images[] with url/caption/credit)
Landing screen
- Header row: ChevronLeft back + title 'How We Got The Bible'
- Hero image (expo-image) driven by useExploreImages() → the new
manifest entry — shows the artwork once uploaded to R2, renders
nothing when absent
- Intro copy (2 paragraphs): what the bundle covers, evangelical
framing, fair to other traditions, explicit rejection of
conspiracy framing per the epic guardrails
- Three nav entries with icon + title + description:
1. Extra-Biblical Literature → ExtraBiblicalIndex (HWGTB-P2-02)
2. Canon Comparison → rendered 'Coming soon' (HWGTB-P3-01 not
yet shipped; route typed ahead so flipping to live navigation
is a one-line change when #1550 lands)
3. Guided Journeys → JourneyBrowse with tab: 'featured'
(journey-id filter support is out of scope; canon-formation
and text-and-translation journeys will surface via
FEATURED_IDS once HWGTB-P3-02 / #1551 and HWGTB-P4-01 / #1552
land)
Explore card
- Title: 'How We Got The Bible'
- Subtitle: 'Canon, manuscripts, translations, and the books
Jude quoted'
- color: '#c89858' — matches the st2 panel accent for visual
continuity across the bundle
- screen: 'HowWeGotTheBibleLanding'
- premium: true — enforced via PREMIUM_SCREENS map; existing
handleNavigate flow fires showUpgrade('feature', 'How We Got
The Bible') for free users
Deferred — R2 hero artwork
The issue specifies placing the artwork at
_tools/art_staging/priority/explore_how_we_got_the_bible.png and
running python _tools/upload_images_to_r2.py --priority. R2 write
access is not available from this session — the manifest entry
points at the planned URL (
https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png
) so uploading the asset to that path in a follow-up is enough to
light up the hero image. Without the upload the landing screen
gracefully renders without the hero (the guarded-render path is
exercised by the loading-flag branch in the hero lookup).
How verified
npx tsc --noEmit — clean
npm run lint (src/) — 0 new warnings on touched files
npx jest (full suite) — 470 suites / 3482 tests pass
8 new tests cover: page title render, intro copy render, 3 landing
entries render, 'Coming soon' pill on Canon Comparison entry, tap →
ExtraBiblicalIndex, tap → JourneyBrowse with featured tab, 'Canon
Comparison' entry has no onPress (so tap is a no-op, not a nav),
back button fires goBack.
Merge order
Depends on #1547 (ExtraBiblicalIndexScreen — PR #1596) for the
primary nav target; the other two entries are safe to merge any
time. Works standalone on master when #1547 hasn't merged: the
Extra-Biblical tap will navigate to a non-registered route until
#1596 lands, at which point it works automatically.
Closes#1549
@github-actions

Copy link
Copy Markdown

Content Pipeline Results

✅ All pipeline checks passed

StepStatusDetails
Schema Validation136482 passed, 77 failed
Build DB
DB Integrity93 passed, 0 failed

Content Pipeline — Quality & Accuracy Report

All content checks passed

Scope: 0 chapter(s) across 0 book(s)


Generated by ci_content_check.py

@github-actions

Copy link
Copy Markdown

Test Results

✅ All tests passed

PassedFailedTotal
Tests✅ 3482❌ 03482
Suites✅ 470❌ 0470

Coverage

StatementsBranchesFunctionsLines

⏱️ Duration: 84.6s

@CraigBuckmaster
CraigBuckmaster merged commit 7e56f96 into masterApr 23, 2026
7 checks passed
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
@CraigBuckmaster
CraigBuckmaster deleted the feature/hwgtb-p2-04-landing-screen branch April 23, 2026 20:35
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster added a commit that referenced this pull request Apr 23, 2026
* feat(app): CanonComparisonScreen (#1550)
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
* fix(types): add BookIntro to ExploreStackParamList
The CanonComparison screen registered BookIntroScreen on ExploreStack
but the param list didn't declare it, causing TS2322 on navigate calls
from CanonComparisonScreen.
Adds the route to ExploreStackParamList alongside the existing
CanonComparison entry. BookIntro also exists on RootStack; same route
on two stacks is fine for React Navigation.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude (for Craig) <claude@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HWGTB-P2-04] App: Explore hero card for "How We Got The Bible"

2 participants

@CraigBuckmaster@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) by CraigBuckmaster · Pull Request #1598 · CraigBuckmaster/ScriptureDeepDive · GitHub
Skip to content

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549) - #1598

Merged
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen
Apr 23, 2026
Merged

feat(app): Explore hero card + HowWeGotTheBibleLandingScreen (#1549)#1598
CraigBuckmaster merged 1 commit into
masterfrom
feature/hwgtb-p2-04-landing-screen

Conversation

@CraigBuckmaster

Copy link
Copy Markdown
Owner

What this does

Adds the surface-level entry point for the HWGTB epic — an Explore hero card and the full-screen landing page it routes to. The landing page surfaces three bundled features (Extra-Biblical Literature, Canon Comparison, Guided Journeys) in a single place, matching the "bundled-feature landing page" precedent used elsewhere in the app.

Closes

Closes#1549

Files added

  • app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC landing page
  • app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests

Files touched

  • app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry in the 'Scholarly Analysis' SECTION + new PREMIUM_SCREENS mapping (HowWeGotTheBibleLanding'How We Got The Bible')
  • app/src/navigation/types.tsHowWeGotTheBibleLanding route (undefined params) + CanonComparison route typed ahead of HWGTB-P3-01 ([HWGTB-P3-01] App: CanonComparisonScreen #1550)
  • app/src/navigation/ExploreStack.tsxStack.Screen registration via lazySuspense()
  • app/assets/explore-images.json + content/meta/explore-images.json — both updated with the new HowWeGotTheBible manifest key using the tool-level inline-images variant specified by the issue (count: null, contentType: null, images[] with url / caption / credit)

Landing screen

  • Header: ChevronLeft back button + title "How We Got The Bible"
  • Hero image via expo-image + useExploreImages() → the new manifest entry. Shows the artwork once uploaded to R2; renders nothing when absent (graceful)
  • Intro copy (2 paragraphs): what the bundle covers, evangelical framing, fair to other traditions, explicit rejection of conspiracy framing — per epic guardrails
  • Three navigation entries with icon + title + description:
    1. Extra-Biblical LiteratureExtraBiblicalIndex (HWGTB-P2-02 → PR feat(app): ExtraBiblicalIndexScreen (#1547) #1596)
    2. Canon Comparison → rendered as "Coming soon" (HWGTB-P3-01 not yet shipped; route typed ahead so flipping to live navigation is a one-line change when [HWGTB-P3-01] App: CanonComparisonScreen #1550 lands — canonComparisonReady = true)
    3. Guided JourneysJourneyBrowse with tab: 'featured'

Note on Guided Journeys navigation

The issue's suggested param shape was { filter: { ids: ['canon-formation', 'text-and-translation'] } }, but JourneyBrowseScreen's current ExploreStackParamList entry only supports { tab?, filterLens? }. Filter-by-journey-id is not yet supported in the browse screen. Per the issue's fallback guidance ("or whatever filter-param shape JourneyBrowseScreen already accepts"), landing on tab: 'featured' is the closest fit — once HWGTB-P3-02 (#1551) and HWGTB-P4-01 (#1552) author the two journeys, they'll surface via FEATURED_IDS.

Explore card

  • Title: "How We Got The Bible"
  • Subtitle: "Canon, manuscripts, translations, and the books Jude quoted"
  • Color: #c89858 — matches the st2 panel accent from feat(app): SecondTemplePanel component (#1546) #1595 for visual continuity across the bundle
  • Screen: HowWeGotTheBibleLanding
  • Premium: true — enforced via PREMIUM_SCREENS map; existing handleNavigate flow fires showUpgrade('feature', 'How We Got The Bible') for free users

Placed in the "Scholarly Analysis" section alongside Debates, Difficult Passages, and Content Library — conceptually closest neighbors.

Deferred: R2 hero artwork

The issue specifies placing artwork at _tools/art_staging/priority/explore_how_we_got_the_bible.png and running python _tools/upload_images_to_r2.py --priority. R2 write access is not available from this session — the manifest entry points at the planned URL (https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png) so uploading the asset to that path in a follow-up is enough to light up the hero image. Without the upload, the landing screen gracefully renders without the hero (the guarded-render path is exercised by the test suite's mocked hook).

How I verified

  • npx tsc --noEmit — clean ✅
  • npm run lint on touched files — 0 new warnings (4 pre-existing master warnings in unrelated files are out of scope) ✅
  • npx jest (full suite) — 470 suites / 3482 tests pass

Tests (8/8 passing)

 ✓ renders the page title
✓ renders the intro copy (evangelical-framed)
✓ renders all three landing entries
✓ Canon Comparison shows "Coming soon" label (HWGTB-P3-01 not yet shipped)
✓ tapping Extra-Biblical Literature navigates to ExtraBiblicalIndex
✓ tapping Guided Journeys navigates to JourneyBrowse with featured tab
✓ Canon Comparison entry has no onPress handler (no navigation fired)
✓ back button fires navigation.goBack

Merge order

Depends on: #1547 (PR #1596ExtraBiblicalIndexScreen) for the primary nav target. Works standalone on master when #1596 hasn't merged — the Extra-Biblical tap will navigate to a non-registered route until #1596 lands, at which point it works automatically.

Follow-up activation tasks:

Rollback

Revert this PR. Landing screen deleted, Explore card entry removed, manifest entries dropped. CanonComparison + HowWeGotTheBibleLanding routes leave the param list. Other routes (ExtraBiblicalIndex, ExtraBiblicalDetail) remain intact (they're owned by #1596 / #1597).


Generated by Claude Code

Adds the surface-level entry point for the HWGTB epic — an Explore
hero card and the full-screen landing page it routes to. The landing
page surfaces three bundled features (Extra-Biblical Literature, Canon
Comparison, Guided Journeys) in a single place, matching the
"bundled-feature landing page" precedent used elsewhere.
Files added
app/src/screens/HowWeGotTheBibleLandingScreen.tsx — 315 LOC
app/__tests__/screens/HowWeGotTheBibleLandingScreen.test.tsx — 8 tests
Files touched
app/src/screens/ExploreMenuScreen.tsx — new FeatureCardData entry
in the 'Scholarly Analysis' SECTION; new PREMIUM_SCREENS mapping
('HowWeGotTheBibleLanding' → 'How We Got The Bible')
app/src/navigation/types.ts — HowWeGotTheBibleLanding
route (undefined params) + CanonComparison route typed ahead of
HWGTB-P3-01 (#1550)
app/src/navigation/ExploreStack.tsx — Stack.Screen registration
via lazySuspense()
app/assets/explore-images.json
content/meta/explore-images.json — both updated with the new
'HowWeGotTheBible' manifest key using the tool-level inline-images
variant specified by the issue (count: null, contentType: null,
images[] with url/caption/credit)
Landing screen
- Header row: ChevronLeft back + title 'How We Got The Bible'
- Hero image (expo-image) driven by useExploreImages() → the new
manifest entry — shows the artwork once uploaded to R2, renders
nothing when absent
- Intro copy (2 paragraphs): what the bundle covers, evangelical
framing, fair to other traditions, explicit rejection of
conspiracy framing per the epic guardrails
- Three nav entries with icon + title + description:
1. Extra-Biblical Literature → ExtraBiblicalIndex (HWGTB-P2-02)
2. Canon Comparison → rendered 'Coming soon' (HWGTB-P3-01 not
yet shipped; route typed ahead so flipping to live navigation
is a one-line change when #1550 lands)
3. Guided Journeys → JourneyBrowse with tab: 'featured'
(journey-id filter support is out of scope; canon-formation
and text-and-translation journeys will surface via
FEATURED_IDS once HWGTB-P3-02 / #1551 and HWGTB-P4-01 / #1552
land)
Explore card
- Title: 'How We Got The Bible'
- Subtitle: 'Canon, manuscripts, translations, and the books
Jude quoted'
- color: '#c89858' — matches the st2 panel accent for visual
continuity across the bundle
- screen: 'HowWeGotTheBibleLanding'
- premium: true — enforced via PREMIUM_SCREENS map; existing
handleNavigate flow fires showUpgrade('feature', 'How We Got
The Bible') for free users
Deferred — R2 hero artwork
The issue specifies placing the artwork at
_tools/art_staging/priority/explore_how_we_got_the_bible.png and
running python _tools/upload_images_to_r2.py --priority. R2 write
access is not available from this session — the manifest entry
points at the planned URL (
https://contentcompanionstudy.com/art/explore/how-we-got-the-bible.png
) so uploading the asset to that path in a follow-up is enough to
light up the hero image. Without the upload the landing screen
gracefully renders without the hero (the guarded-render path is
exercised by the loading-flag branch in the hero lookup).
How verified
npx tsc --noEmit — clean
npm run lint (src/) — 0 new warnings on touched files
npx jest (full suite) — 470 suites / 3482 tests pass
8 new tests cover: page title render, intro copy render, 3 landing
entries render, 'Coming soon' pill on Canon Comparison entry, tap →
ExtraBiblicalIndex, tap → JourneyBrowse with featured tab, 'Canon
Comparison' entry has no onPress (so tap is a no-op, not a nav),
back button fires goBack.
Merge order
Depends on #1547 (ExtraBiblicalIndexScreen — PR #1596) for the
primary nav target; the other two entries are safe to merge any
time. Works standalone on master when #1547 hasn't merged: the
Extra-Biblical tap will navigate to a non-registered route until
#1596 lands, at which point it works automatically.
Closes#1549
@github-actions

Copy link
Copy Markdown

Content Pipeline Results

✅ All pipeline checks passed

StepStatusDetails
Schema Validation136482 passed, 77 failed
Build DB
DB Integrity93 passed, 0 failed

Content Pipeline — Quality & Accuracy Report

All content checks passed

Scope: 0 chapter(s) across 0 book(s)


Generated by ci_content_check.py

@github-actions

Copy link
Copy Markdown

Test Results

✅ All tests passed

PassedFailedTotal
Tests✅ 3482❌ 03482
Suites✅ 470❌ 0470

Coverage

StatementsBranchesFunctionsLines

⏱️ Duration: 84.6s

@CraigBuckmaster
CraigBuckmaster merged commit 7e56f96 into masterApr 23, 2026
7 checks passed
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
@CraigBuckmaster
CraigBuckmaster deleted the feature/hwgtb-p2-04-landing-screen branch April 23, 2026 20:35
CraigBuckmaster pushed a commit that referenced this pull request Apr 23, 2026
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
CraigBuckmaster added a commit that referenced this pull request Apr 23, 2026
* feat(app): CanonComparisonScreen (#1550)
Interactive side-by-side of the four major canon traditions. The
conversion-driving screen for the "How We Got The Bible" bundle —
readers see the Protestant, Catholic, Orthodox, and Ethiopian canons
next to each other, with book-diff highlighting, founding-council
timelines, and tap-through to per-book detail.
Files added
app/src/db/content/canonTraditions.ts — data access layer
(getAllCanonTraditions, getCanonTraditionById, defensive
sqlite_master table-exists guard)
app/src/hooks/useCanonTraditions.ts — loader + book-membership
computation (common vs subset book ids per tradition)
app/src/components/CanonColumn.tsx — one tradition's column
(header, scrollable book list with per-book tradition badges,
expandable distinctives, locked-preview variant for free tier)
app/src/screens/CanonComparisonScreen.tsx — the screen
app/__tests__/screens/CanonComparisonScreen.test.tsx — 12 tests
Files touched
app/src/db/content/index.ts — barrel export
app/src/types/meta.ts — CanonTradition,
CanonListSection, CanonDistinctive, CanonFormationEvent,
CanonTraditionRow
app/src/navigation/types.ts — CanonComparison,
ExtraBiblicalIndex, ExtraBiblicalDetail, BookIntro typed for
ExploreStack (ExtraBiblical routes typed ahead for cross-stack
consistency with #1596/#1597; BookIntro added so the canon-column
book tap can route without cross-tab hops)
app/src/navigation/ExploreStack.tsx — CanonComparison +
BookIntro Stack.Screen registrations via lazySuspense()
Layout — useWindowDimensions() driven (no third-party orientation
library, no Dimensions.addEventListener per the issue guidance)
Landscape (width > height): horizontal scroll across 4 columns,
each 320px wide with vertical book lists
Portrait (width <= height): tabs at top, one column visible at
a time, tap-to-switch
Column rendering
Header : tradition label + book count + first 2 formation events
Book list : scrollable; section headers (OT / NT / etc.); books in
all 4 traditions render in neutral style; books unique to a
subset carry gold-tinted tradition-id badges (Prot / Cath / EO /
Eth) showing which traditions contain them
Distinctives: expandable block at the bottom (2-4 entries from
the authored content)
Tap biblical book (present in books table) → BookIntro
Tap extrabiblical book (not in books table) → ExtraBiblicalDetail
(HWGTB-P2-03 / PR #1597)
Header
Back button + title "Canon Comparison" + right-aligned "How did
this happen?" CTA → JourneyDetail journeyId='canon-formation'
(HWGTB-P3-02 / #1551 — when the journey lands this activates)
Formation timeline footer
Expandable; merges all formation_events from all 4 traditions,
sorted by year, annotated with the source tradition's label.
Renders "{N} events across the four traditions" header.
Premium gating
Free tier: Protestant + Catholic columns fully visible. Orthodox
+ Ethiopian columns render header + first 5 rows with a gold
"✨ Unlock full canon" CTA that fires showUpgrade('feature',
'Canon Comparison'). Premium tier: all 4 columns fully readable.
Portrait tab labels show a 🔒 indicator for gated tabs.
How verified
npx tsc --noEmit — clean
npx eslint (touched files) — 0 warnings
npx jest (full suite) — 470 suites / 3486 tests pass
12 new tests cover:
- portrait: 4 tradition tabs render, active column renders,
tab tap switches visible column
- landscape: all 4 columns render simultaneously (no tabs)
- header "How did this happen?" CTA + navigation to canon-formation
journey
- premium gating: free-tier 🔒 on Orthodox/Ethiopian tabs, unlock
CTA fires showUpgrade, premium user sees no locks
- formation timeline: footer renders event count, expand shows
merged events sorted by year with tradition annotations
Merge order
Depends on #1539 (canon_traditions schema) and #1542 (the 4
seeded traditions). Works against a pre-#1539 DB: the table-exists
guard returns [] and the screen shows 'Canon data not yet
available' cleanly.
Pairs with #1548 (PR #1597 — ExtraBiblicalDetail) for extrabib
taps, and #1551 (canon-formation journey) for the header CTA.
Follow-up activation
When #1598's HowWeGotTheBibleLandingScreen ships alongside this,
flip its canonComparisonReady = true constant so the landing
entry activates live nav (currently rendered as 'Coming soon').
Closes#1550
* fix(types): add BookIntro to ExploreStackParamList
The CanonComparison screen registered BookIntroScreen on ExploreStack
but the param list didn't declare it, causing TS2322 on navigate calls
from CanonComparisonScreen.
Adds the route to ExploreStackParamList alongside the existing
CanonComparison entry. BookIntro also exists on RootStack; same route
on two stacks is fine for React Navigation.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude (for Craig) <claude@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HWGTB-P2-04] App: Explore hero card for "How We Got The Bible"

2 participants

@CraigBuckmaster@claude