Files
goal-planner/frontend/components/GoalInputForm.tsx
T
2026-11-02 15:52:53 +08:00

87 lines
5.4 KiB
TypeScript

import React, { useState } from 'react';
interface GoalInputFormProps {
onGeneratePlan: (goal: string, additionalInfo?: string) => void;
}
const GoalInputForm: React.FC<GoalInputFormProps> = ({ onGeneratePlan }) => {
const [goal, setGoal] = useState('');
const [additionalInfo, setAdditionalInfo] = useState('');
const [showAdditional, setShowAdditional] = useState(false);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (goal.trim()) {
onGeneratePlan(goal.trim(), additionalInfo.trim() || undefined);
}
};
const handleExampleClick = (exampleGoal: string) => {
setGoal(exampleGoal);
onGeneratePlan(exampleGoal);
};
return (
<div className="bg-white dark:bg-slate-800 p-8 rounded-xl shadow-lg border border-slate-200 dark:border-slate-700 text-center">
<h2 className="text-2xl font-bold text-slate-800 dark:text-slate-100 mb-2">What's Your Next Big Goal?</h2>
<p className="text-slate-600 dark:text-slate-400 mb-6">Describe what you want to accomplish, and we'll map out the steps.</p>
<form onSubmit={handleSubmit}>
<textarea
value={goal}
onChange={(e) => setGoal(e.target.value)}
placeholder="e.g., Launch a new personal blog about cooking"
className="w-full p-4 bg-white dark:bg-slate-700 text-slate-900 dark:text-slate-100 border border-slate-300 dark:border-slate-600 rounded-lg mb-2 focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-shadow text-lg placeholder:text-slate-400 dark:placeholder:text-slate-500"
rows={3}
/>
{/* Toggle additional info */}
<button
type="button"
onClick={() => setShowAdditional(!showAdditional)}
className="flex items-center gap-1.5 text-sm text-slate-500 dark:text-slate-400 hover:text-green-600 dark:hover:text-green-400 transition-colors mb-2 mx-auto"
>
<svg xmlns="http://www.w3.org/2000/svg" className={`h-4 w-4 transition-transform duration-200 ${showAdditional ? 'rotate-90' : ''}`} fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
</svg>
{showAdditional ? '收起' : 'Import Plan (Markdown)'}
</button>
{showAdditional && (
<div className="mb-4 animate-in fade-in duration-200">
<textarea
value={additionalInfo}
onChange={(e) => setAdditionalInfo(e.target.value)}
placeholder={'粘贴从其他 AI 或工具生成的任务计划(支持 Markdown),AI 将据此生成结构化任务列表。\n\n例如:\n## 阶段一:需求分析\n- 用户调研\n- 竞品分析\n\n## 阶段二:开发\n- 前端开发\n- 后端开发'}
className="w-full p-4 bg-slate-50 dark:bg-slate-700/50 text-slate-900 dark:text-slate-100 border border-slate-200 dark:border-slate-500 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-shadow text-sm placeholder:text-slate-400 dark:placeholder:text-slate-500 font-mono"
rows={8}
/>
{additionalInfo.trim() && (
<p className="text-xs text-green-600 dark:text-green-400 mt-1">
✅ Plan imported, AI will generate structured tasks based on it
</p>
)}
</div>
)}
<button
type="submit"
disabled={!goal.trim()}
className="w-full bg-green-600 text-white font-semibold px-6 py-3 rounded-lg hover:bg-green-700 transition-colors disabled:bg-slate-400 dark:disabled:bg-slate-600 disabled:cursor-not-allowed"
>
Generate My Plan
</button>
</form>
<div className="mt-6">
<p className="text-sm text-slate-500 dark:text-slate-400">Or try an example:</p>
<div className="flex flex-wrap justify-center gap-2 mt-2">
<button onClick={() => handleExampleClick('Plan a 2-week backpacking trip through Southeast Asia')} className="text-xs bg-slate-100 dark:bg-slate-700 text-slate-700 dark:text-slate-300 px-3 py-1 rounded-full hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors">Plan a trip</button>
<button onClick={() => handleExampleClick('Learn to play the guitar in 3 months')} className="text-xs bg-slate-100 dark:bg-slate-700 text-slate-700 dark:text-slate-300 px-3 py-1 rounded-full hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors">Learn a skill</button>
<button onClick={() => handleExampleClick('Build and launch a simple SaaS product')} className="text-xs bg-slate-100 dark:bg-slate-700 text-slate-700 dark:text-slate-300 px-3 py-1 rounded-full hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors">Launch a product</button>
</div>
</div>
</div>
);
};
export default GoalInputForm;