import { useState } from "react"; import { cn } from "~/lib/utils"; import { MessageSquare, Sparkles, Copy, Twitter, Edit2, Trash2, Plus, RefreshCw, } from "lucide-react"; import { Button } from "@/routes/ui/button"; import { ChainIcon } from "../components/shared/ChainIcon"; export interface Tweet { number: number; content: string; type: "hook" | "analysis" | "implication" | "conclusion" | "disclaimer"; includeChart?: boolean; } export interface ThreadRequest { tokenAddress: string; tokenSymbol: string; chain: string; topic?: string; length: number; tone: "bullish" | "neutral" | "bearish"; } export interface GeneratedThread { tweets: Tweet[]; metadata: { tokenSymbol: string; keyStats: Record; }; } export interface ThreadGeneratorPanelProps { /** Current token info */ tokenAddress?: string; tokenSymbol?: string; chain?: string; /** Callback when thread is generated */ onGenerate?: (request: ThreadRequest) => void; /** Callback when thread is exported */ onExport?: (format: "copy" | "twitter") => void; /** Additional class names */ className?: string; } /** * ThreadGeneratorPanel - AI-powered Twitter thread generator * * Features: * - Auto-fill token info from current page * - Customizable thread length (5-10 tweets) * - Tone selection (bullish/neutral/bearish) * - AI-generated thread structure (Hook → Analysis → Implications → Conclusion) * - Edit individual tweets * - Reorder tweets * - Export options (copy all, tweet directly) */ export function ThreadGeneratorPanel({ tokenAddress, tokenSymbol, chain, onGenerate, onExport, className, }: ThreadGeneratorPanelProps) { const [request, setRequest] = useState({ tokenAddress: tokenAddress || "", tokenSymbol: tokenSymbol || "", chain: chain || "solana", topic: "", length: 7, tone: "bullish", }); const [generatedThread, setGeneratedThread] = useState(null); const [isGenerating, setIsGenerating] = useState(false); const [editingTweet, setEditingTweet] = useState(null); // Mock generated thread const mockThread: GeneratedThread = { tweets: [ { number: 1, content: `🧵 ${request.tokenSymbol} is showing massive volume spike (+200%) in the last 24h. Here's what you need to know šŸ‘‡`, type: "hook", }, { number: 2, content: `Contract analysis:\nāœ… Verified on-chain\nāœ… Ownership renounced\nāœ… LP locked for 90 days\nāœ… No proxy contracts\n\nSolid fundamentals from a security perspective.`, type: "analysis", }, { number: 3, content: `Holder distribution looks healthy:\n• 1,234 holders\n• Top 10 hold only 35%\n• No single whale dominance\n\nThis suggests organic growth and reduced rug pull risk.`, type: "analysis", }, { number: 4, content: `Liquidity: $50K\nVolume/Liquidity ratio: 2.0x\n\nStrong trading activity relative to liquidity. This is a bullish signal for price discovery.`, type: "analysis", }, { number: 5, content: `Social sentiment is turning positive:\n• 500 Twitter mentions (24h)\n• 1,200 Telegram messages\n• Growing community engagement\n\nMomentum is building.`, type: "implication", }, { number: 6, content: `What this means:\n\nWe're seeing early signs of a potential breakout. Volume precedes price, and the fundamentals support sustained growth.`, type: "implication", }, { number: 7, content: `TL;DR:\nāœ… Verified & safe contract\nāœ… Healthy holder distribution\nāœ… Strong volume growth\nāœ… Positive social sentiment\n\nDYOR, but this one's worth watching closely. šŸ‘€`, type: "conclusion", }, ], metadata: { tokenSymbol: request.tokenSymbol, keyStats: { price: 0.0001234, change24h: 15.5, volume: 100000, liquidity: 50000, }, }, }; const handleGenerate = async () => { setIsGenerating(true); await onGenerate?.(request); // Mock: simulate generation setTimeout(() => { setGeneratedThread(mockThread); setIsGenerating(false); }, 2000); }; const handleEditTweet = (number: number, newContent: string) => { if (!generatedThread) return; const updatedTweets = generatedThread.tweets.map((tweet) => tweet.number === number ? { ...tweet, content: newContent } : tweet ); setGeneratedThread({ ...generatedThread, tweets: updatedTweets }); setEditingTweet(null); }; const handleDeleteTweet = (number: number) => { if (!generatedThread) return; const updatedTweets = generatedThread.tweets .filter((tweet) => tweet.number !== number) .map((tweet, index) => ({ ...tweet, number: index + 1 })); setGeneratedThread({ ...generatedThread, tweets: updatedTweets }); }; const handleAddTweet = () => { if (!generatedThread) return; const newTweet: Tweet = { number: generatedThread.tweets.length + 1, content: "New tweet content...", type: "analysis", }; setGeneratedThread({ ...generatedThread, tweets: [...generatedThread.tweets, newTweet], }); }; return (
{/* Header */}

AI Thread Generator

Create Twitter threads with AI

{/* Content */}
{!generatedThread ? ( <> {/* Input Form */}
{/* Token Info */}
{request.tokenSymbol || \"Not selected\"} {request.chain && }
{/* Topic */}
setRequest({ ...request, topic: e.target.value })} className=\"w-full p-2 text-sm border rounded\" />
{/* Length */}
{/* Tone */}
{([\"bullish\", \"neutral\", \"bearish\"] as const).map((tone) => ( ))}
{/* Generate Button */} ) : ( <> {/* Generated Thread Preview */}

Preview

{/* Tweets */}
{generatedThread.tweets.map((tweet) => (
{editingTweet === tweet.number ? (