Sets up the foundational elements for the NewsCaster AI application. This includes: - Initializing the project with Vite and React. - Defining core types for articles and player state. - Configuring build tools and TypeScript. - Adding essential dependencies like React, Vite, and Google's Gemini API client. - Providing initial README instructions for running locally. - Setting up basic styling and structure in index.html. - Defining available voices and playback constants. - Implementing utility functions for audio handling.
60 lines
2.1 KiB
TypeScript
60 lines
2.1 KiB
TypeScript
import React from 'react';
|
|
import { Article } from '../types';
|
|
import { FileText } from 'lucide-react';
|
|
|
|
interface ReaderViewProps {
|
|
article?: Article | null;
|
|
}
|
|
|
|
export const ReaderView: React.FC<ReaderViewProps> = ({ article }) => {
|
|
if (!article) {
|
|
return (
|
|
<div className="h-full flex flex-col items-center justify-center text-slate-400 p-12 border-2 border-dashed border-slate-200 rounded-2xl bg-slate-50/50">
|
|
<FileText className="w-12 h-12 mb-4 opacity-50" />
|
|
<p className="text-lg font-medium">Select an article to read along</p>
|
|
<p className="text-sm">The text will appear here while you listen.</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Split text by newlines to create paragraphs
|
|
const paragraphs = article.text
|
|
? article.text.split('\n').filter(p => p.trim().length > 0)
|
|
: [];
|
|
|
|
return (
|
|
<div className="bg-white rounded-2xl border border-slate-200 shadow-sm overflow-hidden h-[calc(100vh-12rem)] flex flex-col">
|
|
<div className="p-6 border-b border-slate-100 bg-white sticky top-0 z-10">
|
|
<h2 className="text-2xl font-bold text-slate-900 leading-tight">
|
|
{article.title}
|
|
</h2>
|
|
<a
|
|
href={article.url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="text-sm text-blue-600 hover:underline mt-2 inline-block"
|
|
>
|
|
{new URL(article.url).hostname}
|
|
</a>
|
|
</div>
|
|
|
|
<div className="flex-grow overflow-y-auto p-6 sm:p-8 space-y-6 custom-scrollbar bg-white">
|
|
{paragraphs.length > 0 ? (
|
|
paragraphs.map((paragraph, idx) => (
|
|
<p key={idx} className="text-lg text-slate-700 leading-relaxed font-serif">
|
|
{paragraph}
|
|
</p>
|
|
))
|
|
) : (
|
|
<div className="space-y-4 animate-pulse">
|
|
<div className="h-4 bg-slate-100 rounded w-3/4"></div>
|
|
<div className="h-4 bg-slate-100 rounded w-full"></div>
|
|
<div className="h-4 bg-slate-100 rounded w-5/6"></div>
|
|
<p className="text-slate-400 italic mt-4">Extracting article content...</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|