zen-gitsync 2.0.5 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -2
- package/package.json +3 -1
- package/src/ui/client/src/App.vue +417 -123
- package/src/ui/client/src/components/CommitForm.vue +284 -211
- package/src/ui/client/src/components/GitStatus.vue +556 -171
- package/src/ui/client/src/components/LogList.vue +778 -94
- package/src/ui/client/src/stores/gitLogStore.ts +328 -13
- package/src/ui/client/stats.html +1 -1
- package/src/ui/public/assets/index-DaPynzAr.js +10 -0
- package/src/ui/public/assets/index-qfIezZmd.css +1 -0
- package/src/ui/public/assets/vendor-BcSuWc8z.js +45 -0
- package/src/ui/public/index.html +3 -3
- package/src/ui/server/index.js +287 -40
- package/src/ui/public/assets/index-CALk9kKc.js +0 -9
- package/src/ui/public/assets/index-D3zIiSNw.css +0 -1
- package/src/ui/public/assets/vendor-BfXVsoKv.js +0 -45
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted, computed } from 'vue'
|
|
2
|
+
import { ref, onMounted, computed, watch } from 'vue'
|
|
3
3
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
4
4
|
// import { io } from 'socket.io-client'
|
|
5
|
-
import { Refresh, ArrowLeft, ArrowRight, Folder, Document, ArrowUp, RefreshRight } from '@element-plus/icons-vue'
|
|
5
|
+
import { Refresh, ArrowLeft, ArrowRight, Folder, Document, ArrowUp, RefreshRight, Check, Close } from '@element-plus/icons-vue'
|
|
6
6
|
import { useGitLogStore } from '../stores/gitLogStore'
|
|
7
7
|
import { useGitStore } from '../stores/gitStore'
|
|
8
8
|
|
|
@@ -303,15 +303,14 @@ function handleFileClick(file: {path: string, type: string}) {
|
|
|
303
303
|
getFileDiff(file.path)
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
-
//
|
|
307
|
-
function
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
306
|
+
// 暂存单个文件
|
|
307
|
+
async function stageFile(filePath: string) {
|
|
308
|
+
await gitLogStore.addFileToStage(filePath)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// 取消暂存单个文件
|
|
312
|
+
async function unstageFile(filePath: string) {
|
|
313
|
+
await gitLogStore.unstageFile(filePath)
|
|
315
314
|
}
|
|
316
315
|
|
|
317
316
|
// 刷新Git状态的方法
|
|
@@ -349,26 +348,57 @@ async function revertFileChanges(filePath: string) {
|
|
|
349
348
|
// 刷新Git状态
|
|
350
349
|
await loadStatus()
|
|
351
350
|
} else {
|
|
352
|
-
|
|
351
|
+
// 使用自定义错误信息,避免显示undefined
|
|
352
|
+
ElMessage.error(result.error ? `撤回失败: ${result.error}` : '撤回文件修改失败,请重试')
|
|
353
353
|
}
|
|
354
354
|
} catch (error) {
|
|
355
|
-
//
|
|
356
|
-
if ((error as Error).message
|
|
357
|
-
|
|
355
|
+
// 用户取消操作不显示错误
|
|
356
|
+
if ((error as any) === 'cancel' || (error as Error).message === 'cancel') {
|
|
357
|
+
// 用户取消操作,不做任何处理,也不显示错误
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 其他错误情况才显示错误消息
|
|
362
|
+
// 避免显示undefined错误信息
|
|
363
|
+
const errorMessage = (error as Error).message || '未知错误';
|
|
364
|
+
if (errorMessage !== 'undefined') {
|
|
365
|
+
ElMessage.error(`撤回文件修改失败: ${errorMessage}`)
|
|
366
|
+
} else {
|
|
367
|
+
ElMessage.error('撤回文件修改失败,请重试')
|
|
358
368
|
}
|
|
359
369
|
}
|
|
360
370
|
}
|
|
361
371
|
|
|
372
|
+
// 提取文件名和目录
|
|
373
|
+
function getFileName(path: string): string {
|
|
374
|
+
const parts = path.split('/')
|
|
375
|
+
return parts[parts.length - 1]
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function getFileDirectory(path: string): string {
|
|
379
|
+
const parts = path.split('/')
|
|
380
|
+
if (parts.length <= 1) return ''
|
|
381
|
+
|
|
382
|
+
// 保留所有除最后一个部分的路径
|
|
383
|
+
return parts.slice(0, -1).join('/')
|
|
384
|
+
}
|
|
385
|
+
|
|
362
386
|
onMounted(() => {
|
|
363
387
|
// App.vue已经加载了Git相关数据,此时只需加载状态
|
|
364
388
|
// 如果已有初始目录,则只需加载状态
|
|
365
389
|
loadStatus()
|
|
366
390
|
})
|
|
367
391
|
|
|
392
|
+
// 监听autoUpdateEnabled的变化,手动调用toggleAutoUpdate
|
|
393
|
+
watch(() => gitLogStore.autoUpdateEnabled, (newValue, oldValue) => {
|
|
394
|
+
console.log(`自动更新状态变更: ${oldValue} -> ${newValue}`)
|
|
395
|
+
// 调用store中的方法来实现服务器通信功能
|
|
396
|
+
gitLogStore.toggleAutoUpdate()
|
|
397
|
+
}, { immediate: false })
|
|
398
|
+
|
|
368
399
|
// onUnmounted(() => {
|
|
369
400
|
// socket.disconnect()
|
|
370
401
|
// })
|
|
371
|
-
|
|
372
402
|
// 暴露刷新方法给父组件
|
|
373
403
|
defineExpose({
|
|
374
404
|
refreshStatus
|
|
@@ -377,49 +407,165 @@ defineExpose({
|
|
|
377
407
|
|
|
378
408
|
<template>
|
|
379
409
|
<div class="card">
|
|
380
|
-
<div class="current-directory">
|
|
381
|
-
<el-icon><Folder /></el-icon>
|
|
382
|
-
<span>{{ currentDirectory }}</span>
|
|
383
|
-
<el-button type="primary" size="small" @click="openDirectoryDialog" plain>
|
|
384
|
-
切换目录
|
|
385
|
-
</el-button>
|
|
386
|
-
</div>
|
|
387
410
|
<div class="status-header">
|
|
388
|
-
<h2>Git
|
|
389
|
-
<
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
411
|
+
<h2>Git 状态</h2>
|
|
412
|
+
<div class="header-actions">
|
|
413
|
+
<el-tooltip
|
|
414
|
+
:content="gitLogStore.autoUpdateEnabled ? '禁用自动更新文件状态' : '启用自动更新文件状态'"
|
|
415
|
+
placement="top"
|
|
416
|
+
:hide-after="1000"
|
|
417
|
+
>
|
|
418
|
+
<el-switch
|
|
419
|
+
v-model="gitLogStore.autoUpdateEnabled"
|
|
420
|
+
style="--el-switch-on-color: #67C23A; --el-switch-off-color: #909399; margin-right: 10px;"
|
|
421
|
+
inline-prompt
|
|
422
|
+
:active-icon="Check"
|
|
423
|
+
:inactive-icon="Close"
|
|
424
|
+
class="auto-update-switch"
|
|
425
|
+
/>
|
|
426
|
+
</el-tooltip>
|
|
427
|
+
<el-tooltip content="刷新状态" placement="top" :hide-after="1000">
|
|
428
|
+
<el-button
|
|
429
|
+
type="primary"
|
|
430
|
+
:icon="Refresh"
|
|
431
|
+
circle
|
|
432
|
+
size="small"
|
|
433
|
+
@click="refreshStatus"
|
|
434
|
+
:loading="isRefreshing"
|
|
435
|
+
/>
|
|
436
|
+
</el-tooltip>
|
|
437
|
+
</div>
|
|
400
438
|
</div>
|
|
401
|
-
|
|
402
|
-
<div
|
|
403
|
-
<div
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
439
|
+
|
|
440
|
+
<div class="card-content">
|
|
441
|
+
<div class="current-directory">
|
|
442
|
+
<el-icon><Folder /></el-icon>
|
|
443
|
+
<span>{{ currentDirectory }}</span>
|
|
444
|
+
<el-button type="primary" size="small" @click="openDirectoryDialog" plain>
|
|
445
|
+
切换目录
|
|
446
|
+
</el-button>
|
|
447
|
+
</div>
|
|
448
|
+
|
|
449
|
+
<div v-if="!gitStore.isGitRepo" class="status-box">
|
|
450
|
+
当前目录不是一个Git仓库
|
|
451
|
+
</div>
|
|
452
|
+
|
|
453
|
+
<!-- 现代化、简洁的文件列表 -->
|
|
454
|
+
<div v-if="gitLogStore.fileList.length" class="file-list-container">
|
|
455
|
+
<!-- 分组显示文件 -->
|
|
456
|
+
<div v-if="gitLogStore.fileList.some(f => f.type === 'added')" class="file-group">
|
|
457
|
+
<div class="file-group-header">已暂存的更改</div>
|
|
458
|
+
<div class="file-list">
|
|
459
|
+
<div
|
|
460
|
+
v-for="file in gitLogStore.fileList.filter(f => f.type === 'added')"
|
|
461
|
+
:key="file.path"
|
|
462
|
+
class="file-item"
|
|
463
|
+
@click="handleFileClick(file)"
|
|
464
|
+
>
|
|
465
|
+
<div class="file-info">
|
|
466
|
+
<div class="file-path-container">
|
|
467
|
+
<span class="file-name">{{ getFileName(file.path) }}</span>
|
|
468
|
+
<span class="file-directory">{{ getFileDirectory(file.path) }}</span>
|
|
469
|
+
</div>
|
|
470
|
+
</div>
|
|
471
|
+
<div class="file-actions">
|
|
472
|
+
<el-tooltip content="取消暂存" placement="top" :hide-after="1000">
|
|
473
|
+
<el-button
|
|
474
|
+
type="warning"
|
|
475
|
+
size="small"
|
|
476
|
+
circle
|
|
477
|
+
@click.stop="unstageFile(file.path)"
|
|
478
|
+
>-</el-button>
|
|
479
|
+
</el-tooltip>
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
</div>
|
|
483
|
+
</div>
|
|
484
|
+
|
|
485
|
+
<div v-if="gitLogStore.fileList.some(f => f.type === 'modified' || f.type === 'deleted')" class="file-group">
|
|
486
|
+
<div class="file-group-header">未暂存的更改</div>
|
|
487
|
+
<div class="file-list">
|
|
488
|
+
<div
|
|
489
|
+
v-for="file in gitLogStore.fileList.filter(f => f.type === 'modified' || f.type === 'deleted')"
|
|
490
|
+
:key="file.path"
|
|
491
|
+
class="file-item"
|
|
492
|
+
@click="handleFileClick(file)"
|
|
493
|
+
>
|
|
494
|
+
<div class="file-info">
|
|
495
|
+
<div class="file-status-indicator" :class="file.type"></div>
|
|
496
|
+
<div class="file-path-container">
|
|
497
|
+
<span class="file-name">{{ getFileName(file.path) }}</span>
|
|
498
|
+
<span class="file-directory">{{ getFileDirectory(file.path) }}</span>
|
|
499
|
+
</div>
|
|
500
|
+
</div>
|
|
501
|
+
<div class="file-actions">
|
|
502
|
+
<el-tooltip content="添加到暂存区" placement="top" :hide-after="1000">
|
|
503
|
+
<el-button
|
|
504
|
+
type="success"
|
|
505
|
+
size="small"
|
|
506
|
+
circle
|
|
507
|
+
@click.stop="stageFile(file.path)"
|
|
508
|
+
>+</el-button>
|
|
509
|
+
</el-tooltip>
|
|
510
|
+
<el-tooltip content="撤回修改" placement="top" :hide-after="1000">
|
|
511
|
+
<el-button
|
|
512
|
+
type="danger"
|
|
513
|
+
size="small"
|
|
514
|
+
:icon="RefreshRight"
|
|
515
|
+
circle
|
|
516
|
+
@click.stop="revertFileChanges(file.path)"
|
|
517
|
+
/>
|
|
518
|
+
</el-tooltip>
|
|
519
|
+
</div>
|
|
520
|
+
</div>
|
|
521
|
+
</div>
|
|
522
|
+
</div>
|
|
523
|
+
|
|
524
|
+
<div v-if="gitLogStore.fileList.some(f => f.type === 'untracked')" class="file-group">
|
|
525
|
+
<div class="file-group-header">未跟踪的文件</div>
|
|
526
|
+
<div class="file-list">
|
|
527
|
+
<div
|
|
528
|
+
v-for="file in gitLogStore.fileList.filter(f => f.type === 'untracked')"
|
|
529
|
+
:key="file.path"
|
|
530
|
+
class="file-item"
|
|
531
|
+
@click="handleFileClick(file)"
|
|
532
|
+
>
|
|
533
|
+
<div class="file-info">
|
|
534
|
+
<div class="file-status-indicator untracked"></div>
|
|
535
|
+
<div class="file-path-container">
|
|
536
|
+
<span class="file-name">{{ getFileName(file.path) }}</span>
|
|
537
|
+
<span class="file-directory">{{ getFileDirectory(file.path) }}</span>
|
|
538
|
+
</div>
|
|
539
|
+
</div>
|
|
540
|
+
<div class="file-actions">
|
|
541
|
+
<el-tooltip content="添加到暂存区" placement="top" :hide-after="1000">
|
|
542
|
+
<el-button
|
|
543
|
+
type="success"
|
|
544
|
+
size="small"
|
|
545
|
+
circle
|
|
546
|
+
@click.stop="stageFile(file.path)"
|
|
547
|
+
>+</el-button>
|
|
548
|
+
</el-tooltip>
|
|
549
|
+
<el-tooltip content="删除文件" placement="top" :hide-after="1000">
|
|
550
|
+
<el-button
|
|
551
|
+
type="danger"
|
|
552
|
+
size="small"
|
|
553
|
+
:icon="Close"
|
|
554
|
+
circle
|
|
555
|
+
@click.stop="revertFileChanges(file.path)"
|
|
556
|
+
/>
|
|
557
|
+
</el-tooltip>
|
|
558
|
+
</div>
|
|
559
|
+
</div>
|
|
560
|
+
</div>
|
|
411
561
|
</div>
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
:icon="RefreshRight"
|
|
418
|
-
circle
|
|
419
|
-
@click.stop="revertFileChanges(file.path)"
|
|
420
|
-
/>
|
|
421
|
-
</el-tooltip>
|
|
562
|
+
</div>
|
|
563
|
+
|
|
564
|
+
<div v-else-if="gitStore.isGitRepo" class="empty-status">
|
|
565
|
+
<div class="empty-icon">
|
|
566
|
+
<el-icon><Document /></el-icon>
|
|
422
567
|
</div>
|
|
568
|
+
<div class="empty-text">没有检测到任何更改</div>
|
|
423
569
|
</div>
|
|
424
570
|
</div>
|
|
425
571
|
|
|
@@ -505,6 +651,7 @@ defineExpose({
|
|
|
505
651
|
:title="`文件差异: ${selectedFile}`"
|
|
506
652
|
width="80%"
|
|
507
653
|
destroy-on-close
|
|
654
|
+
class="diff-dialog"
|
|
508
655
|
>
|
|
509
656
|
<div v-loading="isLoadingDiff" class="diff-content">
|
|
510
657
|
<div v-if="diffContent" v-html="formatDiff(diffContent)" class="diff-formatted"></div>
|
|
@@ -535,226 +682,418 @@ defineExpose({
|
|
|
535
682
|
.card {
|
|
536
683
|
background-color: #fff;
|
|
537
684
|
border-radius: 8px;
|
|
538
|
-
box-shadow: 0 2px
|
|
539
|
-
|
|
540
|
-
|
|
685
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.03);
|
|
686
|
+
border: 1px solid rgba(0, 0, 0, 0.03);
|
|
687
|
+
height: 100%;
|
|
688
|
+
width: 100%;
|
|
689
|
+
display: flex;
|
|
690
|
+
flex-direction: column;
|
|
691
|
+
overflow: hidden;
|
|
541
692
|
}
|
|
542
693
|
|
|
543
694
|
.status-header {
|
|
544
695
|
display: flex;
|
|
545
696
|
justify-content: space-between;
|
|
546
697
|
align-items: center;
|
|
547
|
-
|
|
698
|
+
padding: 8px 16px;
|
|
699
|
+
border-bottom: 1px solid #f0f0f0;
|
|
700
|
+
height: 36px;
|
|
548
701
|
}
|
|
549
702
|
|
|
550
703
|
.status-header h2 {
|
|
551
704
|
margin: 0;
|
|
705
|
+
font-size: 16px;
|
|
706
|
+
font-weight: 500;
|
|
707
|
+
color: #303133;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.header-actions {
|
|
711
|
+
display: flex;
|
|
712
|
+
align-items: center;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
.card-content {
|
|
716
|
+
padding: 15px;
|
|
717
|
+
overflow-y: auto;
|
|
718
|
+
flex: 1;
|
|
719
|
+
display: flex;
|
|
720
|
+
flex-direction: column;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
.current-directory {
|
|
724
|
+
display: flex;
|
|
725
|
+
align-items: center;
|
|
726
|
+
margin-bottom: 16px;
|
|
727
|
+
padding: 10px;
|
|
728
|
+
background-color: #f8f9fa;
|
|
729
|
+
border-radius: 6px;
|
|
730
|
+
font-family: monospace;
|
|
731
|
+
border: 1px solid #f0f0f0;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
.current-directory .el-icon {
|
|
735
|
+
margin-right: 8px;
|
|
736
|
+
color: #409eff;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.current-directory span {
|
|
740
|
+
flex-grow: 1;
|
|
741
|
+
word-break: break-all;
|
|
742
|
+
margin-right: 10px;
|
|
552
743
|
}
|
|
553
744
|
|
|
554
745
|
.status-box {
|
|
555
746
|
white-space: pre-wrap;
|
|
556
747
|
font-family: monospace;
|
|
557
|
-
background-color: #
|
|
558
|
-
padding:
|
|
559
|
-
border-radius:
|
|
560
|
-
margin-bottom:
|
|
561
|
-
max-height:
|
|
748
|
+
background-color: #f8f9fa;
|
|
749
|
+
padding: 16px;
|
|
750
|
+
border-radius: 6px;
|
|
751
|
+
margin-bottom: 20px;
|
|
752
|
+
max-height: 200px;
|
|
562
753
|
overflow-y: auto;
|
|
754
|
+
border: 1px solid #f0f0f0;
|
|
755
|
+
font-size: 14px;
|
|
756
|
+
line-height: 1.5;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/* 现代化的文件列表容器 */
|
|
760
|
+
.file-list-container {
|
|
761
|
+
flex: 1;
|
|
762
|
+
overflow: hidden;
|
|
763
|
+
display: flex;
|
|
764
|
+
flex-direction: column;
|
|
765
|
+
margin-bottom: 0;
|
|
766
|
+
gap: 12px;
|
|
767
|
+
height: calc(100% - 70px); /* 给底部留出些空间 */
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
.file-group {
|
|
771
|
+
background-color: #f8f9fa;
|
|
772
|
+
border-radius: 6px;
|
|
773
|
+
overflow: hidden;
|
|
774
|
+
border: 1px solid #ebeef5;
|
|
775
|
+
margin-bottom: 12px;
|
|
776
|
+
display: flex;
|
|
777
|
+
flex-direction: column;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/* 让每个文件组根据内容自动增长 */
|
|
781
|
+
.file-group {
|
|
782
|
+
flex: 0 1 auto; /* 不主动增长,但允许缩小,基于内容大小 */
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/* 最后一个分组可以吸收剩余空间 */
|
|
786
|
+
.file-group:last-child {
|
|
787
|
+
margin-bottom: 0;
|
|
788
|
+
flex: 1 1 auto; /* 可以增长占用剩余空间 */
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
.file-group-header {
|
|
792
|
+
font-size: 14px;
|
|
793
|
+
font-weight: bold;
|
|
794
|
+
padding: 8px 12px;
|
|
795
|
+
background-color: #f0f2f5;
|
|
796
|
+
color: #606266;
|
|
797
|
+
border-bottom: 1px solid #ebeef5;
|
|
798
|
+
flex-shrink: 0; /* 防止header被压缩 */
|
|
563
799
|
}
|
|
564
800
|
|
|
565
801
|
.file-list {
|
|
566
|
-
max-height: 300px;
|
|
567
802
|
overflow-y: auto;
|
|
803
|
+
min-height: 40px; /* 最小高度 */
|
|
804
|
+
flex-grow: 1; /* 允许文件列表在文件组内扩展 */
|
|
805
|
+
padding: 0;
|
|
806
|
+
margin: 0;
|
|
807
|
+
scrollbar-width: thin; /* Firefox */
|
|
808
|
+
scrollbar-color: rgba(144, 147, 153, 0.3) transparent; /* Firefox */
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/* Webkit浏览器的滚动条样式 */
|
|
812
|
+
.file-list::-webkit-scrollbar {
|
|
813
|
+
width: 6px;
|
|
814
|
+
height: 6px;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
.file-list::-webkit-scrollbar-thumb {
|
|
818
|
+
background-color: rgba(144, 147, 153, 0.3);
|
|
819
|
+
border-radius: 4px;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
.file-list::-webkit-scrollbar-thumb:hover {
|
|
823
|
+
background-color: rgba(144, 147, 153, 0.5);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.file-list::-webkit-scrollbar-track {
|
|
827
|
+
background-color: transparent;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
/* 让每个文件列表自适应高度,使其在容器中更好地分配空间 */
|
|
831
|
+
.file-list:empty {
|
|
832
|
+
display: none; /* 如果列表为空,不显示 */
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/* 当没有足够的项目填充列表时,禁用滚动 */
|
|
836
|
+
.file-list:has(.empty-file-group) {
|
|
837
|
+
overflow-y: hidden;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/* 替换为更兼容的选择器 */
|
|
841
|
+
/* 改用直接为empty-file-group父容器添加样式 */
|
|
842
|
+
.empty-file-container {
|
|
843
|
+
overflow-y: hidden !important; /* 强制禁用滚动 */
|
|
844
|
+
display: flex;
|
|
845
|
+
flex-direction: column;
|
|
846
|
+
align-items: stretch;
|
|
847
|
+
flex: 1;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
.empty-file-group {
|
|
851
|
+
padding: 16px;
|
|
852
|
+
text-align: center;
|
|
853
|
+
color: #909399;
|
|
854
|
+
font-size: 13px;
|
|
855
|
+
font-style: italic;
|
|
856
|
+
display: flex;
|
|
857
|
+
align-items: center;
|
|
858
|
+
justify-content: center;
|
|
859
|
+
min-height: 50px; /* 增加最小高度 */
|
|
860
|
+
background-color: #f8f9fa;
|
|
861
|
+
border-radius: 4px;
|
|
862
|
+
margin: 8px;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/* 自定义每个分组的展开逻辑 */
|
|
866
|
+
/* 已暂存文件分组 - 保持小巧 */
|
|
867
|
+
.file-group:nth-child(1) {
|
|
868
|
+
flex: 0 1 auto;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/* 未暂存更改分组 - 稍微大一些 */
|
|
872
|
+
.file-group:nth-child(2) {
|
|
873
|
+
flex: 0 1 auto;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/* 未跟踪文件分组 - 可以占据剩余空间 */
|
|
877
|
+
.file-group:nth-child(3) {
|
|
878
|
+
flex: 1 1 auto;
|
|
568
879
|
}
|
|
569
880
|
|
|
570
881
|
.file-item {
|
|
571
882
|
padding: 8px 12px;
|
|
572
|
-
margin-bottom: 5px;
|
|
573
|
-
border-radius: 4px;
|
|
574
|
-
cursor: pointer;
|
|
575
883
|
display: flex;
|
|
576
884
|
align-items: center;
|
|
577
885
|
justify-content: space-between;
|
|
886
|
+
border-bottom: 1px solid #ebeef5;
|
|
887
|
+
cursor: pointer;
|
|
888
|
+
transition: background-color 0.2s;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
.file-item:last-child {
|
|
892
|
+
border-bottom: none;
|
|
578
893
|
}
|
|
579
894
|
|
|
580
895
|
.file-item:hover {
|
|
581
|
-
background-color: #
|
|
896
|
+
background-color: #ecf5ff;
|
|
582
897
|
}
|
|
583
898
|
|
|
584
899
|
.file-info {
|
|
585
900
|
display: flex;
|
|
586
901
|
align-items: center;
|
|
587
902
|
flex-grow: 1;
|
|
903
|
+
overflow: hidden;
|
|
904
|
+
white-space: nowrap;
|
|
905
|
+
gap: 8px;
|
|
588
906
|
}
|
|
589
907
|
|
|
590
|
-
.file-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
908
|
+
.file-status-indicator {
|
|
909
|
+
width: 6px;
|
|
910
|
+
height: 6px;
|
|
911
|
+
border-radius: 50%;
|
|
912
|
+
background-color: #409eff;
|
|
913
|
+
flex-shrink: 0;
|
|
594
914
|
}
|
|
595
915
|
|
|
596
|
-
.file-
|
|
597
|
-
|
|
916
|
+
.file-status-indicator.added {
|
|
917
|
+
background-color: #67c23a;
|
|
598
918
|
}
|
|
599
919
|
|
|
600
|
-
.file-
|
|
601
|
-
|
|
602
|
-
padding: 2px 6px;
|
|
603
|
-
border-radius: 10px;
|
|
604
|
-
margin-right: 10px;
|
|
605
|
-
flex-shrink: 0;
|
|
920
|
+
.file-status-indicator.modified {
|
|
921
|
+
background-color: #409eff;
|
|
606
922
|
}
|
|
607
923
|
|
|
608
|
-
.
|
|
609
|
-
background-color: #
|
|
610
|
-
color: #67c23a;
|
|
924
|
+
.file-status-indicator.deleted {
|
|
925
|
+
background-color: #f56c6c;
|
|
611
926
|
}
|
|
612
927
|
|
|
613
|
-
.
|
|
614
|
-
background-color: #
|
|
615
|
-
color: #409eff;
|
|
928
|
+
.file-status-indicator.untracked {
|
|
929
|
+
background-color: #e6a23c;
|
|
616
930
|
}
|
|
617
931
|
|
|
618
|
-
.
|
|
619
|
-
|
|
620
|
-
|
|
932
|
+
.file-path-container {
|
|
933
|
+
display: flex;
|
|
934
|
+
flex-direction: column;
|
|
935
|
+
overflow: hidden;
|
|
621
936
|
}
|
|
622
937
|
|
|
623
|
-
.
|
|
624
|
-
|
|
625
|
-
color: #
|
|
938
|
+
.file-name {
|
|
939
|
+
font-weight: 500;
|
|
940
|
+
color: #303133;
|
|
941
|
+
overflow: hidden;
|
|
942
|
+
text-overflow: ellipsis;
|
|
943
|
+
line-height: 1.2;
|
|
626
944
|
}
|
|
627
945
|
|
|
628
|
-
.file-
|
|
629
|
-
font-
|
|
630
|
-
|
|
946
|
+
.file-directory {
|
|
947
|
+
font-size: 12px;
|
|
948
|
+
color: #909399;
|
|
949
|
+
overflow: hidden;
|
|
950
|
+
text-overflow: ellipsis;
|
|
951
|
+
line-height: 1.2;
|
|
631
952
|
}
|
|
632
953
|
|
|
633
|
-
.
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
padding: 10px;
|
|
639
|
-
background-color: #f5f7fa;
|
|
640
|
-
border-radius: 4px;
|
|
954
|
+
.file-actions {
|
|
955
|
+
display: flex;
|
|
956
|
+
gap: 5px;
|
|
957
|
+
opacity: 0;
|
|
958
|
+
transition: opacity 0.2s;
|
|
641
959
|
}
|
|
642
960
|
|
|
643
|
-
.
|
|
644
|
-
|
|
645
|
-
line-height: 1.5;
|
|
961
|
+
.file-item:hover .file-actions {
|
|
962
|
+
opacity: 1;
|
|
646
963
|
}
|
|
647
964
|
|
|
648
|
-
.
|
|
965
|
+
.empty-status {
|
|
649
966
|
display: flex;
|
|
650
|
-
|
|
967
|
+
flex-direction: column;
|
|
651
968
|
align-items: center;
|
|
969
|
+
justify-content: center;
|
|
970
|
+
height: calc(100% - 70px);
|
|
971
|
+
background-color: #f8f9fa;
|
|
972
|
+
border-radius: 6px;
|
|
973
|
+
border: 1px solid #ebeef5;
|
|
652
974
|
margin-top: 15px;
|
|
653
975
|
}
|
|
654
976
|
|
|
655
|
-
.
|
|
656
|
-
|
|
977
|
+
.empty-icon {
|
|
978
|
+
font-size: 32px;
|
|
979
|
+
color: #c0c4cc;
|
|
980
|
+
margin-bottom: 10px;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
.empty-text {
|
|
984
|
+
color: #909399;
|
|
657
985
|
font-size: 14px;
|
|
658
|
-
color: #606266;
|
|
659
986
|
}
|
|
660
987
|
|
|
661
|
-
|
|
988
|
+
/* 添加针对空内容区域的样式 */
|
|
989
|
+
.card-content:empty {
|
|
662
990
|
display: flex;
|
|
663
991
|
align-items: center;
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
border
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
.current-directory .el-icon {
|
|
672
|
-
margin-right: 8px;
|
|
673
|
-
color: #409eff;
|
|
992
|
+
justify-content: center;
|
|
993
|
+
background-color: #f8f9fa;
|
|
994
|
+
border-radius: 6px;
|
|
995
|
+
border: 1px dashed #dcdfe6;
|
|
996
|
+
color: #909399;
|
|
997
|
+
height: 100%;
|
|
674
998
|
}
|
|
675
999
|
|
|
676
|
-
.
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
margin-right: 10px;
|
|
1000
|
+
.card-content:empty::after {
|
|
1001
|
+
content: '没有Git状态信息可显示';
|
|
1002
|
+
font-size: 14px;
|
|
680
1003
|
}
|
|
681
1004
|
|
|
1005
|
+
/* 添加目录浏览相关样式 */
|
|
682
1006
|
.browser-current-path {
|
|
683
|
-
margin-bottom: 10px;
|
|
684
|
-
font-size: 14px;
|
|
685
|
-
color: #606266;
|
|
686
|
-
background-color: #f5f7fa;
|
|
687
|
-
padding: 8px 12px;
|
|
688
|
-
border-radius: 4px;
|
|
689
1007
|
font-family: monospace;
|
|
690
|
-
|
|
1008
|
+
margin-bottom: 15px;
|
|
1009
|
+
padding: 10px;
|
|
1010
|
+
background-color: #f5f7fa;
|
|
1011
|
+
border-radius: 6px;
|
|
1012
|
+
overflow-x: auto;
|
|
1013
|
+
white-space: nowrap;
|
|
1014
|
+
border: 1px solid #ebeef5;
|
|
691
1015
|
}
|
|
692
1016
|
|
|
693
1017
|
.browser-error {
|
|
694
|
-
margin-bottom: 10px;
|
|
695
1018
|
color: #f56c6c;
|
|
696
|
-
|
|
1019
|
+
margin: 10px 0;
|
|
1020
|
+
padding: 10px;
|
|
697
1021
|
background-color: #fef0f0;
|
|
698
1022
|
border-radius: 4px;
|
|
1023
|
+
border-left: 3px solid #f56c6c;
|
|
699
1024
|
}
|
|
700
1025
|
|
|
701
|
-
.
|
|
702
|
-
padding: 10px;
|
|
703
|
-
height: 400px;
|
|
1026
|
+
.browser-nav {
|
|
704
1027
|
display: flex;
|
|
705
|
-
|
|
1028
|
+
gap: 10px;
|
|
1029
|
+
margin-bottom: 10px;
|
|
706
1030
|
}
|
|
707
1031
|
|
|
708
|
-
.
|
|
709
|
-
|
|
1032
|
+
.no-padding-left {
|
|
1033
|
+
padding-left: 12px;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
.directory-browser {
|
|
1037
|
+
height: 400px;
|
|
1038
|
+
border: 1px solid #ebeef5;
|
|
1039
|
+
border-radius: 6px;
|
|
1040
|
+
overflow: hidden;
|
|
710
1041
|
display: flex;
|
|
711
|
-
|
|
712
|
-
position: sticky;
|
|
713
|
-
top: 0;
|
|
714
|
-
background-color: #fff;
|
|
715
|
-
z-index: 1;
|
|
716
|
-
padding: 10px 0;
|
|
1042
|
+
flex-direction: column;
|
|
717
1043
|
}
|
|
718
1044
|
|
|
719
1045
|
.directory-items-container {
|
|
720
1046
|
flex: 1;
|
|
721
1047
|
overflow-y: auto;
|
|
1048
|
+
background-color: #f8f9fa;
|
|
1049
|
+
padding: 10px;
|
|
722
1050
|
}
|
|
723
1051
|
|
|
724
1052
|
.directory-items {
|
|
725
1053
|
list-style: none;
|
|
726
1054
|
padding: 0;
|
|
727
1055
|
margin: 0;
|
|
1056
|
+
display: grid;
|
|
1057
|
+
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
|
1058
|
+
gap: 10px;
|
|
728
1059
|
}
|
|
729
1060
|
|
|
730
1061
|
.directory-item {
|
|
731
|
-
padding: 8px 12px;
|
|
732
|
-
margin-bottom: 5px;
|
|
733
|
-
border-radius: 4px;
|
|
734
|
-
cursor: pointer;
|
|
735
1062
|
display: flex;
|
|
736
1063
|
align-items: center;
|
|
1064
|
+
padding: 8px;
|
|
1065
|
+
cursor: pointer;
|
|
1066
|
+
border-radius: 4px;
|
|
1067
|
+
background-color: white;
|
|
1068
|
+
border: 1px solid #ebeef5;
|
|
1069
|
+
transition: all 0.2s;
|
|
1070
|
+
overflow: hidden;
|
|
1071
|
+
white-space: nowrap;
|
|
1072
|
+
text-overflow: ellipsis;
|
|
1073
|
+
gap: 5px;
|
|
737
1074
|
}
|
|
738
1075
|
|
|
739
1076
|
.directory-item:hover {
|
|
740
|
-
background-color: #
|
|
1077
|
+
background-color: #ecf5ff;
|
|
1078
|
+
border-color: #c6e2ff;
|
|
741
1079
|
}
|
|
742
1080
|
|
|
743
1081
|
.directory-item.directory {
|
|
1082
|
+
background-color: #f0f7ff;
|
|
744
1083
|
color: #409eff;
|
|
745
1084
|
}
|
|
746
1085
|
|
|
747
|
-
.directory-item.
|
|
748
|
-
|
|
1086
|
+
.directory-item .el-icon {
|
|
1087
|
+
margin-right: 5px;
|
|
1088
|
+
flex-shrink: 0;
|
|
749
1089
|
}
|
|
750
1090
|
|
|
751
|
-
.directory-item .el-icon {
|
|
752
|
-
|
|
1091
|
+
.directory-item.directory .el-icon {
|
|
1092
|
+
color: #409eff;
|
|
753
1093
|
}
|
|
754
1094
|
|
|
755
|
-
.directory-item
|
|
756
|
-
|
|
757
|
-
word-break: break-all;
|
|
1095
|
+
.directory-item.file .el-icon {
|
|
1096
|
+
color: #909399;
|
|
758
1097
|
}
|
|
759
1098
|
|
|
760
1099
|
.directory-buttons {
|
|
@@ -762,41 +1101,87 @@ defineExpose({
|
|
|
762
1101
|
gap: 10px;
|
|
763
1102
|
margin-top: 10px;
|
|
764
1103
|
}
|
|
765
|
-
|
|
766
|
-
/* 移除按钮左侧的内边距 */
|
|
767
|
-
.no-padding-left {
|
|
768
|
-
padding-left: 8px !important;
|
|
769
|
-
}
|
|
770
1104
|
</style>
|
|
771
1105
|
|
|
772
|
-
<!--
|
|
1106
|
+
<!-- 非scoped样式,使diff格式化样式对动态内容生效 -->
|
|
773
1107
|
<style>
|
|
774
1108
|
.diff-header {
|
|
775
1109
|
font-weight: bold;
|
|
776
1110
|
background-color: #e6f1fc;
|
|
777
|
-
padding:
|
|
778
|
-
margin:
|
|
1111
|
+
padding: 5px;
|
|
1112
|
+
margin: 8px 0;
|
|
1113
|
+
border-radius: 4px;
|
|
1114
|
+
color: #0366d6;
|
|
1115
|
+
border-bottom: 1px solid #c8e1ff;
|
|
779
1116
|
}
|
|
780
1117
|
|
|
781
1118
|
.diff-old-file, .diff-new-file {
|
|
782
|
-
color: #
|
|
1119
|
+
color: #586069;
|
|
1120
|
+
padding: 2px 5px;
|
|
1121
|
+
font-family: monospace;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
.diff-old-file {
|
|
1125
|
+
color: #cb2431;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
.diff-new-file {
|
|
1129
|
+
color: #22863a;
|
|
783
1130
|
}
|
|
784
1131
|
|
|
785
1132
|
.diff-hunk-header {
|
|
786
1133
|
color: #6f42c1;
|
|
1134
|
+
background-color: #f1f8ff;
|
|
1135
|
+
padding: 2px 5px;
|
|
1136
|
+
margin: 5px 0;
|
|
1137
|
+
border-radius: 3px;
|
|
1138
|
+
font-family: monospace;
|
|
787
1139
|
}
|
|
788
1140
|
|
|
789
1141
|
.diff-added {
|
|
790
1142
|
background-color: #e6ffed;
|
|
791
|
-
color: #
|
|
1143
|
+
color: #22863a;
|
|
1144
|
+
padding: 0 5px;
|
|
1145
|
+
border-left: 4px solid #22863a;
|
|
1146
|
+
font-family: monospace;
|
|
1147
|
+
display: block;
|
|
1148
|
+
margin: 2px 0;
|
|
792
1149
|
}
|
|
793
1150
|
|
|
794
1151
|
.diff-removed {
|
|
795
1152
|
background-color: #ffeef0;
|
|
796
|
-
color: #
|
|
1153
|
+
color: #cb2431;
|
|
1154
|
+
padding: 0 5px;
|
|
1155
|
+
border-left: 4px solid #cb2431;
|
|
1156
|
+
font-family: monospace;
|
|
1157
|
+
display: block;
|
|
1158
|
+
margin: 2px 0;
|
|
797
1159
|
}
|
|
798
1160
|
|
|
799
1161
|
.diff-context {
|
|
800
1162
|
color: #444;
|
|
1163
|
+
padding: 0 5px;
|
|
1164
|
+
font-family: monospace;
|
|
1165
|
+
display: block;
|
|
1166
|
+
margin: 2px 0;
|
|
1167
|
+
background-color: #fafbfc;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
/* 增加自动更新开关的样式 */
|
|
1171
|
+
.auto-update-switch .el-switch__core {
|
|
1172
|
+
transition: all 0.3s ease-in-out;
|
|
1173
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
.auto-update-switch .el-switch__core:hover {
|
|
1177
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
.auto-update-switch.is-checked .el-switch__core {
|
|
1181
|
+
box-shadow: 0 2px 5px rgba(103, 194, 58, 0.3);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
.auto-update-switch.is-checked .el-switch__core:hover {
|
|
1185
|
+
box-shadow: 0 2px 8px rgba(103, 194, 58, 0.5);
|
|
801
1186
|
}
|
|
802
1187
|
</style>
|