Add a live word / character count indicator to the chat composer#61
Open
DragonnZhang wants to merge 2 commits into
Open
Add a live word / character count indicator to the chat composer#61DragonnZhang wants to merge 2 commits into
DragonnZhang wants to merge 2 commits into
Conversation
Adds a small draft count indicator to the composer toolbar that shows the current word count inline (hidden when the draft is empty or in compact mode) with a hover tooltip breaking down words, characters, and lines. - composer-count.ts: pure computeComposerCounts/shouldShowComposerCount helpers (Unicode-aware character count, whitespace-collapsing words, newline lines) with unit tests. - ComposerCountIndicator.tsx: derived-state indicator over the composer's existing plain-text input; exposes data-* counts for e2e. - Wires the indicator into the FreeFormInput toolbar bottom row. - Adds chat.composerWords/Characters/Lines i18n keys (plural-neutral label form) to all 7 locales. - e2e/assertions/composer-count.assert.ts: CDP assertion driving real typing. Closes #60
Resolve merge conflict in docs/loop/feature-ledger.md (append-only ledger) by keeping the branch's reconciled superset, which already includes the reduce-motion (#51) row plus all newer loop entries. Locale files auto-merged cleanly; i18n parity verified (7 locales, 1547 keys each, no dups).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #60
What & why
OpenWork's chat composer (
FreeFormInput) gave no feedback about how muchyou've written. The toolbar already surfaces a context-usage indicator, a model
picker, a thinking-level picker and an attach control — but there was no length
feedback for the draft itself, which comparable desktop composers/editors
(Codex desktop, VS Code / Google Docs status bars, the Claude/ChatGPT message
boxes) all provide.
This adds a small, unobtrusive draft count indicator to the composer toolbar:
Words: 12), only while the composer hasnon-whitespace text — so the empty composer stays clean;
Lines;
inputtext (no new state, no persistence);
compactMode(mirroring the context / thinking / model controls) andhidden entirely when the draft is empty.
Frontend-only. No qwen-code backend change — the composer already stores the
draft as a plain-text string, so the indicator is pure derived state.
Changes
lib/composer-count.ts— purecomputeComposerCounts/shouldShowComposerCounthelpers (Unicode-aware character count via codepoints, whitespace-collapsing word count, newline-based line count), DOM-free
and unit-tested.
components/app-shell/input/ComposerCountIndicator.tsx— the indicator:renders
nullfor an empty draft, shows the word count inline with the fullbreakdown in a tooltip, and exposes
data-word-count/data-char-count/data-line-countfor e2e.components/app-shell/input/FreeFormInput.tsx— slots the indicator intothe toolbar bottom row (between the left badge group and the flex spacer,
!compactMode).chat.composerWords,chat.composerCharacters,chat.composerLines) added to all 7 locales, using a plural-neutral labelform (
"Words: {{count}}") so no per-locale plural categories are needed.e2e/assertions/composer-count.assert.ts— new CDP assertion (below).Verification (DoD)
bun run typecheck:all— zero new errors.packages/{core,shared,server-core,server,session-tools-core,ui}all pass clean;apps/electronshows only its 11 pre-existing baseline errors (auto-update.tsowner/repo×4, asettings-default-thinkingtest tuple ×5, two test files importingvitest) — none in the files this PR touches.composer-count.test.ts10/10 pass (empty / whitespace-only, single vs. multiple words, collapsed internal whitespace, multi-line, emoji/Unicode character counting). Touched-area suites (renderer/lib) 141/141 pass; the one unrelatedSAFE_MODE_CONFIGfailure pre-dates this change.bun run lint:i18n:parity— OK (6 locales, 1545 keys each — +3, all present in every locale).bun run electron:build:renderer) — ✅ builds cleanly.bun build e2e/assertions/composer-count.assert.ts) — ✅.CDP e2e assertion (
composer-count.assert.ts)Drives the real built app over CDP entirely in the draft (no-session) state — no
seeded conversation and no backend:
[data-testid="composer-count"]) is absent.Input.insertText) ofhello worldmakes it appear withdata-word-count="2"anddata-char-count="11".againupdates the counts live todata-word-count="3"/data-char-count="17"— proving per-keystroke reactivity.Part of the autonomous desktop-feature loop (
loop-bot).Generated by Claude Code