import React, { useState, useEffect } from 'react'; import { Type, Copy, RotateCcw, Globe, Download, AlertCircle, Clock, X } from 'lucide-react'; import ToolLayout from '../components/ToolLayout'; import CopyButton from '../components/CopyButton'; import { extractContentFromUrl, CONTENT_TYPE_INFO } from '../utils/contentExtractor'; const TextLengthTool = () => { const [text, setText] = useState(''); const [url, setUrl] = useState(''); const [isLoading, setIsLoading] = useState(false); const [urlResult, setUrlResult] = useState(null); const [error, setError] = useState(''); const [useArticleOnly, setUseArticleOnly] = useState(true); const [stats, setStats] = useState({ characters: 0, charactersNoSpaces: 0, words: 0, sentences: 0, paragraphs: 0, lines: 0, bytes: 0 }); const [showDetails, setShowDetails] = useState(false); // Calculate text statistics useEffect(() => { const calculateStats = () => { if (!text) { setStats({ characters: 0, charactersNoSpaces: 0, words: 0, sentences: 0, paragraphs: 0, lines: 0, bytes: 0 }); return; } // Characters const characters = text.length; const charactersNoSpaces = text.replace(/\s/g, '').length; // Words (split by whitespace and filter empty strings) const words = text.trim() ? text.trim().split(/\s+/).length : 0; // Sentences (split by sentence endings) const sentences = text.trim() ? text.split(/[.!?]+/).filter(s => s.trim().length > 0).length : 0; // Paragraphs (split by double line breaks or more) const paragraphs = text.trim() ? text.split(/\n\s*\n/).filter(p => p.trim().length > 0).length : 0; // Lines (split by line breaks) const lines = text ? text.split('\n').length : 0; // Bytes (UTF-8 encoding) const bytes = new TextEncoder().encode(text).length; setStats({ characters, charactersNoSpaces, words, sentences, paragraphs, lines, bytes }); }; calculateStats(); }, [text]); // Handle URL fetching const fetchUrlContent = async () => { if (!url.trim()) { setError('Please enter a valid URL'); return; } setIsLoading(true); setError(''); setUrlResult(null); try { const result = await extractContentFromUrl(url.trim()); if (result.success) { setUrlResult(result); // Set text based on user preference const textToAnalyze = useArticleOnly ? result.articleText : result.allText; setText(textToAnalyze); setError(''); } else { setError(result.error); setUrlResult(null); } } catch (err) { let errorMessage = err.message; if (errorMessage.includes('Failed to fetch')) { errorMessage = 'Unable to fetch content due to CORS restrictions or network issues'; } setError(errorMessage); setUrlResult(null); } finally { setIsLoading(false); } }; const clearText = () => { setText(''); setUrlResult(null); setError(''); }; const clearUrl = () => { setUrl(''); setUrlResult(null); setError(''); }; const loadSample = () => { setText(`Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum! Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium?`); }; const formatNumber = (num) => { return num.toLocaleString(); }; const getReadingTime = () => { // Average reading speed: 200-250 words per minute const wordsPerMinute = 225; const minutes = Math.ceil(stats.words / wordsPerMinute); return minutes === 1 ? '1 minute' : `${minutes} minutes`; }; const getTypingTime = () => { // Average typing speed: 40 words per minute const wordsPerMinute = 40; const minutes = Math.ceil(stats.words / wordsPerMinute); return minutes === 1 ? '1 minute' : `${minutes} minutes`; }; return ( {/* URL Input Section */}

Analyze Content from URL

setUrl(e.target.value)} placeholder="https://example.com/article" className="tool-input w-full pr-10" disabled={isLoading} /> {url && !isLoading && ( )}
{/* URL Result Status */} {urlResult && (
{CONTENT_TYPE_INFO[urlResult.contentType].emoji} {CONTENT_TYPE_INFO[urlResult.contentType].label}
{CONTENT_TYPE_INFO[urlResult.contentType].description}
{urlResult.title && (
{urlResult.title}
)}
Article: {urlResult.metrics.articleWordCount} words • Total: {urlResult.metrics.totalWordCount} words • Ratio: {Math.round(urlResult.metrics.contentRatio * 100)}%
)} {/* Error Display */} {error && (
{error}
{error.includes('fetch') && (

Common solutions:

  • Some websites block cross-origin requests for security
  • Try copying the article text manually and pasting it below
  • The site might require JavaScript to load content
  • Check if the URL is accessible and returns HTML content
)}
)}
{/* Controls */}
{/* Text Input */}