dsh-remote-workspaces 0.1.0 → 0.1.1

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/client.js +139 -40
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-remote-workspaces",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "Open folders on remote hosts over SSH as DeepSeek Harness workspaces — a non-invasive DSH bundle.",
6
6
  "license": "MIT",
package/src/client.js CHANGED
@@ -75,15 +75,81 @@ window.__ModuleLoader__.load({
75
75
  var exports = module.exports
76
76
  var React = require('react')
77
77
 
78
- var sectionStyle = { padding: 16, fontSize: 14, lineHeight: 1.6, maxWidth: 820 }
79
- var labelStyle = { color: 'var(--dsw-alias-label-secondary, #888)', margin: 0, fontSize: 12.5 }
78
+ var sectionStyle = { padding: 16, fontSize: 14, lineHeight: 1.6, maxWidth: 820, color: 'inherit' }
79
+ var labelStyle = { color: '#8b8f98', margin: 0, fontSize: 12.5 }
80
80
  var monoStyle = { fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace', fontSize: 12.5 }
81
- var btnStyle = { padding: '5px 12px', cursor: 'pointer' }
82
- var inputStyle = { padding: '5px 8px', fontSize: 13, width: '100%', boxSizing: 'border-box' }
83
- var dangerColor = 'var(--dsw-alias-danger, #c00)'
84
- var successColor = 'var(--dsw-alias-success, #0a0)'
85
- var borderColor = 'var(--dsw-alias-border, #333)'
86
- var chipStyle = { display: 'inline-block', padding: '1px 8px', borderRadius: 10, background: 'rgba(127,127,127,0.18)', fontSize: 11.5, lineHeight: '18px' }
81
+ // Control styling mirrors the "网关接入 查询状态" button (plugins/
82
+ // dsh-gateway-agent): neutral translucent surfaces + `color: inherit` so the
83
+ // text follows the host theme in both dark and light themes. The primary
84
+ // button is a fixed brand fill, matching the reference's S.primary.
85
+ var btnStyle = {
86
+ padding: '7px 14px', fontSize: 13.5, cursor: 'pointer',
87
+ background: 'rgba(127,127,127,0.12)', color: 'inherit',
88
+ border: '1px solid rgba(127,127,127,0.3)', borderRadius: 6, whiteSpace: 'nowrap',
89
+ }
90
+ var mobileBtnStyle = {
91
+ padding: '11px 14px', fontSize: 14, cursor: 'pointer',
92
+ background: 'rgba(127,127,127,0.12)', color: 'inherit',
93
+ border: '1px solid rgba(127,127,127,0.3)', borderRadius: 6, minHeight: 44, whiteSpace: 'nowrap',
94
+ }
95
+ var btnPrim = {
96
+ padding: '7px 14px', fontSize: 13.5, cursor: 'pointer',
97
+ background: '#6e56cf', color: '#fff', border: '1px solid transparent',
98
+ borderRadius: 6, fontWeight: 600, whiteSpace: 'nowrap',
99
+ }
100
+ var btnPrimMob = {
101
+ padding: '11px 14px', fontSize: 14, cursor: 'pointer',
102
+ background: '#6e56cf', color: '#fff', border: '1px solid transparent',
103
+ borderRadius: 6, fontWeight: 600, minHeight: 44, whiteSpace: 'nowrap',
104
+ }
105
+ var btnDanger = {
106
+ padding: '7px 14px', fontSize: 13.5, cursor: 'pointer',
107
+ background: '#e5484d', color: '#fff', border: '1px solid transparent',
108
+ borderRadius: 6, fontWeight: 600, whiteSpace: 'nowrap',
109
+ }
110
+ var btnDangerMob = {
111
+ padding: '11px 14px', fontSize: 14, cursor: 'pointer',
112
+ background: '#e5484d', color: '#fff', border: '1px solid transparent',
113
+ borderRadius: 6, fontWeight: 600, minHeight: 44, whiteSpace: 'nowrap',
114
+ }
115
+ var inputStyle = {
116
+ padding: '7px 10px', fontSize: 13.5, width: '100%', boxSizing: 'border-box',
117
+ background: 'rgba(127,127,127,0.08)', color: 'inherit',
118
+ border: '1px solid rgba(127,127,127,0.3)', borderRadius: 6,
119
+ }
120
+ var mobileInputStyle = {
121
+ padding: '9px 12px', fontSize: 16, width: '100%', boxSizing: 'border-box', minHeight: 44,
122
+ background: 'rgba(127,127,127,0.08)', color: 'inherit',
123
+ border: '1px solid rgba(127,127,127,0.3)', borderRadius: 6,
124
+ }
125
+ var mobileSectionStyle = { padding: 12, fontSize: 14, lineHeight: 1.6, color: 'inherit' }
126
+ var dangerColor = '#e5484d'
127
+ var successColor = '#46a758'
128
+ var borderColor = 'rgba(127,127,127,0.3)'
129
+ var modalBg = '#1f1f21'
130
+ var modalText = '#e8e8e8'
131
+ var chipStyle = { display: 'inline-block', padding: '1px 8px', borderRadius: 10, background: 'rgba(127,127,127,0.18)', fontSize: 11.5, lineHeight: '18px', color: 'inherit' }
132
+
133
+ // Detect a narrow (mobile) viewport so the UI can switch to a stacked,
134
+ // larger-touch-target layout. Pure clickable hooks; no CSS build step.
135
+ function useIsMobile() {
136
+ var state = React.useState(false)
137
+ var matches = state[0]
138
+ var setMatches = state[1]
139
+ React.useEffect(function () {
140
+ if (typeof window === 'undefined' || !window.matchMedia) return
141
+ var mq = window.matchMedia('(max-width: 640px)')
142
+ function onChange(e) { setMatches(e.matches) }
143
+ setMatches(mq.matches)
144
+ if (mq.addEventListener) mq.addEventListener('change', onChange)
145
+ else if (mq.addListener) mq.addListener(onChange)
146
+ return function () {
147
+ if (mq.removeEventListener) mq.removeEventListener('change', onChange)
148
+ else if (mq.removeListener) mq.removeListener(onChange)
149
+ }
150
+ }, [])
151
+ return matches
152
+ }
87
153
 
88
154
  function pathBasename(p) {
89
155
  if (!p) return ''
@@ -135,6 +201,7 @@ window.__ModuleLoader__.load({
135
201
  var deletingState = React.useState(false)
136
202
  var deleting = deletingState[0]
137
203
  var setDeleting = deletingState[1]
204
+ var isMobile = useIsMobile()
138
205
 
139
206
  React.useEffect(function () {
140
207
  var alive = true
@@ -285,7 +352,7 @@ window.__ModuleLoader__.load({
285
352
 
286
353
  return React.createElement(
287
354
  'div',
288
- { style: sectionStyle },
355
+ { className: 'dsh-rw-btn', style: isMobile ? mobileSectionStyle : sectionStyle },
289
356
  React.createElement('div', { style: { fontWeight: 600, fontSize: 16, marginBottom: 8 } }, '远程工作区'),
290
357
  React.createElement('p', { style: { margin: '0 0 12px' } },
291
358
  '管理 SSH 主机与已打开的远程工作区。添加远程工作区请在侧边栏「添加工作区」里选「远程目录」。'),
@@ -295,9 +362,9 @@ window.__ModuleLoader__.load({
295
362
  error !== null
296
363
  ? React.createElement('p', { style: { color: dangerColor, margin: '0 0 12px' } }, error)
297
364
  : null,
298
- React.createElement('div', { style: { display: 'flex', gap: 8, marginBottom: 12 } },
299
- React.createElement('button', { type: 'button', onClick: openNew, disabled: !remote, style: btnStyle }, '添加主机'),
300
- React.createElement('button', { type: 'button', onClick: toggleAliases, disabled: !remote, style: btnStyle }, '从 ~/.ssh/config 导入'),
365
+ React.createElement('div', { style: Object.assign({ display: 'flex', gap: 8, marginBottom: 12, flexWrap: 'wrap' }, isMobile ? { flexDirection: 'column' } : {}) },
366
+ React.createElement('button', { type: 'button', onClick: openNew, disabled: !remote, style: Object.assign({}, btnPrim, isMobile ? btnPrimMob : {}) }, '添加主机'),
367
+ React.createElement('button', { type: 'button', onClick: toggleAliases, disabled: !remote, style: Object.assign({}, btnStyle, isMobile ? mobileBtnStyle : {}) }, '从 ~/.ssh/config 导入'),
301
368
  ),
302
369
  showAliases
303
370
  ? React.createElement('div', { style: { border: '1px solid ' + borderColor, borderRadius: 6, padding: 10, marginBottom: 12 } },
@@ -334,18 +401,19 @@ window.__ModuleLoader__.load({
334
401
  function () { doTest(machine) },
335
402
  function () { openEdit(machine) },
336
403
  function () { doDelete(machine) },
404
+ isMobile,
337
405
  )
338
406
  }),
339
407
  ),
340
408
  deleteTarget !== null
341
- ? React.createElement('div', { style: { position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.45)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 10000 } },
342
- React.createElement('div', { style: { background: 'var(--dsw-alias-bg, #1c1c1c)', border: '1px solid ' + borderColor, borderRadius: 8, padding: 16, width: 440, maxWidth: '90vw', color: 'var(--dsw-alias-text, #ddd)' } },
409
+ ? React.createElement('div', { style: { position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.45)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 10000, padding: 16 } },
410
+ React.createElement('div', { style: { background: modalBg, border: '1px solid ' + borderColor, borderRadius: 8, padding: isMobile ? 14 : 16, width: 440, maxWidth: '100%', color: modalText } },
343
411
  React.createElement('div', { style: { fontWeight: 600, fontSize: 15, marginBottom: 10 } }, '删除主机'),
344
412
  React.createElement('p', { style: { margin: '0 0 12px', lineHeight: 1.6 } },
345
413
  '确定删除主机「' + (deleteTarget.alias || deleteTarget.host) + '」吗?(远端数据不受影响)'),
346
- React.createElement('div', { style: { display: 'flex', gap: 8, justifyContent: 'flex-end' } },
347
- React.createElement('button', { type: 'button', onClick: closeDelete, disabled: deleting, style: btnStyle }, '取消'),
348
- React.createElement('button', { type: 'button', onClick: confirmDelete, disabled: deleting, style: Object.assign({}, btnStyle, { background: dangerColor, color: '#fff', borderColor: dangerColor }) }, deleting ? '删除中…' : '删除'),
414
+ React.createElement('div', { style: Object.assign({ display: 'flex', gap: 8, justifyContent: 'flex-end' }, isMobile ? { flexDirection: 'column' } : {}) },
415
+ React.createElement('button', { type: 'button', onClick: closeDelete, disabled: deleting, style: Object.assign({}, btnStyle, isMobile ? mobileBtnStyle : {}) }, '取消'),
416
+ React.createElement('button', { type: 'button', onClick: confirmDelete, disabled: deleting, style: isMobile ? btnDangerMob : btnDanger }, deleting ? '删除中…' : '删除'),
349
417
  ),
350
418
  ),
351
419
  )
@@ -353,22 +421,33 @@ window.__ModuleLoader__.load({
353
421
  )
354
422
  }
355
423
 
356
- function MachineRow(machine, result, open, onToggle, onTest, onEdit, onDelete) {
424
+ function MachineRow(machine, result, open, onToggle, onTest, onEdit, onDelete, isMobile) {
357
425
  var summary = [machine.alias || '(未命名)']
358
426
  if (machine.host) summary.push(machine.host)
359
427
  if (machine.user) summary.push('@' + machine.user)
360
428
  if (machine.port) summary.push(':' + machine.port)
429
+ var mobileBtn = isMobile ? Object.assign({}, mobileBtnStyle) : btnStyle
430
+ var dangerBtn = isMobile ? btnDangerMob : btnDanger
431
+ function action(label, handler, style) {
432
+ return React.createElement('button', { type: 'button', onClick: function (e) { e.stopPropagation(); handler() }, style: style }, label)
433
+ }
434
+ var testBtn = action('测试连接', onTest, mobileBtn)
435
+ var editBtn = action('编辑', onEdit, mobileBtn)
436
+ var deleteBtn = action('删除', onDelete, dangerBtn)
361
437
  return React.createElement(
362
438
  'div',
363
439
  { style: { borderTop: '1px solid ' + borderColor, padding: '8px 0' } },
364
440
  React.createElement('div', { onClick: onToggle, style: { display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' } },
365
- React.createElement('span', { style: { color: 'var(--dsw-alias-label-secondary, #888)', width: 16, flexShrink: 0 } }, open ? '▾' : '▸'),
441
+ React.createElement('span', { style: { color: '#8b8f98', width: 16, flexShrink: 0 } }, open ? '▾' : '▸'),
366
442
  React.createElement('span', { style: Object.assign({}, monoStyle, { fontWeight: 600, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }) }, summary.join(' ')),
367
443
  React.createElement('span', { style: { flex: 1 } }),
368
- React.createElement('button', { type: 'button', onClick: function (e) { e.stopPropagation(); onTest() }, style: btnStyle }, '测试连接'),
369
- React.createElement('button', { type: 'button', onClick: function (e) { e.stopPropagation(); onEdit() }, style: btnStyle }, '编辑'),
370
- React.createElement('button', { type: 'button', onClick: function (e) { e.stopPropagation(); onDelete() }, style: btnStyle }, '删除'),
444
+ isMobile ? null : testBtn,
445
+ isMobile ? null : editBtn,
446
+ isMobile ? null : deleteBtn,
371
447
  ),
448
+ isMobile
449
+ ? React.createElement('div', { style: { display: 'flex', gap: 8, marginTop: 6, paddingLeft: 24, flexWrap: 'wrap' } }, testBtn, editBtn, deleteBtn)
450
+ : null,
372
451
  React.createElement('div', { style: { display: 'flex', gap: 6, marginTop: 4, flexWrap: 'wrap', paddingLeft: 24 } },
373
452
  machine.identityFile
374
453
  ? React.createElement('span', { title: '私钥:' + machine.identityFile, style: chipStyle }, '私钥 ' + pathBasename(machine.identityFile))
@@ -403,6 +482,7 @@ window.__ModuleLoader__.load({
403
482
  })
404
483
  var values = valuesState[0]
405
484
  var setValues = valuesState[1]
485
+ var isMobile = useIsMobile()
406
486
 
407
487
  function set(field) {
408
488
  return function (e) {
@@ -420,13 +500,15 @@ window.__ModuleLoader__.load({
420
500
  function field(label, name, type, placeholder) {
421
501
  return React.createElement('div', { style: { marginBottom: 8 } },
422
502
  React.createElement('div', { style: labelStyle }, label),
423
- React.createElement('input', { type: type || 'text', value: values[name], onChange: set(name), placeholder: placeholder || '', style: inputStyle }),
503
+ React.createElement('input', { type: type || 'text', value: values[name], onChange: set(name), placeholder: placeholder || '', style: isMobile ? mobileInputStyle : inputStyle }),
424
504
  )
425
505
  }
426
506
 
507
+ var formBtn = isMobile ? mobileBtnStyle : btnStyle
508
+ var formBtnPrim = isMobile ? btnPrimMob : btnPrim
427
509
  return React.createElement(
428
510
  'form',
429
- { onSubmit: submit, style: { border: '1px solid ' + borderColor, borderRadius: 6, padding: 12, marginBottom: 12 } },
511
+ { onSubmit: submit, style: { border: '1px solid ' + borderColor, borderRadius: 6, padding: isMobile ? 10 : 12, marginBottom: 12 } },
430
512
  React.createElement('div', { style: { fontWeight: 600, marginBottom: 8 } }, props.form.isNew ? '添加主机' : '编辑主机'),
431
513
  field('别名(alias)', 'alias', 'text', '如 dev'),
432
514
  field('主机地址(host)', 'host', 'text', '如 192.168.1.10 或 example.com'),
@@ -435,9 +517,9 @@ window.__ModuleLoader__.load({
435
517
  field('私钥路径(identityFile)', 'identityFile', 'text', '如 ~/.ssh/id_rsa,留空用默认密钥'),
436
518
  field('密码(password)', 'password', 'password', props.form.isNew ? '可选' : '留空保持不变,输入则替换'),
437
519
  field('私钥口令(passphrase)', 'passphrase', 'password', props.form.isNew ? '可选' : '留空保持不变'),
438
- React.createElement('div', { style: { display: 'flex', gap: 8, marginTop: 4 } },
439
- React.createElement('button', { type: 'submit', style: btnStyle }, '保存'),
440
- React.createElement('button', { type: 'button', onClick: props.onCancel, style: btnStyle }, '取消'),
520
+ React.createElement('div', { style: Object.assign({ display: 'flex', gap: 8, marginTop: 4 }, isMobile ? { flexDirection: 'column' } : {}) },
521
+ React.createElement('button', { type: 'submit', style: formBtnPrim }, '保存'),
522
+ React.createElement('button', { type: 'button', onClick: props.onCancel, style: formBtn }, '取消'),
441
523
  ),
442
524
  )
443
525
  }
@@ -477,7 +559,7 @@ window.__ModuleLoader__.load({
477
559
  background: hover ? 'rgba(127,127,127,0.16)' : 'transparent',
478
560
  fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',
479
561
  fontSize: 13,
480
- color: entry.dir ? 'var(--dsw-alias-text, #ddd)' : 'var(--dsw-alias-label-secondary, #888)',
562
+ color: entry.dir ? 'inherit' : 'rgba(232,232,232,0.55)',
481
563
  }
482
564
  return React.createElement(
483
565
  'div',
@@ -490,7 +572,7 @@ window.__ModuleLoader__.load({
490
572
  },
491
573
  React.createElement('span', { style: { width: 18, textAlign: 'center', flexShrink: 0 } }, entry.dir ? '📁' : '📄'),
492
574
  React.createElement('span', { style: { flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, entry.name),
493
- entry.dir ? React.createElement('span', { style: { color: 'var(--dsw-alias-label-secondary, #888)', flexShrink: 0 } }, '/') : null,
575
+ entry.dir ? React.createElement('span', { style: { color: '#8b8f98', flexShrink: 0 } }, '/') : null,
494
576
  )
495
577
  }
496
578
 
@@ -527,6 +609,7 @@ window.__ModuleLoader__.load({
527
609
  var pathInputState = React.useState('')
528
610
  var pathInput = pathInputState[0]
529
611
  var setPathInput = pathInputState[1]
612
+ var isMobile = useIsMobile()
530
613
 
531
614
  // Reset per open edge, then load machines.
532
615
  React.useEffect(function () {
@@ -636,20 +719,20 @@ window.__ModuleLoader__.load({
636
719
  { style: { position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.45)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 10000 } },
637
720
  React.createElement(
638
721
  'div',
639
- { style: { background: 'var(--dsw-alias-bg, #1c1c1c)', border: '1px solid ' + borderColor, borderRadius: 8, padding: 16, width: 560, maxWidth: '92vw', maxHeight: '82vh', overflow: 'auto', color: 'var(--dsw-alias-text, #ddd)' } },
722
+ { className: 'dsh-rw-btn', style: { background: modalBg, border: '1px solid ' + borderColor, borderRadius: 8, padding: isMobile ? 14 : 16, width: 560, maxWidth: '92vw', maxHeight: '82vh', overflow: 'auto', color: modalText } },
640
723
  React.createElement('div', { style: { display: 'flex', alignItems: 'center', marginBottom: 12 } },
641
724
  React.createElement('span', { style: { fontWeight: 600, fontSize: 15 } }, '打开文件夹'),
642
725
  React.createElement('span', { style: { flex: 1 } }),
643
- React.createElement('button', { type: 'button', onClick: onCancel, style: btnStyle }, '取消'),
726
+ React.createElement('button', { type: 'button', onClick: onCancel, style: isMobile ? mobileBtnStyle : btnStyle }, '取消'),
644
727
  ),
645
728
  React.createElement('div', { style: { display: 'flex', gap: 8, marginBottom: 12 } },
646
- React.createElement('button', { type: 'button', onClick: function () { setMode('local') }, style: Object.assign({}, btnStyle, mode === 'local' ? { border: '2px solid ' + successColor } : {}) }, '本地文件夹'),
647
- React.createElement('button', { type: 'button', onClick: function () { setMode('remote') }, style: Object.assign({}, btnStyle, mode === 'remote' ? { border: '2px solid ' + successColor } : {}) }, '远程目录'),
729
+ React.createElement('button', { type: 'button', onClick: function () { setMode('local') }, style: Object.assign({}, btnStyle, isMobile ? { flex: 1 } : {}, isMobile ? mobileBtnStyle : {}, mode === 'local' ? { background: '#6e56cf', color: '#fff', border: '1px solid transparent' } : {}) }, '本地文件夹'),
730
+ React.createElement('button', { type: 'button', onClick: function () { setMode('remote') }, style: Object.assign({}, btnStyle, isMobile ? { flex: 1 } : {}, isMobile ? mobileBtnStyle : {}, mode === 'remote' ? { background: '#6e56cf', color: '#fff', border: '1px solid transparent' } : {}) }, '远程目录'),
648
731
  ),
649
732
  mode === 'local'
650
733
  ? React.createElement('div', {},
651
734
  React.createElement('p', { style: { margin: '0 0 12px' } }, '在本机打开系统文件夹选择器,选取一个本地目录作为工作区。'),
652
- React.createElement('button', { type: 'button', onClick: doLocal, disabled: localPicking || busy, style: btnStyle }, localPicking ? '等待选择…' : '选择本地文件夹'),
735
+ React.createElement('button', { type: 'button', onClick: doLocal, disabled: localPicking || busy, style: Object.assign({}, btnStyle, isMobile ? { width: '100%' } : {}, isMobile ? mobileBtnStyle : {}) }, localPicking ? '等待选择…' : '选择本地文件夹'),
653
736
  )
654
737
  : React.createElement('div', {},
655
738
  React.createElement('div', { style: { marginBottom: 8 } }, '选择 SSH 主机(在「设置 → 远程工作区」中配置):'),
@@ -662,7 +745,7 @@ window.__ModuleLoader__.load({
662
745
  var m = machines.find(function (x) { return x.id === id })
663
746
  if (m) pickMachine(m)
664
747
  },
665
- style: Object.assign({}, inputStyle, { marginBottom: 8 }),
748
+ style: Object.assign({}, isMobile ? mobileInputStyle : inputStyle, { marginBottom: 8 }),
666
749
  },
667
750
  React.createElement('option', { value: '' }, '选择主机…'),
668
751
  machines.map(function (m) {
@@ -671,7 +754,7 @@ window.__ModuleLoader__.load({
671
754
  ),
672
755
  selected
673
756
  ? React.createElement('div', { style: { border: '1px solid ' + borderColor, borderRadius: 6, padding: 10 } },
674
- React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 } },
757
+ React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8, flexWrap: 'wrap' } },
675
758
  React.createElement('input', {
676
759
  type: 'text',
677
760
  value: pathInput,
@@ -679,10 +762,12 @@ window.__ModuleLoader__.load({
679
762
  onKeyDown: function (e) { if (e.key === 'Enter') jumpTo() },
680
763
  placeholder: '输入绝对路径,或 ~ 回到主目录',
681
764
  spellCheck: false,
682
- style: Object.assign({}, monoStyle, { flex: 1, minWidth: 0, padding: '5px 8px', fontSize: 13, boxSizing: 'border-box' }),
765
+ style: Object.assign({}, monoStyle, isMobile
766
+ ? { flex: '1 1 100%', minWidth: 0, padding: '9px 8px', fontSize: 16, boxSizing: 'border-box' }
767
+ : { flex: 1, minWidth: 0, padding: '5px 8px', fontSize: 13, boxSizing: 'border-box' }),
683
768
  }),
684
- React.createElement('button', { type: 'button', onClick: jumpTo, disabled: !browse || browse.loading, style: btnStyle }, '跳转'),
685
- React.createElement('button', { type: 'button', onClick: goUp, disabled: !browse || browse.loading || !browse.path || browse.path === '/', style: btnStyle }, '上一级'),
769
+ React.createElement('button', { type: 'button', onClick: jumpTo, disabled: !browse || browse.loading, style: Object.assign({}, btnStyle, isMobile ? { flex: 1 } : {}, isMobile ? mobileBtnStyle : {}) }, '跳转'),
770
+ React.createElement('button', { type: 'button', onClick: goUp, disabled: !browse || browse.loading || !browse.path || browse.path === '/', style: Object.assign({}, btnStyle, isMobile ? { flex: 1 } : {}, isMobile ? mobileBtnStyle : {}) }, '上一级'),
686
771
  ),
687
772
  browse && browse.loading
688
773
  ? React.createElement('div', { style: labelStyle }, '加载中…')
@@ -701,7 +786,7 @@ window.__ModuleLoader__.load({
701
786
  )
702
787
  : null,
703
788
  React.createElement('div', { style: { marginTop: 10 } },
704
- React.createElement('button', { type: 'button', onClick: doOpenRemote, disabled: opening || busy || (browse && browse.loading), style: btnStyle },
789
+ React.createElement('button', { type: 'button', onClick: doOpenRemote, disabled: opening || busy || (browse && browse.loading), style: Object.assign({}, btnPrim, isMobile ? { width: '100%' } : {}, isMobile ? btnPrimMob : {}) },
705
790
  opening ? '打开中…' : '打开此目录'),
706
791
  ),
707
792
  )
@@ -714,6 +799,20 @@ window.__ModuleLoader__.load({
714
799
  exports.inject = ['slots', 'remote', 'uiWorkspace']
715
800
 
716
801
  exports.apply = function apply(ctx) {
802
+ // Inject a small set of theme-aware control styles (hover / focus /
803
+ // disabled). Backgrounds are deliberately left to the theme so buttons
804
+ // adapt to dark and light instead of forcing a hard-coded box.
805
+ if (typeof document !== 'undefined' && document.head && !document.getElementById('dsh-rw-controls')) {
806
+ var styleEl = document.createElement('style')
807
+ styleEl.id = 'dsh-rw-controls'
808
+ styleEl.textContent = [
809
+ '.dsh-rw-btn button:disabled{opacity:.5;cursor:not-allowed}',
810
+ '.dsh-rw-btn button:focus-visible{outline:2px solid #6e56cf;outline-offset:2px}',
811
+ '.dsh-rw-btn input:focus,.dsh-rw-btn select:focus{box-shadow:0 0 0 1px #6e56cf}',
812
+ ].join('\n')
813
+ document.head.appendChild(styleEl)
814
+ }
815
+
717
816
  var mount = ctx.remote.$mount({ package: PACKAGE, descriptors: INVOCATIONS })
718
817
  var getRemote = function () { return ctx.get('remote.' + NAMESPACE) }
719
818