Vertical.ai / frontend /src /components /SourceGuide.jsx
Abhisingh-18's picture
Mirror of github.com/Abhisingh18/Vertical.ai
1f7ead8 verified
Raw
History Blame Contribute Delete
5.72 kB
import React, { useState } from 'react';
import {
Headphones, Video, Network, FileText, Component,
HelpCircle, Package, Columns, Projector, Activity,
Loader2, X, BookOpen
} from 'lucide-react';
import { generateSourceContent } from '../api';
// Tool definitions
const TOOLS = [
{ id: 'audio', label: 'Audio Overview', icon: Headphones, color: 'text-purple-600', bg: 'bg-purple-50' },
{ id: 'video', label: 'Video Overview', icon: Video, color: 'text-red-600', bg: 'bg-red-50' },
{ id: 'mind_map', label: 'Mind Map', icon: Network, color: 'text-blue-600', bg: 'bg-blue-50' },
{ id: 'reports', label: 'Reports', icon: FileText, color: 'text-emerald-600', bg: 'bg-emerald-50' },
{ id: 'flashcards', label: 'Flashcards', icon: Component, color: 'text-amber-600', bg: 'bg-amber-50' },
{ id: 'quiz', label: 'Quiz', icon: HelpCircle, color: 'text-cyan-600', bg: 'bg-cyan-50' },
{ id: 'artifact', label: 'Create Artifact', icon: Package, color: 'text-indigo-600', bg: 'bg-indigo-50' },
{ id: 'infographic', label: 'Infographic', icon: Columns, color: 'text-pink-600', bg: 'bg-pink-50' },
{ id: 'slides', label: 'Slide Deck', icon: Projector, color: 'text-orange-600', bg: 'bg-orange-50' },
{ id: 'data_table', label: 'Data Table', icon: Activity, color: 'text-teal-600', bg: 'bg-teal-50' },
];
const SourceGuide = ({ onGenerate, activeCitation, onCloseCitation, notebookId }) => {
const [generating, setGenerating] = useState(null);
const handleToolClick = async (toolId) => {
if (generating) return;
setGenerating(toolId);
try {
const result = await generateSourceContent(toolId, notebookId);
// Callback to Notebook to insert the result
onGenerate(toolId, result.answer);
} catch (error) {
console.error(error);
alert("Failed to generate content: " + (error.response?.data?.detail || error.message));
} finally {
setGenerating(null);
}
};
// If a citation is active, show the Citation View (mini-panel)
if (activeCitation) {
return (
<div className="h-full border-l border-slate-200 bg-white flex flex-col">
<div className="p-4 border-b border-slate-100 flex items-center justify-between">
<h3 className="font-semibold text-slate-700 flex items-center gap-2">
<BookOpen size={16} /> Source Guide
</h3>
<button onClick={onCloseCitation} className="p-1 hover:bg-slate-100 rounded-full text-slate-400">
<X size={16} />
</button>
</div>
<div className="p-4 flex-1 overflow-y-auto">
<div className="bg-blue-50 border border-blue-100 p-4 rounded-xl mb-4">
<span className="text-xs font-bold text-blue-600 uppercase">Selected Source</span>
<h4 className="font-medium text-slate-900 mt-1">{activeCitation.paper_id}</h4>
</div>
<p className="p-4 bg-slate-50 rounded-lg text-slate-700 italic border-l-4 border-slate-300">
"{activeCitation.text_snippet}"
</p>
<div className="mt-4 text-center">
<button onClick={onCloseCitation} className="text-sm text-blue-600 hover:underline">
Back to Tools
</button>
</div>
</div>
</div>
);
}
return (
<div className="h-full border-l border-slate-200 bg-white flex flex-col">
<div className="p-6 border-b border-slate-100">
<h2 className="text-lg font-bold text-slate-800">Source Guide</h2>
<p className="text-sm text-slate-500 mt-1">Transform your sources into...</p>
</div>
<div className="flex-1 overflow-y-auto p-4">
<div className="grid grid-cols-2 gap-3">
{TOOLS.map((tool) => {
const Icon = tool.icon;
const isProcessing = generating === tool.id;
return (
<button
key={tool.id}
onClick={() => handleToolClick(tool.id)}
disabled={!!generating}
className={`flex flex-col items-center justify-center gap-3 p-4 rounded-xl border border-slate-100 hover:border-slate-300 hover:shadow-md transition-all text-center bg-white group disabled:opacity-50 h-32 ${isProcessing ? 'bg-slate-50' : ''}`}
>
<div className={`w-12 h-12 rounded-full flex items-center justify-center ${tool.bg} ${tool.color} group-hover:scale-110 transition-transform`}>
{isProcessing ? <Loader2 size={24} className="animate-spin" /> : <Icon size={24} />}
</div>
<div>
<h3 className="font-semibold text-slate-700 text-sm">{tool.label}</h3>
{isProcessing && <p className="text-[10px] text-slate-400 mt-0.5">Generating...</p>}
</div>
</button>
);
})}
</div>
</div>
</div>
);
};
export default SourceGuide;