@@ -57,6 +57,8 @@ export default function Index({
5757 const [ saveStatus , setSaveStatus ] = useState < 'saved' | 'saving' | 'error' > ( 'saved' ) ;
5858 const saveTimeoutRef = useRef < NodeJS . Timeout | null > ( null ) ;
5959 const lastContentRef = useRef < string > ( '' ) ;
60+ const [ wordCount , setWordCount ] = useState ( 0 ) ;
61+ const [ charCount , setCharCount ] = useState ( 0 ) ;
6062
6163 const editor = useEditor (
6264 {
@@ -183,7 +185,7 @@ export default function Index({
183185
184186 return false ;
185187 } ,
186- handleDrop : ( view , event , slice , moved ) => {
188+ handleDrop : ( view , event , _slice , moved ) => {
187189 if ( moved ) return false ;
188190
189191 const files = event . dataTransfer ?. files ;
@@ -227,6 +229,14 @@ export default function Index({
227229 } ,
228230 onUpdate : ( { editor } ) => {
229231 if ( ! note ) return ;
232+
233+ // Update word and character counts
234+ const text = editor . state . doc . textContent ;
235+ const words = text . trim ( ) ? text . trim ( ) . split ( / \s + / ) . length : 0 ;
236+ const chars = text . length ;
237+ setWordCount ( words ) ;
238+ setCharCount ( chars ) ;
239+
230240 const html = editor . getHTML ( ) ;
231241 if ( html !== note . content && html !== lastContentRef . current ) {
232242 lastContentRef . current = html ;
@@ -262,6 +272,13 @@ export default function Index({
262272 editor . commands . setContent ( note . content || '' , false ) ;
263273 lastContentRef . current = note . content || '' ;
264274
275+ // Update word and character counts
276+ const text = editor . state . doc . textContent ;
277+ const words = text . trim ( ) ? text . trim ( ) . split ( / \s + / ) . length : 0 ;
278+ const chars = text . length ;
279+ setWordCount ( words ) ;
280+ setCharCount ( chars ) ;
281+
265282 try {
266283 const docSize = editor . state . doc . content . size ;
267284 if ( from <= docSize && to <= docSize ) {
@@ -446,7 +463,8 @@ export default function Index({
446463 const currentFolder = getCurrentFolder ( ) ;
447464
448465 return (
449- < div className = "flex h-full flex-1 flex-col" >
466+ < >
467+ < div className = "flex h-full flex-1 flex-col" >
450468 < div className = "border-border flex-shrink-0 border-b p-4" >
451469 < div className = "mb-4 flex items-center justify-between" >
452470 < div className = "flex flex-1 items-center gap-3" >
@@ -460,23 +478,6 @@ export default function Index({
460478 </ div >
461479
462480 < div className = "flex items-center gap-2" >
463- { /* Save status indicator */ }
464- < div className = "flex items-center mr-2" title = {
465- saveStatus === 'saving' ? 'Saving' :
466- saveStatus === 'saved' ? 'Saved' :
467- 'Error saving'
468- } >
469- { saveStatus === 'saving' && (
470- < div className = "h-3 w-3 rounded-full bg-orange-500 animate-pulse" />
471- ) }
472- { saveStatus === 'saved' && (
473- < div className = "h-3 w-3 rounded-full bg-green-500" />
474- ) }
475- { saveStatus === 'error' && (
476- < div className = "h-3 w-3 rounded-full bg-red-500" />
477- ) }
478- </ div >
479-
480481 < div className = "relative" >
481482 < Button
482483 variant = "ghost"
@@ -610,18 +611,62 @@ export default function Index({
610611 />
611612 </ div >
612613
613- < style dangerouslySetInnerHTML = { { __html : editorStyles } } />
614+ { /* Status Bar - VSCode Style */ }
615+ < div className = "border-t bg-primary/5 dark:bg-primary/10 px-3 py-0.5 flex items-center justify-between text-[11px] font-mono" >
616+ { /* Left side - Word and character count */ }
617+ < div className = "flex items-center gap-3" >
618+ { ( wordCount > 0 || charCount > 0 ) && (
619+ < >
620+ < span className = "hover:bg-muted px-1.5 py-0.5 rounded cursor-default" >
621+ { wordCount } { wordCount === 1 ? 'word' : 'words' }
622+ </ span >
623+ < span className = "hover:bg-muted px-1.5 py-0.5 rounded cursor-default" >
624+ { charCount } { charCount === 1 ? 'character' : 'characters' }
625+ </ span >
626+ </ >
627+ ) }
628+ </ div >
629+
630+ { /* Right side - Save status */ }
631+ < div className = "flex items-center gap-1 px-1.5 py-0.5 hover:bg-muted rounded cursor-default" title = {
632+ saveStatus === 'saving' ? 'Saving changes...' :
633+ saveStatus === 'saved' ? 'All changes saved' :
634+ 'Error saving changes'
635+ } >
636+ { saveStatus === 'saving' && (
637+ < >
638+ < div className = "h-1.5 w-1.5 rounded-full bg-orange-500 animate-pulse" />
639+ < span > Saving</ span >
640+ </ >
641+ ) }
642+ { saveStatus === 'saved' && (
643+ < >
644+ < div className = "h-1.5 w-1.5 rounded-full bg-green-500" />
645+ < span > Saved</ span >
646+ </ >
647+ ) }
648+ { saveStatus === 'error' && (
649+ < >
650+ < div className = "h-1.5 w-1.5 rounded-full bg-red-500" />
651+ < span className = "text-red-500" > Error</ span >
652+ </ >
653+ ) }
654+ </ div >
655+ </ div >
614656
615- { note && (
616- < MoveNoteModal
617- isOpen = { isMoveModalOpen }
618- onClose = { ( ) => setIsMoveModalOpen ( false ) }
619- onMove = { handleMoveNote }
620- folders = { folders || [ ] }
621- currentFolderId = { note . folderId }
622- noteTitle = { note . title }
623- />
624- ) }
625- </ div >
657+ < style dangerouslySetInnerHTML = { { __html : editorStyles } } />
658+
659+ { note && (
660+ < MoveNoteModal
661+ isOpen = { isMoveModalOpen }
662+ onClose = { ( ) => setIsMoveModalOpen ( false ) }
663+ onMove = { handleMoveNote }
664+ folders = { folders || [ ] }
665+ currentFolderId = { note . folderId }
666+ noteTitle = { note . title }
667+ />
668+ ) }
669+ </ div >
670+ </ >
626671 ) ;
627672}
0 commit comments