@morehao/dsh-github-trending 0.7.2 → 0.7.3

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/client.js +118 -42
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.7.3] - 2026-11-01
4
+
5
+ > 订阅页三处修复:待首次分析的仓库不再点出必败请求、添加订阅改弹窗、变更预览抽屉改紧凑 md 预览。
6
+
7
+ ### 修复
8
+
9
+ - **单仓「触发分析」必败请求**:新添加、尚未跑过发版检查的仓库(`status=baseline`)在列表里也可点击「触发分析」,
10
+ 但单仓分析走 `--stages releases` 不合并 pending,核心会报 `repo ... is not in the subscription list` 后立即失败。
11
+ 现在 `baseline` 行的「触发分析」禁用并提示「待首次分析后才能触发」;分析失败时把核心「未纳入订阅 / 无发版记录」
12
+ 类错误翻成一句人话,错误条稳定可见,不再一闪而过。
13
+
14
+ ### 变更
15
+
16
+ - **添加订阅改为居中模态弹窗**:工具条内联输入框改为弹窗(输入 owner/repo + 实时校验 + 回车提交 + Esc/遮罩关闭);
17
+ 添加失败就地显示错误。
18
+
19
+ ### 改进
20
+
21
+ - **变更预览抽屉**:正文包一层纸面卡(不再直接贴页面底色),移植原型紧凑 markdown 排版(h1 15 / h2 13 带强调左边框),
22
+ 不再复用日报的大号样式;抽屉遮罩加深 + 模糊、阴影加强,观感与设计原型一致。
23
+
3
24
  ## [v0.7.2] - 2026-11-01
4
25
 
5
26
  > 依赖升级:`@morehao/dsh-plugin-kit` 0.1.0 → **0.2.1**。
