feat: manage about highlight fallback copy via payload

This commit is contained in:
syntaxbullet
2026-06-22 12:51:51 +02:00
parent 856ab84252
commit 78af786a52
4 changed files with 55 additions and 11 deletions

View File

@@ -134,6 +134,16 @@ export const aboutFields: Field[] = [
textarea('heading', 'Heading', aboutContent.highlights.heading), textarea('heading', 'Heading', aboutContent.highlights.heading),
ctaGroup('cta', 'CTA', aboutContent.highlights.cta.label, aboutContent.highlights.cta.url), ctaGroup('cta', 'CTA', aboutContent.highlights.cta.label, aboutContent.highlights.cta.url),
text('hoverLabel', 'Card hover label', aboutContent.highlights.hoverLabel), text('hoverLabel', 'Card hover label', aboutContent.highlights.hoverLabel),
{
name: 'fallbackWinner',
label: 'Fallback winner text',
type: 'group',
fields: [
text('name', 'Name fallback', aboutContent.highlights.fallbackWinner.name),
text('category', 'Category fallback', aboutContent.highlights.fallbackWinner.category),
text('awardType', 'Award type fallback', aboutContent.highlights.fallbackWinner.awardType),
],
},
{ {
name: 'year', name: 'year',
label: 'Fallback winner year', label: 'Fallback winner year',

View File

@@ -1230,6 +1230,11 @@ export interface Page {
url?: string | null; url?: string | null;
}; };
hoverLabel?: string | null; hoverLabel?: string | null;
fallbackWinner?: {
name?: string | null;
category?: string | null;
awardType?: string | null;
};
year?: number | null; year?: number | null;
/** /**
* Choose up to 8 Preisträger to show. If empty, the frontend falls back to winners from the selected year. * Choose up to 8 Preisträger to show. If empty, the frontend falls back to winners from the selected year.
@@ -4169,6 +4174,13 @@ export interface PagesSelect<T extends boolean = true> {
url?: T; url?: T;
}; };
hoverLabel?: T; hoverLabel?: T;
fallbackWinner?:
| T
| {
name?: T;
category?: T;
awardType?: T;
};
year?: T; year?: T;
selectedWinners?: T; selectedWinners?: T;
}; };

View File

@@ -50,6 +50,11 @@ export const aboutContent = {
cta: { label: 'Alle Preisträger', url: '/preistraeger' }, cta: { label: 'Alle Preisträger', url: '/preistraeger' },
hoverLabel: 'Detail →', hoverLabel: 'Detail →',
year: 2025, year: 2025,
fallbackWinner: {
name: 'Preisträger',
category: 'Preisträger',
awardType: 'Auszeichnung',
},
selectedWinners: [], selectedWinners: [],
}, },
testimonials: testimonialsContent, testimonials: testimonialsContent,

View File

@@ -21,7 +21,11 @@ type AboutCms = Partial<typeof aboutContent> & {
hero?: Partial<typeof aboutContent.hero> & { backgroundImage?: unknown } hero?: Partial<typeof aboutContent.hero> & { backgroundImage?: unknown }
prize?: Partial<typeof aboutContent.prize> & { image?: unknown } prize?: Partial<typeof aboutContent.prize> & { image?: unknown }
mittelstand?: Partial<typeof aboutContent.mittelstand> & { image?: unknown } mittelstand?: Partial<typeof aboutContent.mittelstand> & { image?: unknown }
highlights?: Partial<typeof aboutContent.highlights> & { fallbackImage?: unknown; selectedWinners?: unknown[] | null } highlights?: Partial<typeof aboutContent.highlights> & {
fallbackImage?: unknown
fallbackWinner?: Partial<typeof aboutContent.highlights.fallbackWinner>
selectedWinners?: unknown[] | null
}
} }
type TextRow = { text?: string | null } type TextRow = { text?: string | null }
@@ -63,15 +67,19 @@ function HighlightedText({ text, highlight }: { text: string; highlight: string
) )
} }
const normalizeWinner = (doc: CmsRouteDoc | undefined, fallbackImage: string): Winner | undefined => { const normalizeWinner = (
doc: CmsRouteDoc | undefined,
fallbackImage: string,
fallbackWinner: typeof aboutContent.highlights.fallbackWinner,
): Winner | undefined => {
if (!doc) return undefined if (!doc) return undefined
return { return {
id: String(doc.id), id: String(doc.id),
slug: String(doc.slug || ''), slug: String(doc.slug || ''),
name: String(doc.title || 'Preisträger'), name: String(doc.title || fallbackWinner.name),
category: String(doc.category || 'Preisträger'), category: String(doc.category || fallbackWinner.category),
year: Number(doc.year || aboutContent.highlights.year), year: Number(doc.year || aboutContent.highlights.year),
type: String(doc.awardType || 'Auszeichnung'), type: String(doc.awardType || fallbackWinner.awardType),
img: mediaUrl(doc.image, fallbackImage), img: mediaUrl(doc.image, fallbackImage),
shortDesc: String(doc.shortDesc || doc.description || doc.meta?.description || ''), shortDesc: String(doc.shortDesc || doc.description || doc.meta?.description || ''),
longDesc: String(doc.longDesc || doc.description || doc.meta?.description || ''), longDesc: String(doc.longDesc || doc.description || doc.meta?.description || ''),
@@ -85,10 +93,15 @@ const normalizeWinner = (doc: CmsRouteDoc | undefined, fallbackImage: string): W
} }
} }
const winnerFromRelationship = (entry: unknown, allDocs: CmsRouteDoc[], fallbackImage: string) => { const winnerFromRelationship = (
if (entry && typeof entry === 'object') return normalizeWinner(entry as CmsRouteDoc, fallbackImage) entry: unknown,
allDocs: CmsRouteDoc[],
fallbackImage: string,
fallbackWinner: typeof aboutContent.highlights.fallbackWinner,
) => {
if (entry && typeof entry === 'object') return normalizeWinner(entry as CmsRouteDoc, fallbackImage, fallbackWinner)
const doc = allDocs.find((item) => String(item.id) === String(entry)) const doc = allDocs.find((item) => String(item.id) === String(entry))
return normalizeWinner(doc, fallbackImage) return normalizeWinner(doc, fallbackImage, fallbackWinner)
} }
const About: React.FC = () => { const About: React.FC = () => {
@@ -108,10 +121,14 @@ const About: React.FC = () => {
highlights.fallbackImage, highlights.fallbackImage,
`/images/${aboutContent.highlights.fallbackImageFilename}`, `/images/${aboutContent.highlights.fallbackImageFilename}`,
) )
const highlightFallbackWinner = useMemo(
() => ({ ...aboutContent.highlights.fallbackWinner, ...(highlights.fallbackWinner || {}) }),
[highlights],
)
const highlightWinners = useMemo(() => { const highlightWinners = useMemo(() => {
const selected = fallbackArray<unknown>(highlights.selectedWinners, []) const selected = fallbackArray<unknown>(highlights.selectedWinners, [])
.map((entry) => winnerFromRelationship(entry, cmsWinners, highlightFallbackImage)) .map((entry) => winnerFromRelationship(entry, cmsWinners, highlightFallbackImage, highlightFallbackWinner))
.filter((winner): winner is Winner => Boolean(winner)) .filter((winner): winner is Winner => Boolean(winner))
if (selected.length) return selected.slice(0, 8) if (selected.length) return selected.slice(0, 8)
@@ -120,12 +137,12 @@ const About: React.FC = () => {
Boolean(winner) && winner?.year === Number(highlights.year || aboutContent.highlights.year) Boolean(winner) && winner?.year === Number(highlights.year || aboutContent.highlights.year)
const cmsByYear = cmsWinners const cmsByYear = cmsWinners
.map((winner) => normalizeWinner(winner, highlightFallbackImage)) .map((winner) => normalizeWinner(winner, highlightFallbackImage, highlightFallbackWinner))
.filter(isWinnerFromYear) .filter(isWinnerFromYear)
.slice(0, 8) .slice(0, 8)
return cmsByYear.length ? cmsByYear : FALLBACK_HIGHLIGHTS return cmsByYear.length ? cmsByYear : FALLBACK_HIGHLIGHTS
}, [cmsWinners, highlightFallbackImage, highlights]) }, [cmsWinners, highlightFallbackImage, highlightFallbackWinner, highlights])
return ( return (
<div className="animate-fade-in"> <div className="animate-fade-in">