import React, { useState } from 'react';
const SCENARIOS = {
dropdown: {
title: "Custom UI Select Dropdown",
juniorPrompt: "Build a custom React dropdown select component.",
juniorCode: `import React, { useState } from 'react';
// ⚠️ Basic custom dropdown
export default function Dropdown() {
const [open, setOpen] = useState(false);
const [selected, setSelected] = useState('Select Option');
const options = ['Option 1', 'Option 2', 'Option 3'];
return (
<div className="relative">
<div
onClick={() => setOpen(!open)}
className="p-3 bg-slate-800 border rounded cursor-pointer"
>
{selected}
</div>
{open && (
<div className="absolute top-12 left-0 w-full bg-slate-800 border rounded">
{options.map(opt => (
<div
key={opt}
onClick={() => { setSelected(opt); setOpen(false); }}
className="p-3 hover:bg-slate-700 cursor-pointer"
>
{opt}
</div>
))}
</div>
)}
</div>
);
}`,
seniorPrompt: "Write an accessible, keyboard-navigable custom dropdown component. Use native button and list elements, implement role='listbox', and support arrow key selection and Escape to close.",
seniorCode: `import React, { useState, useRef, useEffect } from 'react';
// 🛡️ Accessible keyboard-navigable dropdown
export default function Dropdown() {
const [open, setOpen] = useState(false);
const [selected, setSelected] = useState('Option 1');
const [focusedIndex, setFocusedIndex] = useState(-1);
const options = ['Option 1', 'Option 2', 'Option 3'];
const containerRef = useRef(null);
useEffect(() => {
function handleClickOutside(event) {
if (containerRef.current && !containerRef.current.contains(event.target)) {
setOpen(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
const handleKeyDown = (e) => {
if (e.key === 'Escape') setOpen(false);
if (e.key === 'ArrowDown') {
e.preventDefault();
setFocusedIndex(prev => (prev + 1) % options.length);
}
if (e.key === 'ArrowUp') {
e.preventDefault();
setFocusedIndex(prev => (prev - 1 + options.length) % options.length);
}
if (e.key === 'Enter' && focusedIndex >= 0) {
e.preventDefault();
setSelected(options[focusedIndex]);
setOpen(false);
}
};
return (
<div ref={containerRef} onKeyDown={handleKeyDown} className="relative w-64">
<button
aria-haspopup="listbox"
aria-expanded={open}
onClick={() => setOpen(!open)}
className="w-full p-3 bg-slate-800 border border-slate-700 rounded-xl text-left flex justify-between items-center focus:ring-2 focus:ring-cyan-500 outline-none"
>
<span>{selected}</span>
<span>{open ? '▲' : '▼'}</span>
</button>
{open && (
<ul
role="listbox"
aria-label="Options list"
className="absolute top-14 left-0 w-full bg-slate-800 border border-slate-700 rounded-xl overflow-hidden shadow-2xl z-10"
>
{options.map((opt, idx) => (
<li
key={opt}
role="option"
aria-selected={selected === opt}
onClick={() => { setSelected(opt); setOpen(false); }}
className={`p-3 cursor-pointer text-sm transition-colors ${
selected === opt ? 'bg-cyan-600/30 text-cyan-400 font-bold' : ''
} ${focusedIndex === idx ? 'bg-slate-700 text-white font-bold' : 'text-slate-300 hover:bg-slate-700/50'}`}
>
{opt}
</li>
))}
</ul>
)}
</div>
);
}`,
metrics: {
junior: { a11y: "15%", perf: "60%", security: "90%" },
senior: { a11y: "100%", perf: "95%", security: "98%" }
}
},
debounce: {
title: "Search Auto-complete Field",
juniorPrompt: "Create a React search input that queries an API on change.",
juniorCode: `import React, { useState } from 'react';
// ⚠️ No debouncing search input
export default function Search() {
const [val, setVal] = useState('');
const handleChange = (e) => {
setVal(e.target.value);
// Fires API on every single keystroke!
fetch(`/api/search?q=${e.target.value}`);
};
return (
<input
type="text"
value={val}
onChange={handleChange}
placeholder="Type to search..."
className="p-3 bg-slate-800 border rounded"
/>
);
}`,
seniorPrompt: "Implement a debounced React search input. Only fire the API request 300ms after the user stops typing, sanitize the search queries, and handle race conditions.",
seniorCode: `import React, { useState, useEffect } from 'react';
// 🛡️ Debounced and clean search input
export default function Search() {
const [val, setVal] = useState('');
const [debouncedValue, setDebouncedValue] = useState('');
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(val.trim());
}, 300);
return () => clearTimeout(handler);
}, [val]);
useEffect(() => {
if (!debouncedValue) return;
let active = true;
// Sanitize query parameters
const query = encodeURIComponent(debouncedValue);
fetch(`/api/search?q=${query}`)
.then(res => res.json())
.then(data => {
// Prevent race condition (discard results if user typed more)
if (active) {
console.log('Results loaded:', data);
}
});
return () => {
active = false;
};
}, [debouncedValue]);
return (
<input
type="text"
value={val}
onChange={(e) => setVal(e.target.value)}
placeholder="Type to search (debounced)..."
className="w-full p-3 bg-slate-800 border border-slate-700 rounded-xl focus:ring-2 focus:ring-cyan-500 outline-none text-white placeholder:text-slate-500"
/>
);
}`,
metrics: {
junior: { a11y: "80%", perf: "10%", security: "40%" },
senior: { a11y: "95%", perf: "98%", security: "95%" }
}
}
};
export default function PromptStudio() {
const [scenario, setScenario] = useState('dropdown');
const [promptType, setPromptType] = useState('senior');
const active = SCENARIOS[scenario];
const code = promptType === 'junior' ? active.juniorCode : active.seniorCode;
const prompt = promptType === 'junior' ? active.juniorPrompt : active.seniorPrompt;
const metrics = promptType === 'junior' ? active.metrics.junior : active.metrics.senior;
return (
<div className="bg-slate-950 p-6 sm:p-8 rounded-3xl text-white border border-slate-800 shadow-2xl min-h-[600px] flex flex-col justify-between">
<div className="w-full">
{}
<div className="flex gap-2 mb-6">
{Object.entries(SCENARIOS).map(([key, data]) => (
<button
key={key}
onClick={() => setScenario(key)}
className={`px-4 py-2 text-xs font-black rounded-lg border transition-all ${
scenario === key
? 'bg-cyan-500 text-slate-950 border-cyan-400 shadow-lg shadow-cyan-500/20'
: 'bg-slate-900 text-slate-400 border-slate-800 hover:text-white'
}`}
>
{data.title}
</button>
))}
</div>
{}
<div className="flex bg-slate-900 p-1 rounded-2xl mb-8 border border-slate-800 relative overflow-hidden">
<button
onClick={() => setPromptType('junior')}
className={`flex-1 py-3 rounded-xl text-sm font-extrabold transition-all relative z-10 ${
promptType === 'junior' ? 'bg-red-500/20 text-red-400 border border-red-500/30' : 'text-slate-400 hover:text-slate-200'
}`}
>
Junior Prompt
</button>
<button
onClick={() => setPromptType('senior')}
className={`flex-1 py-3 rounded-xl text-sm font-extrabold transition-all relative z-10 ${
promptType === 'senior' ? 'bg-green-500/20 text-green-400 border border-green-500/30' : 'text-slate-400 hover:text-slate-200'
}`}
>
Senior (Pro) Prompt
</button>
</div>
{}
<div className="bg-slate-900 border border-slate-800 p-5 rounded-2xl mb-6 flex flex-col gap-2">
<span className="text-[10px] uppercase font-black tracking-widest text-slate-500">PROMPT GIVEN:</span>
<p className="text-sm font-medium italic text-slate-200">"{prompt}"</p>
</div>
{}
<div className="grid grid-cols-3 gap-4 mb-6">
<div className="bg-slate-900/50 border border-slate-800 p-3 rounded-xl text-center">
<span className="block text-[10px] text-slate-500 font-bold uppercase mb-1">A11y (ARIA)</span>
<span className={`text-lg font-black ${promptType === 'junior' ? 'text-red-400' : 'text-green-400'}`}>
{metrics.a11y}
</span>
</div>
<div className="bg-slate-900/50 border border-slate-800 p-3 rounded-xl text-center">
<span className="block text-[10px] text-slate-500 font-bold uppercase mb-1">Performance</span>
<span className={`text-lg font-black ${promptType === 'junior' ? 'text-red-400' : 'text-green-400'}`}>
{metrics.perf}
</span>
</div>
<div className="bg-slate-900/50 border border-slate-800 p-3 rounded-xl text-center">
<span className="block text-[10px] text-slate-500 font-bold uppercase mb-1">Clean/Security</span>
<span className={`text-lg font-black ${promptType === 'junior' ? 'text-red-400' : 'text-green-400'}`}>
{metrics.security}
</span>
</div>
</div>
{}
<div className="bg-slate-900 rounded-2xl border border-slate-800 p-6 flex flex-col items-center justify-center min-h-[150px] mb-4">
<span className="text-[10px] text-slate-500 font-bold uppercase mb-4">Live Rendered Interactive Output:</span>
{scenario === 'dropdown' ? (
<div className="relative w-64 h-36">
{promptType === 'junior' ? (
<div className="p-3 bg-slate-800 border border-slate-700 rounded-xl text-left cursor-pointer" onClick={() => alert('Basic dropdown rendered. Lacks focus accessibility!')}>
Select Option
</div>
) : (
<div className="w-full">
<button className="w-full p-3 bg-slate-800 border border-slate-700 rounded-xl text-left flex justify-between items-center focus:ring-2 focus:ring-cyan-500 outline-none">
<span>Option 1</span>
<span>▼</span>
</button>
</div>
)}
</div>
) : (
<div className="w-full max-w-sm h-36">
<input
type="text"
placeholder={promptType === 'junior' ? "Fires API query on every key..." : "Only queries 300ms after you stop typing..."}
className="w-full p-3 bg-slate-800 border border-slate-700 rounded-xl focus:ring-2 focus:ring-cyan-500 outline-none text-sm"
/>
</div>
)}
</div>
</div>
</div>
);
}