Spaces:
Configuration error
Configuration error
| import React, { useState } from 'react'; | |
| import Header from './components/Header'; | |
| import SummaryResult from './components/SummaryResult'; | |
| import { summarizeText } from './services/gemini'; | |
| import { SummaryState } from './types'; | |
| const App: React.FC = () => { | |
| const [state, setState] = useState<SummaryState>({ | |
| originalText: '', | |
| summary: '', | |
| isLoading: false, | |
| error: null, | |
| }); | |
| const handleSummarize = async () => { | |
| if (!state.originalText.trim()) { | |
| setState(prev => ({ ...prev, error: "Please enter some text to summarize." })); | |
| return; | |
| } | |
| setState(prev => ({ ...prev, isLoading: true, error: null, summary: '' })); | |
| try { | |
| const summary = await summarizeText(state.originalText); | |
| setState(prev => ({ ...prev, summary, isLoading: false })); | |
| } catch (err) { | |
| setState(prev => ({ | |
| ...prev, | |
| isLoading: false, | |
| error: err instanceof Error ? err.message : "An unexpected error occurred." | |
| })); | |
| } | |
| }; | |
| const handleClear = () => { | |
| setState({ | |
| originalText: '', | |
| summary: '', | |
| isLoading: false, | |
| error: null, | |
| }); | |
| }; | |
| return ( | |
| <div className="min-h-screen flex flex-col"> | |
| <Header /> | |
| <main className="flex-grow py-12 px-4 bg-gray-50"> | |
| <div className="max-w-4xl mx-auto"> | |
| <div className="bg-white border border-gray-200 rounded-2xl p-6 shadow-sm transition-all focus-within:ring-2 focus-within:ring-indigo-100"> | |
| <div className="flex items-center justify-between mb-4"> | |
| <label htmlFor="inputText" className="text-sm font-semibold text-gray-700 uppercase tracking-wider"> | |
| Original Content | |
| </label> | |
| <div className="text-xs text-gray-400 font-medium"> | |
| {state.originalText.length} characters | |
| </div> | |
| </div> | |
| <textarea | |
| id="inputText" | |
| className="w-full h-64 p-4 text-gray-800 placeholder-gray-400 border border-gray-100 rounded-xl resize-none focus:outline-none focus:border-indigo-200 bg-gray-50/50 transition-colors text-lg leading-relaxed" | |
| placeholder="Paste the text you want to summarize..." | |
| value={state.originalText} | |
| onChange={(e) => setState(prev => ({ ...prev, originalText: e.target.value, error: null }))} | |
| disabled={state.isLoading} | |
| /> | |
| <div className="mt-6 flex flex-col sm:flex-row gap-3"> | |
| <button | |
| onClick={handleSummarize} | |
| disabled={state.isLoading || !state.originalText.trim()} | |
| className={`flex-grow h-12 flex items-center justify-center gap-2 px-6 rounded-xl font-bold text-white transition-all shadow-md active:scale-95 ${state.isLoading || !state.originalText.trim() | |
| ? 'bg-gray-300 cursor-not-allowed' | |
| : 'bg-indigo-600 hover:bg-indigo-700 hover:shadow-indigo-200' | |
| }`} | |
| > | |
| {state.isLoading ? 'Summarizing...' : 'Summarize Text'} | |
| </button> | |
| <button | |
| onClick={handleClear} | |
| disabled={state.isLoading || !state.originalText} | |
| className="h-12 px-6 border border-gray-200 text-gray-600 font-semibold rounded-xl hover:bg-gray-50 transition-all disabled:opacity-50 active:scale-95" | |
| > | |
| Clear | |
| </button> | |
| </div> | |
| {state.error && ( | |
| <div className="mt-4 p-4 bg-red-50 border border-red-100 text-red-700 text-sm font-medium rounded-xl"> | |
| {state.error} | |
| </div> | |
| )} | |
| </div> | |
| <SummaryResult summary={state.summary} /> | |
| </div> | |
| </main> | |
| </div> | |
| ); | |
| }; | |
| export default App; | |