Files
Jyotisha/frontend/src/components/birth-time-guide-turn.tsx
T
Jesse_ChenandCursor e8fa1ce4ea
Independent Staging Quality Gate / validate (push) Successful in 9m19s
Independent Staging Quality Gate / publish (push) Successful in 9m54s
fix(frontend): raise dark contrast, expand hit areas, and surface input limits
Dark muted surfaces missed WCAG AA; action and tertiary tokens plus a 32-pair contract close that. Hit targets, remaining-count, and Enter-to-send follow the interaction audit without changing visual sizes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-30 11:19:50 +08:00

69 lines
3.0 KiB
TypeScript

"use client";
import { useState } from "react";
import { CharacterRemaining } from "@/components/character-remaining";
import { characterRemainingVisible } from "@/lib/character-remaining";
import type { JourneyProgress } from "@/lib/birth-time-journey-turn";
import { protectOnboardingPhrases } from "@/lib/onboarding-copy";
type BirthTimeGuideTurnProps = {
readonly question: string;
readonly progress: JourneyProgress;
readonly pending: boolean;
readonly onSubmit: (message: string) => void;
readonly onSkip: () => void;
readonly onPause: () => void;
};
const guideRemainingId = "birth-time-guide-remaining";
export function BirthTimeGuideTurn(props: BirthTimeGuideTurnProps) {
const [message, setMessage] = useState("");
const phase = props.progress.adaptiveRound > 0
? `自适应第 ${props.progress.adaptiveRound} / ${props.progress.maxAdaptiveRounds} 轮`
: "基础证据";
const showRemaining = characterRemainingVisible(message.length, 500);
const describedBy = showRemaining
? `birth-time-guide-hint ${guideRemainingId}`
: "birth-time-guide-hint";
return (
<div className="birth-time-guide-turn" aria-live="polite">
<div className="birth-time-question-progress">
<b>{phase}</b>
<span>已确认 {props.progress.confirmedEvidenceCount} / {props.progress.baselineDomainCount} 个领域</span>
</div>
<p className="birth-time-guide-question">{protectOnboardingPhrases(props.question)}</p>
<label className="birth-time-guide-composer">
<span className="character-remaining-row">
说说这段经历
<CharacterRemaining id={guideRemainingId} length={message.length} maxLength={500} />
</span>
<textarea
aria-describedby={describedBy}
disabled={props.pending}
maxLength={500}
rows={3}
value={message}
onChange={(event) => setMessage(event.target.value)}
onKeyDown={(event) => {
if (event.nativeEvent.isComposing) return;
if (event.key === "Enter" && !event.shiftKey && message.trim()) {
event.preventDefault();
props.onSubmit(message.trim());
}
}}
/>
</label>
<p id="birth-time-guide-hint" className="birth-time-guide-hint">Enter 发送,Shift+Enter 换行。说出大概年份也可以,不需要为了校正而猜测。</p>
<div className="birth-time-guided-actions">
<button className="button-text birth-time-guided-action" disabled={props.pending} type="button" onClick={props.onPause}>暂停,稍后继续</button>
<button className="button-secondary birth-time-guided-action" disabled={props.pending} type="button" onClick={props.onSkip}>不记得,跳过</button>
<button className="button-primary birth-time-guided-action" disabled={props.pending || !message.trim()} type="button" onClick={() => props.onSubmit(message.trim())}>
{props.pending ? "整理中…" : "整理为经历草稿"}
</button>
</div>
</div>
);
}