diff --git a/src/renderer/components/Editor/Editor.css b/src/renderer/components/Editor/Editor.css
index 875f0d1..5056595 100644
--- a/src/renderer/components/Editor/Editor.css
+++ b/src/renderer/components/Editor/Editor.css
@@ -45,6 +45,22 @@
opacity: 0.5;
}
+.statusbar-right {
+ margin-left: auto;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.statusbar-wordcount {
+ letter-spacing: 0.01em;
+}
+
+.statusbar-sep {
+ opacity: 0.45;
+ margin: 0 3px;
+}
+
.statusbar-share-btn {
background: none;
border: none;
diff --git a/src/renderer/components/Editor/MarkdownEditor.tsx b/src/renderer/components/Editor/MarkdownEditor.tsx
index dfcf2bf..01c79e7 100644
--- a/src/renderer/components/Editor/MarkdownEditor.tsx
+++ b/src/renderer/components/Editor/MarkdownEditor.tsx
@@ -685,7 +685,7 @@ export function MarkdownEditor(): JSX.Element {
const [commentDraft, setCommentDraft] = useState('')
const [wordStats, setWordStats] = useState<{ atCursor: number; total: number }>({ atCursor: 0, total: 0 })
const wordTotalRef = useRef(0)
- const { activeFilePath, activeFileContent, setContent, annotations, fontSize, theme, focusMode, scrollPositions, pendingScrollToLine, clearPendingScrollToLine, selectionWordCount } = useEditorStore()
+ const { activeFilePath, activeFileContent, setContent, annotations, fontSize, theme, focusMode, scrollPositions, pendingScrollToLine, clearPendingScrollToLine, selectionWordCount, projectWordCount } = useEditorStore()
function saveComment(): void {
if (!pendingComment || !commentDraft.trim()) return
@@ -1137,16 +1137,45 @@ export function MarkdownEditor(): JSX.Element {
{selectionWordCount !== null && (
{selectionWordCount.toLocaleString()} selected
)}
-
+
+ {(() => {
+ const docWc = countWords(activeFileContent)
+ const sentences = activeFileContent
+ .split(/[.!?]+/)
+ .map((s: string) => s.trim())
+ .filter((s: string) => s.length > 0 && /\w/.test(s))
+ const avgLen = sentences.length > 0
+ ? Math.round((sentences.map((s: string) => countWords(s)).reduce((a: number, b: number) => a + b, 0) / sentences.length) * 10) / 10
+ : null
+ const fmt = (n: number) => n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n)
+ return (
+
+ {fmt(docWc)}
+ /
+ {fmt(projectWordCount)}
+ {avgLen !== null && (
+ <>
+ ·
+ {avgLen}w
+ >
+ )}
+
+ )
+ })()}
+
+
)}
diff --git a/src/renderer/components/Toolbar/AnalysisToolbar.tsx b/src/renderer/components/Toolbar/AnalysisToolbar.tsx
index 10b473c..eac2639 100644
--- a/src/renderer/components/Toolbar/AnalysisToolbar.tsx
+++ b/src/renderer/components/Toolbar/AnalysisToolbar.tsx
@@ -373,9 +373,7 @@ export function AnalysisToolbar(): JSX.Element {
const critiqueCount = annotations.filter((a) => a.type === 'critique').length
const totalCount = passiveCount + pastProgressiveCount + weakVerbsCount + clichesCount + consistencyCount + styleCount + showTellCount + critiqueCount
const anyActive = Boolean(analysisMode)
- const docWordCount = countWords(activeFileContent)
const sentenceStats = activeFileContent ? computeSentenceStats(activeFileContent) : null
- const avgSentenceLen = sentenceStats ? Math.round(sentenceStats.avg * 10) / 10 : null
const paragraphRhythm = activeFileContent ? computeParagraphRhythm(activeFileContent) : []
const maxParaWords = paragraphRhythm.length > 0 ? Math.max(...paragraphRhythm.map(p => p.words)) : 1
@@ -676,22 +674,6 @@ export function AnalysisToolbar(): JSX.Element {
- {activeFilePath && (
-
- {formatWordCount(docWordCount)}
- /
- {formatWordCount(projectWordCount)}
- {avgSentenceLen !== null && (
- <>
- ·
- {avgSentenceLen}w
- >
- )}
-
- )}
{isDirty && (
●