@morehao/dsh-github-trending 0.4.3 → 0.4.4
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 +11 -0
- package/client.js +83 -72
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v0.4.4] - 2026-10-31
|
|
4
|
+
|
|
5
|
+
### 变更
|
|
6
|
+
|
|
7
|
+
- **概览榜单支持日/周/月三周期切换**:概览页「最近榜单」区块此前只展示日榜,现在按日榜 / 周榜 / 月榜分段展示,每个周期各自显示最近若干期,点格子可直接跳到榜单页对应期数;分段按钮上显示各周期期数。仅在调度启用多个周期时出现分段控件。
|
|
8
|
+
- **精简空日期展示**:不再把没有记录的日期逐个铺成「无记录」卡片,只渲染真正有记录的期数;完全无记录时显示空状态提示。今天尚未运行且调度开启时,日榜末尾保留一个「等待 {时间}」状态位。
|
|
9
|
+
|
|
10
|
+
### 修复
|
|
11
|
+
|
|
12
|
+
- **时间格式统一为 24 小时制**:`localTime` / `shortTime` / 下次运行时间等展示改用 `hourCycle: 'h23'`,避免不同环境下出现 12 小时制与 24 小时制混用。
|
|
13
|
+
|
|
3
14
|
## [v0.4.3] - 2026-10-31
|
|
4
15
|
|
|
5
16
|
### 变更
|
package/client.js
CHANGED
|
@@ -280,9 +280,10 @@ var DICT = {
|
|
|
280
280
|
"overview.ready.repo": "仓库",
|
|
281
281
|
"overview.ready.github": "GitHub",
|
|
282
282
|
"overview.ready.view": "查看",
|
|
283
|
-
"overview.week.title": "
|
|
283
|
+
"overview.week.title": "最近榜单",
|
|
284
284
|
"overview.week.all": "全部运行记录",
|
|
285
|
-
"overview.week.
|
|
285
|
+
"overview.week.empty": "还没有运行记录",
|
|
286
|
+
"overview.week.selectPeriod": "选择榜单周期",
|
|
286
287
|
"overview.week.wait": "等待 {time}",
|
|
287
288
|
"overview.live.title": "正在运行",
|
|
288
289
|
"overview.live.core": "核心执行中",
|
|
@@ -607,9 +608,10 @@ var DICT = {
|
|
|
607
608
|
"overview.ready.repo": "Repository",
|
|
608
609
|
"overview.ready.github": "GitHub",
|
|
609
610
|
"overview.ready.view": "View",
|
|
610
|
-
"overview.week.title": "
|
|
611
|
+
"overview.week.title": "Recent leaderboards",
|
|
611
612
|
"overview.week.all": "All runs",
|
|
612
|
-
"overview.week.
|
|
613
|
+
"overview.week.empty": "No runs yet",
|
|
614
|
+
"overview.week.selectPeriod": "Choose leaderboard period",
|
|
613
615
|
"overview.week.wait": "Waiting for {time}",
|
|
614
616
|
"overview.live.title": "Running",
|
|
615
617
|
"overview.live.core": "Core is working",
|
|
@@ -970,7 +972,7 @@ var CSS = `
|
|
|
970
972
|
.dshgt-md a:hover{text-decoration:underline;}
|
|
971
973
|
|
|
972
974
|
/* ——— 周期标签 / 分段 ——— */
|
|
973
|
-
.dshgt-pchip{display:inline-flex;align-items:center;height:20px;padding:0 8px;border-radius:999px;font-size:11px;font-weight:600;line-height:18px;white-space:nowrap;border:1px solid var(--gt-border);color:var(--gt-muted);background:var(--gt-bg);}
|
|
975
|
+
.dshgt-pchip{display:inline-flex;align-items:center;justify-content:center;height:20px;padding:0 8px;border-radius:999px;font-size:11px;font-weight:600;line-height:18px;white-space:nowrap;border:1px solid var(--gt-border);color:var(--gt-muted);background:var(--gt-bg);}
|
|
974
976
|
.dshgt-pchip.daily{color:var(--gt-accent);border-color:color-mix(in srgb,var(--gt-accent) 35%,var(--gt-border));background:color-mix(in srgb,var(--gt-accent) 9%,var(--gt-bg));}
|
|
975
977
|
.dshgt-pchip.weekly{color:#7c3aed;border-color:#ddd6fe;background:#f5f3ff;}
|
|
976
978
|
.dshgt-pchip.monthly{color:#0f766e;border-color:#99f6e4;background:#f0fdfa;}
|
|
@@ -980,6 +982,8 @@ var CSS = `
|
|
|
980
982
|
.dshgt-period-seg button.on{background:var(--gt-bg);color:var(--gt-fg);font-weight:600;box-shadow:0 1px 2px rgba(15,23,42,.08);}
|
|
981
983
|
.dshgt-period-count{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--gt-muted);background:color-mix(in srgb,var(--gt-fg) 6%,var(--gt-bg));border-radius:999px;padding:0 6px;line-height:16px;}
|
|
982
984
|
.dshgt-period-seg button.on .dshgt-period-count{color:var(--gt-accent);background:color-mix(in srgb,var(--gt-accent) 12%,var(--gt-bg));}
|
|
985
|
+
.dshgt-overview-seg{margin-bottom:8px;}
|
|
986
|
+
.dshgt-overview-empty{padding:14px 2px;}
|
|
983
987
|
|
|
984
988
|
/* ——— 运行记录 ——— */
|
|
985
989
|
.dshgt-runs-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}
|
|
@@ -1202,7 +1206,15 @@ function localTime(iso) {
|
|
|
1202
1206
|
if (iso === null || iso === void 0) return "—";
|
|
1203
1207
|
const date = new Date(iso);
|
|
1204
1208
|
if (Number.isNaN(date.getTime())) return "—";
|
|
1205
|
-
return date.toLocaleString(
|
|
1209
|
+
return date.toLocaleString(void 0, {
|
|
1210
|
+
year: "numeric",
|
|
1211
|
+
month: "2-digit",
|
|
1212
|
+
day: "2-digit",
|
|
1213
|
+
hour: "2-digit",
|
|
1214
|
+
minute: "2-digit",
|
|
1215
|
+
second: "2-digit",
|
|
1216
|
+
hourCycle: "h23"
|
|
1217
|
+
});
|
|
1206
1218
|
}
|
|
1207
1219
|
async function copyText(value) {
|
|
1208
1220
|
try {
|
|
@@ -1217,7 +1229,13 @@ function shortTime(iso) {
|
|
|
1217
1229
|
if (iso === null || iso === void 0) return "—";
|
|
1218
1230
|
const date = new Date(iso);
|
|
1219
1231
|
if (Number.isNaN(date.getTime())) return "—";
|
|
1220
|
-
return date.toLocaleString(void 0, {
|
|
1232
|
+
return date.toLocaleString(void 0, {
|
|
1233
|
+
month: "2-digit",
|
|
1234
|
+
day: "2-digit",
|
|
1235
|
+
hour: "2-digit",
|
|
1236
|
+
minute: "2-digit",
|
|
1237
|
+
hourCycle: "h23"
|
|
1238
|
+
});
|
|
1221
1239
|
}
|
|
1222
1240
|
|
|
1223
1241
|
// client/api.ts
|
|
@@ -2188,38 +2206,6 @@ function digestTarget(record, timeZone) {
|
|
|
2188
2206
|
const period = recordPeriod(record);
|
|
2189
2207
|
return { period, bucket: periodBucket(period, info.date) };
|
|
2190
2208
|
}
|
|
2191
|
-
function buildDigestDates(records, options) {
|
|
2192
|
-
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
2193
|
-
const today = zonedDateString(now, options.timeZone);
|
|
2194
|
-
const earliest = addDays(today, -(DIGEST_WINDOW_DAYS - 1));
|
|
2195
|
-
const groups = /* @__PURE__ */ new Map();
|
|
2196
|
-
for (const record of records) {
|
|
2197
|
-
if (recordPeriod(record) !== "daily") continue;
|
|
2198
|
-
const info = recordDate(record, options.timeZone);
|
|
2199
|
-
if (info === void 0) continue;
|
|
2200
|
-
if (info.date < earliest || info.date > today) continue;
|
|
2201
|
-
const group = groups.get(info.date);
|
|
2202
|
-
if (group === void 0) groups.set(info.date, { records: [record], derivedFromAt: info.derivedFromAt });
|
|
2203
|
-
else {
|
|
2204
|
-
group.records.push(record);
|
|
2205
|
-
group.derivedFromAt = group.derivedFromAt || info.derivedFromAt;
|
|
2206
|
-
}
|
|
2207
|
-
}
|
|
2208
|
-
const days = [];
|
|
2209
|
-
for (const [date, group] of groups) {
|
|
2210
|
-
const sorted = [...group.records].sort((a, b) => b.at.localeCompare(a.at));
|
|
2211
|
-
const preferred = sorted.find(
|
|
2212
|
-
(record2) => record2.preview !== void 0 && record2.ok && record2.kind !== "dry-run" && !record2.skipped
|
|
2213
|
-
);
|
|
2214
|
-
const record = preferred ?? sorted[0];
|
|
2215
|
-
if (record === void 0) continue;
|
|
2216
|
-
const info = recordDate(record, options.timeZone);
|
|
2217
|
-
const legacy = record.legacy === true || info?.derivedFromAt === true || group.derivedFromAt;
|
|
2218
|
-
days.push({ date, record, status: digestStatus(record), legacy });
|
|
2219
|
-
}
|
|
2220
|
-
days.sort((a, b) => b.date.localeCompare(a.date));
|
|
2221
|
-
return days;
|
|
2222
|
-
}
|
|
2223
2209
|
function buildPeriodGroups(records, options) {
|
|
2224
2210
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
2225
2211
|
const today = zonedDateString(now, options.timeZone);
|
|
@@ -2265,11 +2251,6 @@ function buildPeriodGroups(records, options) {
|
|
|
2265
2251
|
return { period, days, previewCount: days.filter((day) => day.status === "preview").length };
|
|
2266
2252
|
});
|
|
2267
2253
|
}
|
|
2268
|
-
function recentDates(today, count) {
|
|
2269
|
-
const dates = [];
|
|
2270
|
-
for (let offset = count - 1; offset >= 0; offset -= 1) dates.push(addDays(today, -offset));
|
|
2271
|
-
return dates;
|
|
2272
|
-
}
|
|
2273
2254
|
function formatDayLabel(date, lang) {
|
|
2274
2255
|
let weekday = "";
|
|
2275
2256
|
try {
|
|
@@ -2369,6 +2350,7 @@ function readyRows(t, state) {
|
|
|
2369
2350
|
function OverviewView(props) {
|
|
2370
2351
|
const { t, lang, store, controller } = props;
|
|
2371
2352
|
const state = store.state;
|
|
2353
|
+
const [activePeriod, setActivePeriod] = import_react.default.useState("daily");
|
|
2372
2354
|
if (state === null) {
|
|
2373
2355
|
return h("div", { className: "dshgt-empty" }, store.error ?? t("quickfill.loading"));
|
|
2374
2356
|
}
|
|
@@ -2378,9 +2360,15 @@ function OverviewView(props) {
|
|
|
2378
2360
|
const readyCount = rows.filter((row) => row.ok).length;
|
|
2379
2361
|
const timeZone = state.schedule.timezone;
|
|
2380
2362
|
const today = zonedDateString(/* @__PURE__ */ new Date(), timeZone);
|
|
2381
|
-
const
|
|
2382
|
-
const
|
|
2383
|
-
const
|
|
2363
|
+
const groups = buildPeriodGroups(state.status.history, { timeZone });
|
|
2364
|
+
const groupMap = new Map(groups.map((group) => [group.period, group]));
|
|
2365
|
+
const enabledPeriods = PERIODS.filter((period2) => state.schedule.periods.includes(period2));
|
|
2366
|
+
const periods = enabledPeriods.length > 0 ? enabledPeriods : PERIODS;
|
|
2367
|
+
const period = periods.includes(activePeriod) ? activePeriod : periods[0] ?? "daily";
|
|
2368
|
+
const activeDays = groupMap.get(period)?.days ?? [];
|
|
2369
|
+
const recent = period === "daily" ? activeDays.slice(0, 7) : activeDays;
|
|
2370
|
+
const todayHasDaily = groupMap.get("daily")?.days.some((day) => day.date === today) ?? false;
|
|
2371
|
+
const showWaiting = period === "daily" && !todayHasDaily && state.schedule.enabled;
|
|
2384
2372
|
const lastTarget = last === null ? void 0 : digestTarget(last, timeZone);
|
|
2385
2373
|
return h(
|
|
2386
2374
|
"div",
|
|
@@ -2492,42 +2480,59 @@ function OverviewView(props) {
|
|
|
2492
2480
|
t("overview.week.title"),
|
|
2493
2481
|
h("button", { type: "button", className: "dshgt-linkbtn dshgt-section-tail", onClick: props.onOpenRuns }, t("overview.week.all"))
|
|
2494
2482
|
),
|
|
2495
|
-
h(
|
|
2483
|
+
periods.length > 1 ? h(
|
|
2496
2484
|
"div",
|
|
2497
|
-
{ className: "dshgt-week" },
|
|
2498
|
-
|
|
2499
|
-
const
|
|
2500
|
-
|
|
2501
|
-
const waiting = date === today && state.schedule.enabled;
|
|
2502
|
-
return h(
|
|
2503
|
-
"div",
|
|
2504
|
-
{ className: "dshgt-day", key: date },
|
|
2505
|
-
h("div", { className: "dshgt-day-date" }, date.slice(5).replace("-", "/")),
|
|
2506
|
-
h("div", { className: "dshgt-day-status" }, waiting ? t("overview.week.wait", { time: state.schedule.time }) : t("overview.week.none"))
|
|
2507
|
-
);
|
|
2508
|
-
}
|
|
2485
|
+
{ className: "dshgt-period-seg dshgt-overview-seg", role: "tablist", "aria-label": t("overview.week.selectPeriod") },
|
|
2486
|
+
periods.map((item) => {
|
|
2487
|
+
const on = item === period;
|
|
2488
|
+
const count = groupMap.get(item)?.days.length ?? 0;
|
|
2509
2489
|
return h(
|
|
2510
2490
|
"button",
|
|
2511
2491
|
{
|
|
2492
|
+
key: item,
|
|
2512
2493
|
type: "button",
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2494
|
+
role: "tab",
|
|
2495
|
+
"aria-selected": on ? "true" : "false",
|
|
2496
|
+
className: on ? "on" : "",
|
|
2497
|
+
onClick: () => setActivePeriod(item)
|
|
2517
2498
|
},
|
|
2518
|
-
h("
|
|
2519
|
-
h(
|
|
2520
|
-
"div",
|
|
2521
|
-
{ className: "dshgt-day-status" },
|
|
2522
|
-
h("span", { className: `dshgt-lamp ${STATUS_LAMP[day.status]}` }),
|
|
2523
|
-
dayLabel(t, day)
|
|
2524
|
-
)
|
|
2499
|
+
h("span", null, t(`period.${item}`)),
|
|
2500
|
+
h("span", { className: "dshgt-period-count" }, String(count))
|
|
2525
2501
|
);
|
|
2526
2502
|
})
|
|
2503
|
+
) : null,
|
|
2504
|
+
recent.length === 0 && !showWaiting ? h("div", { className: "dshgt-hint dshgt-overview-empty" }, t("overview.week.empty")) : h(
|
|
2505
|
+
"div",
|
|
2506
|
+
{ className: "dshgt-week" },
|
|
2507
|
+
recent.map(
|
|
2508
|
+
(day) => h(
|
|
2509
|
+
"button",
|
|
2510
|
+
{
|
|
2511
|
+
type: "button",
|
|
2512
|
+
className: "dshgt-day dshgt-day-clickable",
|
|
2513
|
+
key: day.bucket,
|
|
2514
|
+
onClick: () => props.onOpenDigest({ period, bucket: day.bucket }),
|
|
2515
|
+
title: day.record.errorCode === void 0 ? formatBucketLabel(period, day.bucket, lang) : `${formatBucketLabel(period, day.bucket, lang)} · ${day.record.errorCode}`
|
|
2516
|
+
},
|
|
2517
|
+
h("div", { className: "dshgt-day-date" }, shortBucket(period, day.bucket)),
|
|
2518
|
+
h("div", { className: "dshgt-day-status" }, h("span", { className: `dshgt-lamp ${STATUS_LAMP[day.status]}` }), dayLabel(t, day))
|
|
2519
|
+
)
|
|
2520
|
+
),
|
|
2521
|
+
showWaiting ? h(
|
|
2522
|
+
"div",
|
|
2523
|
+
{ className: "dshgt-day" },
|
|
2524
|
+
h("div", { className: "dshgt-day-date" }, today.slice(5).replace("-", "/")),
|
|
2525
|
+
h("div", { className: "dshgt-day-status" }, t("overview.week.wait", { time: state.schedule.time }))
|
|
2526
|
+
) : null
|
|
2527
2527
|
)
|
|
2528
2528
|
)
|
|
2529
2529
|
);
|
|
2530
2530
|
}
|
|
2531
|
+
function shortBucket(period, bucket) {
|
|
2532
|
+
if (period === "daily") return bucket.slice(5).replace("-", "/");
|
|
2533
|
+
if (period === "weekly") return bucket.slice(5);
|
|
2534
|
+
return bucket.slice(2).replace("-", "/");
|
|
2535
|
+
}
|
|
2531
2536
|
|
|
2532
2537
|
// client/runs.ts
|
|
2533
2538
|
var FILTERS = [
|
|
@@ -3892,7 +3897,13 @@ function nextRunText(iso) {
|
|
|
3892
3897
|
if (iso === void 0) return "—";
|
|
3893
3898
|
const date = new Date(iso);
|
|
3894
3899
|
if (Number.isNaN(date.getTime())) return "—";
|
|
3895
|
-
return date.toLocaleString(void 0, {
|
|
3900
|
+
return date.toLocaleString(void 0, {
|
|
3901
|
+
month: "numeric",
|
|
3902
|
+
day: "numeric",
|
|
3903
|
+
hour: "2-digit",
|
|
3904
|
+
minute: "2-digit",
|
|
3905
|
+
hourCycle: "h23"
|
|
3906
|
+
});
|
|
3896
3907
|
}
|
|
3897
3908
|
function apply(ctx) {
|
|
3898
3909
|
const slots = ctx.get?.("slots");
|