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;