Files
nuc/whyrating-templates/src/components/templates/CTATemplateSquare.tsx
Alejandro Gutiérrez ea5775da25 Add WhyRating Templates - brand identity system
Next.js app showcasing WhyRating brand guidelines with interactive
tabs for colors, typography, proportions, logos, voice, downloads,
and AI context. Includes email templates (headers, signatures, CTAs)
and presentation component.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 15:17:42 +01:00

127 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useState } from 'react';
import { WhyMyRatingLogo, PreviewScaler } from '@/components';
export function CTATemplateSquare() {
const [hook, setHook] = useState('Still reading reviews one by one?');
const [valueProp, setValueProp] = useState('Get AI-powered insights in 45 seconds');
const [ctaText, setCtaText] = useState('Try it free at whyrating.com');
const [isDownloading, setIsDownloading] = useState(false);
const downloadPng = async () => {
setIsDownloading(true);
try {
const response = await fetch('/api/screenshot', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
template: 'cta-square',
params: { hook, valueProp, ctaText }
}),
});
if (!response.ok) throw new Error('Screenshot failed');
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.download = `whyrating-cta-square-${Date.now()}.png`;
link.href = url;
link.click();
URL.revokeObjectURL(url);
} catch (error) {
console.error('Download failed:', error);
alert('Download failed. Please try again.');
} finally {
setIsDownloading(false);
}
};
return (
<div className="bg-white dark:bg-stone-900 rounded-xl border border-slate-100 shadow-sm dark:border-stone-700 p-6">
<div className="flex items-center justify-between mb-4">
<div>
<h3 className="text-lg font-semibold text-slate-900 dark:text-stone-50">CTA Post (Square)</h3>
<p className="text-sm text-slate-500 dark:text-stone-500">1080 × 1080px Instagram, Facebook</p>
</div>
<button
onClick={downloadPng}
disabled={isDownloading}
className="px-4 py-2 bg-[var(--ui-primary)] text-white rounded-lg text-sm font-medium hover:bg-[var(--ui-primary-hover)] transition-colors disabled:opacity-50"
>
{isDownloading ? 'Generating...' : 'Download PNG'}
</button>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Preview */}
<PreviewScaler width={540} height={540}>
<div
className="rounded-xl p-12 flex flex-col justify-between relative overflow-hidden bg-gradient-to-br from-slate-800 to-slate-900"
style={{ width: '540px', height: '540px' }}
>
{/* Decorative stars */}
<div className="absolute top-8 right-8 text-[#FBBC05] text-4xl opacity-20"></div>
<div className="absolute bottom-32 left-10 text-[#FBBC05] text-2xl opacity-15"></div>
{/* Hook */}
<div className="pt-4">
<div className="text-white text-3xl font-bold leading-tight max-w-md">{hook}</div>
</div>
{/* Value Prop */}
<div className="flex-1 flex items-center justify-center">
<div className="text-white text-2xl font-medium leading-snug text-center max-w-lg">{valueProp}</div>
</div>
{/* CTA */}
<div className="pb-4">
<div className="bg-[#F59E0B] text-slate-900 text-xl font-bold px-6 py-4 rounded-xl text-center mb-6">
{ctaText}
</div>
<div className="flex justify-center">
<WhyMyRatingLogo size={100} variant="horizontal-v2" colorScheme="dark" />
</div>
</div>
</div>
</PreviewScaler>
{/* Editor */}
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-slate-700 dark:text-stone-300 mb-1">Hook Question</label>
<textarea
value={hook}
onChange={(e) => setHook(e.target.value)}
rows={2}
className="w-full px-3 py-2 border border-slate-300 dark:border-stone-600 rounded-lg bg-white dark:bg-stone-800 text-slate-900 dark:text-stone-50 focus:ring-2 focus:ring-[var(--ui-primary)] focus:border-transparent resize-none"
placeholder="Still reading reviews one by one?"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 dark:text-stone-300 mb-1">Value Proposition</label>
<textarea
value={valueProp}
onChange={(e) => setValueProp(e.target.value)}
rows={3}
className="w-full px-3 py-2 border border-slate-300 dark:border-stone-600 rounded-lg bg-white dark:bg-stone-800 text-slate-900 dark:text-stone-50 focus:ring-2 focus:ring-[var(--ui-primary)] focus:border-transparent resize-none"
placeholder="Get AI-powered insights in 45 seconds"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 dark:text-stone-300 mb-1">Call to Action</label>
<input
type="text"
value={ctaText}
onChange={(e) => setCtaText(e.target.value)}
className="w-full px-3 py-2 border border-slate-300 dark:border-stone-600 rounded-lg bg-white dark:bg-stone-800 text-slate-900 dark:text-stone-50 focus:ring-2 focus:ring-[var(--ui-primary)] focus:border-transparent"
placeholder="Try it free at whyrating.com"
/>
</div>
</div>
</div>
</div>
);
}