Files
0xdesign__design-plugin/design-ide/components/chat/InterviewQuestion.tsx
0xdesign b957873a9b feat: Initial Design IDE project structure
Implements prototype-first development tool with:
- Next.js 15 App Router with TypeScript
- Tailwind CSS + shadcn/ui component library
- AI SDK integration with Claude for variant generation
- Sandpack for live code preview
- Core tools: askQuestion, generateVariant, processFeedback, buildFullStack
- Variant grid with 5-variant display (A-E focus areas)
- Feedback panel for Figma-style commenting
- Project management pages (list, IDE view)
- Supabase client setup for auth and storage

Key differentiator: Generate 5 visual prototypes exploring different
design directions before building, rather than immediate code generation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 18:17:33 -05:00

127 lines
3.6 KiB
TypeScript

'use client';
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Card, CardContent } from '@/components/ui/card';
import { cn } from '@/lib/utils';
import { Check, MessageSquare } from 'lucide-react';
interface QuestionOption {
label: string;
value: string;
}
interface InterviewQuestionProps {
question: string;
options?: QuestionOption[];
allowFreeform?: boolean;
onAnswer: (answer: string) => void;
isAnswered?: boolean;
}
export function InterviewQuestion({
question,
options,
allowFreeform = true,
onAnswer,
isAnswered = false,
}: InterviewQuestionProps) {
const [selectedOption, setSelectedOption] = useState<string | null>(null);
const [freeformText, setFreeformText] = useState('');
const [showFreeform, setShowFreeform] = useState(!options || options.length === 0);
const handleSubmit = () => {
const answer = showFreeform ? freeformText : selectedOption;
if (answer) {
onAnswer(answer);
}
};
if (isAnswered) {
return null;
}
return (
<Card className="bg-muted/50 border-dashed">
<CardContent className="p-4">
<div className="space-y-4">
<p className="text-sm font-medium">{question}</p>
{/* Options */}
{options && options.length > 0 && !showFreeform && (
<div className="flex flex-wrap gap-2">
{options.map((option) => (
<Button
key={option.value}
variant={selectedOption === option.value ? 'default' : 'outline'}
size="sm"
onClick={() => setSelectedOption(option.value)}
className="text-sm"
>
{option.label}
{selectedOption === option.value && (
<Check className="ml-1 h-3 w-3" />
)}
</Button>
))}
{allowFreeform && (
<Button
variant="ghost"
size="sm"
onClick={() => setShowFreeform(true)}
className="text-sm text-muted-foreground"
>
<MessageSquare className="mr-1 h-3 w-3" />
Other
</Button>
)}
</div>
)}
{/* Freeform input */}
{showFreeform && (
<div className="flex gap-2">
<Input
value={freeformText}
onChange={(e) => setFreeformText(e.target.value)}
placeholder="Type your answer..."
className="flex-1"
onKeyDown={(e) => {
if (e.key === 'Enter' && freeformText.trim()) {
handleSubmit();
}
}}
/>
{options && options.length > 0 && (
<Button
variant="ghost"
size="sm"
onClick={() => {
setShowFreeform(false);
setFreeformText('');
}}
>
Back
</Button>
)}
</div>
)}
{/* Submit button */}
<div className="flex justify-end">
<Button
size="sm"
onClick={handleSubmit}
disabled={showFreeform ? !freeformText.trim() : !selectedOption}
>
Answer
</Button>
</div>
</div>
</CardContent>
</Card>
);
}