Add Active/Planned status badges, dim planned studies, sort active first in track lists; v2.8.4
Publish Container / build (push) Successful in 16m49s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-07 14:57:53 -04:00
1 parent db1737baf3
commit cd40ecc207
3 files changed
+25 -9

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "siteforge", "name": "siteforge",
"private": true, "private": true,
"version": "2.8.3", "version": "2.8.4",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
+12
View File
@@ -13110,3 +13110,15 @@
font-size: 0.8rem; font-size: 0.8rem;
color: #e0c070; color: #e0c070;
} }
.study-status-badge {
display: inline-block;
padding: 0.15rem 0.6rem;
border-radius: 999px;
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.study-status-badge.active { background: rgba(201, 168, 76, 0.18); color: #c9a84c; border: 1px solid rgba(201, 168, 76, 0.45); }
.study-status-badge.planned { background: rgba(255, 255, 255, 0.05); color: #9a9486; border: 1px solid rgba(255, 255, 255, 0.15); }
+12 -8
View File
@@ -107,6 +107,10 @@ type StudyCommunityPost = {
pending?: boolean pending?: boolean
} }
function StudyStatusBadge({ status }: { status: 'active' | 'planned' }) {
return <span className={`study-status-badge ${status}`}>{status === 'active' ? 'Active' : 'Planned'}</span>
}
function getLegacyColossiansStudy(content: SiteContent): StudyProgram { function getLegacyColossiansStudy(content: SiteContent): StudyProgram {
const legacySections = content.colossiansStudySections?.length ? content.colossiansStudySections : DEFAULT_COLOSSIANS_STUDY_SECTIONS const legacySections = content.colossiansStudySections?.length ? content.colossiansStudySections : DEFAULT_COLOSSIANS_STUDY_SECTIONS
return { return {
@@ -678,7 +682,7 @@ export function StudyLandingPage({ content }: Props) {
}, []) }, [])
const enrolledStudies = overview?.studies.filter(study => study.enrolled) ?? [] const enrolledStudies = overview?.studies.filter(study => study.enrolled) ?? []
const availableStudies = overview?.studies ?? [] const availableStudies = [...(overview?.studies ?? [])].sort((a, b) => Number(b.status === 'active') - Number(a.status === 'active'))
const totalEnrolled = enrolledStudies.length const totalEnrolled = enrolledStudies.length
const totalCompletedLessons = enrolledStudies.reduce((sum, study) => sum + study.completedLessons, 0) const totalCompletedLessons = enrolledStudies.reduce((sum, study) => sum + study.completedLessons, 0)
const totalLessons = enrolledStudies.reduce((sum, study) => sum + study.totalLessons, 0) const totalLessons = enrolledStudies.reduce((sum, study) => sum + study.totalLessons, 0)
@@ -750,7 +754,7 @@ export function StudyLandingPage({ content }: Props) {
<div key={studyInfo.slug} style={{ padding: '1rem', borderRadius: '12px', background: '#14130f', border: '1px solid #2a2518' }}> <div key={studyInfo.slug} style={{ padding: '1rem', borderRadius: '12px', background: '#14130f', border: '1px solid #2a2518' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem', alignItems: 'flex-start' }}> <div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem', alignItems: 'flex-start' }}>
<div> <div>
<p style={{ margin: 0, fontSize: '0.9rem', color: '#b09e79' }}>{studyInfo.status === 'active' ? 'Active study' : 'Planned study'}</p> <StudyStatusBadge status={studyInfo.status} />
<h3 style={{ margin: '0.35rem 0 0' }}>{studyInfo.title}</h3> <h3 style={{ margin: '0.35rem 0 0' }}>{studyInfo.title}</h3>
<p style={{ margin: '0.4rem 0 0', fontSize: '0.9rem' }}>{studyInfo.completedLessons}/{studyInfo.totalLessons} lessons completed · {studyInfo.noteCount} notes</p> <p style={{ margin: '0.4rem 0 0', fontSize: '0.9rem' }}>{studyInfo.completedLessons}/{studyInfo.totalLessons} lessons completed · {studyInfo.noteCount} notes</p>
</div> </div>
@@ -788,12 +792,12 @@ export function StudyLandingPage({ content }: Props) {
) : ( ) : (
<div style={{ display: 'grid', gap: '1rem' }}> <div style={{ display: 'grid', gap: '1rem' }}>
{availableStudies.map(studyInfo => ( {availableStudies.map(studyInfo => (
<div key={studyInfo.slug} style={{ padding: '1rem', borderRadius: '12px', background: '#14130f', border: '1px solid #2a2518' }}> <div key={studyInfo.slug} style={{ padding: '1rem', borderRadius: '12px', background: '#14130f', border: '1px solid #2a2518', opacity: !studyInfo.enrolled && studyInfo.status === 'planned' ? 0.7 : 1 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem', alignItems: 'flex-start' }}> <div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem', alignItems: 'flex-start' }}>
<div> <div>
<p style={{ margin: 0, fontSize: '0.9rem', color: '#b09e79' }}>{studyInfo.status === 'active' ? 'Active study' : 'Planned study'}</p> <StudyStatusBadge status={studyInfo.status} />
<h3 style={{ margin: '0.35rem 0 0' }}>{studyInfo.title}</h3> <h3 style={{ margin: '0.35rem 0 0' }}>{studyInfo.title}</h3>
<p style={{ margin: '0.4rem 0 0', fontSize: '0.9rem' }}>{studyInfo.completedLessons}/{studyInfo.totalLessons} lessons completed · {studyInfo.noteCount} notes</p> {!studyInfo.enrolled && studyInfo.status === 'planned' ? <p style={{ margin: '0.4rem 0 0', fontSize: '0.9rem', color: '#b09e79' }}>Not open for enrollment yet</p> : <p style={{ margin: '0.4rem 0 0', fontSize: '0.9rem' }}>{studyInfo.completedLessons}/{studyInfo.totalLessons} lessons completed · {studyInfo.noteCount} notes</p>}
</div> </div>
{studyInfo.enrolled && confirmLeaveSlug === studyInfo.slug ? ( {studyInfo.enrolled && confirmLeaveSlug === studyInfo.slug ? (
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center', flexWrap: 'wrap' }}> <div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center', flexWrap: 'wrap' }}>
@@ -3279,12 +3283,12 @@ export function StudyAccountPage() {
) : overview?.studies?.length ? ( ) : overview?.studies?.length ? (
<div style={{ display: 'grid', gap: '1rem' }}> <div style={{ display: 'grid', gap: '1rem' }}>
{overview.studies.map(studyInfo => ( {overview.studies.map(studyInfo => (
<div key={studyInfo.slug} style={{ padding: '1rem', borderRadius: '12px', background: '#14130f', border: '1px solid #2a2518' }}> <div key={studyInfo.slug} style={{ padding: '1rem', borderRadius: '12px', background: '#14130f', border: '1px solid #2a2518', opacity: !studyInfo.enrolled && studyInfo.status === 'planned' ? 0.7 : 1 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem', alignItems: 'flex-start' }}> <div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem', alignItems: 'flex-start' }}>
<div> <div>
<p style={{ margin: 0, fontSize: '0.9rem', color: '#b09e79' }}>{studyInfo.status === 'active' ? 'Active study' : 'Planned study'}</p> <StudyStatusBadge status={studyInfo.status} />
<h3 style={{ margin: '0.35rem 0 0' }}>{studyInfo.title}</h3> <h3 style={{ margin: '0.35rem 0 0' }}>{studyInfo.title}</h3>
<p style={{ margin: '0.4rem 0 0', fontSize: '0.9rem' }}>{studyInfo.completedLessons} of {studyInfo.totalLessons} lessons completed · {studyInfo.noteCount} notes</p> {!studyInfo.enrolled && studyInfo.status === 'planned' ? <p style={{ margin: '0.4rem 0 0', fontSize: '0.9rem', color: '#b09e79' }}>Not open for enrollment yet</p> : <p style={{ margin: '0.4rem 0 0', fontSize: '0.9rem' }}>{studyInfo.completedLessons} of {studyInfo.totalLessons} lessons completed · {studyInfo.noteCount} notes</p>}
</div> </div>
{!studyInfo.enrolled && studyInfo.status === 'planned' ? ( {!studyInfo.enrolled && studyInfo.status === 'planned' ? (
<span style={{ fontSize: '0.85rem', color: '#b09e79' }}>Coming soon</span> <span style={{ fontSize: '0.85rem', color: '#b09e79' }}>Coming soon</span>