wukong-gitlog-cli 1.0.15 → 1.0.16
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/CHANGELOG.md +13 -0
- package/package.json +1 -1
- package/web/app.js +70 -32
- package/web/index.html +2 -0
- package/web/static/style.css +122 -22
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [1.0.16](https://github.com/tomatobybike/wukong-gitlog-cli/compare/v1.0.15...v1.0.16) (2025-12-03)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* 🎸 sider bar UI ([e3a48ab](https://github.com/tomatobybike/wukong-gitlog-cli/commit/e3a48abe5b0148fe0d9dcd42b7b028cad53d4c94))
|
|
11
|
+
* 🎸 ui show ([e9eba58](https://github.com/tomatobybike/wukong-gitlog-cli/commit/e9eba5823333545d598be363b58eca1f6ecfa6ed))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* 🐛 makeline clickEvent ([4ad6378](https://github.com/tomatobybike/wukong-gitlog-cli/commit/4ad6378d88aca2dde6083efde844730443228e48))
|
|
17
|
+
|
|
5
18
|
### [1.0.15](https://github.com/tomatobybike/wukong-gitlog-cli/compare/v1.0.14...v1.0.15) (2025-12-03)
|
|
6
19
|
|
|
7
20
|
|
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -184,14 +184,24 @@ function drawHourlyOvertime(stats, onHourClick) {
|
|
|
184
184
|
data: [
|
|
185
185
|
{
|
|
186
186
|
name: '上班开始',
|
|
187
|
+
nameValue: String(stats.startHour).padStart(2, '0'),
|
|
187
188
|
xAxis: String(stats.startHour).padStart(2, '0')
|
|
188
189
|
},
|
|
189
|
-
{
|
|
190
|
+
{
|
|
191
|
+
name: '下班时间',
|
|
192
|
+
nameValue: String(stats.endHour).padStart(2, '0'),
|
|
193
|
+
xAxis: String(stats.endHour).padStart(2, '0')
|
|
194
|
+
},
|
|
190
195
|
{
|
|
191
196
|
name: '午休开始',
|
|
197
|
+
nameValue: String(stats.lunchStart).padStart(2, '0'),
|
|
192
198
|
xAxis: String(stats.lunchStart).padStart(2, '0')
|
|
193
199
|
},
|
|
194
|
-
{
|
|
200
|
+
{
|
|
201
|
+
name: '午休结束',
|
|
202
|
+
nameValue: String(stats.lunchEnd).padStart(2, '0'),
|
|
203
|
+
xAxis: String(stats.lunchEnd).padStart(2, '0')
|
|
204
|
+
}
|
|
195
205
|
]
|
|
196
206
|
}
|
|
197
207
|
}
|
|
@@ -201,7 +211,14 @@ function drawHourlyOvertime(stats, onHourClick) {
|
|
|
201
211
|
// 点击事件(点击某小时 → 打开侧栏)
|
|
202
212
|
if (typeof onHourClick === 'function') {
|
|
203
213
|
chart.on('click', (p) => {
|
|
204
|
-
|
|
214
|
+
let hour = Number(p.name)
|
|
215
|
+
if(p.componentType === 'markLine') {
|
|
216
|
+
hour = Number(p.data.xAxis)
|
|
217
|
+
}
|
|
218
|
+
// FIXME: remove debug log before production
|
|
219
|
+
console.log('❌', 'hour', hour, p)
|
|
220
|
+
document.getElementById('dayDetailSidebar').classList.remove('show')
|
|
221
|
+
if (Object.is(hour, NaN)) return
|
|
205
222
|
onHourClick(hour, commits[hour])
|
|
206
223
|
})
|
|
207
224
|
}
|
|
@@ -214,6 +231,7 @@ function showSideBarForHour(hour, commitsOrCount) {
|
|
|
214
231
|
// 支持传入 number(仅次数)或 array(详细 commit 列表)
|
|
215
232
|
// 统一复用通用详情侧栏 DOM
|
|
216
233
|
const sidebar = document.getElementById('dayDetailSidebar')
|
|
234
|
+
const backdrop = document.getElementById('sidebarBackdrop')
|
|
217
235
|
const titleEl = document.getElementById('sidebarTitle')
|
|
218
236
|
const contentEl = document.getElementById('sidebarContent')
|
|
219
237
|
|
|
@@ -235,19 +253,22 @@ function showSideBarForHour(hour, commitsOrCount) {
|
|
|
235
253
|
} else if (Array.isArray(commitsOrCount)) {
|
|
236
254
|
// commits 列表:展示作者/时间/消息(最多前 50 条,避免性能问题)
|
|
237
255
|
const commits = commitsOrCount.slice(0, 50)
|
|
238
|
-
contentEl.innerHTML = commits
|
|
256
|
+
contentEl.innerHTML = `<div class="sidebar-list">${commits
|
|
239
257
|
.map((c) => {
|
|
240
258
|
const author = c.author ?? c.name ?? 'unknown'
|
|
241
259
|
const time = c.date ?? c.time ?? ''
|
|
242
260
|
const msg = (c.message ?? c.msg ?? c.body ?? '').replace(/\n/g, ' ')
|
|
243
261
|
return `
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
262
|
+
<div class="sidebar-item">
|
|
263
|
+
<div class="sidebar-item-header">
|
|
264
|
+
<span class="author">👤 ${escapeHtml(author)}</span>
|
|
265
|
+
<span class="time">🕒 ${escapeHtml(time)}</span>
|
|
266
|
+
</div>
|
|
267
|
+
<div class="sidebar-item-message">${escapeHtml(msg)}</div>
|
|
268
|
+
</div>
|
|
269
|
+
`
|
|
249
270
|
})
|
|
250
|
-
.join('')
|
|
271
|
+
.join('')}</div>`
|
|
251
272
|
|
|
252
273
|
if (commitsOrCount.length > 50) {
|
|
253
274
|
const more = commitsOrCount.length - 50
|
|
@@ -257,8 +278,9 @@ function showSideBarForHour(hour, commitsOrCount) {
|
|
|
257
278
|
contentEl.innerHTML = `<div style="font-size:14px;">无可展示数据</div>`
|
|
258
279
|
}
|
|
259
280
|
|
|
260
|
-
// 打开侧栏
|
|
281
|
+
// 打开侧栏 + 遮罩
|
|
261
282
|
sidebar.classList.add('show')
|
|
283
|
+
if (backdrop) backdrop.classList.add('show')
|
|
262
284
|
}
|
|
263
285
|
|
|
264
286
|
// 简单的 HTML 转义,防止 XSS 与布局断裂
|
|
@@ -410,6 +432,7 @@ function drawDailyTrend(commits, onDayClick) {
|
|
|
410
432
|
function showSideBarForWeek(period, weeklyItem, commits = []) {
|
|
411
433
|
// 统一复用通用详情侧栏 DOM
|
|
412
434
|
const sidebar = document.getElementById('dayDetailSidebar')
|
|
435
|
+
const backdrop = document.getElementById('sidebarBackdrop')
|
|
413
436
|
const titleEl = document.getElementById('sidebarTitle')
|
|
414
437
|
const contentEl = document.getElementById('sidebarContent')
|
|
415
438
|
|
|
@@ -426,22 +449,27 @@ function showSideBarForWeek(period, weeklyItem, commits = []) {
|
|
|
426
449
|
if (!commits.length) {
|
|
427
450
|
html += `<div style="padding:10px;color:#777;">该周无提交记录</div>`
|
|
428
451
|
} else {
|
|
429
|
-
html += commits
|
|
452
|
+
html += `<div class="sidebar-list">${commits
|
|
430
453
|
.map((c) => {
|
|
454
|
+
const author = escapeHtml(c.author || 'unknown')
|
|
455
|
+
const time = escapeHtml(c.date || '')
|
|
456
|
+
const msg = escapeHtml((c.message || '').replace(/\n/g, ' '))
|
|
431
457
|
return `
|
|
432
|
-
<div class="
|
|
433
|
-
<div class="
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
458
|
+
<div class="sidebar-item">
|
|
459
|
+
<div class="sidebar-item-header">
|
|
460
|
+
<span class="author">👤 ${author}</span>
|
|
461
|
+
<span class="time">🕒 ${time}</span>
|
|
462
|
+
</div>
|
|
463
|
+
<div class="sidebar-item-message">${msg}</div>
|
|
437
464
|
</div>
|
|
438
465
|
`
|
|
439
466
|
})
|
|
440
|
-
.join('')
|
|
467
|
+
.join('')}</div>`
|
|
441
468
|
}
|
|
442
469
|
|
|
443
470
|
contentEl.innerHTML = html
|
|
444
471
|
sidebar.classList.add('show')
|
|
472
|
+
if (backdrop) backdrop.classList.add('show')
|
|
445
473
|
}
|
|
446
474
|
|
|
447
475
|
function drawWeeklyTrend(weekly, commits, onWeekClick) {
|
|
@@ -543,7 +571,6 @@ function drawWeeklyTrend(weekly, commits, onWeekClick) {
|
|
|
543
571
|
const idx = p.dataIndex
|
|
544
572
|
const w = weekly[idx]
|
|
545
573
|
|
|
546
|
-
|
|
547
574
|
const start = new Date(w.range.start)
|
|
548
575
|
const end = new Date(w.range.end)
|
|
549
576
|
end.setHours(23, 59, 59, 999) // 包含当天
|
|
@@ -828,9 +855,7 @@ function drawDailySeverity(latestByDay, commits, onDayClick) {
|
|
|
828
855
|
|
|
829
856
|
// 若某天 latestHourNormalized 为空,表示「没有下班后到次日上班前的提交」,
|
|
830
857
|
// 这里按 0 小时加班处理,保证折线连续。
|
|
831
|
-
const sev = raw.map((v) =>
|
|
832
|
-
v == null ? 0 : Math.max(0, Number(v) - endH)
|
|
833
|
-
)
|
|
858
|
+
const sev = raw.map((v) => (v == null ? 0 : Math.max(0, Number(v) - endH)))
|
|
834
859
|
|
|
835
860
|
const el = document.getElementById('dailySeverityChart')
|
|
836
861
|
// eslint-disable-next-line no-undef
|
|
@@ -1101,6 +1126,7 @@ function drawDailyTrendSeverity(commits, weekly, onDayClick) {
|
|
|
1101
1126
|
|
|
1102
1127
|
function showDayDetailSidebar(date, count, commits) {
|
|
1103
1128
|
const sidebar = document.getElementById('dayDetailSidebar')
|
|
1129
|
+
const backdrop = document.getElementById('sidebarBackdrop')
|
|
1104
1130
|
const title = document.getElementById('sidebarTitle')
|
|
1105
1131
|
const content = document.getElementById('sidebarContent')
|
|
1106
1132
|
|
|
@@ -1110,17 +1136,19 @@ function showDayDetailSidebar(date, count, commits) {
|
|
|
1110
1136
|
content.innerHTML = commits
|
|
1111
1137
|
.map(
|
|
1112
1138
|
(c) => `
|
|
1113
|
-
<div
|
|
1114
|
-
<div
|
|
1115
|
-
|
|
1116
|
-
|
|
1139
|
+
<div class="sidebar-item">
|
|
1140
|
+
<div class="sidebar-item-header">
|
|
1141
|
+
<span class="author">👤 ${escapeHtml(c.author || 'unknown')}</span>
|
|
1142
|
+
<span class="time">🕒 ${escapeHtml(c.time || c.date || '')}</span>
|
|
1143
|
+
</div>
|
|
1144
|
+
<div class="sidebar-item-message">${escapeHtml(c.msg || c.message || '')}</div>
|
|
1117
1145
|
</div>
|
|
1118
|
-
<hr/>
|
|
1119
1146
|
`
|
|
1120
1147
|
)
|
|
1121
1148
|
.join('')
|
|
1122
1149
|
|
|
1123
1150
|
sidebar.classList.add('show')
|
|
1151
|
+
if (backdrop) backdrop.classList.add('show')
|
|
1124
1152
|
}
|
|
1125
1153
|
|
|
1126
1154
|
function renderKpi(stats) {
|
|
@@ -1132,13 +1160,13 @@ function renderKpi(stats) {
|
|
|
1132
1160
|
// 使用 cutoff + 上下班时间,重新在全部 commits 中计算「加班最晚一次提交」
|
|
1133
1161
|
const cutoff = window.__overnightCutoff ?? 6
|
|
1134
1162
|
const startHour =
|
|
1135
|
-
|
|
1163
|
+
typeof stats.startHour === 'number' && stats.startHour >= 0
|
|
1136
1164
|
? stats.startHour
|
|
1137
|
-
: 9
|
|
1165
|
+
: 9
|
|
1138
1166
|
const endHour =
|
|
1139
|
-
|
|
1167
|
+
typeof stats.endHour === 'number' && stats.endHour >= 0
|
|
1140
1168
|
? stats.endHour
|
|
1141
|
-
: window.__overtimeEndHour ?? 18)
|
|
1169
|
+
: (window.__overtimeEndHour ?? 18)
|
|
1142
1170
|
|
|
1143
1171
|
let latestOut = null
|
|
1144
1172
|
let latestOutHour = null
|
|
@@ -1349,8 +1377,18 @@ function computeAndRenderLatestOvertime(latestByDay) {
|
|
|
1349
1377
|
}
|
|
1350
1378
|
}
|
|
1351
1379
|
|
|
1352
|
-
//
|
|
1380
|
+
// 抽屉关闭交互(按钮 + 点击遮罩)
|
|
1353
1381
|
document.getElementById('sidebarClose').onclick = () => {
|
|
1354
1382
|
document.getElementById('dayDetailSidebar').classList.remove('show')
|
|
1383
|
+
const backdrop = document.getElementById('sidebarBackdrop')
|
|
1384
|
+
if (backdrop) backdrop.classList.remove('show')
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
const sidebarBackdropEl = document.getElementById('sidebarBackdrop')
|
|
1388
|
+
if (sidebarBackdropEl) {
|
|
1389
|
+
sidebarBackdropEl.addEventListener('click', () => {
|
|
1390
|
+
document.getElementById('dayDetailSidebar').classList.remove('show')
|
|
1391
|
+
sidebarBackdropEl.classList.remove('show')
|
|
1392
|
+
})
|
|
1355
1393
|
}
|
|
1356
1394
|
main()
|
package/web/index.html
CHANGED
|
@@ -102,6 +102,8 @@
|
|
|
102
102
|
>
|
|
103
103
|
</footer>
|
|
104
104
|
<!-- 通用:右侧滑出的详情侧栏(小时 / 天 / 周 复用同一个 DOM) -->
|
|
105
|
+
<!-- 背景遮罩,点击可关闭侧栏 -->
|
|
106
|
+
<div id="sidebarBackdrop" class="sidebar-backdrop"></div>
|
|
105
107
|
<div id="dayDetailSidebar" class="sidebar">
|
|
106
108
|
<div class="sidebar-header">
|
|
107
109
|
<span id="sidebarTitle"></span>
|
package/web/static/style.css
CHANGED
|
@@ -189,20 +189,40 @@ td {
|
|
|
189
189
|
margin-bottom: 8px;
|
|
190
190
|
color: #00a76f;
|
|
191
191
|
}
|
|
192
|
+
/* 抽屉 & 遮罩(参考 Material UI Drawer) -------------------- */
|
|
193
|
+
.sidebar-backdrop {
|
|
194
|
+
position: fixed;
|
|
195
|
+
inset: 0;
|
|
196
|
+
background: rgba(15, 23, 42, 0.38); /* 深色半透明遮罩 */
|
|
197
|
+
opacity: 0;
|
|
198
|
+
pointer-events: none;
|
|
199
|
+
transition: opacity 0.25s ease;
|
|
200
|
+
z-index: 1200;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.sidebar-backdrop.show {
|
|
204
|
+
opacity: 1;
|
|
205
|
+
pointer-events: auto;
|
|
206
|
+
}
|
|
207
|
+
|
|
192
208
|
.sidebar {
|
|
193
209
|
position: fixed;
|
|
194
210
|
top: 0;
|
|
195
|
-
right: -
|
|
196
|
-
width:
|
|
211
|
+
right: -460px;
|
|
212
|
+
width: min(460px, 100%);
|
|
197
213
|
height: 100%;
|
|
198
214
|
background: #fff;
|
|
199
|
-
box-shadow:
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
215
|
+
box-shadow:
|
|
216
|
+
0 10px 15px rgba(0, 0, 0, 0.1),
|
|
217
|
+
0 4px 6px rgba(0, 0, 0, 0.08);
|
|
218
|
+
transition: right 0.3s ease;
|
|
219
|
+
z-index: 1300;
|
|
220
|
+
padding: 20px 20px 16px;
|
|
203
221
|
display: flex;
|
|
204
222
|
flex-direction: column;
|
|
205
223
|
box-sizing: border-box;
|
|
224
|
+
border-radius: 12px 0 0 12px;
|
|
225
|
+
border-left: 1px solid rgba(145, 158, 171, 0.24);
|
|
206
226
|
}
|
|
207
227
|
|
|
208
228
|
.sidebar.show {
|
|
@@ -213,35 +233,115 @@ td {
|
|
|
213
233
|
display: flex;
|
|
214
234
|
justify-content: space-between;
|
|
215
235
|
align-items: center;
|
|
216
|
-
font-size:
|
|
217
|
-
|
|
236
|
+
font-size: 16px;
|
|
237
|
+
font-weight: 500;
|
|
238
|
+
margin-bottom: 12px;
|
|
239
|
+
color: #111827;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.sidebar-header span {
|
|
243
|
+
display: inline-flex;
|
|
244
|
+
align-items: center;
|
|
245
|
+
gap: 6px;
|
|
218
246
|
}
|
|
219
247
|
|
|
220
248
|
.sidebar-header button {
|
|
221
|
-
|
|
249
|
+
width: 32px;
|
|
250
|
+
height: 32px;
|
|
251
|
+
display: inline-flex;
|
|
252
|
+
align-items: center;
|
|
253
|
+
justify-content: center;
|
|
254
|
+
background: rgba(148, 163, 184, 0.12);
|
|
222
255
|
border: none;
|
|
223
|
-
|
|
256
|
+
border-radius: 999px;
|
|
257
|
+
font-size: 18px;
|
|
224
258
|
cursor: pointer;
|
|
259
|
+
color: #4b5563;
|
|
260
|
+
transition:
|
|
261
|
+
background 0.2s ease,
|
|
262
|
+
color 0.2s ease,
|
|
263
|
+
box-shadow 0.2s ease;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.sidebar-header button:hover {
|
|
267
|
+
background: rgba(148, 163, 184, 0.22);
|
|
268
|
+
color: #111827;
|
|
269
|
+
box-shadow: 0 2px 6px rgba(15, 23, 42, 0.18);
|
|
225
270
|
}
|
|
226
271
|
|
|
227
272
|
.sidebar-content {
|
|
228
273
|
overflow-y: auto;
|
|
229
|
-
font-size:
|
|
274
|
+
font-size: 13px;
|
|
275
|
+
line-height: 1.6;
|
|
276
|
+
padding-right: 4px;
|
|
230
277
|
}
|
|
231
|
-
|
|
232
|
-
.
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
278
|
+
|
|
279
|
+
.sidebar-content::-webkit-scrollbar {
|
|
280
|
+
width: 6px;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.sidebar-content::-webkit-scrollbar-thumb {
|
|
284
|
+
background: rgba(148, 163, 184, 0.6);
|
|
285
|
+
border-radius: 999px;
|
|
238
286
|
}
|
|
239
|
-
|
|
240
|
-
|
|
287
|
+
|
|
288
|
+
.sidebar-content::-webkit-scrollbar-track {
|
|
289
|
+
background: transparent;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* 抽屉中的提交列表(参考 MUI List / ListItem) ------------- */
|
|
293
|
+
.sidebar-list {
|
|
294
|
+
display: flex;
|
|
295
|
+
flex-direction: column;
|
|
296
|
+
gap: 8px;
|
|
297
|
+
padding: 4px 0;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.sidebar-item,
|
|
301
|
+
.hour-commit,
|
|
302
|
+
.week-commit {
|
|
303
|
+
padding: 10px 12px;
|
|
304
|
+
border-radius: 8px;
|
|
305
|
+
background: #f9fafb;
|
|
306
|
+
border: 1px solid rgba(148, 163, 184, 0.25);
|
|
307
|
+
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
|
308
|
+
transition:
|
|
309
|
+
background 0.18s ease,
|
|
310
|
+
box-shadow 0.18s ease,
|
|
311
|
+
transform 0.1s ease;
|
|
312
|
+
margin: 8px 0;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.sidebar-item:hover,
|
|
316
|
+
.hour-commit:hover,
|
|
317
|
+
.week-commit:hover {
|
|
318
|
+
background: #f3f4ff;
|
|
319
|
+
box-shadow: 0 3px 8px rgba(15, 23, 42, 0.12);
|
|
320
|
+
transform: translateY(-1px);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.sidebar-item-header {
|
|
324
|
+
display: flex;
|
|
325
|
+
justify-content: space-between;
|
|
326
|
+
align-items: center;
|
|
241
327
|
font-size: 12px;
|
|
242
|
-
|
|
328
|
+
color: #64748b;
|
|
329
|
+
margin-bottom: 4px;
|
|
243
330
|
}
|
|
244
|
-
|
|
331
|
+
|
|
332
|
+
.sidebar-item-header .author {
|
|
333
|
+
font-weight: 600;
|
|
334
|
+
color: #111827;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.sidebar-item-header .time {
|
|
338
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
339
|
+
'Liberation Mono', 'Courier New', monospace;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.sidebar-item-message {
|
|
343
|
+
font-size: 13px;
|
|
344
|
+
color: #111827;
|
|
245
345
|
font-weight: 500;
|
|
246
346
|
word-break: break-word;
|
|
247
347
|
}
|