Add word count strength indicator for form text fields
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>
This commit is contained in:
parent
afa7e43051
commit
08dbd5f5a2
3 changed files with 51 additions and 1 deletions
|
|
@ -42,6 +42,7 @@ import {
|
|||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import { FieldTooltip } from "@/components/ui/field-tooltip";
|
||||
import { InputStrengthIndicator } from "@/components/ui/InputStrengthIndicator";
|
||||
|
||||
export const formSchema = z.object({
|
||||
audienceBrief: z.string().min(10, {
|
||||
|
|
@ -184,6 +185,7 @@ export default function AIRecruiterForm({ onSubmit, isGenerating }: AIRecruiterF
|
|||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<InputStrengthIndicator text={field.value || ""} minWords={150} />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
|
|
@ -208,11 +210,12 @@ export default function AIRecruiterForm({ onSubmit, isGenerating }: AIRecruiterF
|
|||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<InputStrengthIndicator text={field.value || ""} minWords={150} />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
|
||||
{/* Enhance Brief Button */}
|
||||
<div className="space-y-3">
|
||||
<Button
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import {
|
|||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import AssetUploader from '@/components/AssetUploader';
|
||||
import { InputStrengthIndicator } from "@/components/ui/InputStrengthIndicator";
|
||||
|
||||
interface SetupTabProps {
|
||||
form: UseFormReturn<any>;
|
||||
|
|
@ -81,6 +82,7 @@ export function SetupTab({
|
|||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<InputStrengthIndicator text={field.value || ""} minWords={150} />
|
||||
<FormDescription>
|
||||
Provide context about what you want to learn
|
||||
</FormDescription>
|
||||
|
|
@ -103,6 +105,7 @@ export function SetupTab({
|
|||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<InputStrengthIndicator text={field.value || ""} minWords={15} />
|
||||
<FormDescription>
|
||||
E.g., User experience, feature preferences, pain points
|
||||
</FormDescription>
|
||||
|
|
|
|||
44
src/components/ui/InputStrengthIndicator.tsx
Normal file
44
src/components/ui/InputStrengthIndicator.tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
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>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue