dsh-plugin 1.1.2 → 1.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.
Files changed (110) hide show
  1. package/client/client.js +4469 -1445
  2. package/client/client.js.map +1 -1
  3. package/lib/http/routes.js +438 -22
  4. package/lib/index.js +1 -1
  5. package/lib/services/install/install.js +4 -0
  6. package/lib/services/install/npm-check.js +55 -0
  7. package/lib/services/{npm-resolve.js → install/npm-resolve.js} +7 -5
  8. package/lib/services/{preflight.js → install/preflight.js} +15 -4
  9. package/lib/services/{task-queue.js → install/task-queue.js} +155 -66
  10. package/lib/services/loader.js +56 -1
  11. package/lib/services/log.js +138 -0
  12. package/lib/services/probe.js +157 -0
  13. package/lib/services/{profile.js → profile/profile.js} +29 -1
  14. package/lib/services/settings.js +60 -0
  15. package/lib/types/http/routes.d.ts +1 -1
  16. package/lib/types/index.d.ts +1 -1
  17. package/lib/types/services/{install-types.d.ts → install/install-types.d.ts} +3 -0
  18. package/lib/types/services/{install.d.ts → install/install.d.ts} +5 -5
  19. package/lib/types/services/install/npm-check.d.ts +12 -0
  20. package/lib/types/services/{npm-resolve.d.ts → install/npm-resolve.d.ts} +2 -1
  21. package/lib/types/services/{task-queue.d.ts → install/task-queue.d.ts} +5 -1
  22. package/lib/types/services/loader.d.ts +14 -8
  23. package/lib/types/services/log.d.ts +49 -0
  24. package/lib/types/services/probe.d.ts +30 -0
  25. package/lib/types/services/{pending-restart.d.ts → profile/pending-restart.d.ts} +1 -1
  26. package/lib/types/services/{profile.d.ts → profile/profile.d.ts} +2 -0
  27. package/lib/types/services/settings.d.ts +24 -0
  28. package/package.json +1 -1
  29. package/src/client/components/PluginHubSection.tsx +341 -120
  30. package/src/client/components/{CatalogList.tsx → catalog/CatalogList.tsx} +11 -7
  31. package/src/client/components/{PluginCard.tsx → catalog/PluginCard.tsx} +5 -4
  32. package/src/client/components/layout/CatalogControls.tsx +80 -0
  33. package/src/client/components/{CatalogHeader.tsx → layout/CatalogHeader.tsx} +4 -4
  34. package/src/client/components/{CategoryTabs.tsx → layout/CategoryTabs.tsx} +3 -3
  35. package/src/client/components/layout/SectionTabs.tsx +60 -0
  36. package/src/client/components/{AboutModal.tsx → modals/AboutModal.tsx} +7 -7
  37. package/src/client/components/{HubUpdateModal.tsx → modals/HubUpdateModal.tsx} +5 -5
  38. package/src/client/components/modals/InstalledDetailModal.tsx +193 -0
  39. package/src/client/components/modals/LogsModal.tsx +301 -0
  40. package/src/client/components/modals/LogsPathModal.tsx +161 -0
  41. package/src/client/components/{NotificationsModal.tsx → modals/NotificationsModal.tsx} +47 -20
  42. package/src/client/components/{ProgressView.tsx → modals/ProgressView.tsx} +2 -2
  43. package/src/client/components/{modals.tsx → modals/modals.tsx} +117 -40
  44. package/src/client/components/{Dropdown.tsx → ui/Dropdown.tsx} +14 -6
  45. package/src/client/components/ui/Toggle.tsx +28 -0
  46. package/src/client/components/ui/icons.tsx +343 -0
  47. package/src/client/components/views/CustomInstallView.tsx +250 -0
  48. package/src/client/components/views/DiagnosticsView.tsx +172 -0
  49. package/src/client/components/views/InstalledView.tsx +328 -0
  50. package/src/client/components/views/LogsView.tsx +150 -0
  51. package/src/client/components/views/MarketView.tsx +66 -0
  52. package/src/client/components/views/SettingsView.tsx +273 -0
  53. package/src/client/data/catalog.ts +38 -0
  54. package/src/client/data/host.ts +107 -0
  55. package/src/client/data/hub.ts +41 -0
  56. package/src/client/hooks/useCatalog.ts +71 -115
  57. package/src/client/hooks/useIncrementalList.ts +46 -0
  58. package/src/client/hooks/useLanguage.ts +40 -0
  59. package/src/client/hooks/useSettings.ts +90 -0
  60. package/src/client/hooks/useTaskQueue.ts +156 -39
  61. package/src/client/locales.ts +358 -38
  62. package/src/client/logic/constants.ts +87 -0
  63. package/src/client/{lib → logic}/failures.ts +95 -74
  64. package/src/client/logic/install-command.ts +56 -0
  65. package/src/client/logic/installed.ts +207 -0
  66. package/src/client/logic/normalize.ts +52 -0
  67. package/src/client/logic/urls.ts +125 -0
  68. package/src/client/styles/CustomInstallView.module.css +191 -0
  69. package/src/client/styles/DiagnosticsView.module.css +231 -0
  70. package/src/client/styles/Dropdown.module.css +42 -41
  71. package/src/client/styles/Header.module.css +100 -132
  72. package/src/client/styles/InstalledView.module.css +447 -0
  73. package/src/client/styles/List.module.css +6 -0
  74. package/src/client/styles/LogsView.module.css +503 -0
  75. package/src/client/styles/Modal.module.css +352 -70
  76. package/src/client/styles/SectionTabs.module.css +142 -0
  77. package/src/client/styles/SettingsView.module.css +232 -0
  78. package/src/client/styles/Toggle.module.css +60 -0
  79. package/src/client/styles/tokens.module.css +1 -0
  80. package/src/client/types.ts +23 -3
  81. package/src/server/http/routes.ts +414 -22
  82. package/src/server/index.ts +1 -1
  83. package/src/server/services/{install-types.ts → install/install-types.ts} +3 -1
  84. package/src/server/services/{install.ts → install/install.ts} +5 -5
  85. package/src/server/services/install/npm-check.ts +53 -0
  86. package/src/server/services/{npm-resolve.ts → install/npm-resolve.ts} +7 -5
  87. package/src/server/services/{preflight.ts → install/preflight.ts} +16 -4
  88. package/src/server/services/{task-queue.ts → install/task-queue.ts} +157 -63
  89. package/src/server/services/loader.ts +55 -1
  90. package/src/server/services/log.ts +167 -0
  91. package/src/server/services/probe.ts +157 -0
  92. package/src/server/services/{pending-restart.ts → profile/pending-restart.ts} +1 -1
  93. package/src/server/services/{profile.ts → profile/profile.ts} +31 -1
  94. package/src/server/services/settings.ts +79 -0
  95. package/lib/services/install.js +0 -4
  96. package/src/client/components/CatalogControls.tsx +0 -108
  97. package/src/client/components/icons.tsx +0 -129
  98. package/src/client/lib/catalog.ts +0 -293
  99. package/src/client/lib/env.ts +0 -20
  100. /package/lib/services/{install-types.js → install/install-types.js} +0 -0
  101. /package/lib/services/{installed-versions.js → profile/installed-versions.js} +0 -0
  102. /package/lib/services/{pending-restart.js → profile/pending-restart.js} +0 -0
  103. /package/lib/services/{progress.js → profile/progress.js} +0 -0
  104. /package/lib/types/services/{preflight.d.ts → install/preflight.d.ts} +0 -0
  105. /package/lib/types/services/{installed-versions.d.ts → profile/installed-versions.d.ts} +0 -0
  106. /package/lib/types/services/{progress.d.ts → profile/progress.d.ts} +0 -0
  107. /package/src/client/{lib → logic}/format.ts +0 -0
  108. /package/src/client/{lib → logic}/renderMarkdown.ts +0 -0
  109. /package/src/server/services/{installed-versions.ts → profile/installed-versions.ts} +0 -0
  110. /package/src/server/services/{progress.ts → profile/progress.ts} +0 -0
