adtec-core-package 3.1.8 → 3.2.0
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/.idea/codeStyles/Project.xml +61 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/.idea//345/211/215/347/253/257/346/240/270/345/277/203/345/214/205.iml +8 -0
- package/package.json +2 -1
- package/src/assets/style/index.less +30 -42
- package/src/assets/style/scrollbar-classic.less +105 -0
- package/src/assets/style/scrollbar-classic.scss +105 -0
- package/src/components/ElCardList.vue +7 -1
- package/src/components/Scrollbars/ElScrollbars.vue +10 -2
- package/src/components/editor-main/src/assets/styles/_variables.less +1 -1
- package/src/components/upload/DocxJsViewer.vue +2 -16
- package/src/components/upload/FileView.vue +7 -2
- package/src/components/upload/OfficePreview.vue +9 -1
- package/src/components/upload/PdfJsViewer.vue +2 -2
- package/src/config/VxeTableConfig.ts +2 -2
- package/src/css/elementUI/common/var.scss +4 -4
- package/src/css/elementUI/mixins/mixins.scss +4 -28
- package/src/css/elementUI/scrollbar.scss +20 -5
- package/src/css/vxeTableUI/components/table.scss +22 -29
- package/src/utils/excelPreviewUtil.ts +219 -45
- package/src/utils/officePreviewUtil.ts +6 -0
- package/.claude/skills/gitnexus/gitnexus-cli/SKILL.md +0 -83
- package/.claude/skills/gitnexus/gitnexus-debugging/SKILL.md +0 -89
- package/.claude/skills/gitnexus/gitnexus-exploring/SKILL.md +0 -78
- package/.claude/skills/gitnexus/gitnexus-guide/SKILL.md +0 -64
- package/.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md +0 -97
- package/.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md +0 -121
- package/.editorconfig +0 -6
- package/.prettierrc.json +0 -7
- package/.vscode/extensions.json +0 -8
- package/AGENTS.md +0 -43
- package/CLAUDE.md +0 -43
- package/adtec-core-package/adtec-core-package.css +0 -1
- package/adtec-core-package/adtec-core-package.js +0 -41216
- package/adtec-core-package/adtec-core-package.umd.cjs +0 -87
- package/adtec-core-package/favicon.ico +0 -0
- package/adtec-core-package-3.1.7.tgz +0 -0
- package/auto-imports.d.ts +0 -299
- package/env.d.ts +0 -1
- package/eslint.config.js +0 -56
- package/index.html +0 -13
- package/package/.editorconfig +0 -6
- package/package/adtec-core-package/adtec-core-package.css +0 -1
- package/package/adtec-core-package/adtec-core-package.js +0 -41216
- package/package/adtec-core-package/adtec-core-package.umd.cjs +0 -87
- package/package/adtec-core-package/favicon.ico +0 -0
- package/package/index.html +0 -13
- package/package/prebuilt/umo-editor/favicon.ico +0 -0
- package/package/prebuilt/umo-editor/umo-editor.css +0 -1
- package/package/public/favicon.ico +0 -0
- package/package/src/assets/base.css +0 -86
- package/package/src/assets/main.css +0 -35
- package/package/src/components/editor-main/src/extensions/bookmark.js +0 -110
- package/prebuilt/umo-editor/umo-editor.js.map +0 -1
- package/tsconfig.app.json +0 -12
- package/tsconfig.json +0 -11
- package/tsconfig.node.json +0 -18
- package/vite.config.ts +0 -46
- package/vite.config.umo.ts +0 -81
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
@use 'function' as *;
|
|
2
2
|
@use '../common/var' as *;
|
|
3
|
+
@use '../../../assets/style/scrollbar-classic.scss' as classic;
|
|
3
4
|
// forward mixins
|
|
4
5
|
@forward 'config';
|
|
5
6
|
@forward 'function';
|
|
@@ -22,35 +23,10 @@
|
|
|
22
23
|
|
|
23
24
|
// Scrollbar
|
|
24
25
|
@mixin scroll-bar {
|
|
25
|
-
|
|
26
|
-
$scrollbar-track-background: getCssVar('fill-color', 'blank');
|
|
26
|
+
@include classic.adtec-scrollbar-hidden;
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
width: 6px;
|
|
31
|
-
|
|
32
|
-
&:horizontal {
|
|
33
|
-
height: 6px;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
&-thumb {
|
|
37
|
-
border-radius: 5px;
|
|
38
|
-
width: 6px;
|
|
39
|
-
background: $scrollbar-thumb-background;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
&-corner {
|
|
43
|
-
background: $scrollbar-track-background;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
&-track {
|
|
47
|
-
background: $scrollbar-track-background;
|
|
48
|
-
|
|
49
|
-
&-piece {
|
|
50
|
-
background: $scrollbar-track-background;
|
|
51
|
-
width: 6px;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
28
|
+
&:hover {
|
|
29
|
+
@include classic.adtec-scrollbar-active;
|
|
54
30
|
}
|
|
55
31
|
}
|
|
56
32
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
@use 'mixins/mixins' as *;
|
|
4
4
|
@use 'mixins/var' as *;
|
|
5
5
|
@use 'common/var' as *;
|
|
6
|
+
@use '../../assets/style/scrollbar-classic.scss' as classic;
|
|
6
7
|
|
|
7
8
|
@include b(scrollbar) {
|
|
8
9
|
@include set-component-css-var('scrollbar', $scrollbar);
|
|
@@ -16,6 +17,9 @@
|
|
|
16
17
|
@include e(wrap) {
|
|
17
18
|
overflow: auto;
|
|
18
19
|
height: 100%;
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
/* 预留滚动条槽位,避免 thumb 压在正文上 */
|
|
22
|
+
padding-right: calc(var(--el-scrollbar-size, 8px) + 4px);
|
|
19
23
|
|
|
20
24
|
@include m(hidden-default) {
|
|
21
25
|
scrollbar-width: none;
|
|
@@ -31,7 +35,7 @@
|
|
|
31
35
|
width: 0;
|
|
32
36
|
height: 0;
|
|
33
37
|
cursor: pointer;
|
|
34
|
-
border-radius:
|
|
38
|
+
border-radius: calc(var(--el-scrollbar-size, 8px) / 2);
|
|
35
39
|
background-color: var(
|
|
36
40
|
#{getCssVarName('scrollbar-bg-color')},
|
|
37
41
|
map.get($scrollbar, 'bg-color')
|
|
@@ -56,14 +60,17 @@
|
|
|
56
60
|
|
|
57
61
|
@include e(bar) {
|
|
58
62
|
position: absolute;
|
|
59
|
-
right:
|
|
63
|
+
right: 4px;
|
|
60
64
|
bottom: 2px;
|
|
61
65
|
z-index: 1;
|
|
62
|
-
border-radius:
|
|
66
|
+
border-radius: calc(var(--el-scrollbar-size, 8px) / 2);
|
|
67
|
+
opacity: 0;
|
|
68
|
+
transition: opacity getCssVar('transition-duration') ease-out;
|
|
63
69
|
|
|
64
70
|
@include when(vertical) {
|
|
65
|
-
width:
|
|
71
|
+
width: var(--el-scrollbar-size, 8px);
|
|
66
72
|
top: 2px;
|
|
73
|
+
background-color: rgba(0, 0, 0, 0.04);
|
|
67
74
|
|
|
68
75
|
> div {
|
|
69
76
|
width: 100%;
|
|
@@ -71,14 +78,22 @@
|
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
@include when(horizontal) {
|
|
74
|
-
height:
|
|
81
|
+
height: var(--el-scrollbar-size, 8px);
|
|
75
82
|
left: 2px;
|
|
83
|
+
background-color: rgba(0, 0, 0, 0.04);
|
|
76
84
|
|
|
77
85
|
> div {
|
|
78
86
|
height: 100%;
|
|
79
87
|
}
|
|
80
88
|
}
|
|
81
89
|
}
|
|
90
|
+
|
|
91
|
+
&:hover,
|
|
92
|
+
&:active {
|
|
93
|
+
@include e(bar) {
|
|
94
|
+
opacity: 1;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
82
97
|
}
|
|
83
98
|
|
|
84
99
|
.#{$namespace}-scrollbar-fade {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@use '../helpers/baseMixin.scss';
|
|
2
|
+
@use '../../../assets/style/scrollbar-classic.scss' as classic;
|
|
2
3
|
@use './icon.scss';
|
|
3
4
|
@use './table-module/all.scss';
|
|
4
5
|
|
|
@@ -79,34 +80,16 @@
|
|
|
79
80
|
overflow-x: scroll;
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
/*
|
|
83
|
+
/* vxe 表格:hover 时显示现代圆角滚动条 */
|
|
83
84
|
.vxe-table--scroll-x-handle,
|
|
84
85
|
.vxe-table--scroll-y-handle {
|
|
85
|
-
scrollbar-
|
|
86
|
-
-ms-overflow-style: none;
|
|
87
|
-
&::-webkit-scrollbar {
|
|
88
|
-
width: 8px;
|
|
89
|
-
height: 8px;
|
|
90
|
-
background: transparent;
|
|
91
|
-
}
|
|
92
|
-
&::-webkit-scrollbar-thumb {
|
|
93
|
-
background: transparent;
|
|
94
|
-
border-radius: 4px;
|
|
95
|
-
}
|
|
96
|
-
&::-webkit-scrollbar-track {
|
|
97
|
-
background: transparent;
|
|
98
|
-
}
|
|
86
|
+
@include classic.adtec-scrollbar-hidden;
|
|
99
87
|
}
|
|
100
88
|
|
|
101
89
|
.vxe-table:hover {
|
|
102
90
|
.vxe-table--scroll-x-handle,
|
|
103
91
|
.vxe-table--scroll-y-handle {
|
|
104
|
-
scrollbar-
|
|
105
|
-
scrollbar-color: #DDDEE0 transparent;
|
|
106
|
-
}
|
|
107
|
-
.vxe-table--scroll-x-handle::-webkit-scrollbar-thumb,
|
|
108
|
-
.vxe-table--scroll-y-handle::-webkit-scrollbar-thumb {
|
|
109
|
-
background: #DDDEE0;
|
|
92
|
+
@include classic.adtec-vxe-scrollbar-active;
|
|
110
93
|
}
|
|
111
94
|
}
|
|
112
95
|
|
|
@@ -604,10 +587,10 @@
|
|
|
604
587
|
}
|
|
605
588
|
}
|
|
606
589
|
.vxe-table--scroll-x-virtual {
|
|
607
|
-
height: 0
|
|
590
|
+
height: 0;
|
|
608
591
|
}
|
|
609
592
|
.vxe-table--scroll-y-virtual {
|
|
610
|
-
width:
|
|
593
|
+
width: 0;
|
|
611
594
|
}
|
|
612
595
|
.vxe-table--scroll-x-virtual,
|
|
613
596
|
.vxe-table--scroll-y-virtual {
|
|
@@ -635,10 +618,10 @@
|
|
|
635
618
|
.vxe-table--scroll-x-handle {
|
|
636
619
|
overflow-y: hidden;
|
|
637
620
|
overflow-x: scroll;
|
|
638
|
-
height: 8px;
|
|
621
|
+
height: var(--vxe-scrollbar-size, 8px);
|
|
639
622
|
}
|
|
640
623
|
.vxe-table--scroll-x-wrapper {
|
|
641
|
-
height:
|
|
624
|
+
height: 100%;
|
|
642
625
|
}
|
|
643
626
|
.vxe-table--scroll-y-handle,
|
|
644
627
|
.vxe-table--scroll-y-wrapper {
|
|
@@ -650,7 +633,7 @@
|
|
|
650
633
|
.vxe-table--scroll-y-handle {
|
|
651
634
|
overflow-y: scroll;
|
|
652
635
|
overflow-x: hidden;
|
|
653
|
-
width: 8px;
|
|
636
|
+
width: var(--vxe-scrollbar-size, 8px);
|
|
654
637
|
height: 100%;
|
|
655
638
|
}
|
|
656
639
|
.vxe-table--scroll-x-space {
|
|
@@ -925,10 +908,20 @@
|
|
|
925
908
|
border-collapse: separate;
|
|
926
909
|
table-layout: fixed;
|
|
927
910
|
}
|
|
928
|
-
.vxe-table--render-wrapper{
|
|
929
|
-
height:100%;
|
|
911
|
+
.vxe-table--render-wrapper {
|
|
912
|
+
height: 100%;
|
|
913
|
+
display: flex;
|
|
914
|
+
flex-direction: column;
|
|
915
|
+
overflow: hidden;
|
|
916
|
+
|
|
930
917
|
.vxe-table--layout-wrapper {
|
|
931
|
-
|
|
918
|
+
flex: 1;
|
|
919
|
+
min-height: 0;
|
|
920
|
+
height: auto;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
.vxe-table--scroll-x-virtual {
|
|
924
|
+
flex-shrink: 0;
|
|
932
925
|
}
|
|
933
926
|
}
|
|
934
927
|
&:not(.is--empty) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as XLSX from 'xlsx-js-style'
|
|
2
|
+
import { unzipSync } from 'fflate'
|
|
2
3
|
|
|
3
4
|
export interface ExcelPreviewCellStyle {
|
|
4
5
|
backgroundColor?: string
|
|
@@ -43,7 +44,17 @@ export interface ExcelSearchMatch {
|
|
|
43
44
|
|
|
44
45
|
type ColorStyle = { rgb?: string; theme?: number; tint?: number; indexed?: number }
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
type WorkbookStyles = {
|
|
48
|
+
Fonts?: Array<Record<string, unknown>>
|
|
49
|
+
Fills?: Array<Record<string, unknown>>
|
|
50
|
+
Borders?: Array<Record<string, unknown>>
|
|
51
|
+
CellXf?: Array<Record<string, unknown>>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** xlsx-js-style 运行时附带 Styles,官方 WorkBook 类型未声明 */
|
|
55
|
+
type StyledWorkBook = XLSX.WorkBook & { Styles?: WorkbookStyles }
|
|
56
|
+
|
|
57
|
+
/** Excel 默认主题色(Office 2013+,含 accent / hyperlink) */
|
|
47
58
|
const EXCEL_THEME_COLORS: Record<number, string> = {
|
|
48
59
|
0: '#FFFFFF',
|
|
49
60
|
1: '#000000',
|
|
@@ -55,6 +66,68 @@ const EXCEL_THEME_COLORS: Record<number, string> = {
|
|
|
55
66
|
7: '#FFC000',
|
|
56
67
|
8: '#5B9BD5',
|
|
57
68
|
9: '#70AD47',
|
|
69
|
+
10: '#0563C1',
|
|
70
|
+
11: '#954F72',
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Excel 标准 indexed 色板(常用前 16 色) */
|
|
74
|
+
const INDEXED_COLORS: Record<number, string> = {
|
|
75
|
+
0: '#000000',
|
|
76
|
+
1: '#FFFFFF',
|
|
77
|
+
2: '#FF0000',
|
|
78
|
+
3: '#00FF00',
|
|
79
|
+
4: '#0000FF',
|
|
80
|
+
5: '#FFFF00',
|
|
81
|
+
6: '#FF00FF',
|
|
82
|
+
7: '#00FFFF',
|
|
83
|
+
8: '#000000',
|
|
84
|
+
9: '#FFFFFF',
|
|
85
|
+
10: '#FF0000',
|
|
86
|
+
11: '#00FF00',
|
|
87
|
+
12: '#0000FF',
|
|
88
|
+
13: '#FFFF00',
|
|
89
|
+
14: '#FF00FF',
|
|
90
|
+
15: '#00FFFF',
|
|
91
|
+
16: '#800000',
|
|
92
|
+
17: '#008000',
|
|
93
|
+
18: '#000080',
|
|
94
|
+
19: '#808000',
|
|
95
|
+
20: '#800080',
|
|
96
|
+
21: '#008080',
|
|
97
|
+
22: '#C0C0C0',
|
|
98
|
+
23: '#808080',
|
|
99
|
+
24: '#9999FF',
|
|
100
|
+
25: '#993366',
|
|
101
|
+
26: '#FFFFCC',
|
|
102
|
+
27: '#CCFFFF',
|
|
103
|
+
28: '#660066',
|
|
104
|
+
29: '#FF8080',
|
|
105
|
+
30: '#0066CC',
|
|
106
|
+
31: '#CCCCFF',
|
|
107
|
+
40: '#00CCFF',
|
|
108
|
+
41: '#CCFFFF',
|
|
109
|
+
42: '#CCFFCC',
|
|
110
|
+
43: '#FFFF99',
|
|
111
|
+
44: '#99CCFF',
|
|
112
|
+
45: '#FF99CC',
|
|
113
|
+
46: '#CC99FF',
|
|
114
|
+
47: '#FFCC99',
|
|
115
|
+
48: '#3366FF',
|
|
116
|
+
49: '#33CCCC',
|
|
117
|
+
50: '#99CC00',
|
|
118
|
+
51: '#FFCC00',
|
|
119
|
+
52: '#FF9900',
|
|
120
|
+
53: '#FF6600',
|
|
121
|
+
54: '#666699',
|
|
122
|
+
55: '#969696',
|
|
123
|
+
56: '#003366',
|
|
124
|
+
57: '#339966',
|
|
125
|
+
58: '#003300',
|
|
126
|
+
59: '#333300',
|
|
127
|
+
60: '#993300',
|
|
128
|
+
61: '#993366',
|
|
129
|
+
62: '#333399',
|
|
130
|
+
63: '#333333',
|
|
58
131
|
}
|
|
59
132
|
|
|
60
133
|
const BORDER_WIDTH: Record<string, string> = {
|
|
@@ -69,6 +142,16 @@ const BORDER_WIDTH: Record<string, string> = {
|
|
|
69
142
|
|
|
70
143
|
const DEFAULT_COL_WIDTH = 72
|
|
71
144
|
|
|
145
|
+
const isOleXls = (buffer: ArrayBuffer) => {
|
|
146
|
+
const sig = new Uint8Array(buffer, 0, 4)
|
|
147
|
+
return sig[0] === 0xd0 && sig[1] === 0xcf && sig[2] === 0x11 && sig[3] === 0xe0
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const isZipXlsx = (buffer: ArrayBuffer) => {
|
|
151
|
+
const sig = new Uint8Array(buffer, 0, 2)
|
|
152
|
+
return sig[0] === 0x50 && sig[1] === 0x4b
|
|
153
|
+
}
|
|
154
|
+
|
|
72
155
|
const hexToRgb = (hex: string) => {
|
|
73
156
|
const normalized = hex.replace('#', '')
|
|
74
157
|
const value =
|
|
@@ -106,8 +189,9 @@ const resolveColor = (color?: ColorStyle): string | undefined => {
|
|
|
106
189
|
if (raw.length === 6) return `#${raw}`
|
|
107
190
|
return undefined
|
|
108
191
|
}
|
|
192
|
+
if (color.indexed != null) return INDEXED_COLORS[color.indexed]
|
|
109
193
|
if (color.theme != null) {
|
|
110
|
-
const base = EXCEL_THEME_COLORS[color.theme] ?? '#
|
|
194
|
+
const base = EXCEL_THEME_COLORS[color.theme] ?? '#000000'
|
|
111
195
|
return color.tint ? applyTint(base, color.tint) : base
|
|
112
196
|
}
|
|
113
197
|
return undefined
|
|
@@ -116,63 +200,64 @@ const resolveColor = (color?: ColorStyle): string | undefined => {
|
|
|
116
200
|
const resolveBorderSide = (side?: { style?: string; color?: ColorStyle }) => {
|
|
117
201
|
if (!side?.style || side.style === 'none') return undefined
|
|
118
202
|
const width = BORDER_WIDTH[side.style] ?? '1px'
|
|
119
|
-
const color = resolveColor(side.color) ?? '#
|
|
203
|
+
const color = resolveColor(side.color) ?? '#000000'
|
|
120
204
|
const lineStyle = side.style === 'dashed' ? 'dashed' : side.style === 'dotted' ? 'dotted' : 'solid'
|
|
121
205
|
return `${width} ${lineStyle} ${color}`
|
|
122
206
|
}
|
|
123
207
|
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
208
|
+
const toNumber = (value: unknown, fallback = 0) => {
|
|
209
|
+
const num = Number(value)
|
|
210
|
+
return Number.isFinite(num) ? num : fallback
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const isTruthy = (value: unknown) => value === true || value === 1 || value === '1'
|
|
214
|
+
|
|
215
|
+
const styleFromParts = (parts: {
|
|
216
|
+
font?: Record<string, unknown>
|
|
217
|
+
fill?: Record<string, unknown>
|
|
218
|
+
border?: Record<string, unknown>
|
|
219
|
+
alignment?: Record<string, unknown>
|
|
220
|
+
}): ExcelPreviewCellStyle | undefined => {
|
|
128
221
|
const css: ExcelPreviewCellStyle = {}
|
|
129
222
|
|
|
130
|
-
const fill =
|
|
223
|
+
const fill = parts.fill
|
|
131
224
|
if (fill && fill.patternType !== 'none') {
|
|
132
|
-
const
|
|
133
|
-
|
|
225
|
+
const fg = fill.fgColor as ColorStyle | undefined
|
|
226
|
+
const bg = fill.bgColor as ColorStyle | undefined
|
|
227
|
+
const background = resolveColor(fg) || resolveColor(bg)
|
|
228
|
+
if (background) css.backgroundColor = background
|
|
134
229
|
}
|
|
135
230
|
|
|
136
|
-
const font =
|
|
137
|
-
bold?: boolean
|
|
138
|
-
italic?: boolean
|
|
139
|
-
underline?: boolean | string
|
|
140
|
-
sz?: number | string
|
|
141
|
-
color?: ColorStyle
|
|
142
|
-
} | undefined
|
|
231
|
+
const font = parts.font
|
|
143
232
|
if (font) {
|
|
144
|
-
if (font.bold) css.fontWeight = 'bold'
|
|
145
|
-
if (font.italic) css.fontStyle = 'italic'
|
|
233
|
+
if (isTruthy(font.bold)) css.fontWeight = 'bold'
|
|
234
|
+
if (isTruthy(font.italic)) css.fontStyle = 'italic'
|
|
146
235
|
if (font.underline) css.textDecoration = 'underline'
|
|
147
236
|
if (font.sz) css.fontSize = `${font.sz}pt`
|
|
148
|
-
const color = resolveColor(font.color)
|
|
237
|
+
const color = resolveColor(font.color as ColorStyle | undefined)
|
|
149
238
|
if (color) css.color = color
|
|
150
239
|
}
|
|
151
240
|
|
|
152
|
-
const alignment =
|
|
153
|
-
horizontal?: string
|
|
154
|
-
vertical?: string
|
|
155
|
-
wrapText?: boolean
|
|
156
|
-
} | undefined
|
|
241
|
+
const alignment = parts.alignment
|
|
157
242
|
if (alignment) {
|
|
158
|
-
|
|
159
|
-
|
|
243
|
+
const horizontal = alignment.horizontal as string | undefined
|
|
244
|
+
if (horizontal && horizontal !== 'general') {
|
|
245
|
+
css.textAlign = horizontal as ExcelPreviewCellStyle['textAlign']
|
|
160
246
|
}
|
|
161
|
-
|
|
247
|
+
const vertical = alignment.vertical as string | undefined
|
|
248
|
+
if (vertical) {
|
|
162
249
|
css.verticalAlign =
|
|
163
|
-
|
|
164
|
-
? 'middle'
|
|
165
|
-
: (alignment.vertical as ExcelPreviewCellStyle['verticalAlign'])
|
|
250
|
+
vertical === 'center' ? 'middle' : (vertical as ExcelPreviewCellStyle['verticalAlign'])
|
|
166
251
|
}
|
|
167
|
-
if (alignment.wrapText) css.whiteSpace = 'pre-wrap'
|
|
252
|
+
if (isTruthy(alignment.wrapText)) css.whiteSpace = 'pre-wrap'
|
|
168
253
|
}
|
|
169
254
|
|
|
170
|
-
const border =
|
|
255
|
+
const border = parts.border
|
|
171
256
|
if (border) {
|
|
172
|
-
const top = resolveBorderSide(border.top)
|
|
173
|
-
const right = resolveBorderSide(border.right)
|
|
174
|
-
const bottom = resolveBorderSide(border.bottom)
|
|
175
|
-
const left = resolveBorderSide(border.left)
|
|
257
|
+
const top = resolveBorderSide(border.top as { style?: string; color?: ColorStyle })
|
|
258
|
+
const right = resolveBorderSide(border.right as { style?: string; color?: ColorStyle })
|
|
259
|
+
const bottom = resolveBorderSide(border.bottom as { style?: string; color?: ColorStyle })
|
|
260
|
+
const left = resolveBorderSide(border.left as { style?: string; color?: ColorStyle })
|
|
176
261
|
if (top) css.borderTop = top
|
|
177
262
|
if (right) css.borderRight = right
|
|
178
263
|
if (bottom) css.borderBottom = bottom
|
|
@@ -182,6 +267,83 @@ const extractCellStyle = (cell?: XLSX.CellObject): ExcelPreviewCellStyle | undef
|
|
|
182
267
|
return Object.keys(css).length > 0 ? css : undefined
|
|
183
268
|
}
|
|
184
269
|
|
|
270
|
+
const resolveXfStyle = (
|
|
271
|
+
styles: WorkbookStyles | undefined,
|
|
272
|
+
xfIndex: number,
|
|
273
|
+
): ExcelPreviewCellStyle | undefined => {
|
|
274
|
+
if (!styles?.CellXf?.length || xfIndex < 0) return undefined
|
|
275
|
+
const xf = styles.CellXf[xfIndex]
|
|
276
|
+
if (!xf) return undefined
|
|
277
|
+
|
|
278
|
+
const fontId = toNumber(xf.fontId ?? xf.fontid, 0)
|
|
279
|
+
const fillId = toNumber(xf.fillId ?? xf.fillid, 0)
|
|
280
|
+
const borderId = toNumber(xf.borderId ?? xf.borderid, 0)
|
|
281
|
+
|
|
282
|
+
return styleFromParts({
|
|
283
|
+
font: styles.Fonts?.[fontId] as Record<string, unknown> | undefined,
|
|
284
|
+
fill: styles.Fills?.[fillId] as Record<string, unknown> | undefined,
|
|
285
|
+
border: styles.Borders?.[borderId] as Record<string, unknown> | undefined,
|
|
286
|
+
alignment: xf.alignment as Record<string, unknown> | undefined,
|
|
287
|
+
})
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** xlsx-js-style 读入后 cell.s 往往只有 fill,字体/边框需用 XML 中的 s 索引关联 CellXf */
|
|
291
|
+
const parseXlsxStyleIndexMaps = (buffer: ArrayBuffer, sheetCount: number) => {
|
|
292
|
+
if (!isZipXlsx(buffer) || sheetCount <= 0) return [] as Map<string, number>[]
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
const files = unzipSync(new Uint8Array(buffer))
|
|
296
|
+
const decoder = new TextDecoder('utf-8')
|
|
297
|
+
const maps: Map<string, number>[] = []
|
|
298
|
+
|
|
299
|
+
for (let i = 0; i < sheetCount; i++) {
|
|
300
|
+
const path = `xl/worksheets/sheet${i + 1}.xml`
|
|
301
|
+
const xmlBytes = files[path]
|
|
302
|
+
const map = new Map<string, number>()
|
|
303
|
+
if (xmlBytes) {
|
|
304
|
+
const xml = decoder.decode(xmlBytes)
|
|
305
|
+
const cellTagRe = /<c\b([^>/]*)(?:\/>|>)/g
|
|
306
|
+
let match: RegExpExecArray | null
|
|
307
|
+
while ((match = cellTagRe.exec(xml))) {
|
|
308
|
+
const attrs = match[1]
|
|
309
|
+
const addr = attrs.match(/\br="([^"]+)"/)?.[1]
|
|
310
|
+
const styleIndex = attrs.match(/\bs="(\d+)"/)?.[1]
|
|
311
|
+
if (addr && styleIndex != null) {
|
|
312
|
+
map.set(addr, Number(styleIndex))
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
maps.push(map)
|
|
317
|
+
}
|
|
318
|
+
return maps
|
|
319
|
+
} catch {
|
|
320
|
+
return Array.from({ length: sheetCount }, () => new Map<string, number>())
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const extractCellStyle = (
|
|
325
|
+
cell?: XLSX.CellObject,
|
|
326
|
+
styles?: WorkbookStyles,
|
|
327
|
+
xfIndex?: number,
|
|
328
|
+
): ExcelPreviewCellStyle | undefined => {
|
|
329
|
+
if (styles && xfIndex != null && xfIndex >= 0) {
|
|
330
|
+
const resolved = resolveXfStyle(styles, xfIndex)
|
|
331
|
+
if (resolved) return resolved
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (typeof cell?.s === 'number' && styles) {
|
|
335
|
+
return resolveXfStyle(styles, cell.s)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const rawStyle = cell?.s
|
|
339
|
+
if (!rawStyle || typeof rawStyle !== 'object') return undefined
|
|
340
|
+
|
|
341
|
+
// cell.s 对象通常仅含 fill,作为兜底
|
|
342
|
+
return styleFromParts({
|
|
343
|
+
fill: rawStyle as Record<string, unknown>,
|
|
344
|
+
})
|
|
345
|
+
}
|
|
346
|
+
|
|
185
347
|
export const cellStyleToCss = (style?: ExcelPreviewCellStyle): Record<string, string> => {
|
|
186
348
|
if (!style) return {}
|
|
187
349
|
const css: Record<string, string> = {}
|
|
@@ -228,13 +390,23 @@ const parseColWidths = (sheet: XLSX.WorkSheet, startCol: number, endCol: number)
|
|
|
228
390
|
|
|
229
391
|
export const parseExcelWorkbook = async (src: Blob | ArrayBuffer): Promise<ExcelPreviewSheet[]> => {
|
|
230
392
|
const buffer = src instanceof Blob ? await src.arrayBuffer() : src
|
|
231
|
-
const workbook = XLSX.read(buffer, {
|
|
232
|
-
|
|
393
|
+
const workbook = XLSX.read(buffer, {
|
|
394
|
+
type: 'array',
|
|
395
|
+
cellDates: true,
|
|
396
|
+
cellStyles: true,
|
|
397
|
+
...(isOleXls(buffer) ? {} : {}),
|
|
398
|
+
}) as StyledWorkBook
|
|
399
|
+
const styles = workbook.Styles
|
|
400
|
+
const styleIndexMaps = isZipXlsx(buffer)
|
|
401
|
+
? parseXlsxStyleIndexMaps(buffer, workbook.SheetNames.length)
|
|
402
|
+
: []
|
|
403
|
+
|
|
404
|
+
return workbook.SheetNames.map((name, sheetIndex) => {
|
|
233
405
|
const sheet = workbook.Sheets[name]
|
|
234
406
|
const range = sheet?.['!ref'] ? XLSX.utils.decode_range(sheet['!ref']) : null
|
|
235
407
|
return {
|
|
236
408
|
name,
|
|
237
|
-
rows: buildSheetRows(sheet),
|
|
409
|
+
rows: buildSheetRows(sheet, styles, styleIndexMaps[sheetIndex]),
|
|
238
410
|
startCol: range?.s.c ?? 0,
|
|
239
411
|
endCol: range?.e.c ?? 0,
|
|
240
412
|
colWidths: range ? parseColWidths(sheet, range.s.c, range.e.c) : {},
|
|
@@ -242,7 +414,11 @@ export const parseExcelWorkbook = async (src: Blob | ArrayBuffer): Promise<Excel
|
|
|
242
414
|
})
|
|
243
415
|
}
|
|
244
416
|
|
|
245
|
-
const buildSheetRows = (
|
|
417
|
+
const buildSheetRows = (
|
|
418
|
+
sheet?: XLSX.WorkSheet,
|
|
419
|
+
styles?: WorkbookStyles,
|
|
420
|
+
styleIndexMap?: Map<string, number>,
|
|
421
|
+
): ExcelPreviewCell[][] => {
|
|
246
422
|
if (!sheet || !sheet['!ref']) return []
|
|
247
423
|
const range = XLSX.utils.decode_range(sheet['!ref'])
|
|
248
424
|
const colWidths = parseColWidths(sheet, range.s.c, range.e.c)
|
|
@@ -268,13 +444,14 @@ const buildSheetRows = (sheet?: XLSX.WorkSheet): ExcelPreviewCell[][] => {
|
|
|
268
444
|
const addr = XLSX.utils.encode_cell({ r, c })
|
|
269
445
|
const cellObj = sheet[addr]
|
|
270
446
|
const merge = mergeStarts.get(`${r},${c}`)
|
|
447
|
+
const xfIndex = styleIndexMap?.get(addr)
|
|
271
448
|
row.push({
|
|
272
449
|
value: formatCellValue(cellObj),
|
|
273
450
|
row: r,
|
|
274
451
|
col: c,
|
|
275
452
|
rowSpan: merge?.rowSpan,
|
|
276
453
|
colSpan: merge?.colSpan,
|
|
277
|
-
style: extractCellStyle(cellObj),
|
|
454
|
+
style: extractCellStyle(cellObj, styles, xfIndex),
|
|
278
455
|
width: colWidths[c],
|
|
279
456
|
})
|
|
280
457
|
}
|
|
@@ -302,6 +479,3 @@ export const searchExcelSheets = (
|
|
|
302
479
|
})
|
|
303
480
|
return matches
|
|
304
481
|
}
|
|
305
|
-
|
|
306
|
-
export const cellKey = (sheetIndex: number, row: number, col: number) =>
|
|
307
|
-
`${sheetIndex}:${row}:${col}`
|
|
@@ -120,3 +120,9 @@ export const isLegacyDocFile = (type?: string, name?: string, fileUrl?: string)
|
|
|
120
120
|
/** 弹层等场景:使用 OfficePreview 内置标题栏(PDF / Word / Excel) */
|
|
121
121
|
export const isHeaderPreviewFile = (type?: string, name?: string, fileUrl?: string) =>
|
|
122
122
|
HEADER_PREVIEW_TYPES.has(toOfficePreviewType(type, name, fileUrl))
|
|
123
|
+
|
|
124
|
+
/** pdf.js 加载参数:依赖 PDF 内嵌字体与浏览器系统字体 */
|
|
125
|
+
export const buildPdfJsLoadOptions = (data: ArrayBuffer) => ({
|
|
126
|
+
data,
|
|
127
|
+
useSystemFonts: true,
|
|
128
|
+
})
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: gitnexus-cli
|
|
3
|
-
description: "Use when the user needs to run GitNexus CLI commands like analyze/index a repo, check status, clean the index, generate a wiki, or list indexed repos. Examples: \"Index this repo\", \"Reanalyze the codebase\", \"Generate a wiki\""
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# GitNexus CLI Commands
|
|
7
|
-
|
|
8
|
-
All commands work via `npx` — no global install required.
|
|
9
|
-
|
|
10
|
-
## Commands
|
|
11
|
-
|
|
12
|
-
### analyze — Build or refresh the index
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npx gitnexus analyze
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Run from the project root. This parses all source files, builds the knowledge graph, writes it to `.gitnexus/`, and generates CLAUDE.md / AGENTS.md context files.
|
|
19
|
-
|
|
20
|
-
| Flag | Effect |
|
|
21
|
-
| -------------- | ---------------------------------------------------------------- |
|
|
22
|
-
| `--force` | Force full re-index even if up to date |
|
|
23
|
-
| `--embeddings` | Enable embedding generation for semantic search (off by default) |
|
|
24
|
-
| `--drop-embeddings` | Drop existing embeddings on rebuild. By default, an `analyze` without `--embeddings` preserves them. |
|
|
25
|
-
|
|
26
|
-
**When to run:** First time in a project, after major code changes, or when `gitnexus://repo/{name}/context` reports the index is stale. In Claude Code, a PostToolUse hook detects staleness after `git commit` and `git merge` and notifies the agent to run `analyze` — the hook does not run analyze itself, to avoid blocking the agent for up to 120s and risking KuzuDB corruption on timeout.
|
|
27
|
-
|
|
28
|
-
### status — Check index freshness
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npx gitnexus status
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Shows whether the current repo has a GitNexus index, when it was last updated, and symbol/relationship counts. Use this to check if re-indexing is needed.
|
|
35
|
-
|
|
36
|
-
### clean — Delete the index
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
npx gitnexus clean
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Deletes the `.gitnexus/` directory and unregisters the repo from the global registry. Use before re-indexing if the index is corrupt or after removing GitNexus from a project.
|
|
43
|
-
|
|
44
|
-
| Flag | Effect |
|
|
45
|
-
| --------- | ------------------------------------------------- |
|
|
46
|
-
| `--force` | Skip confirmation prompt |
|
|
47
|
-
| `--all` | Clean all indexed repos, not just the current one |
|
|
48
|
-
|
|
49
|
-
### wiki — Generate documentation from the graph
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
npx gitnexus wiki
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Generates repository documentation from the knowledge graph using an LLM. Requires an API key (saved to `~/.gitnexus/config.json` on first use).
|
|
56
|
-
|
|
57
|
-
| Flag | Effect |
|
|
58
|
-
| ------------------- | ----------------------------------------- |
|
|
59
|
-
| `--force` | Force full regeneration |
|
|
60
|
-
| `--model <model>` | LLM model (default: minimax/minimax-m2.5) |
|
|
61
|
-
| `--base-url <url>` | LLM API base URL |
|
|
62
|
-
| `--api-key <key>` | LLM API key |
|
|
63
|
-
| `--concurrency <n>` | Parallel LLM calls (default: 3) |
|
|
64
|
-
| `--gist` | Publish wiki as a public GitHub Gist |
|
|
65
|
-
|
|
66
|
-
### list — Show all indexed repos
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
npx gitnexus list
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Lists all repositories registered in `~/.gitnexus/registry.json`. The MCP `list_repos` tool provides the same information.
|
|
73
|
-
|
|
74
|
-
## After Indexing
|
|
75
|
-
|
|
76
|
-
1. **Read `gitnexus://repo/{name}/context`** to verify the index loaded
|
|
77
|
-
2. Use the other GitNexus skills (`exploring`, `debugging`, `impact-analysis`, `refactoring`) for your task
|
|
78
|
-
|
|
79
|
-
## Troubleshooting
|
|
80
|
-
|
|
81
|
-
- **"Not inside a git repository"**: Run from a directory inside a git repo
|
|
82
|
-
- **Index is stale after re-analyzing**: Restart Claude Code to reload the MCP server
|
|
83
|
-
- **Embeddings slow**: Omit `--embeddings` (it's off by default) or set `OPENAI_API_KEY` for faster API-based embedding
|