package/client.js CHANGED
@@ -472,6 +472,8 @@ var DICT = {
472
472
  "subs.meta.thisWeek": "本周 {from} ~ {to} · {changed} 个仓库有变化",
473
473
  "subs.meta.lastCheck": "上次发版检查 {time}",
474
474
  "subs.add": "添加",
475
+ "subs.add.title": "添加订阅仓库",
476
+ "subs.add.exists": "{repo} 已在订阅列表中",
475
477
  "subs.add.placeholder": "denoland/deno",
476
478
  "subs.add.confirm": "添加",
477
479
  "subs.adding": "添加中…",
@@ -485,6 +487,7 @@ var DICT = {
485
487
  "subs.row.changesRepo": "查看 {repo} 的变更",
486
488
  "subs.row.trigger": "触发分析",
487
489
  "subs.row.triggerRepo": "只对 {repo} 生成变更分析",
490
+ "subs.row.triggerFresh": "待首次分析后才能触发",
488
491
  "subs.search.placeholder": "搜索仓库",
489
492
  "subs.search.label": "搜索仓库",
490
493
  "subs.toolbar.add": "+ 添加仓库",
@@ -521,7 +524,7 @@ var DICT = {
521
524
  "subs.confirm.cancel": "取消",
522
525
  "subs.confirm.ok": "确认移除",
523
526
  "subs.empty": "还没有订阅任何仓库",
524
- "subs.empty.hint": "在上面的输入框里输入 owner/repo,回车添加。",
527
+ "subs.empty.hint": "点「+ 添加仓库」输入 owner/repo 添加。",
525
528
  "subs.empty.match": "没有匹配的仓库",
526
529
  "subs.empty.match.hint": "按 Esc 清空搜索,或换一个 owner / 名字。",
527
530
  "subs.empty.clear": "清除搜索",
@@ -994,6 +997,8 @@ var DICT = {
994
997
  "subs.meta.thisWeek": "This week {from} ~ {to} · {changed} repos changed",
995
998
  "subs.meta.lastCheck": "Last release check {time}",
996
999
  "subs.add": "Add",
1000
+ "subs.add.title": "Add a repository",
1001
+ "subs.add.exists": "{repo} is already subscribed",
997
1002
  "subs.add.placeholder": "denoland/deno",
998
1003
  "subs.add.confirm": "Add",
999
1004
  "subs.adding": "Adding…",
@@ -1007,6 +1012,7 @@ var DICT = {
1007
1012
  "subs.row.changesRepo": "Show changes for {repo}",
1008
1013
  "subs.row.trigger": "Analyze",
1009
1014
  "subs.row.triggerRepo": "Generate change analysis for {repo} only",
1015
+ "subs.row.triggerFresh": "Available after the first analysis",
1010
1016
  "subs.search.placeholder": "Search repositories",
1011
1017
  "subs.search.label": "Search repositories",
1012
1018
  "subs.toolbar.add": "+ Add repository",
@@ -1043,7 +1049,7 @@ var DICT = {
1043
1049
  "subs.confirm.cancel": "Cancel",
1044
1050
  "subs.confirm.ok": "Remove",
1045
1051
  "subs.empty": "No repos subscribed yet",
1046
- "subs.empty.hint": "Type owner/repo in the field above and press Enter to add one.",
1052
+ "subs.empty.hint": 'Click "+ Add repository" and enter owner/repo to add one.',
1047
1053
  "subs.empty.match": "No matching repos",
1048
1054
  "subs.empty.match.hint": "Press Esc to clear the search, or try another owner / name.",
1049
1055
  "subs.empty.clear": "Clear search",
@@ -1462,9 +1468,6 @@ var CSS = `
1462
1468
  .dshgt-subs-search input:focus{outline:2px solid color-mix(in srgb,var(--gt-accent) 30%,transparent);outline-offset:1px;border-color:color-mix(in srgb,var(--gt-accent) 45%,var(--gt-border));}
1463
1469
  .dshgt-subs-search input::placeholder{color:var(--gt-muted);}
1464
1470
  .dshgt-subs-toolbar-spacer{flex:1 1 auto;min-width:0;}
1465
- .dshgt-subs-addform{display:flex;align-items:center;gap:6px;}
1466
- .dshgt-subs-addform input{height:32px;box-sizing:border-box;width:200px;padding:0 9px;border:1px solid var(--gt-border);border-radius:8px;background:var(--gt-bg);color:var(--gt-fg);font:inherit;font-size:12.5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;}
1467
- .dshgt-subs-addform input:focus{outline:2px solid color-mix(in srgb,var(--gt-accent) 30%,transparent);outline-offset:1px;}
1468
1471
  .dshgt-subs-act.gen{color:var(--gt-muted);}
1469
1472
  .dshgt-subs-act.gen:hover{color:var(--gt-accent);background:color-mix(in srgb,var(--gt-accent) 10%,transparent);}
1470
1473
  .dshgt-subs-act.gen:disabled{opacity:.5;cursor:not-allowed;}
@@ -1528,8 +1531,8 @@ var CSS = `
1528
1531
  .dshgt-subs-linkbtn{appearance:none;border:0;background:none;font:inherit;font-size:12.5px;color:var(--gt-accent);cursor:pointer;padding:2px 4px;border-radius:5px;}
1529
1532
  .dshgt-subs-linkbtn:hover{text-decoration:underline;}
1530
1533
  .dshgt-subs-confirm-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--gt-muted);}
1531
- .dshgt-subs-drawer-mask{position:fixed;inset:0;z-index:2147483000;display:flex;justify-content:flex-end;background:color-mix(in srgb,var(--gt-fg) 26%,transparent);}
1532
- .dshgt-subs-drawer{width:460px;max-width:100%;height:100%;display:flex;flex-direction:column;background:var(--gt-bg);border-left:1px solid var(--gt-border);box-shadow:-24px 0 60px color-mix(in srgb,var(--gt-fg) 16%,transparent);}
1534
+ .dshgt-subs-drawer-mask{position:fixed;inset:0;z-index:2147483000;display:flex;justify-content:flex-end;background:color-mix(in srgb,var(--gt-fg) 34%,transparent);backdrop-filter:blur(1.5px);}
1535
+ .dshgt-subs-drawer{width:460px;max-width:100%;height:100%;display:flex;flex-direction:column;background:var(--gt-bg);border-left:1px solid var(--gt-border);box-shadow:-30px 0 70px rgba(15,23,42,.3);}
1533
1536
  .dshgt-subs-drawer-head{flex:none;display:flex;align-items:flex-start;gap:10px;padding:16px 20px 12px;border-bottom:1px solid var(--gt-border);}
1534
1537
  .dshgt-subs-drawer-main{flex:1;min-width:0;}
1535
1538
  .dshgt-subs-drawer-repo{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;font-weight:600;word-break:break-all;}
@@ -1541,6 +1544,26 @@ var CSS = `
1541
1544
  .dshgt-subs-vol .label{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;}
1542
1545
  .dshgt-subs-drawer-note{margin-top:auto;padding-top:12px;border-top:1px solid var(--gt-border);font-size:11.5px;color:var(--gt-muted);line-height:1.65;word-break:break-word;}
1543
1546
  .dshgt-subs-drawer-raw{margin:0;padding:12px 14px;border-radius:8px;background:color-mix(in srgb,var(--gt-fg) 5%,var(--gt-card));font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.65;white-space:pre-wrap;overflow-wrap:break-word;}
1547
+ /* 抽屉正文纸面:md 铺在卡面上(与日报预览 .dshgt-digest-sheet 同一观感),不再直接贴页面底色。 */
1548
+ .dshgt-subs-drawer-doc{border:1px solid var(--gt-border);border-radius:10px;background:var(--gt-card);padding:14px 16px;}
1549
+ .dshgt-subs-drawer-doc .dshgt-subs-drawer-raw{background:transparent;padding:0;}
1550
+ /* 抽屉专用紧凑 md 排版:覆盖日报的大号 .dshgt-md(h1 24 / h2 18),保留结构其余样式。 */
1551
+ .dshgt-subs-drawer-doc .dshgt-md{font-size:12.5px;line-height:1.7;}
1552
+ .dshgt-subs-drawer-doc .dshgt-md-h1{font-size:15px;margin:0 0 4px;}
1553
+ .dshgt-subs-drawer-doc .dshgt-md-h2{font-size:13px;margin:14px 0 6px;padding-left:8px;border-left:3px solid var(--gt-accent);}
1554
+ .dshgt-subs-drawer-doc .dshgt-md-h3{font-size:12.5px;}
1555
+ .dshgt-subs-drawer-doc .dshgt-md-h4,.dshgt-subs-drawer-doc .dshgt-md-h5,.dshgt-subs-drawer-doc .dshgt-md-h6{font-size:12px;}
1556
+ .dshgt-subs-drawer-doc .dshgt-md-p{font-size:12.5px;margin:6px 0;}
1557
+ .dshgt-subs-drawer-doc .dshgt-md-list{font-size:12.5px;padding-left:18px;}
1558
+ .dshgt-subs-drawer-doc .dshgt-md-list li{margin:3px 0;}
1559
+ .dshgt-subs-drawer-doc .dshgt-md-quote{font-size:12.5px;}
1560
+ .dshgt-subs-drawer-doc .dshgt-md-table{min-width:0;font-size:12px;}
1561
+ .dshgt-subs-drawer-doc .dshgt-md-pre{font-size:11.5px;padding:10px 12px;}
1562
+ .dshgt-subs-drawer-doc .dshgt-md-code{font-size:11.5px;}
1563
+ /* 添加订阅居中小弹窗 */
1564
+ .dshgt-addmodal{max-width:420px;}
1565
+ .dshgt-addmodal-input{height:34px;width:100%;}
1566
+ .dshgt-addmodal-err{color:var(--gt-err);}
1544
1567
  @media (max-width:1040px){
1545
1568
  .dshgt-subs-thead,.dshgt-subs-row{grid-template-columns:240px 120px 110px minmax(0,1fr);}
1546
1569
  .dshgt-subs-table.is-selecting .dshgt-subs-thead,.dshgt-subs-table.is-selecting .dshgt-subs-row{grid-template-columns:22px 240px 120px 110px minmax(0,1fr);}
@@ -4471,6 +4494,9 @@ var DATE_RE2 = /^\d{4}-\d{2}-\d{2}$/;
4471
4494
  function errorText(failure) {
4472
4495
  return failure instanceof Error ? failure.message : String(failure);
4473
4496
  }
4497
+ function isNotReadyMessage(message) {
4498
+ return /is not in the subscription list|has no release document|no release record|not subscribed/i.test(message);
4499
+ }
4474
4500
  function monthDay(value) {
4475
4501
  if (value === void 0 || value === "") return "—";
4476
4502
  return DATE_RE2.test(value) ? value.slice(5) : value;
@@ -4597,7 +4623,7 @@ function DocDrawer(props) {
4597
4623
  { kind: "err", title: t("subs.drawer.title", { repo }) },
4598
4624
  h("div", null, error),
4599
4625
  h("div", { style: { marginTop: 8 } }, h(Btn, { small: true, onClick: () => setAttempt((current2) => current2 + 1) }, t("subs.drawer.retry")))
4600
- ) : parseFailed || nodes === null ? h("pre", { className: "dshgt-subs-drawer-raw" }, doc?.markdown ?? "") : h("div", { className: "dshgt-md" }, nodes);
4626
+ ) : parseFailed || nodes === null ? h("div", { className: "dshgt-subs-drawer-doc" }, h("pre", { className: "dshgt-subs-drawer-raw" }, doc?.markdown ?? "")) : h("div", { className: "dshgt-subs-drawer-doc" }, h("div", { className: "dshgt-md" }, nodes));
4601
4627
  return h(
4602
4628
  "div",
4603
4629
  {
@@ -4688,6 +4714,7 @@ function SubscriptionsView(props) {
4688
4714
  const [openRepo, setOpenRepo] = import_react.default.useState(null);
4689
4715
  const [addOpen, setAddOpen] = import_react.default.useState(false);
4690
4716
  const [addValue, setAddValue] = import_react.default.useState("");
4717
+ const [addError, setAddError] = import_react.default.useState(null);
4691
4718
  const [analyzing, setAnalyzing] = import_react.default.useState(null);
4692
4719
  const [result, setResult] = import_react.default.useState(null);
4693
4720
  const load = import_react.default.useCallback((signal) => {
@@ -4717,12 +4744,13 @@ function SubscriptionsView(props) {
4717
4744
  setBusy("add");
4718
4745
  setError(null);
4719
4746
  setNote(null);
4747
+ setAddError(null);
4720
4748
  postSubscriptions("add", [repo]).then((next) => {
4721
4749
  setList(next);
4722
4750
  setAddValue("");
4723
4751
  setAddOpen(false);
4724
4752
  setNote(t("subs.add.queued", { repo }));
4725
- }).catch((failure) => setError(errorText(failure))).finally(() => setBusy(null));
4753
+ }).catch((failure) => setAddError(errorText(failure))).finally(() => setBusy(null));
4726
4754
  };
4727
4755
  const removeOne = (repo) => {
4728
4756
  setBusy(`remove:${repo}`);
@@ -4757,11 +4785,13 @@ function SubscriptionsView(props) {
4757
4785
  postReleasesRun(repo).then((record) => {
4758
4786
  setResult({ scope: repo === void 0 ? "all" : "one", ...repo === void 0 ? {} : { repo }, ok: record.status !== "failed", changed: record.changed });
4759
4787
  if (record.status === "failed" && record.errorMessage !== void 0) {
4760
- setError(t("subs.analyze.failed", { message: record.errorMessage }));
4788
+ const notReady = isNotReadyMessage(record.errorMessage);
4789
+ setError(notReady ? t("subs.row.triggerFresh") : t("subs.analyze.failed", { message: record.errorMessage }));
4761
4790
  }
4762
4791
  load();
4763
4792
  }).catch((failure) => {
4764
- setError(errorText(failure));
4793
+ const message = errorText(failure);
4794
+ setError(isNotReadyMessage(message) ? t("subs.row.triggerFresh") : message);
4765
4795
  setResult({ scope: repo === void 0 ? "all" : "one", ...repo === void 0 ? {} : { repo }, ok: false, changed: 0 });
4766
4796
  }).finally(() => setAnalyzing(null));
4767
4797
  };
@@ -4798,6 +4828,7 @@ function SubscriptionsView(props) {
4798
4828
  const item = row.item;
4799
4829
  const tone = toneOf(item?.status);
4800
4830
  const rowAnalyzing = analyzing !== null && analyzing.scope === "one" && analyzing.repo === row.name;
4831
+ const fresh = item?.status === "baseline";
4801
4832
  const checkbox = selecting ? h(
4802
4833
  "span",
4803
4834
  { key: "cb", role: "cell", className: "dshgt-subs-cbwrap" },
@@ -4843,12 +4874,12 @@ function SubscriptionsView(props) {
4843
4874
  {
4844
4875
  type: "button",
4845
4876
  className: "dshgt-subs-act gen",
4846
- "aria-label": t("subs.row.triggerRepo", { repo: row.name }),
4847
- title: t("subs.row.triggerRepo", { repo: row.name }),
4848
- disabled: globalBusy || busy !== null,
4877
+ "aria-label": fresh ? t("subs.row.triggerFresh") : t("subs.row.triggerRepo", { repo: row.name }),
4878
+ title: fresh ? t("subs.row.triggerFresh") : t("subs.row.triggerRepo", { repo: row.name }),
4879
+ disabled: globalBusy || busy !== null || fresh,
4849
4880
  onClick: (event) => {
4850
4881
  event.stopPropagation();
4851
- runAnalyze(row.name);
4882
+ if (!fresh) runAnalyze(row.name);
4852
4883
  }
4853
4884
  },
4854
4885
  t("subs.row.trigger")
@@ -4936,33 +4967,7 @@ function SubscriptionsView(props) {
4936
4967
  })
4937
4968
  ),
4938
4969
  h("div", { className: "dshgt-subs-toolbar-spacer" }),
4939
- addOpen ? h(
4940
- "div",
4941
- { className: "dshgt-subs-addform" },
4942
- h("input", {
4943
- type: "text",
4944
- value: addValue,
4945
- placeholder: t("subs.add.placeholder"),
4946
- "aria-label": t("subs.add.placeholder"),
4947
- autoComplete: "off",
4948
- spellCheck: false,
4949
- autoFocus: true,
4950
- onInput: (event) => setAddValue(event.target.value),
4951
- onKeyDown: (event) => {
4952
- if (event.isComposing === true) return;
4953
- if (event.key === "Enter" && canAdd && !alreadySubscribed) addRepo(addValue.trim());
4954
- if (event.key === "Escape") {
4955
- setAddOpen(false);
4956
- setAddValue("");
4957
- }
4958
- }
4959
- }),
4960
- h(
4961
- Btn,
4962
- { small: true, variant: "primary", disabled: busy !== null || !canAdd || alreadySubscribed, onClick: () => canAdd && !alreadySubscribed && addRepo(addValue.trim()) },
4963
- t("subs.add.confirm")
4964
- )
4965
- ) : h(
4970
+ h(
4966
4971
  Btn,
4967
4972
  {
4968
4973
  small: true,
@@ -4970,6 +4975,7 @@ function SubscriptionsView(props) {
4970
4975
  onClick: () => {
4971
4976
  setAddOpen(true);
4972
4977
  setAddValue("");
4978
+ setAddError(null);
4973
4979
  }
4974
4980
  },
4975
4981
  t("subs.toolbar.add")
@@ -5065,6 +5071,76 @@ function SubscriptionsView(props) {
5065
5071
  )
5066
5072
  )
5067
5073
  ),
5074
+ addOpen ? h(
5075
+ "div",
5076
+ {
5077
+ className: "dshgt-modal-mask",
5078
+ onClick: (event) => {
5079
+ if (event.target === event.currentTarget) {
5080
+ setAddOpen(false);
5081
+ setAddValue("");
5082
+ setAddError(null);
5083
+ }
5084
+ }
5085
+ },
5086
+ h(
5087
+ "div",
5088
+ { className: "dshgt-modal dshgt-addmodal", role: "dialog", "aria-modal": "true", "aria-label": t("subs.add.title") },
5089
+ h("h3", { style: { margin: 0, fontSize: 14 } }, t("subs.add.title")),
5090
+ h("input", {
5091
+ type: "text",
5092
+ className: "dshgt-input dshgt-addmodal-input",
5093
+ value: addValue,
5094
+ placeholder: t("subs.add.placeholder"),
5095
+ "aria-label": t("subs.add.placeholder"),
5096
+ autoComplete: "off",
5097
+ spellCheck: false,
5098
+ autoFocus: true,
5099
+ onInput: (event) => {
5100
+ setAddValue(event.target.value);
5101
+ if (addError !== null) setAddError(null);
5102
+ },
5103
+ onKeyDown: (event) => {
5104
+ if (event.isComposing === true) return;
5105
+ if (event.key === "Enter" && canAdd && !alreadySubscribed && busy === null) addRepo(addValue.trim());
5106
+ if (event.key === "Escape") {
5107
+ setAddOpen(false);
5108
+ setAddValue("");
5109
+ setAddError(null);
5110
+ }
5111
+ }
5112
+ }),
5113
+ addValue.trim() !== "" && !canAdd ? h("p", { className: "dshgt-hint dshgt-addmodal-err", style: { margin: 0 } }, t("subs.input.invalid")) : null,
5114
+ alreadySubscribed ? h("p", { className: "dshgt-hint", style: { margin: 0 } }, t("subs.add.exists", { repo: addValue.trim() })) : null,
5115
+ addError === null ? null : h("p", { className: "dshgt-hint dshgt-addmodal-err", style: { margin: 0 } }, addError),
5116
+ h(
5117
+ "div",
5118
+ { className: "dshgt-footer", style: { justifyContent: "flex-end" } },
5119
+ h(
5120
+ Btn,
5121
+ {
5122
+ small: true,
5123
+ onClick: () => {
5124
+ setAddOpen(false);
5125
+ setAddValue("");
5126
+ setAddError(null);
5127
+ }
5128
+ },
5129
+ t("subs.cancel")
5130
+ ),
5131
+ h(
5132
+ Btn,
5133
+ {
5134
+ small: true,
5135
+ variant: "primary",
5136
+ disabled: busy !== null || !canAdd || alreadySubscribed,
5137
+ onClick: () => canAdd && !alreadySubscribed && addRepo(addValue.trim())
5138
+ },
5139
+ busy === "add" ? t("subs.adding") : t("subs.add.confirm")
5140
+ )
5141
+ )
5142
+ )
5143
+ ) : null,
5068
5144
  openRepo === null ? null : h(DocDrawer, {
5069
5145
  key: openRepo,
5070
5146
  t,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morehao/dsh-github-trending",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "GitHub 趋势日报插件:每天定时 spawn 本地 trendradar 核心,抓取 Trending、生成中文简介与总结,提交到你的仓库并自动合并 PR。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",