@@ -506,189 +506,196 @@ function GitPanel({ selectedProject, isMobile }) {
506
506
</ button >
507
507
</ div >
508
508
509
- { /* Tab Navigation */ }
510
- < div className = "flex border-b border-gray-200 dark:border-gray-700" >
511
- < button
512
- onClick = { ( ) => setActiveView ( 'changes' ) }
513
- className = { `flex-1 px-4 py-2 text-sm font-medium transition-colors ${
514
- activeView === 'changes'
515
- ? 'text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400'
516
- : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white'
517
- } `}
518
- >
519
- < div className = "flex items-center justify-center gap-2" >
520
- < FileText className = "w-4 h-4" />
521
- < span > Changes</ span >
509
+ { /* Git Repository Not Found Message */ }
510
+ { gitStatus ?. error ? (
511
+ < div className = "flex-1 flex flex-col items-center justify-center text-gray-500 dark:text-gray-400 px-6 py-12" >
512
+ < GitBranch className = "w-20 h-20 mb-6 opacity-30" />
513
+ < h3 className = "text-xl font-medium mb-3 text-center" > { gitStatus . error } </ h3 >
514
+ { gitStatus . details && (
515
+ < p className = "text-sm text-center leading-relaxed mb-6 max-w-md" > { gitStatus . details } </ p >
516
+ ) }
517
+ < div className = "p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800 max-w-md" >
518
+ < p className = "text-sm text-blue-700 dark:text-blue-300 text-center" >
519
+ < strong > Tip:</ strong > Run < code className = "bg-blue-100 dark:bg-blue-900 px-2 py-1 rounded font-mono text-xs" > git init</ code > in your project directory to initialize git source control.
520
+ </ p >
522
521
</ div >
523
- </ button >
524
- < button
525
- onClick = { ( ) => setActiveView ( 'history' ) }
526
- className = { `flex-1 px-4 py-2 text-sm font-medium transition-colors ${
527
- activeView === 'history'
528
- ? 'text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400'
529
- : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white'
530
- } `}
531
- >
532
- < div className = "flex items-center justify-center gap-2" >
533
- < History className = "w-4 h-4" />
534
- < span > History</ span >
522
+ </ div >
523
+ ) : (
524
+ < >
525
+ { /* Tab Navigation - Only show when git is available */ }
526
+ < div className = "flex border-b border-gray-200 dark:border-gray-700" >
527
+ < button
528
+ onClick = { ( ) => setActiveView ( 'changes' ) }
529
+ className = { `flex-1 px-4 py-2 text-sm font-medium transition-colors ${
530
+ activeView === 'changes'
531
+ ? 'text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400'
532
+ : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white'
533
+ } `}
534
+ >
535
+ < div className = "flex items-center justify-center gap-2" >
536
+ < FileText className = "w-4 h-4" />
537
+ < span > Changes</ span >
538
+ </ div >
539
+ </ button >
540
+ < button
541
+ onClick = { ( ) => setActiveView ( 'history' ) }
542
+ className = { `flex-1 px-4 py-2 text-sm font-medium transition-colors ${
543
+ activeView === 'history'
544
+ ? 'text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400'
545
+ : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white'
546
+ } `}
547
+ >
548
+ < div className = "flex items-center justify-center gap-2" >
549
+ < History className = "w-4 h-4" />
550
+ < span > History</ span >
551
+ </ div >
552
+ </ button >
535
553
</ div >
536
- </ button >
537
- </ div >
538
554
539
- { /* Changes View */ }
540
- { activeView === 'changes' && (
541
- < >
542
- { /* Commit Message Input */ }
543
- < div className = "px-4 py-3 border-b border-gray-200 dark:border-gray-700" >
544
- < div className = "relative" >
545
- < textarea
546
- ref = { textareaRef }
547
- value = { commitMessage }
548
- onChange = { ( e ) => setCommitMessage ( e . target . value ) }
549
- placeholder = "Message (Ctrl+Enter to commit)"
550
- className = "w-full px-3 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 resize-none pr-20"
551
- rows = "3"
552
- onKeyDown = { ( e ) => {
553
- if ( e . key === 'Enter' && ( e . ctrlKey || e . metaKey ) ) {
554
- handleCommit ( ) ;
555
- }
556
- } }
557
- />
558
- < div className = "absolute right-2 top-2 flex gap-1" >
555
+ { /* Changes View */ }
556
+ { activeView === 'changes' && (
557
+ < >
558
+ { /* Commit Message Input */ }
559
+ < div className = "px-4 py-3 border-b border-gray-200 dark:border-gray-700" >
560
+ < div className = "relative" >
561
+ < textarea
562
+ ref = { textareaRef }
563
+ value = { commitMessage }
564
+ onChange = { ( e ) => setCommitMessage ( e . target . value ) }
565
+ placeholder = "Message (Ctrl+Enter to commit)"
566
+ className = "w-full px-3 py-2 text-sm border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 resize-none pr-20"
567
+ rows = "3"
568
+ onKeyDown = { ( e ) => {
569
+ if ( e . key === 'Enter' && ( e . ctrlKey || e . metaKey ) ) {
570
+ handleCommit ( ) ;
571
+ }
572
+ } }
573
+ />
574
+ < div className = "absolute right-2 top-2 flex gap-1" >
575
+ < button
576
+ onClick = { generateCommitMessage }
577
+ disabled = { selectedFiles . size === 0 || isGeneratingMessage }
578
+ className = "p-1.5 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 disabled:opacity-50 disabled:cursor-not-allowed"
579
+ title = "Generate commit message"
580
+ >
581
+ { isGeneratingMessage ? (
582
+ < RefreshCw className = "w-4 h-4 animate-spin" />
583
+ ) : (
584
+ < Sparkles className = "w-4 h-4" />
585
+ ) }
586
+ </ button >
587
+ < div style = { { display : 'none' } } >
588
+ < MicButton
589
+ onTranscript = { ( transcript ) => setCommitMessage ( transcript ) }
590
+ mode = "default"
591
+ className = "p-1.5"
592
+ />
593
+ </ div >
594
+ </ div >
595
+ </ div >
596
+ < div className = "flex items-center justify-between mt-2" >
597
+ < span className = "text-xs text-gray-500" >
598
+ { selectedFiles . size } file{ selectedFiles . size !== 1 ? 's' : '' } selected
599
+ </ span >
600
+ < button
601
+ onClick = { handleCommit }
602
+ disabled = { ! commitMessage . trim ( ) || selectedFiles . size === 0 || isCommitting }
603
+ className = "px-3 py-1 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center space-x-1"
604
+ >
605
+ < Check className = "w-3 h-3" />
606
+ < span > { isCommitting ? 'Committing...' : 'Commit' } </ span >
607
+ </ button >
608
+ </ div >
609
+ </ div >
610
+ </ >
611
+ ) }
612
+
613
+ { /* File Selection Controls - Only show in changes view and when git is working */ }
614
+ { activeView === 'changes' && gitStatus && ! gitStatus . error && (
615
+ < div className = "px-4 py-2 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between" >
616
+ < span className = "text-xs text-gray-600 dark:text-gray-400" >
617
+ { selectedFiles . size } of { ( gitStatus ?. modified ?. length || 0 ) + ( gitStatus ?. added ?. length || 0 ) + ( gitStatus ?. deleted ?. length || 0 ) + ( gitStatus ?. untracked ?. length || 0 ) } files selected
618
+ </ span >
619
+ < div className = "flex gap-2" >
559
620
< button
560
- onClick = { generateCommitMessage }
561
- disabled = { selectedFiles . size === 0 || isGeneratingMessage }
562
- className = "p-1.5 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 disabled:opacity-50 disabled:cursor-not-allowed"
563
- title = "Generate commit message"
621
+ onClick = { ( ) => {
622
+ const allFiles = new Set ( [
623
+ ...( gitStatus ?. modified || [ ] ) ,
624
+ ...( gitStatus ?. added || [ ] ) ,
625
+ ...( gitStatus ?. deleted || [ ] ) ,
626
+ ...( gitStatus ?. untracked || [ ] )
627
+ ] ) ;
628
+ setSelectedFiles ( allFiles ) ;
629
+ } }
630
+ className = "text-xs text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300"
564
631
>
565
- { isGeneratingMessage ? (
566
- < RefreshCw className = "w-4 h-4 animate-spin" />
567
- ) : (
568
- < Sparkles className = "w-4 h-4" />
569
- ) }
632
+ Select All
633
+ </ button >
634
+ < span className = "text-gray-300 dark:text-gray-600" > |</ span >
635
+ < button
636
+ onClick = { ( ) => setSelectedFiles ( new Set ( ) ) }
637
+ className = "text-xs text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300"
638
+ >
639
+ Deselect All
570
640
</ button >
571
- < div style = { { display : 'none' } } >
572
- < MicButton
573
- onTranscript = { ( transcript ) => setCommitMessage ( transcript ) }
574
- mode = "default"
575
- className = "p-1.5"
576
- />
577
- </ div >
578
641
</ div >
579
642
</ div >
580
- < div className = "flex items-center justify-between mt-2" >
581
- < span className = "text-xs text-gray-500" >
582
- { selectedFiles . size } file{ selectedFiles . size !== 1 ? 's' : '' } selected
583
- </ span >
643
+ ) }
644
+
645
+ { /* Status Legend Toggle */ }
646
+ { ! gitStatus ?. error && (
647
+ < div className = "border-b border-gray-200 dark:border-gray-700" >
584
648
< button
585
- onClick = { handleCommit }
586
- disabled = { ! commitMessage . trim ( ) || selectedFiles . size === 0 || isCommitting }
587
- className = "px-3 py-1 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center space-x-1"
649
+ onClick = { ( ) => setShowLegend ( ! showLegend ) }
650
+ className = "w-full px-4 py-2 bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-750 text-xs text-gray-600 dark:text-gray-400 flex items-center justify-center gap-1"
588
651
>
589
- < Check className = "w-3 h-3" />
590
- < span > { isCommitting ? 'Committing...' : 'Commit' } </ span >
652
+ < Info className = "w-3 h-3" />
653
+ < span > File Status Guide</ span >
654
+ { showLegend ? < ChevronDown className = "w-3 h-3" /> : < ChevronRight className = "w-3 h-3" /> }
591
655
</ button >
656
+
657
+ { showLegend && (
658
+ < div className = "px-4 py-3 bg-gray-50 dark:bg-gray-800 text-xs" >
659
+ < div className = { `${ isMobile ? 'grid grid-cols-2 gap-3 justify-items-center' : 'flex justify-center gap-6' } ` } >
660
+ < div className = "flex items-center gap-2" >
661
+ < span className = "inline-flex items-center justify-center w-5 h-5 bg-yellow-100 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-300 rounded border border-yellow-200 dark:border-yellow-800 font-bold text-xs" >
662
+ M
663
+ </ span >
664
+ < span className = "text-gray-600 dark:text-gray-400 italic" > Modified</ span >
665
+ </ div >
666
+ < div className = "flex items-center gap-2" >
667
+ < span className = "inline-flex items-center justify-center w-5 h-5 bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300 rounded border border-green-200 dark:border-green-800 font-bold text-xs" >
668
+ A
669
+ </ span >
670
+ < span className = "text-gray-600 dark:text-gray-400 italic" > Added</ span >
671
+ </ div >
672
+ < div className = "flex items-center gap-2" >
673
+ < span className = "inline-flex items-center justify-center w-5 h-5 bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300 rounded border border-red-200 dark:border-red-800 font-bold text-xs" >
674
+ D
675
+ </ span >
676
+ < span className = "text-gray-600 dark:text-gray-400 italic" > Deleted</ span >
677
+ </ div >
678
+ < div className = "flex items-center gap-2" >
679
+ < span className = "inline-flex items-center justify-center w-5 h-5 bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300 rounded border border-gray-300 dark:border-gray-600 font-bold text-xs" >
680
+ U
681
+ </ span >
682
+ < span className = "text-gray-600 dark:text-gray-400 italic" > Untracked</ span >
683
+ </ div >
684
+ </ div >
685
+ </ div >
686
+ ) }
592
687
</ div >
593
- </ div >
688
+ ) }
594
689
</ >
595
690
) }
596
691
597
- { /* File Selection Controls - Only show in changes view and when git is working */ }
598
- { activeView === 'changes' && gitStatus && ! gitStatus . error && (
599
- < div className = "px-4 py-2 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between" >
600
- < span className = "text-xs text-gray-600 dark:text-gray-400" >
601
- { selectedFiles . size } of { ( gitStatus ?. modified ?. length || 0 ) + ( gitStatus ?. added ?. length || 0 ) + ( gitStatus ?. deleted ?. length || 0 ) + ( gitStatus ?. untracked ?. length || 0 ) } files selected
602
- </ span >
603
- < div className = "flex gap-2" >
604
- < button
605
- onClick = { ( ) => {
606
- const allFiles = new Set ( [
607
- ...( gitStatus ?. modified || [ ] ) ,
608
- ...( gitStatus ?. added || [ ] ) ,
609
- ...( gitStatus ?. deleted || [ ] ) ,
610
- ...( gitStatus ?. untracked || [ ] )
611
- ] ) ;
612
- setSelectedFiles ( allFiles ) ;
613
- } }
614
- className = "text-xs text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300"
615
- >
616
- Select All
617
- </ button >
618
- < span className = "text-gray-300 dark:text-gray-600" > |</ span >
619
- < button
620
- onClick = { ( ) => setSelectedFiles ( new Set ( ) ) }
621
- className = "text-xs text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300"
622
- >
623
- Deselect All
624
- </ button >
625
- </ div >
626
- </ div >
627
- ) }
628
-
629
- { /* Status Legend Toggle */ }
630
- < div className = "border-b border-gray-200 dark:border-gray-700" >
631
- < button
632
- onClick = { ( ) => setShowLegend ( ! showLegend ) }
633
- className = "w-full px-4 py-2 bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-750 text-xs text-gray-600 dark:text-gray-400 flex items-center justify-center gap-1"
634
- >
635
- < Info className = "w-3 h-3" />
636
- < span > File Status Guide</ span >
637
- { showLegend ? < ChevronDown className = "w-3 h-3" /> : < ChevronRight className = "w-3 h-3" /> }
638
- </ button >
639
-
640
- { showLegend && (
641
- < div className = "px-4 py-3 bg-gray-50 dark:bg-gray-800 text-xs" >
642
- < div className = { `${ isMobile ? 'grid grid-cols-2 gap-3 justify-items-center' : 'flex justify-center gap-6' } ` } >
643
- < div className = "flex items-center gap-2" >
644
- < span className = "inline-flex items-center justify-center w-5 h-5 bg-yellow-100 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-300 rounded border border-yellow-200 dark:border-yellow-800 font-bold text-xs" >
645
- M
646
- </ span >
647
- < span className = "text-gray-600 dark:text-gray-400 italic" > Modified</ span >
648
- </ div >
649
- < div className = "flex items-center gap-2" >
650
- < span className = "inline-flex items-center justify-center w-5 h-5 bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300 rounded border border-green-200 dark:border-green-800 font-bold text-xs" >
651
- A
652
- </ span >
653
- < span className = "text-gray-600 dark:text-gray-400 italic" > Added</ span >
654
- </ div >
655
- < div className = "flex items-center gap-2" >
656
- < span className = "inline-flex items-center justify-center w-5 h-5 bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300 rounded border border-red-200 dark:border-red-800 font-bold text-xs" >
657
- D
658
- </ span >
659
- < span className = "text-gray-600 dark:text-gray-400 italic" > Deleted</ span >
660
- </ div >
661
- < div className = "flex items-center gap-2" >
662
- < span className = "inline-flex items-center justify-center w-5 h-5 bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300 rounded border border-gray-300 dark:border-gray-600 font-bold text-xs" >
663
- U
664
- </ span >
665
- < span className = "text-gray-600 dark:text-gray-400 italic" > Untracked</ span >
666
- </ div >
667
- </ div >
668
- </ div >
669
- ) }
670
- </ div >
671
-
672
- { /* File List - Changes View */ }
673
- { activeView === 'changes' && (
692
+ { /* File List - Changes View - Only show when git is available */ }
693
+ { activeView === 'changes' && ! gitStatus ?. error && (
674
694
< div className = { `flex-1 overflow-y-auto ${ isMobile ? 'pb-20' : '' } ` } >
675
695
{ isLoading ? (
676
696
< div className = "flex items-center justify-center h-32" >
677
697
< RefreshCw className = "w-6 h-6 animate-spin text-gray-400" />
678
698
</ div >
679
- ) : gitStatus ?. error ? (
680
- < div className = "flex flex-col items-center justify-center h-48 text-gray-500 dark:text-gray-400 px-6" >
681
- < GitBranch className = "w-16 h-16 mb-4 opacity-30" />
682
- < p className = "text-lg font-medium mb-2 text-center" > { gitStatus . error } </ p >
683
- { gitStatus . details && (
684
- < p className = "text-sm text-center leading-relaxed" > { gitStatus . details } </ p >
685
- ) }
686
- < div className = "mt-4 p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800" >
687
- < p className = "text-xs text-blue-700 dark:text-blue-300 text-center" >
688
- < strong > Tip:</ strong > Run < code className = "bg-blue-100 dark:bg-blue-900 px-1 rounded" > git init</ code > in your project directory to initialize git source control.
689
- </ p >
690
- </ div >
691
- </ div >
692
699
) : ! gitStatus || ( ! gitStatus . modified ?. length && ! gitStatus . added ?. length && ! gitStatus . deleted ?. length && ! gitStatus . untracked ?. length ) ? (
693
700
< div className = "flex flex-col items-center justify-center h-32 text-gray-500 dark:text-gray-400" >
694
701
< GitCommit className = "w-12 h-12 mb-2 opacity-50" />
@@ -705,8 +712,8 @@ function GitPanel({ selectedProject, isMobile }) {
705
712
</ div >
706
713
) }
707
714
708
- { /* History View */ }
709
- { activeView === 'history' && (
715
+ { /* History View - Only show when git is available */ }
716
+ { activeView === 'history' && ! gitStatus ?. error && (
710
717
< div className = { `flex-1 overflow-y-auto ${ isMobile ? 'pb-20' : '' } ` } >
711
718
{ isLoading ? (
712
719
< div className = "flex items-center justify-center h-32" >
0 commit comments