Companion: rules-based, context-aware writing advice
Replace the kitten's random generic tips with a deterministic, LLM-free prose checker that reads the actual document and surfaces one gentle, bilingual note at a time — quoting a slice of her own sentence so the advice is clearly about *this* draft. Rules (all conservative, tuned for a Mandarin-native ESL writer): run-ons, comma splices, unclear antecedents, Oxford comma, a/an, uncountable plurals, capitalize languages/days/months, subject-verb agreement, plural-after-number, double determiner, "there is" + plural, its/it's, than/then, comma-after-transition, doubled words, lowercase "i", sentence capitals, and spacing around punctuation. Each rule is paired with false-positive guards (e.g. "a university", "After dinner, I went home and read", existing Oxford lists) and pinned by a 45-case Vitest suite (npm test). Also: bubbles now linger proportional to how much there is to read (zh+en) and pause-on-hover, so denser advice no longer vanishes mid-read. Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
This commit is contained in:
@@ -9,6 +9,7 @@ interface Props {
|
||||
saveStatus: SaveStatus
|
||||
editTick: number
|
||||
acceptTick: number
|
||||
text: string
|
||||
}
|
||||
|
||||
// Emoji placeholder per mood, used for any mood a companion has no Lottie for.
|
||||
@@ -26,8 +27,14 @@ const STORAGE_KEY = 'petal.companion'
|
||||
// useCompanion and shows a Mandarin-first speech bubble for cheers, tips, and
|
||||
// break reminders. Clicking the mascot opens a picker to switch companions
|
||||
// (the choice persists in localStorage).
|
||||
export function PetalCompanion({ wordCount, saveStatus, editTick, acceptTick }: Props) {
|
||||
const { mood, bubble, dismiss } = useCompanion({ wordCount, saveStatus, editTick, acceptTick })
|
||||
export function PetalCompanion({ wordCount, saveStatus, editTick, acceptTick, text }: Props) {
|
||||
const { mood, bubble, dismiss, holdBubble, releaseBubble } = useCompanion({
|
||||
wordCount,
|
||||
saveStatus,
|
||||
editTick,
|
||||
acceptTick,
|
||||
text,
|
||||
})
|
||||
|
||||
const [companionId, setCompanionId] = useState<string>(() => {
|
||||
try {
|
||||
@@ -136,6 +143,8 @@ export function PetalCompanion({ wordCount, saveStatus, editTick, acceptTick }:
|
||||
<div
|
||||
role="status"
|
||||
onClick={dismiss}
|
||||
onMouseEnter={holdBubble}
|
||||
onMouseLeave={releaseBubble}
|
||||
className="petal-bubble pointer-events-auto max-w-[260px] cursor-pointer p-3 pr-3.5"
|
||||
style={{
|
||||
background: 'var(--color-surface)',
|
||||
|
||||
Reference in New Issue
Block a user