extended version
This commit is contained in:
@@ -6,6 +6,7 @@ import { Checkbox } from "@/components/ui/checkbox";
|
|||||||
import { Stats } from "@/components/Stats";
|
import { Stats } from "@/components/Stats";
|
||||||
import LetterDensity from "@/components/LetterDensity";
|
import LetterDensity from "@/components/LetterDensity";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
|
import WordDensity from "@/components/WordDensity";
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
includeSpaces: true,
|
includeSpaces: true,
|
||||||
@@ -58,6 +59,24 @@ export default function Home() {
|
|||||||
result.letterDensity[char] = +(result.letterDensity[char] / totalLetters).toFixed(3);
|
result.letterDensity[char] = +(result.letterDensity[char] / totalLetters).toFixed(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const words = inputText.toLowerCase().match(/[a-zäöüß]+/gi) || [];
|
||||||
|
const totalWords = words.length;
|
||||||
|
result.wordDensity = {};
|
||||||
|
|
||||||
|
for (let word of words) {
|
||||||
|
result.wordDensity[word] = (result.wordDensity[word] || 0) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let word in result.wordDensity) {
|
||||||
|
result.wordDensity[word] = +(result.wordDensity[word] / totalWords).toFixed(3);
|
||||||
|
}
|
||||||
|
result.lineCount = (inputText.match(/\n/g) || []).length + 1;
|
||||||
|
result.spaceCount = (inputText.match(/ /g) || []).length;
|
||||||
|
const sortedWords = Object.entries(result.wordDensity).sort((a, b) => b[1] - a[1]);
|
||||||
|
result.topWord = sortedWords[0]?.[0] ?? null;
|
||||||
|
result.topWordFrequency = sortedWords[0] ? +(sortedWords[0][1] * 100).toFixed(1) : null;
|
||||||
|
|
||||||
|
|
||||||
setAnalysis(result);
|
setAnalysis(result);
|
||||||
}, [text, includeSpaces, useCustomLimit, charLimit]);
|
}, [text, includeSpaces, useCustomLimit, charLimit]);
|
||||||
|
|
||||||
@@ -116,8 +135,15 @@ export default function Home() {
|
|||||||
charCount={analysis.charCount}
|
charCount={analysis.charCount}
|
||||||
wordCount={analysis.wordCount}
|
wordCount={analysis.wordCount}
|
||||||
sentenceCount={analysis.sentenceCount}
|
sentenceCount={analysis.sentenceCount}
|
||||||
|
lineCount={analysis.lineCount}
|
||||||
|
spaceCount={analysis.spaceCount}
|
||||||
|
topWord={analysis.topWord}
|
||||||
|
topWordFrequency={analysis.topWordFrequency}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<LetterDensity density={analysis.letterDensity} />
|
<LetterDensity density={analysis.letterDensity} />
|
||||||
|
<WordDensity density={analysis.wordDensity} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,29 +4,56 @@ interface StatsProps {
|
|||||||
charCount: number;
|
charCount: number;
|
||||||
wordCount: number;
|
wordCount: number;
|
||||||
sentenceCount: number;
|
sentenceCount: number;
|
||||||
|
lineCount: number;
|
||||||
|
spaceCount: number;
|
||||||
|
topWord: string | null;
|
||||||
|
topWordFrequency: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Stats({ charCount, wordCount, sentenceCount }: StatsProps) {
|
export function Stats({ charCount, wordCount, sentenceCount, lineCount, spaceCount, topWord, topWordFrequency }: StatsProps) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col md:flex-row space-x-4 gap-4 w-full">
|
<div className="grid grid-cols-1 md:grid-cols-3 md:flex-row gap-4 w-full">
|
||||||
<Card className="w-full">
|
<Card className="w-full">
|
||||||
<CardHeader className="relative">
|
<CardHeader>
|
||||||
<CardTitle className="text-6xl font-semibold tabular-nums">{charCount}</CardTitle>
|
<CardTitle className="text-6xl font-semibold tabular-nums">{charCount}</CardTitle>
|
||||||
<CardDescription>Total Characters</CardDescription>
|
<CardDescription>Total Characters</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="w-full">
|
<Card className="w-full ">
|
||||||
<CardHeader className="relative">
|
<CardHeader>
|
||||||
<CardTitle className="text-6xl font-semibold tabular-nums">{wordCount}</CardTitle>
|
<CardTitle className="text-6xl font-semibold tabular-nums">{wordCount}</CardTitle>
|
||||||
<CardDescription>Word Count</CardDescription>
|
<CardDescription>Word Count</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="w-full">
|
<Card className="w-full ">
|
||||||
<CardHeader className="relative">
|
<CardHeader>
|
||||||
<CardTitle className="text-6xl font-semibold tabular-nums">{sentenceCount}</CardTitle>
|
<CardTitle className="text-6xl font-semibold tabular-nums">{sentenceCount}</CardTitle>
|
||||||
<CardDescription>Sentence Count</CardDescription>
|
<CardDescription>Sentence Count</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
</Card>
|
</Card>
|
||||||
|
<Card className="w-full">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-6xl font-semibold tabular-nums">{lineCount}</CardTitle>
|
||||||
|
<CardDescription>Line Count</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
<Card className="w-full ">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-6xl font-semibold tabular-nums">{spaceCount}</CardTitle>
|
||||||
|
<CardDescription>Spaces</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
<Card className="w-full">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-4xl font-semibold tabular-nums">
|
||||||
|
{topWord ?? "—"}
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Top word{topWordFrequency !== null ? ` (${topWordFrequency}%)` : ""}
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
46
src/components/WordDensity.tsx
Normal file
46
src/components/WordDensity.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"use client";
|
||||||
|
import { Progress } from "@/components/ui/progress";
|
||||||
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
|
||||||
|
|
||||||
|
type WordDensityProps = {
|
||||||
|
density: Record<string, number>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function WordDensity({ density }: WordDensityProps) {
|
||||||
|
const sorted = Object.entries(density).sort((a, b) => b[1] - a[1]);
|
||||||
|
const firstFive = sorted.slice(0, 5);
|
||||||
|
const rest = sorted.slice(5);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-auto w-full pt-8">
|
||||||
|
<h2 className="text-2xl">Word Density</h2>
|
||||||
|
<div className="flex flex-col py-4 gap-2">
|
||||||
|
{firstFive.map(([word, value]) => (
|
||||||
|
<div className="flex flex-row items-center" key={word}>
|
||||||
|
<p className="pr-4 text-lg uppercase">{word}</p>
|
||||||
|
<Progress className="h-4 flex-1" value={value * 100} />
|
||||||
|
<p className="pl-4">{(value * 100).toFixed(2)}%</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{rest.length > 0 && (
|
||||||
|
<Accordion type="single" collapsible>
|
||||||
|
<AccordionItem value="item-1">
|
||||||
|
<AccordionTrigger className="text-xl">See more</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
<div className="flex flex-col py-4 gap-2">
|
||||||
|
{rest.map(([word, value]) => (
|
||||||
|
<div className="flex flex-row items-center" key={word}>
|
||||||
|
<p className="pr-4 text-lg uppercase">{word}</p>
|
||||||
|
<Progress className="h-4 flex-1" value={value * 100} />
|
||||||
|
<p className="pl-4">{(value * 100).toFixed(2)}%</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user