💄 move the word counts to the bottom bar

This commit is contained in:
TC
2026-06-14 19:30:18 +10:00
parent e69d588443
commit 223b583f18
3 changed files with 56 additions and 29 deletions

View File

@@ -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;

View File

@@ -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 && (
<span className="statusbar-selection-wordcount">{selectionWordCount.toLocaleString()} selected</span>
)}
<button
className="statusbar-share-btn"
onClick={async () => {
const fileName = activeFilePath.split('/').pop()?.replace(/\.md$/, '') ?? 'document'
await window.api.exportPDF(activeFileContent, fileName)
}}
title="Export document as PDF"
>
</button>
<div className="statusbar-right">
{(() => {
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 (
<span
className="statusbar-wordcount"
title={`This document: ${docWc.toLocaleString()} words · Entire project: ${projectWordCount.toLocaleString()} words${avgLen !== null ? ` · Avg sentence: ${avgLen} words` : ''}`}
>
{fmt(docWc)}
<span className="statusbar-sep">/</span>
{fmt(projectWordCount)}
{avgLen !== null && (
<>
<span className="statusbar-sep">·</span>
{avgLen}w
</>
)}
</span>
)
})()}
<button
className="statusbar-share-btn"
onClick={async () => {
const fileName = activeFilePath.split('/').pop()?.replace(/\.md$/, '') ?? 'document'
await window.api.exportPDF(activeFileContent, fileName)
}}
title="Export document as PDF"
>
</button>
</div>
</div>
)}
</div>

View File

@@ -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 {
</div>
<div className="toolbar-right">
{activeFilePath && (
<span
className="toolbar-wordcount"
title={`This document: ${docWordCount.toLocaleString()} words · Entire project: ${projectWordCount.toLocaleString()} words${avgSentenceLen !== null ? ` · Avg sentence: ${avgSentenceLen} words` : ''}`}
>
{formatWordCount(docWordCount)}
<span className="toolbar-wordcount-sep">/</span>
{formatWordCount(projectWordCount)}
{avgSentenceLen !== null && (
<>
<span className="toolbar-wordcount-sep">·</span>
{avgSentenceLen}w
</>
)}
</span>
)}
{isDirty && (
<span className="toolbar-dirty" title="Unsaved changes — press Cmd+S to save">