Make homepage study card admin-editable with NEW tag controls

This commit is contained in:
nmemmert
2026-05-12 12:47:13 -04:00
parent 853e56bd91
commit affd903f40
13 changed files with 3701 additions and 18 deletions
+49
View File
@@ -225,6 +225,53 @@ function sanitizeArchivedSeriesNotes(value) {
.filter(item => item.heading || item.body)
}
function sanitizeColossiansStudySections(value) {
const source = Array.isArray(value) ? value : []
return source
.filter(item => item && typeof item === 'object')
.map(item => ({
id: typeof item.id === 'string' && item.id.trim() ? item.id.trim() : randomUUID(),
chapter: Number.isInteger(item.chapter) && item.chapter >= 1 && item.chapter <= 999 ? item.chapter : 1,
reference: typeof item.reference === 'string' ? item.reference.trim().slice(0, 40) : '',
title: typeof item.title === 'string' ? item.title.trim().slice(0, 160) : '',
audioEmbedUrl: sanitizeUrl(item.audioEmbedUrl),
passageText: typeof item.passageText === 'string' ? item.passageText.trim().slice(0, 12000) : '',
summary: typeof item.summary === 'string' ? item.summary.trim().slice(0, 600) : '',
commentary: typeof item.commentary === 'string' ? item.commentary.trim().slice(0, 12000) : '',
greekNotes: Array.isArray(item.greekNotes)
? item.greekNotes.filter(note => typeof note === 'string').map(note => note.trim()).filter(Boolean).slice(0, 20)
: [],
studyQuestions: Array.isArray(item.studyQuestions)
? item.studyQuestions.filter(question => typeof question === 'string').map(question => question.trim()).filter(Boolean).slice(0, 20)
: [],
...(typeof item.releasedAt === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/.test(item.releasedAt) ? { releasedAt: item.releasedAt } : {}),
}))
.filter(item => item.title || item.summary || item.commentary || item.greekNotes.length > 0 || item.studyQuestions.length > 0 || item.passageText)
}
function sanitizeStudies(value) {
const source = Array.isArray(value) ? value : []
return source
.filter(item => item && typeof item === 'object')
.map(item => ({
id: typeof item.id === 'string' && item.id.trim() ? item.id.trim() : randomUUID(),
slug: typeof item.slug === 'string' ? item.slug.trim().toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '') : '',
title: typeof item.title === 'string' ? item.title.trim().slice(0, 160) : '',
description: typeof item.description === 'string' ? item.description.trim().slice(0, 800) : '',
homepageEyebrow: typeof item.homepageEyebrow === 'string' ? item.homepageEyebrow.trim().slice(0, 80) : '',
showOnHomepage: item.showOnHomepage === true,
showNewTag: item.showNewTag === true,
newTagLabel: typeof item.newTagLabel === 'string' ? item.newTagLabel.trim().slice(0, 24) : '',
status: item.status === 'planned' ? 'planned' : 'active',
difficulty: item.difficulty === 'advanced' ? 'advanced' : (item.difficulty === 'intermediate' ? 'intermediate' : 'beginner'),
estimatedHours: Number.isFinite(Number(item.estimatedHours)) ? Math.max(1, Math.min(500, Number(item.estimatedHours))) : 8,
completionBadge: typeof item.completionBadge === 'string' ? item.completionBadge.trim().slice(0, 120) : '',
numberOfChapters: Number.isInteger(item.numberOfChapters) && item.numberOfChapters >= 1 && item.numberOfChapters <= 999 ? item.numberOfChapters : 1,
sections: sanitizeColossiansStudySections(item.sections),
}))
.filter(item => item.slug && item.title)
}
function sanitizeArchivedSeries(value) {
const source = Array.isArray(value) ? value : []
return source
@@ -269,6 +316,8 @@ export function sanitizeSiteContent(siteContent) {
customLinks: sanitizeCustomLinks(siteContent.customLinks),
customBlocks: sanitizeCustomBlocks(siteContent.customBlocks),
archivedSeries: sanitizeArchivedSeries(siteContent.archivedSeries),
studies: sanitizeStudies(siteContent.studies),
colossiansStudySections: sanitizeColossiansStudySections(siteContent.colossiansStudySections),
redirects: sanitizeRedirectRules(siteContent.redirects),
podcastFeaturedLinks: sanitizeFeaturedLinks(siteContent.podcastFeaturedLinks ?? DEFAULT_PODCAST_FEATURED_LINKS),
seo: {