@@ -23,6 +23,12 @@
23
23
  padding: 2px 4px 4px 2px;
24
24
  }
25
25
 
26
+ /* 滚动加载哨兵:透明 1px 元素,进入视口即触发下一批渲染(无可见外观,不占排版空间) */
27
+ .moreSentinel {
28
+ flex-shrink: 0;
29
+ height: 1px;
30
+ }
31
+
26
32
  .card {
27
33
  display: flex;
28
34
  align-items: stretch;
@@ -0,0 +1,503 @@
1
+ /* DSH-Plugin Hub — the community plugin marketplace for DeepSeek Harness.
2
+ * Website: https://dsh-plugin.org
3
+ * GitHub: https://github.com/dshplugin/dsh-plugin-hub
4
+ *
5
+ * System logs: one row per entry — time, level badge (OK green / FAIL red /
6
+ * WARN amber / INFO grey), event code and the message. Header holds the
7
+ * refresh / copy-all / export (.log download) actions. */
8
+
9
+ .panel {
10
+ display: flex;
11
+ flex-direction: column;
12
+ min-width: 0;
13
+ }
14
+
15
+ /* 头部:说明文字独占一行,操作按钮组独立一行靠左(打开查看器 / 导出日志 / 刷新日志) */
16
+ .head {
17
+ display: flex;
18
+ flex-direction: column;
19
+ align-items: stretch;
20
+ gap: 6px;
21
+ padding: 8px 12px;
22
+ border-bottom: 1px solid var(--hub-border-1);
23
+ }
24
+
25
+ .headHint {
26
+ min-width: 0;
27
+ font-size: 11px;
28
+ line-height: 16px;
29
+ color: var(--hub-text-tertiary);
30
+ }
31
+
32
+ .actions {
33
+ flex: none;
34
+ display: flex;
35
+ align-items: center;
36
+ justify-content: flex-start;
37
+ gap: 6px;
38
+ }
39
+
40
+ .btn {
41
+ flex: none;
42
+ height: 24px;
43
+ padding: 0 10px;
44
+ font-size: 11.5px;
45
+ font-weight: 500;
46
+ color: var(--hub-text-secondary);
47
+ background: var(--hub-bg-hover);
48
+ border: 1px solid var(--hub-border-2);
49
+ border-radius: 6px;
50
+ cursor: pointer;
51
+ user-select: none;
52
+ transition: color 0.12s ease, background-color 0.12s ease, border-color 0.12s ease;
53
+ }
54
+
55
+ .btn:hover:not(:disabled) {
56
+ color: var(--hub-text-primary);
57
+ background: var(--hub-bg-2);
58
+ }
59
+
60
+ .btn:disabled {
61
+ opacity: 0.55;
62
+ cursor: default;
63
+ }
64
+
65
+ /* 主操作:导出日志,品牌色实底 */
66
+ .btnPrimary {
67
+ color: #ffffff;
68
+ background: var(--hub-brand);
69
+ border-color: var(--hub-brand);
70
+ }
71
+
72
+ .btnPrimary:hover:not(:disabled) {
73
+ background: var(--hub-brand-hover);
74
+ border-color: var(--hub-brand-hover);
75
+ }
76
+
77
+ /* 日志列表:一行一条,悬浮高亮;超出限高内部滚动 */
78
+ .list {
79
+ max-height: 340px;
80
+ overflow-y: auto;
81
+ display: flex;
82
+ flex-direction: column;
83
+ }
84
+
85
+ .entry {
86
+ display: flex;
87
+ align-items: baseline;
88
+ gap: 8px;
89
+ padding: 5px 12px;
90
+ min-width: 0;
91
+ font-size: 11px;
92
+ line-height: 16px;
93
+ }
94
+
95
+ .entry:hover {
96
+ background: var(--hub-bg-hover);
97
+ }
98
+
99
+ .time {
100
+ flex: none;
101
+ font-variant-numeric: tabular-nums;
102
+ color: var(--hub-text-tertiary);
103
+ white-space: nowrap;
104
+ }
105
+
106
+ /* 事件码:等宽小字 */
107
+ .event {
108
+ flex: none;
109
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
110
+ font-size: 10.5px;
111
+ color: var(--hub-text-tertiary);
112
+ white-space: nowrap;
113
+ }
114
+
115
+ /* 描述:占满剩余宽度,过长省略(悬浮看全) */
116
+ .message {
117
+ flex: 1;
118
+ min-width: 0;
119
+ color: var(--hub-text-primary);
120
+ white-space: nowrap;
121
+ overflow: hidden;
122
+ text-overflow: ellipsis;
123
+ }
124
+
125
+ /* —— 系统日志入口 —— */
126
+
127
+ /* 日志文件位置行:展示真实存放路径 + 一键在系统文件管理器中打开 */
128
+ .pathRow {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: 8px;
132
+ padding: 6px 12px;
133
+ border-bottom: 1px solid var(--hub-border-1);
134
+ }
135
+
136
+ .pathLabel {
137
+ flex: none;
138
+ font-size: 11px;
139
+ line-height: 16px;
140
+ color: var(--hub-text-tertiary);
141
+ }
142
+
143
+ /* 路径文本:等宽、省略,悬浮看全 —— 默认存放位置合法可用,用户无需改 */
144
+ .pathText {
145
+ flex: 1;
146
+ min-width: 0;
147
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
148
+ font-size: 10.5px;
149
+ line-height: 16px;
150
+ color: var(--hub-text-secondary);
151
+ white-space: nowrap;
152
+ overflow: hidden;
153
+ text-overflow: ellipsis;
154
+ }
155
+
156
+ /* 打开失败 / 打开中出错提示:红色小字,出现即提醒换手动定位 */
157
+ .footFail {
158
+ flex: none;
159
+ font-size: 11px;
160
+ line-height: 16px;
161
+ color: var(--hub-danger-text);
162
+ }
163
+
164
+ /* —— 日志存放位置弹窗 —— */
165
+
166
+ /* 弹窗主体:说明文字 → 输入行(手输 + 选择目录)→ 底部操作 */
167
+ .pathDialog {
168
+ display: flex;
169
+ flex-direction: column;
170
+ gap: 10px;
171
+ }
172
+
173
+ .pathDialogDesc {
174
+ font-size: 11px;
175
+ line-height: 16px;
176
+ color: var(--hub-text-tertiary);
177
+ }
178
+
179
+ /* 输入行:手输路径占满宽度,「选择目录」按钮收在右侧 */
180
+ .pathDialogRow {
181
+ display: flex;
182
+ align-items: center;
183
+ gap: 6px;
184
+ }
185
+
186
+ /* 提示 + 「恢复默认」一行:提示左、动作右 */
187
+ .pathDialogReset {
188
+ display: flex;
189
+ align-items: center;
190
+ justify-content: space-between;
191
+ gap: 8px;
192
+ }
193
+
194
+ .pathDialogHint {
195
+ font-size: 11px;
196
+ line-height: 16px;
197
+ color: var(--hub-text-tertiary);
198
+ }
199
+
200
+ /* 「恢复默认」链接按钮:低调文字、不占空间,hover 下划线提示可点 */
201
+ .linkBtn {
202
+ flex: none;
203
+ padding: 0;
204
+ font-size: 11.5px;
205
+ line-height: 16px;
206
+ font-weight: 500;
207
+ color: var(--hub-brand);
208
+ background: none;
209
+ border: none;
210
+ cursor: pointer;
211
+ }
212
+
213
+ .linkBtn:hover {
214
+ text-decoration: underline;
215
+ }
216
+
217
+ /* 路径输入框:等宽小字、占满宽度(与设置页文本框同构) */
218
+ .pathDraft {
219
+ flex: 1;
220
+ min-width: 0;
221
+ height: 26px;
222
+ padding: 0 9px;
223
+ font-size: 11.5px;
224
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
225
+ color: var(--hub-text-primary);
226
+ background: var(--hub-bg-1);
227
+ border: 1px solid var(--hub-border-input);
228
+ border-radius: 6px;
229
+ outline: none;
230
+ transition: border-color 0.12s ease;
231
+ }
232
+
233
+ .pathDraft:focus {
234
+ border-color: var(--hub-brand-border);
235
+ }
236
+
237
+ .pathDraft::placeholder {
238
+ color: var(--hub-text-disabled);
239
+ }
240
+
241
+ /* 底部操作:取消 / 保存,右对齐 */
242
+ .pathDialogFoot {
243
+ display: flex;
244
+ justify-content: flex-end;
245
+ gap: 6px;
246
+ }
247
+
248
+ /* 预览行:整行可点击打开查看器,内嵌通用日志行(button 重置默认外观) */
249
+ .previewRow {
250
+ display: block;
251
+ width: 100%;
252
+ padding: 0;
253
+ text-align: left;
254
+ background: none;
255
+ border: none;
256
+ cursor: pointer;
257
+ user-select: none;
258
+ }
259
+
260
+ /* —— 系统日志查看器弹窗 —— */
261
+
262
+ /* 筛选栏:类别/级别 chip 横排,可换行 */
263
+ .filterBar {
264
+ display: flex;
265
+ align-items: center;
266
+ flex-wrap: wrap;
267
+ gap: 6px;
268
+ padding: 2px 0 0;
269
+ }
270
+
271
+ /* 筛选 chip:胶囊按钮,选中 = 品牌蓝浅底 */
272
+ .filterChip {
273
+ flex: none;
274
+ height: 22px;
275
+ padding: 0 10px;
276
+ font-size: 11px;
277
+ line-height: 20px;
278
+ color: var(--hub-text-secondary);
279
+ background: transparent;
280
+ border: 1px solid var(--hub-border-2);
281
+ border-radius: 11px;
282
+ cursor: pointer;
283
+ user-select: none;
284
+ transition: color 0.12s ease, background-color 0.12s ease, border-color 0.12s ease;
285
+ }
286
+
287
+ .filterChip:hover {
288
+ color: var(--hub-text-primary);
289
+ background: var(--hub-bg-hover);
290
+ }
291
+
292
+ /* 选中 chip 悬浮时保持品牌蓝语义:hover 规则特异性更高,若不单独覆盖会把
293
+ 蓝色选中态冲成灰色,颜色搭配就乱了 */
294
+ .filterChipActive,
295
+ .filterChipActive:hover {
296
+ color: var(--hub-brand);
297
+ background: var(--hub-brand-tint);
298
+ border-color: var(--hub-brand-border-soft);
299
+ font-weight: 500;
300
+ }
301
+
302
+ .filterChipActive:hover {
303
+ background: var(--hub-brand-tint-strong);
304
+ border-color: var(--hub-brand-border);
305
+ }
306
+
307
+ /* 搜索框:占满筛选行剩余宽度 */
308
+ .search {
309
+ flex: 1;
310
+ min-width: 140px;
311
+ }
312
+
313
+ .searchInput {
314
+ width: 100%;
315
+ height: 24px;
316
+ padding: 0 8px;
317
+ font-size: 11px;
318
+ line-height: 16px;
319
+ color: var(--hub-text-primary);
320
+ background: var(--hub-bg-2);
321
+ border: 1px solid var(--hub-border-2);
322
+ border-radius: 6px;
323
+ outline: none;
324
+ transition: border-color 0.12s ease, background-color 0.12s ease;
325
+ }
326
+
327
+ .searchInput:focus {
328
+ border-color: var(--hub-brand);
329
+ background: var(--hub-bg-1);
330
+ }
331
+
332
+ .searchInput::placeholder {
333
+ color: var(--hub-text-tertiary);
334
+ }
335
+
336
+ /* 日志列表:弹窗主体,独占高度内滚动,头部与底部操作栏始终可见 */
337
+ .logList {
338
+ flex: 1 1 auto;
339
+ min-height: 0;
340
+ overflow-y: auto;
341
+ display: flex;
342
+ flex-direction: column;
343
+ padding: 4px 0 6px;
344
+ }
345
+
346
+ /* 加载更多:居中主按钮,整行可点 */
347
+ .more {
348
+ flex: none;
349
+ align-self: center;
350
+ margin: 10px 0 4px;
351
+ height: 26px;
352
+ padding: 0 18px;
353
+ font-size: 11.5px;
354
+ font-weight: 500;
355
+ color: var(--hub-brand);
356
+ background: var(--hub-brand-tint);
357
+ border: 1px solid var(--hub-brand-border-soft);
358
+ border-radius: 6px;
359
+ cursor: pointer;
360
+ user-select: none;
361
+ transition: color 0.12s ease, background-color 0.12s ease, border-color 0.12s ease;
362
+ }
363
+
364
+ .more:hover:not(:disabled) {
365
+ color: #ffffff;
366
+ background: var(--hub-brand);
367
+ border-color: var(--hub-brand);
368
+ }
369
+
370
+ .more:disabled {
371
+ opacity: 0.55;
372
+ cursor: default;
373
+ }
374
+
375
+ /* 拉完收尾:居中灰字 + 总数 */
376
+ .moreEnd {
377
+ flex: none;
378
+ padding: 12px 0 4px;
379
+ text-align: center;
380
+ font-size: 11px;
381
+ line-height: 16px;
382
+ color: var(--hub-text-tertiary);
383
+ font-variant-numeric: tabular-nums;
384
+ }
385
+
386
+ /* 底部操作栏:路径(左)+ 计数 + 打开/复制/导出(右) */
387
+ .foot {
388
+ display: flex;
389
+ align-items: center;
390
+ gap: 8px;
391
+ padding: 8px 12px;
392
+ border-top: 1px solid var(--hub-border-1);
393
+ }
394
+
395
+ .footPath {
396
+ flex: 1;
397
+ min-width: 0;
398
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
399
+ font-size: 10.5px;
400
+ line-height: 16px;
401
+ color: var(--hub-text-tertiary);
402
+ white-space: nowrap;
403
+ overflow: hidden;
404
+ text-overflow: ellipsis;
405
+ }
406
+
407
+ .footCount {
408
+ flex: none;
409
+ font-size: 11px;
410
+ line-height: 16px;
411
+ color: var(--hub-text-tertiary);
412
+ font-variant-numeric: tabular-nums;
413
+ }
414
+
415
+ .footActions {
416
+ flex: none;
417
+ display: inline-flex;
418
+ align-items: center;
419
+ gap: 6px;
420
+ }
421
+
422
+ /* 级别徽章:与类别徽章同排,颜色区分严重程度 */
423
+ .badge {
424
+ flex: none;
425
+ font-size: 10px;
426
+ font-weight: 600;
427
+ letter-spacing: 0.3px;
428
+ }
429
+
430
+ .badgeSuccess {
431
+ color: var(--hub-success);
432
+ }
433
+
434
+ .badgeError {
435
+ color: var(--hub-danger-text);
436
+ }
437
+
438
+ .badgeWarn {
439
+ color: var(--hub-warning);
440
+ }
441
+
442
+ .badgeInfo {
443
+ color: var(--hub-text-secondary);
444
+ }
445
+
446
+ .badgeDebug {
447
+ color: var(--hub-text-tertiary);
448
+ }
449
+
450
+ /* 类别徽章:小圆角标签,颜色区分功能域 —— 安装/卸载/更新一眼可辨 */
451
+ .catBadge {
452
+ flex: none;
453
+ font-size: 10px;
454
+ line-height: 16px;
455
+ font-weight: 500;
456
+ border-radius: 4px;
457
+ padding: 0 6px;
458
+ border: 1px solid transparent;
459
+ }
460
+
461
+ .catInstall {
462
+ color: var(--hub-brand);
463
+ border-color: var(--hub-brand-border-soft);
464
+ background: var(--hub-brand-tint);
465
+ }
466
+
467
+ .catUninstall {
468
+ color: var(--hub-danger-text);
469
+ border-color: var(--hub-danger-border);
470
+ background: var(--hub-danger-tint);
471
+ }
472
+
473
+ .catUpdate {
474
+ color: var(--hub-warning);
475
+ border-color: var(--hub-warning-border);
476
+ background: var(--hub-warning-tint);
477
+ }
478
+
479
+ .catDiagnostics {
480
+ color: var(--hub-success);
481
+ border-color: var(--hub-success-border);
482
+ background: var(--hub-success-tint);
483
+ }
484
+
485
+ .catSettings {
486
+ color: var(--hub-warn);
487
+ border-color: var(--hub-warn-border);
488
+ background: var(--hub-warn-tint);
489
+ }
490
+
491
+ .catSystem {
492
+ color: var(--hub-text-secondary);
493
+ border-color: var(--hub-border-2);
494
+ background: var(--hub-bg-hover);
495
+ }
496
+
497
+ /* 空态 / 加载 / 失败提示 */
498
+ .empty {
499
+ padding: 28px 12px;
500
+ text-align: center;
501
+ font-size: 11.5px;
502
+ color: var(--hub-text-tertiary);
503
+ }