File size: 4,864 Bytes
e058d03 8b65a0f fe844e6 e058d03 34d6b36 e058d03 34d6b36 e058d03 34d6b36 e058d03 fe844e6 e058d03 34d6b36 e058d03 641c44a fe844e6 8b65a0f e058d03 8b65a0f e058d03 8b65a0f e058d03 8b65a0f e058d03 8b65a0f e058d03 8b65a0f e058d03 8b65a0f e058d03 8b65a0f fe844e6 e058d03 8b65a0f 34d6b36 641c44a 8b65a0f e058d03 641c44a e058d03 8b65a0f e058d03 fe844e6 8b65a0f e058d03 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | 'use client';
import { useState, useEffect } from 'react';
import { ArticleGenerationModal, ArticleGenerationParams } from './ArticleGenerationModal';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
interface ArticleProps {
className?: string;
sourceArticle: string;
onSourceArticleChange: (text: string) => void;
isSourceLocked: boolean;
onSourceLockedChange: (locked: boolean) => void;
}
export function Article({
className = '',
sourceArticle,
onSourceArticleChange,
isSourceLocked,
onSourceLockedChange,
}: ArticleProps) {
const [wordCount, setWordCount] = useState(0);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isGeneratingArticle, setIsGeneratingArticle] = useState(false);
const [isExpandOpen, setIsExpandOpen] = useState(false);
const updateWordCount = (text: string) => {
const words = text.trim().split(/\s+/).length;
setWordCount(text.trim() === '' ? 0 : words);
};
useEffect(() => {
updateWordCount(sourceArticle);
}, [sourceArticle]);
const handleSourceArticleChange = (text: string) => {
if (!isSourceLocked) {
onSourceArticleChange(text);
}
};
const handleGenerateArticle = async (params: ArticleGenerationParams) => {
setIsGeneratingArticle(true);
try {
// Call the API to generate article
const response = await fetch('/api/generate-article', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params),
});
if (response.ok) {
const { article } = await response.json();
onSourceArticleChange(article);
setIsModalOpen(false);
} else {
console.error('Failed to generate article');
}
} catch (error) {
console.error('Error generating article:', error);
} finally {
setIsGeneratingArticle(false);
}
};
return (
<Card className={`flex flex-col h-full ${className}`}>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-4 px-6 pt-2">
<CardTitle className="text-lg font-semibold">
π Source Article
</CardTitle>
<div className="flex items-center space-x-4">
<Button
onClick={() => setIsModalOpen(true)}
disabled={isSourceLocked}
size="sm"
>
β¨ Generate
</Button>
<span className="text-sm text-muted-foreground">
{wordCount} words
</span>
<div className="flex items-center space-x-2">
<Checkbox
id="lock-source"
checked={isSourceLocked}
onCheckedChange={onSourceLockedChange}
/>
<Label htmlFor="lock-source" className="text-sm cursor-pointer">
π Lock
</Label>
</div>
<Button
onClick={() => setIsExpandOpen(true)}
disabled={isSourceLocked}
variant="outline"
size="sm"
>
β€’ Expand
</Button>
</div>
</CardHeader>
<CardContent className="flex-1 px-6 pb-6 overflow-hidden">
<Textarea
value={sourceArticle}
onChange={(e) => handleSourceArticleChange(e.target.value)}
placeholder="Paste or type your source article here (articles, passages, etc.)..."
disabled={isSourceLocked}
className="w-full h-full resize-none"
/>
</CardContent>
<ArticleGenerationModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
onGenerate={handleGenerateArticle}
isGenerating={isGeneratingArticle}
/>
{/* Full-screen editor dialog for comfortable editing */}
<Dialog open={isExpandOpen} onOpenChange={setIsExpandOpen}>
<DialogContent className="w-[98vw] sm:max-w-none md:max-w-[90vw] h-[70vh] max-h-[95vh] p-0 flex flex-col">
<DialogHeader className="px-6 pt-6 pb-2">
<DialogTitle>π Edit Source Article</DialogTitle>
</DialogHeader>
<div className="flex-1 px-6 pb-6">
<Textarea
value={sourceArticle}
onChange={(e) => handleSourceArticleChange(e.target.value)}
placeholder="Paste or type your source article here (articles, passages, etc.)..."
disabled={isSourceLocked}
className="w-full h-full resize-none"
/>
</div>
</DialogContent>
</Dialog>
</Card>
);
} |