extended version
This commit is contained in:
@@ -6,6 +6,7 @@ import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Stats } from "@/components/Stats";
|
||||
import LetterDensity from "@/components/LetterDensity";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import WordDensity from "@/components/WordDensity";
|
||||
|
||||
const config = {
|
||||
includeSpaces: true,
|
||||
@@ -58,6 +59,24 @@ export default function Home() {
|
||||
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);
|
||||
}, [text, includeSpaces, useCustomLimit, charLimit]);
|
||||
|
||||
@@ -116,8 +135,15 @@ export default function Home() {
|
||||
charCount={analysis.charCount}
|
||||
wordCount={analysis.wordCount}
|
||||
sentenceCount={analysis.sentenceCount}
|
||||
lineCount={analysis.lineCount}
|
||||
spaceCount={analysis.spaceCount}
|
||||
topWord={analysis.topWord}
|
||||
topWordFrequency={analysis.topWordFrequency}
|
||||
/>
|
||||
|
||||
|
||||
<LetterDensity density={analysis.letterDensity} />
|
||||
<WordDensity density={analysis.wordDensity} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -4,29 +4,56 @@ interface StatsProps {
|
||||
charCount: number;
|
||||
wordCount: 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 (
|
||||
<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">
|
||||
<CardHeader className="relative">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-6xl font-semibold tabular-nums">{charCount}</CardTitle>
|
||||
<CardDescription>Total Characters</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
<Card className="w-full">
|
||||
<CardHeader className="relative">
|
||||
<Card className="w-full ">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-6xl font-semibold tabular-nums">{wordCount}</CardTitle>
|
||||
<CardDescription>Word Count</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
<Card className="w-full">
|
||||
<CardHeader className="relative">
|
||||
<Card className="w-full ">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-6xl font-semibold tabular-nums">{sentenceCount}</CardTitle>
|
||||
<CardDescription>Sentence Count</CardDescription>
|
||||
</CardHeader>
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
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