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>
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user