Redesign study landing page: track cards, numbered steps, tidier hero and Q&A callout, themed progress bars; v2.10.8
Publish Container / build (push) Has been cancelled
Publish Container / build (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
52568db82b
commit
669cd6555c
4 files changed
+296
-116
No files matched your search
+95
-113
@@ -911,8 +911,8 @@ export function StudyLandingPage({ content }: Props) {
|
||||
<span style={{ color: '#7a7060', fontSize: '0.9rem' }}>{study.completedLessons}/{study.totalLessons} lessons completed</span>
|
||||
<span style={{ color: '#7a7060', fontSize: '0.9rem' }}>{study.noteCount} notes</span>
|
||||
</div>
|
||||
<div style={{ marginTop: '0.75rem', height: '10px', width: '100%', background: '#27231b', borderRadius: '999px', overflow: 'hidden' }}>
|
||||
<div style={{ width: `${progress}%`, height: '100%', background: '#e0c070' }} />
|
||||
<div className="study-progress-track" role="progressbar" aria-valuemin={0} aria-valuemax={100} aria-valuenow={progress} style={{ marginTop: '0.75rem' }}>
|
||||
<div className="study-progress-fill" style={{ width: `${progress}%` }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="study-module-row-right" style={{ display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
|
||||
@@ -942,6 +942,54 @@ export function StudyLandingPage({ content }: Props) {
|
||||
)
|
||||
}
|
||||
|
||||
const availableCount = activeStudies.length + completeStudies.length
|
||||
|
||||
const renderTrackCard = (study: StudyProgram, variant: 'active' | 'complete' | 'planned') => {
|
||||
const releasedCount = study.sections.filter(isSectionReleased).length
|
||||
const nextLabel = getNextReleaseLabel(study)
|
||||
const book = variant === 'complete' ? (content.finishedBooks ?? []).find(item => item.studySlug === study.slug) : undefined
|
||||
const body = (
|
||||
<>
|
||||
<div className="study-track-top">
|
||||
<span className={`study-track-status study-track-status--${variant}`}>
|
||||
{variant === 'active' ? 'In progress · start anytime' : variant === 'complete' ? 'Complete · self-paced' : 'Coming soon'}
|
||||
</span>
|
||||
{study.difficulty && <span className={`study-difficulty study-difficulty--${study.difficulty}`}>{study.difficulty}</span>}
|
||||
</div>
|
||||
<h3 className="study-track-title">{study.title}</h3>
|
||||
<p className="study-track-desc">{study.description}</p>
|
||||
<ul className="study-track-facts">
|
||||
{variant === 'planned' ? (
|
||||
<li>
|
||||
{study.startsAt && new Date(study.startsAt).getTime() > Date.now()
|
||||
? `Starts ${new Date(study.startsAt).toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric' })}`
|
||||
: 'Preparing lesson structure and media'}
|
||||
</li>
|
||||
) : (
|
||||
<>
|
||||
<li>{variant === 'complete' ? `All ${study.sections.length} lessons available` : releasedCount > 0 ? `${releasedCount} of ${study.sections.length} lessons available` : 'Lessons will be published soon'}</li>
|
||||
{variant === 'active' && nextLabel && <li>Next lesson: {nextLabel}</li>}
|
||||
{study.estimatedHours ? <li>About {study.estimatedHours} hours</li> : null}
|
||||
</>
|
||||
)}
|
||||
</ul>
|
||||
{variant !== 'planned' && <span className="study-track-cta">View lessons →</span>}
|
||||
</>
|
||||
)
|
||||
return (
|
||||
<div className="study-track-wrap" key={study.id}>
|
||||
{variant === 'planned'
|
||||
? <article className="study-track-card study-track-card--planned" aria-disabled="true">{body}</article>
|
||||
: <Link to={`/study/${study.slug}`} className="study-track-card">{body}</Link>}
|
||||
{book && (
|
||||
<p className="study-track-listen">
|
||||
Just want to listen? <Link to={`/finished/${book.id}`}>Open the audio playlist — no account needed →</Link>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="study-index-page" aria-label="Study hub">
|
||||
<section className="section-study-course-hero">
|
||||
@@ -950,16 +998,22 @@ export function StudyLandingPage({ content }: Props) {
|
||||
<h1>Study at Your Own Pace</h1>
|
||||
<p className="study-course-hero-copy">Pick a study track, move lesson by lesson on your own schedule, and keep personal notes as you grow through each passage.</p>
|
||||
<div className="study-course-meta">
|
||||
<span>{activeStudies.length + completeStudies.length} {activeStudies.length + completeStudies.length === 1 ? 'study' : 'studies'} available{completeStudies.length > 0 ? ` (${completeStudies.length} finished, start anytime)` : ''}{plannedStudies.length > 0 ? ` · ${plannedStudies.length} coming soon` : ''}</span>
|
||||
<span>Self-paced flow</span>
|
||||
<span>Self-paced</span>
|
||||
<span>Personal notes</span>
|
||||
<span>Audio + commentary</span>
|
||||
<span>Free account</span>
|
||||
</div>
|
||||
<div className="study-course-hero-actions">
|
||||
{firstActiveStudyFirstReleasedSection && <Link to={`/study/${firstActiveStudy.slug}/${firstActiveStudyFirstReleasedSection.id}`} className="btn-primary">Start Learning</Link>}
|
||||
<Link to="/study/signup" className="btn-primary">Create Account or Login</Link>
|
||||
<Link to="/study/account" className="btn-secondary">My Account</Link>
|
||||
{firstActiveStudyFirstReleasedSection
|
||||
? <Link to={`/study/${firstActiveStudy.slug}/${firstActiveStudyFirstReleasedSection.id}`} className="btn-primary">Start Learning</Link>
|
||||
: <a href="#study-tracks" className="btn-primary">Browse Studies</a>}
|
||||
<Link to="/study/signup" className="btn-secondary">Create Free Account or Sign In</Link>
|
||||
</div>
|
||||
<p className="study-hub-count">
|
||||
{availableCount} {availableCount === 1 ? 'study' : 'studies'} available
|
||||
{completeStudies.length > 0 ? ` (${completeStudies.length} finished, start anytime)` : ''}
|
||||
{plannedStudies.length > 0 ? ` · ${plannedStudies.length} coming soon` : ''}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -969,63 +1023,33 @@ export function StudyLandingPage({ content }: Props) {
|
||||
<p>How It Works</p>
|
||||
<h2>A Simple Self-Paced Rhythm</h2>
|
||||
</div>
|
||||
<div className="study-hub-flow-grid">
|
||||
<article className="study-hub-flow-card">
|
||||
<p className="study-module-lesson">Step 1</p>
|
||||
<h3>Choose Your Track</h3>
|
||||
<p>Start with any active study and begin at lesson one, or jump back in where you left off.</p>
|
||||
</article>
|
||||
<article className="study-hub-flow-card">
|
||||
<p className="study-module-lesson">Step 2</p>
|
||||
<h3>Work Each Lesson</h3>
|
||||
<p>Read the text, listen to audio, review commentary, and process key Greek word notes.</p>
|
||||
</article>
|
||||
<article className="study-hub-flow-card">
|
||||
<p className="study-module-lesson">Step 3</p>
|
||||
<h3>Save Notes and Continue</h3>
|
||||
<p>Keep personal notes per lesson and build your own study archive over time.</p>
|
||||
</article>
|
||||
</div>
|
||||
<ol className="study-hub-steps">
|
||||
{[
|
||||
{ title: 'Choose Your Track', body: 'Start with any active study and begin at lesson one, or jump back in where you left off.' },
|
||||
{ title: 'Work Each Lesson', body: 'Read the text, listen to audio, review commentary, and process key Greek word notes.' },
|
||||
{ title: 'Save Notes and Continue', body: 'Keep personal notes per lesson and build your own study archive over time.' },
|
||||
].map((step, index) => (
|
||||
<li className="study-hub-step" key={step.title}>
|
||||
<span className="study-hub-step-number" aria-hidden="true">{index + 1}</span>
|
||||
<h3>{step.title}</h3>
|
||||
<p>{step.body}</p>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="study-tracks" className="section-study-module" aria-label="Available studies">
|
||||
<div className="section-inner">
|
||||
<div className="study-module-header">
|
||||
<p>Available Now</p>
|
||||
<h2>Current Study Tracks</h2>
|
||||
{activeStudies.length > 0 && (
|
||||
<section id="study-tracks" className="section-study-module" aria-label="Available studies">
|
||||
<div className="section-inner">
|
||||
<div className="study-module-header">
|
||||
<p>Available Now</p>
|
||||
<h2>Current Study Tracks</h2>
|
||||
</div>
|
||||
<div className="study-track-grid">{activeStudies.map(study => renderTrackCard(study, 'active'))}</div>
|
||||
</div>
|
||||
<div className="study-module-list">
|
||||
{activeStudies.map(study => (
|
||||
(() => {
|
||||
const releasedCount = study.sections.filter(isSectionReleased).length
|
||||
return (
|
||||
<Link key={study.id} to={`/study/${study.slug}`} className="study-module-row">
|
||||
<div className="study-module-row-left">
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', marginBottom: '0.5rem', flexWrap: 'wrap' }}>
|
||||
<p className="study-module-lesson">Start Anytime</p>
|
||||
{study.difficulty && <span style={{ backgroundColor: study.difficulty === 'advanced' ? '#d32f2f' : (study.difficulty === 'intermediate' ? '#f57c00' : '#388e3c'), color: '#fff', padding: '0.25rem 0.75rem', borderRadius: '16px', fontSize: '0.75rem', fontWeight: '600', textTransform: 'capitalize' }}>{study.difficulty}</span>}
|
||||
</div>
|
||||
<h3>{study.title}</h3>
|
||||
<p>{study.description}</p>
|
||||
{study.estimatedHours && <p style={{ fontSize: '0.875rem', color: '#666', marginTop: '0.5rem' }}>⏱ {study.estimatedHours} hours</p>}
|
||||
</div>
|
||||
<div className="study-module-row-right">
|
||||
<p className="study-module-focus">Track Snapshot</p>
|
||||
<p>{releasedCount > 0 ? `${releasedCount} lessons available now` : 'Lessons will be published soon.'}</p>
|
||||
<p>{(() => {
|
||||
const next = getNextReleaseLabel(study)
|
||||
if (next) return `Next lesson: ${next}`
|
||||
return study.sections.length > 0 ? 'New lessons release on a regular schedule.' : 'Pacing details coming with first lesson release.'
|
||||
})()}</p>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
})()
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{completeStudies.length > 0 && (
|
||||
<section className="section-study-module" aria-label="Finished studies" id="finished-studies">
|
||||
@@ -1034,32 +1058,7 @@ export function StudyLandingPage({ content }: Props) {
|
||||
<p>Study On Your Own Time</p>
|
||||
<h2>Finished Studies</h2>
|
||||
</div>
|
||||
<div className="study-module-list">
|
||||
{completeStudies.map(study => {
|
||||
const book = (content.finishedBooks ?? []).find(item => item.studySlug === study.slug)
|
||||
return (
|
||||
<div key={study.id}>
|
||||
<Link to={`/study/${study.slug}`} className="study-module-row">
|
||||
<div className="study-module-row-left">
|
||||
<p className="study-module-lesson">Complete · Start Anytime</p>
|
||||
<h3>{study.title}</h3>
|
||||
<p>{study.description}</p>
|
||||
</div>
|
||||
<div className="study-module-row-right">
|
||||
<p className="study-module-focus">Self-Paced</p>
|
||||
<p>All {study.sections.length} lessons available now</p>
|
||||
<p>No schedule — go as fast or slow as you like.</p>
|
||||
</div>
|
||||
</Link>
|
||||
{book && (
|
||||
<p style={{ margin: '0.4rem 0 0', fontSize: '0.9rem' }}>
|
||||
Just want to listen? <Link to={`/finished/${book.id}`}>Open the audio playlist — no account needed →</Link>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div className="study-track-grid">{completeStudies.map(study => renderTrackCard(study, 'complete'))}</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
@@ -1071,41 +1070,24 @@ export function StudyLandingPage({ content }: Props) {
|
||||
<p>Coming Soon</p>
|
||||
<h2>Next Study Tracks</h2>
|
||||
</div>
|
||||
<div className="study-module-list">
|
||||
{plannedStudies.map(study => (
|
||||
<article key={study.id} className="study-module-row study-module-row--disabled" aria-disabled="true">
|
||||
<div className="study-module-row-left">
|
||||
<p className="study-module-lesson">Planned</p>
|
||||
<h3>{study.title}</h3>
|
||||
<p>{study.description}</p>
|
||||
</div>
|
||||
<div className="study-module-row-right">
|
||||
<p className="study-module-focus">Status</p>
|
||||
<p>{study.startsAt && new Date(study.startsAt).getTime() > Date.now()
|
||||
? `Starts ${new Date(study.startsAt).toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric' })}`
|
||||
: 'Preparing lesson structure and media.'}</p>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
<div className="study-track-grid">{plannedStudies.map(study => renderTrackCard(study, 'planned'))}</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
<section className="section-study-module" aria-label="Q&A">
|
||||
<div className="section-inner" style={{ textAlign: 'center', padding: '3rem 1rem' }}>
|
||||
<p className="eyebrow">Have a question from the Word?</p>
|
||||
<h2 style={{ fontSize: '1.5rem', fontWeight: 700, margin: '0.5rem 0 0.75rem', color: '#f0e9cc' }}>Ask Nate a Question</h2>
|
||||
<p style={{ color: '#8a7f5a', maxWidth: '480px', margin: '0 auto 1.5rem', fontSize: '0.95rem' }}>
|
||||
Submit a Bible or theology question and it may be answered in a future episode or the Q&A archive.
|
||||
</p>
|
||||
<div style={{ display: 'flex', gap: '0.75rem', justifyContent: 'center', flexWrap: 'wrap' }}>
|
||||
<a href="/questions" className="btn-primary">Browse Q&A Archive →</a>
|
||||
<a href="/contact" className="btn-secondary">Submit a Question</a>
|
||||
<div className="section-inner">
|
||||
<div className="study-hub-ask">
|
||||
<p className="eyebrow">Have a question from the Word?</p>
|
||||
<h2>Ask Nate a Question</h2>
|
||||
<p>Submit a Bible or theology question and it may be answered in a future episode or the Q&A archive.</p>
|
||||
<div className="study-hub-ask-actions">
|
||||
<Link to="/questions" className="btn-primary">Browse Q&A Archive →</Link>
|
||||
<Link to="/contact" className="btn-secondary">Submit a Question</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user