diff --git a/App.tsx b/App.tsx index 8f8a46c..bd1b7dc 100644 --- a/App.tsx +++ b/App.tsx @@ -198,6 +198,18 @@ export default function App() { }); }, [playerState.currentArticleId]); + const handleSegmentSelect = useCallback((articleId: string, index: number) => { + setPlayerState(prev => ({ + ...prev, + currentArticleId: articleId, + isPlaying: true + })); + updateArticle(articleId, { + currentSegmentIndex: index, + status: PlaybackStatus.PLAYING + }); + }, []); + // -- Keyboard Shortcuts -- useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { @@ -478,6 +490,7 @@ export default function App() { article={viewingArticle} settings={settings} onToggleAutoScroll={() => setSettings(s => ({...s, autoScroll: !s.autoScroll}))} + onSegmentSelect={(index) => viewingArticle && handleSegmentSelect(viewingArticle.id, index)} /> @@ -490,6 +503,7 @@ export default function App() { article={viewingArticle} settings={settings} onToggleAutoScroll={() => setSettings(s => ({...s, autoScroll: !s.autoScroll}))} + onSegmentSelect={(index) => viewingArticle && handleSegmentSelect(viewingArticle.id, index)} /> diff --git a/components/ReaderView.tsx b/components/ReaderView.tsx index 01fdb71..4b0cb9a 100644 --- a/components/ReaderView.tsx +++ b/components/ReaderView.tsx @@ -7,9 +7,10 @@ interface ReaderViewProps { article?: Article | null; settings?: ReaderSettings; onToggleAutoScroll?: () => void; + onSegmentSelect?: (index: number) => void; } -export const ReaderView: React.FC = ({ article, settings, onToggleAutoScroll }) => { +export const ReaderView: React.FC = ({ article, settings, onToggleAutoScroll, onSegmentSelect }) => { const scrollRef = useRef(null); // Auto-scroll to active segment @@ -100,7 +101,7 @@ export const ReaderView: React.FC = ({ article, settings, onTog
{article.segments.length > 0 ? ( article.segments.map((segment, idx) => { @@ -109,11 +110,16 @@ export const ReaderView: React.FC = ({ article, settings, onTog
onSegmentSelect?.(idx)} + title="Click to play from here" + className={` + transition-all duration-200 whitespace-pre-wrap rounded-xl p-3 sm:p-4 -mx-2 sm:-mx-4 border-l-4 mb-2 + ${getLeadingClass()} + ${isActive + ? 'text-slate-900 dark:text-white bg-blue-50 dark:bg-blue-900/20 border-blue-500 shadow-sm' + : 'text-slate-700 dark:text-slate-300 border-transparent hover:bg-slate-100 dark:hover:bg-slate-800/50 cursor-pointer hover:border-slate-300 dark:hover:border-slate-600' + } + `} > {segment.text}
diff --git a/services/geminiService.ts b/services/geminiService.ts index 6b96f80..5ba85fb 100644 --- a/services/geminiService.ts +++ b/services/geminiService.ts @@ -49,52 +49,20 @@ function cleanAndMinifyHtml(rawHtml: string): string { const doc = parser.parseFromString(rawHtml, 'text/html'); // 1. Remove heavy technical tags + // We remove these because they consume tokens and provide no semantic value for text extraction. const technicalTags = ['script', 'style', 'noscript', 'iframe', 'svg', 'link', 'meta', 'button', 'input', 'form', 'img', 'picture', 'video']; technicalTags.forEach(tag => { const elements = doc.querySelectorAll(tag); elements.forEach(el => el.remove()); }); - // 2. Remove semantic layout tags that are usually clutter - const layoutTags = ['nav', 'footer', 'aside', 'header']; - layoutTags.forEach(tag => { - const elements = doc.querySelectorAll(tag); - elements.forEach(el => el.remove()); - }); + // NOTE: We intentionally DO NOT remove semantic tags like