Implements a traffic light indicator beneath paragraph fields to guide users on content adequacy. Shows red (<33%), yellow (33-99%), or green (≥100%) based on word count progress toward minimum targets. Fields updated: - Research Brief: 150 words minimum - Discussion Topics: 15 words minimum - Audience Brief: 150 words minimum - Research Objective: 150 words minimum 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
44 lines
1.3 KiB
TypeScript
44 lines
1.3 KiB
TypeScript
import * as React from "react";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface InputStrengthIndicatorProps {
|
|
text: string;
|
|
minWords: number;
|
|
className?: string;
|
|
}
|
|
|
|
export function InputStrengthIndicator({
|
|
text,
|
|
minWords,
|
|
className
|
|
}: InputStrengthIndicatorProps) {
|
|
const wordCount = text.trim() ? text.trim().split(/\s+/).filter(Boolean).length : 0;
|
|
const percentage = (wordCount / minWords) * 100;
|
|
|
|
const getState = () => {
|
|
if (percentage >= 100) return { level: 3, label: "Good length", color: "bg-green-500" };
|
|
if (percentage >= 33) return { level: 2, label: "Getting there", color: "bg-yellow-500" };
|
|
return { level: 1, label: "Add more detail", color: "bg-red-500" };
|
|
};
|
|
|
|
const state = getState();
|
|
|
|
return (
|
|
<div className={cn("flex items-center gap-2 mt-1.5 text-xs text-muted-foreground", className)}>
|
|
<div className="flex gap-1">
|
|
{[1, 2, 3].map((dot) => (
|
|
<div
|
|
key={dot}
|
|
className={cn(
|
|
"w-2 h-2 rounded-full",
|
|
dot <= state.level ? state.color : "bg-muted"
|
|
)}
|
|
/>
|
|
))}
|
|
</div>
|
|
<span>{wordCount} / {minWords} words</span>
|
|
<span className="text-muted-foreground/70">·</span>
|
|
<span>{state.label}</span>
|
|
</div>
|
|
);
|
|
}
|