Files
site-builder/craft/src/components/sections/_cta-helpers.tsx
T

89 lines
3.4 KiB
TypeScript
Raw Normal View History

import { CSSProperties } from 'react';
import { escapeHtml, escapeAttr, safeUrl } from '../../utils/escape';
export type CtaVariant = 'primary' | 'outline' | 'ghost';
export interface CtaButton {
text: string;
href: string;
variant?: CtaVariant;
target?: '_blank';
}
export interface CtaStyleDefaults {
primaryBg: string;
primaryText: string;
outlineText: string;
}
/**
* Read the effective list of CTAs for a section, falling back to legacy
* primary/secondary props when ctas[] is absent. New sections write ctas[]
* directly; old sections keep rendering until the user touches the settings.
*/
export function normalizeCtas(props: {
ctas?: CtaButton[];
buttonText?: string;
buttonHref?: string;
secondaryButtonText?: string;
secondaryButtonHref?: string;
}): CtaButton[] {
if (Array.isArray(props.ctas) && props.ctas.length > 0) {
return props.ctas.filter((c) => c && (c.text || c.href));
}
const legacy: CtaButton[] = [];
if (props.buttonText) legacy.push({ text: props.buttonText, href: props.buttonHref || '#', variant: 'primary' });
if (props.secondaryButtonText) legacy.push({ text: props.secondaryButtonText, href: props.secondaryButtonHref || '#', variant: 'outline' });
return legacy;
}
export function ctaInlineStyle(cta: CtaButton, defaults: CtaStyleDefaults): CSSProperties {
const variant = cta.variant || 'primary';
switch (variant) {
case 'outline':
return {
display: 'inline-block', padding: '14px 36px',
backgroundColor: 'transparent', color: defaults.outlineText,
textDecoration: 'none', borderRadius: '8px',
fontWeight: 600, fontSize: '16px',
border: `2px solid ${defaults.outlineText}`,
};
case 'ghost':
return {
display: 'inline-block', padding: '14px 24px',
backgroundColor: 'transparent', color: defaults.outlineText,
textDecoration: 'underline', borderRadius: '8px',
fontWeight: 600, fontSize: '16px',
};
case 'primary':
default:
return {
display: 'inline-block', padding: '14px 36px',
backgroundColor: defaults.primaryBg, color: defaults.primaryText,
textDecoration: 'none', borderRadius: '8px',
fontWeight: 600, fontSize: '16px',
};
}
}
export function ctaCssString(cta: CtaButton, defaults: CtaStyleDefaults): string {
const variant = cta.variant || 'primary';
switch (variant) {
case 'outline':
return `display:inline-block;padding:14px 36px;background-color:transparent;color:${defaults.outlineText};text-decoration:none;border-radius:8px;font-weight:600;font-size:16px;border:2px solid ${defaults.outlineText}`;
case 'ghost':
return `display:inline-block;padding:14px 24px;background-color:transparent;color:${defaults.outlineText};text-decoration:underline;border-radius:8px;font-weight:600;font-size:16px`;
case 'primary':
default:
return `display:inline-block;padding:14px 36px;background-color:${defaults.primaryBg};color:${defaults.primaryText};text-decoration:none;border-radius:8px;font-weight:600;font-size:16px`;
}
}
export function ctasToHtml(ctas: CtaButton[], defaults: CtaStyleDefaults): string {
return ctas.map((c) => {
const target = c.target === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : '';
return `<a href="${escapeAttr(safeUrl(c.href || '#'))}"${target} style="${ctaCssString(c, defaults)}">${escapeHtml(c.text || '')}</a>`;
}).join('');
}