PromptBuilder
promptbuilder-1779379195873.tsx
'use client'
import { useState } from 'react'
const TEMPLATES = [
{ id: 'role', label: 'System role', color: '#6366f1', content: 'You are a {role} expert who {expertise}.' },
{ id: 'task', label: 'Task', color: '#C9A84C', content: 'Your task is to {action} for {target}.' },
{ id: 'context', label: 'Context', color: '#22c55e', content: 'Context: {context}' },
{ id: 'format', label: 'Output format', color: '#f59e0b', content: 'Respond with {format}. Be {tone}.' },
{ id: 'example', label: 'Example', color: '#ec4899', content: 'Example: {example}' },
]
const VARS: Record<string, string[]> = {
role: ['React developer', 'UX designer', 'technical writer', 'data scientist'],
expertise: ['builds production components', 'creates accessible UIs', 'explains complex concepts'],
action: ['generate a component', 'review the code', 'write documentation', 'debug the issue'],
target: ['a Next.js app', 'a design system', 'enterprise clients', 'beginners'],
context: ['Using React 18 + TypeScript', 'Dark mode first', 'Tailwind CSS v4', 'App Router'],
format: ['TypeScript code', 'a markdown document', 'a JSON object', 'step-by-step instructions'],
tone: ['concise', 'detailed', 'beginner-friendly', 'technical'],
example: ['GlowButton component', 'data fetching pattern', 'form validation'],
}
export default function PromptBuilder() {
const [blocks, setBlocks] = useState<string[]>(['role', 'task'])
const [selections, setSelections] = useState<Record<string, Record<string, string>>>({})
function resolveTemplate(id: string): string {
const tpl = TEMPLATES.find(t => t.id === id)!
return tpl.content.replace(/{(w+)}/g, (_, key) => {
const sel = selections[id]?.[key]
if (sel) return sel
return `{${key}}`
})
}
const fullPrompt = blocks.map(resolveTemplate).join(' ')
const tokens = Math.ceil(fullPrompt.split(' ').length * 1.3)
return (
<div style={{ background: '#0A0A0A', padding: 24, display: 'flex', gap: 20, minHeight: 360 }}>
{/* Builder */}
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 12 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 }}>
<div style={{ color: '#F5F5F0', fontSize: 14, fontWeight: 700 }}>Prompt Builder</div>
<span style={{ color: 'rgba(255,255,255,0.3)', fontSize: 12 }}>~{tokens} tokens</span>
</div>
{blocks.map((id, idx) => {
const tpl = TEMPLATES.find(t => t.id === id)!
const vars = (tpl.content.match(/{(w+)}/g) || []).map(v => v.slice(1, -1))
return (
<div key={`${id}-${idx}`} style={{ background: '#111', border: `1px solid ${tpl.color}25`, borderRadius: 10, padding: 14 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
<span style={{ color: tpl.color, fontSize: 11, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.05em' }}>{tpl.label}</span>
<button onClick={() => setBlocks(b => b.filter((_, i) => i !== idx))} style={{ background: 'none', border: 'none', color: 'rgba(255,255,255,0.25)', cursor: 'pointer', fontSize: 16, padding: 0 }}>×</button>
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
{vars.filter(v => VARS[v]).map(v => (
<select key={v} value={selections[id]?.[v] || ''}
onChange={e => setSelections(s => ({ ...s, [id]: { ...s[id], [v]: e.target.value } }))}
style={{ background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.1)', color: selections[id]?.[v] ? '#F5F5F0' : 'rgba(255,255,255,0.3)', borderRadius: 6, padding: '4px 8px', fontSize: 12, cursor: 'pointer' }}>
<option value="">{v}</option>
{VARS[v].map(opt => <option key={opt} value={opt}>{opt}</option>)}
</select>
))}
</div>
</div>
)
})}
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
{TEMPLATES.filter(t => !blocks.includes(t.id)).map(tpl => (
<button key={tpl.id} onClick={() => setBlocks(b => [...b, tpl.id])} style={{ background: tpl.color + '12', border: `1px solid ${tpl.color}25`, color: tpl.color, borderRadius: 6, padding: '4px 10px', cursor: 'pointer', fontSize: 12 }}>+ {tpl.label}</button>
))}
</div>
</div>
{/* Preview */}
<div style={{ width: 220, display: 'flex', flexDirection: 'column', gap: 10 }}>
<div style={{ color: '#F5F5F0', fontSize: 14, fontWeight: 700, marginBottom: 4 }}>Preview</div>
<div style={{ flex: 1, background: '#111', border: '1px solid rgba(255,255,255,0.06)', borderRadius: 10, padding: 14, fontSize: 12, color: 'rgba(255,255,255,0.6)', lineHeight: 1.7, wordBreak: 'break-word' }}>
{fullPrompt || <span style={{ color: 'rgba(255,255,255,0.2)' }}>Add blocks to build your prompt</span>}
</div>
<button onClick={() => navigator.clipboard.writeText(fullPrompt)} style={{ background: '#C9A84C', color: '#0A0A0A', border: 'none', borderRadius: 8, padding: '9px', fontWeight: 700, cursor: 'pointer', fontSize: 13 }}>Copy prompt</button>
</div>
</div>
)
}Component info
CategoryAI-Specific
Frameworkreact
TierFREE
Views0
Copies0
About
Visual prompt builder with template blocks, variable injection, token counter, and copy output
More from AI-Specific
import React, { useState, useEffect } from 'react';
interface ChatBubbleProps {
message: string;
isAI: boolean;
}
const ChatBubble: React.FC<ChatBubbleProps> = ({ message, isAI }) => {
const [isTyping, setIsTyping] = useState(false);
const ChatBubble
AI-Specific
import React, { useState, useEffect } from 'react';
interface Props {
text: string;
speed: number;
}
const StreamingText: React.FC<Props> = ({ text, speed }) => {
const [displayedText, setDisplayedText] = useState('');
const [tokens, setTokStreamingText
AI-Specific
'use client'
import { useState, useRef, useEffect } from 'react'
interface Msg { id: number; role: 'user' | 'assistant'; content: string; streaming?: boolean }
const RESPONSES = [
"Here's a React component for you:
```tsx
export default function ChatInterface
AI-Specific