dsh-mesh-access 1.4.4 → 1.4.6

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 CHANGED
@@ -178,3 +178,11 @@
178
178
 
179
179
  - 「入口登录」三个模式按钮改为分段滑块(segmented toggle):胶囊容器内
180
180
  密钥 / 账号密码 / 关闭 三段,当前模式高亮滑块样式,点其它段即切换。
181
+
182
+ ## 1.4.5 — 滑块加模式说明
183
+
184
+ - 滑块上方加标签「门锁模式(三选一…当前:xx)」,下方加一行三种模式含义说明。
185
+
186
+ ## 1.4.6 — 修复所有复制按钮同时显示「已复制」
187
+
188
+ - copied 状态由布尔改为记录被复制的值,各按钮只在自己的值刚复制时显示「已复制」。
package/lib/client.js CHANGED
@@ -108,7 +108,7 @@ window.__ModuleLoader__.load({
108
108
  const [tunnelBusy, setTunnelBusy] = react.useState(false)
109
109
  const [err, setErr] = react.useState(null)
110
110
  const [tunnelErr, setTunnelErr] = react.useState(null)
111
- const [copied, setCopied] = react.useState(false)
111
+ const [copied, setCopied] = react.useState('')
112
112
  const [formOpen, setFormOpen] = react.useState(false)
113
113
  const [form, setForm] = react.useState({})
114
114
 
@@ -218,8 +218,8 @@ window.__ModuleLoader__.load({
218
218
 
219
219
  const copy = (text) => {
220
220
  const done = () => {
221
- setCopied(true)
222
- setTimeout(() => setCopied(false), 1600)
221
+ setCopied(text)
222
+ setTimeout(() => setCopied(''), 1600)
223
223
  }
224
224
  if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(text).then(done, () => {})
225
225
  else done()
@@ -269,7 +269,7 @@ window.__ModuleLoader__.load({
269
269
  Card, { title: '访问地址' },
270
270
  h('div', { style: S.row },
271
271
  h('code', { style: { ...S.mono, wordBreak: 'break-all' } }, url),
272
- h('button', { style: S.btn, onClick: () => copy(url) }, copied ? '已复制' : '复制'),
272
+ h('button', { style: S.btn, onClick: () => copy(url) }, copied === url ? '已复制' : '复制'),
273
273
  ),
274
274
  h('div', { style: S.hint },
275
275
  '这条地址已经带上本进程的 token,直接点开就能进;它会种下 30 天 cookie,之后裸地址也进得去。',
@@ -346,7 +346,7 @@ window.__ModuleLoader__.load({
346
346
  tn.urlSigned
347
347
  ? h('div', { style: S.row, marginTop: 12 },
348
348
  h('code', { style: { ...S.mono, wordBreak: 'break-all' } }, tn.urlSigned),
349
- h('button', { style: S.btn, onClick: () => copy(tn.urlSigned) }, copied ? '已复制' : '复制'),
349
+ h('button', { style: S.btn, onClick: () => copy(tn.urlSigned) }, copied === tn.urlSigned ? '已复制' : '复制'),
350
350
  )
351
351
  : null,
352
352
  h('div', { style: S.hint },
@@ -402,7 +402,9 @@ window.__ModuleLoader__.load({
402
402
  },
403
403
  onClick: () => { if (!authBusy && !active) setMode(m) },
404
404
  }, label)
405
+ const modeNames = { key: '密钥', basic: '账号密码', off: '已关闭' }
405
406
  return h('div', null,
407
+ h('div', { style: S.hint }, '门锁模式(三选一,点选切换;同一时间只有一种生效,当前:' + (modeNames[a.mode] || a.mode) + '):'),
406
408
  h('div', {
407
409
  style: {
408
410
  display: 'inline-flex', gap: 4, padding: 4, borderRadius: 999,
@@ -412,20 +414,25 @@ window.__ModuleLoader__.load({
412
414
  },
413
415
  modes.map(x => segItem(x.m, x.label, a.mode === x.m)),
414
416
  ),
417
+ h('div', { style: { ...S.hint, marginTop: 6 } },
418
+ '密钥=无弹窗(手机用带密钥的地址认证一次,30 天免登录) · ',
419
+ '账号密码=浏览器弹窗(登录一次 24 小时内仅该设备免登录) · ',
420
+ '关闭=无门锁(任何拿到地址的人都能进,不建议)',
421
+ ),
415
422
  authMsg ? h('div', { style: { ...S.hint, color: '#7ee787', marginTop: 8 } }, authMsg) : null,
416
423
  a.mode === 'key'
417
424
  ? h('div', { style: { marginTop: 10 } },
418
425
  h('div', { style: S.hint }, '密钥(只读,可复制;怀疑泄露就点重置,旧密钥立即作废):'),
419
426
  h('div', { style: S.row, marginTop: 6 },
420
427
  h('input', { style: { ...S.input, ...S.mono, flex: 1 }, readOnly: true, value: a.key || '', onFocus: (e) => e.target.select() }),
421
- h('button', { style: S.btn, onClick: () => copy(a.key) }, copied ? '已复制' : '复制'),
428
+ h('button', { style: S.btn, onClick: () => copy(a.key) }, copied === a.key ? '已复制' : '复制'),
422
429
  h('button', { style: S.btn, disabled: authBusy, onClick: () => { if (window.confirm('重置后旧密钥立刻作废,所有用旧密钥的设备都要重新认证。继续?')) runAuth({ resetKey: true }, '已重置:用新地址重新认证各设备') } }, '重置'),
423
430
  ),
424
431
  firstUrl ? h('div', { style: { marginTop: 8 } },
425
432
  h('div', { style: S.hint }, '手机首次打开(认证一次,30 天内该设备免登录、无弹窗):'),
426
433
  h('div', { style: S.row, marginTop: 6 },
427
434
  h('code', { style: { ...S.mono, wordBreak: 'break-all', flex: 1 } }, firstUrl),
428
- h('button', { style: S.btn, onClick: () => copy(firstUrl) }, copied ? '已复制' : '复制'),
435
+ h('button', { style: S.btn, onClick: () => copy(firstUrl) }, copied === firstUrl ? '已复制' : '复制'),
429
436
  ),
430
437
  ) : null,
431
438
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mesh-access",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
4
4
  "description": "Control your DSH from your phone: opens a port on the mesh/VPN interface from inside the running server process, so a phone browser gets the same instance and the same session list — no SSH, no second dsh. Also reachable from another PC, a GUI NAS, or a TV box.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",