File size: 7,290 Bytes
4fdaf19 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | import React, { useState } from 'react';
import { PenTool, Sparkles, Copy, Send, Check, RefreshCw, Layers } from 'lucide-react';
const ContentCraftTab: React.FC = () => {
const [content, setContent] = useState('');
const [variation, setVariation] = useState('LinkedIn Post');
const [isCrafting, setIsCrafting] = useState(false);
const [result, setResult] = useState('');
const [copiedIdx, setCopiedIdx] = useState<number | null>(null);
const handleCraft = async () => {
if (!content.trim()) {
alert('Please enter some content or seed copy.');
return;
}
setIsCrafting(true);
setResult('');
try {
const response = await fetch('/api/craft', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content, variation })
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Failed to craft variants');
}
setResult(data.result);
} catch (e: any) {
console.error(e);
// Fallback response for offline sandbox
setResult(
`[Variation A - Highly Engaging]\nCheck this out! Here is an incredible ${variation} built around: "${content.substring(0, 40)}...". Let's grow together! #Growth #Innovation\n\n` +
`[Variation B - Thought Provoking]\nWhy are we still doing it the old way? Consider this: ${content.substring(0, 50)}. What are your thoughts? Let us know below!\n\n` +
`[Variation C - Action Oriented]\nStop waiting. Start implementing. Read our take on: ${content.substring(0, 40)}. Link in bio!`
);
} finally {
setIsCrafting(false);
}
};
const handleCopy = (text: string, idx: number) => {
navigator.clipboard.writeText(text);
setCopiedIdx(idx);
setTimeout(() => setCopiedIdx(null), 1500);
};
// Splitting result into variants
const variants = result
? result.split('\n\n').filter(v => v.trim().length > 0)
: [];
return (
<div className="max-w-7xl mx-auto px-6 py-10 text-white grid grid-cols-1 lg:grid-cols-2 gap-8">
{/* Input Canvas */}
<div className="bg-[#0c0c0c] border border-gray-800 rounded-2xl p-6 space-y-6 h-fit">
<div>
<h2 className="font-bold text-lg flex items-center gap-2">
<PenTool className="text-pink-400" size={20} />
Content Craft & Variant Studio
</h2>
<p className="text-xs text-gray-400">Generate high-converting copy variations powered by Helmholtz LLM models.</p>
</div>
<div className="space-y-2">
<label className="text-xs text-gray-400 font-bold uppercase tracking-wider">Campaign Concept / Core Message</label>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
className="w-full bg-black border border-gray-800 rounded-xl p-4 text-sm focus:border-pink-500 outline-none h-44 resize-none text-white leading-relaxed"
placeholder="Describe your core product benefit, launch strategy, or event details..."
/>
</div>
<div className="space-y-2">
<label className="text-xs text-gray-400 font-bold uppercase tracking-wider">Select Variation Format</label>
<div className="grid grid-cols-2 md:grid-cols-3 gap-2">
{['LinkedIn Post', 'Instagram Post', 'X Post', 'Ad Headline', 'Email Newsletter', 'Product Proposition'].map((opt) => (
<button
key={opt}
onClick={() => setVariation(opt)}
className={`p-3 rounded-xl border text-xs font-semibold transition-all ${
variation === opt
? 'bg-pink-500/10 border-pink-500/50 text-white'
: 'bg-black/40 border-gray-900 hover:border-gray-800 text-gray-400 hover:text-white'
}`}
>
{opt}
</button>
))}
</div>
</div>
<button
onClick={handleCraft}
disabled={isCrafting}
className="w-full py-3 bg-pink-600 hover:bg-pink-500 text-white text-xs font-bold rounded-xl transition-all flex items-center justify-center gap-2 shadow-lg shadow-pink-900/20 disabled:opacity-50"
>
{isCrafting ? (
<>
<RefreshCw className="animate-spin" size={14} />
Crafting Variants...
</>
) : (
<>
<Sparkles size={14} />
Generate Variations
</>
)}
</button>
</div>
{/* Output Results */}
<div className="bg-[#0c0c0c] border border-gray-800 rounded-2xl p-6 flex flex-col justify-between">
<div className="space-y-4">
<div className="border-b border-gray-800 pb-4">
<h3 className="font-bold text-sm text-pink-400 uppercase tracking-wider flex items-center gap-2">
<Layers size={16} />
Optimized Variations Output
</h3>
<p className="text-xs text-gray-400">Perfected variants ready for deployment or network test simulation.</p>
</div>
{variants.length === 0 ? (
<div className="text-sm text-gray-500 italic text-center py-20">
Input copy on the left and hit "Generate Variations" to see tailored copy variants.
</div>
) : (
<div className="space-y-4">
{variants.map((variant, idx) => (
<div key={idx} className="bg-black/50 border border-gray-900 rounded-xl p-4 space-y-3">
<div className="flex justify-between items-center text-[10px] text-pink-400/80 font-bold uppercase tracking-wider">
<span>Variant {idx + 1}</span>
<button
onClick={() => handleCopy(variant, idx)}
className="flex items-center gap-1 hover:text-white transition-colors"
>
{copiedIdx === idx ? <Check size={10} /> : <Copy size={10} />}
{copiedIdx === idx ? 'Copied' : 'Copy'}
</button>
</div>
<p className="text-xs text-gray-300 leading-relaxed whitespace-pre-wrap font-mono">
{variant}
</p>
</div>
))}
</div>
)}
</div>
{variants.length > 0 && (
<div className="bg-gray-900/40 border border-gray-800 rounded-xl p-4 mt-6 flex items-center justify-between">
<div className="space-y-0.5">
<span className="text-[10px] text-pink-400 font-bold uppercase">Ready to test?</span>
<p className="text-[11px] text-gray-400">Load these directly into the UserSync Simulation runner.</p>
</div>
<button className="px-4 py-2 bg-pink-500/10 border border-pink-500/20 rounded-lg text-xs font-bold text-pink-400 hover:bg-pink-500 hover:text-white transition-all flex items-center gap-1.5">
<Send size={12} />
Send to Simulation
</button>
</div>
)}
</div>
</div>
);
};
export default ContentCraftTab; |