extended version

This commit is contained in:
Dominik Natter
2025-03-28 10:31:04 +01:00
parent 0e0ba8fe9f
commit fdf551167e
3 changed files with 106 additions and 7 deletions

View File

@@ -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>

View File

@@ -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>
);
}

View 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>
);
}