@dingpenghui/dsh-obsidian-sync 3.4.2
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/README.md +131 -0
- package/cordis.patch.yml +23 -0
- package/lib/client.js +372 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +41 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +810 -0
- package/lib/index.js.map +1 -0
- package/package.json +91 -0
- package/src/client/PluginDetailPage.module.css +81 -0
- package/src/client/css-module.d.ts +9 -0
- package/src/client/index.ts +109 -0
- package/src/client/plugin-detail-controller.ts +137 -0
- package/src/client/plugin-detail-page.tsx +106 -0
- package/src/index.ts +897 -0
- package/src/locales/index.ts +40 -0
- package/src/shared.ts +24 -0
- package/src/slot-contract.d.ts +42 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-obsidian-sync 详情页:点击插件列表中的插件名字后打开的画面。
|
|
3
|
+
* 展示使用前提条件(vault 路径 / 搜索开关 / 索引间隔)并带保存控件。
|
|
4
|
+
*/
|
|
5
|
+
import type * as React from 'react'
|
|
6
|
+
import type { PropsLocale, PropsRuntime, InjectFace, TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'
|
|
7
|
+
import { SettingsForm, Switch } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
8
|
+
import type { ObsidianSyncPageFace } from './plugin-detail-controller.ts'
|
|
9
|
+
import css from './PluginDetailPage.module.css'
|
|
10
|
+
|
|
11
|
+
/** 渲染器为详情页绑定的 props。 */
|
|
12
|
+
export type ObsidianSyncDetailPageProps =
|
|
13
|
+
& PropsRuntime<'plugins.bundle.config'>
|
|
14
|
+
& PropsLocale<'settings.dsh-obsidian-sync'>
|
|
15
|
+
& InjectFace<ObsidianSyncPageFace>
|
|
16
|
+
|
|
17
|
+
/** 从 locale 字典派生 SettingsForm 的标签文案。 */
|
|
18
|
+
function formLabels(t: TranslateNS<'settings.dsh-obsidian-sync'>) {
|
|
19
|
+
return {
|
|
20
|
+
unavailable: t('form.unavailable'),
|
|
21
|
+
readOnly: t('form.readOnly'),
|
|
22
|
+
saveFailed: t('form.saveFailed'),
|
|
23
|
+
save: t('form.save'),
|
|
24
|
+
saving: t('form.saving'),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 渲染详情页:一行摘要(`view: 'summary'`)或前提条件表单(`view: 'page'`)。
|
|
30
|
+
* @param props - 视图、locale 文案、表单快照与动作。
|
|
31
|
+
* @returns 摘要文字,或带保存控件的前提条件表单。
|
|
32
|
+
*/
|
|
33
|
+
export function ObsidianSyncDetailPage(props: ObsidianSyncDetailPageProps) {
|
|
34
|
+
const { t } = props
|
|
35
|
+
const state = props.useObsidianSyncPage((snapshot) => snapshot)
|
|
36
|
+
|
|
37
|
+
if (props.view === 'summary') {
|
|
38
|
+
return t('description')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const disabled = !state.writable
|
|
42
|
+
const vaultPath = state.vaultPath
|
|
43
|
+
const searchEnabled = state.searchEnabled
|
|
44
|
+
const indexRefreshMs = state.indexRefreshMs
|
|
45
|
+
|
|
46
|
+
// 布尔字段:以宿主当前值决定开/关,空草稿视为无用户覆盖 → 回落默认(true)。
|
|
47
|
+
const searchOn = searchEnabled.text !== '' ? searchEnabled.text === 'true' : true
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<SettingsForm labels={formLabels(t)} state={state} onSave={props.save} onDiscard={props.discard}>
|
|
51
|
+
<div className={css.page}>
|
|
52
|
+
<div className={css.hint}>{t('page.vaultPath.hint')}</div>
|
|
53
|
+
<div className={css.field}>
|
|
54
|
+
<div className={css.fieldText}>
|
|
55
|
+
<div className={css.title}>{t('page.vaultPath.label')}</div>
|
|
56
|
+
</div>
|
|
57
|
+
<input
|
|
58
|
+
type="text"
|
|
59
|
+
className={css.input}
|
|
60
|
+
value={vaultPath.text}
|
|
61
|
+
placeholder="E:/dsh-workspace/obsidian-vault"
|
|
62
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
63
|
+
props.edit('vaultPath', e.target.value)
|
|
64
|
+
}}
|
|
65
|
+
disabled={disabled}
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div className={css.field}>
|
|
70
|
+
<div className={css.fieldText}>
|
|
71
|
+
<div className={css.title}>{t('page.searchEnabled.label')}</div>
|
|
72
|
+
<div className={css.subHint}>{t('page.searchEnabled.hint')}</div>
|
|
73
|
+
</div>
|
|
74
|
+
<Switch
|
|
75
|
+
checked={searchOn}
|
|
76
|
+
onChange={(next: boolean) => {
|
|
77
|
+
props.edit('searchEnabled', String(next))
|
|
78
|
+
}}
|
|
79
|
+
label={t('page.searchEnabled.label')}
|
|
80
|
+
disabled={disabled}
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<div className={css.field}>
|
|
85
|
+
<div className={css.fieldText}>
|
|
86
|
+
<div className={css.title}>{t('page.indexRefreshMs.label')}</div>
|
|
87
|
+
<div className={css.subHint}>{t('page.indexRefreshMs.hint')}</div>
|
|
88
|
+
</div>
|
|
89
|
+
<input
|
|
90
|
+
type="text"
|
|
91
|
+
inputMode="numeric"
|
|
92
|
+
className={css.inputSmall}
|
|
93
|
+
value={indexRefreshMs.text}
|
|
94
|
+
placeholder="60000"
|
|
95
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
96
|
+
props.edit('indexRefreshMs', e.target.value)
|
|
97
|
+
}}
|
|
98
|
+
disabled={disabled}
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div className={css.gitHint}>{t('page.gitHint')}</div>
|
|
103
|
+
</div>
|
|
104
|
+
</SettingsForm>
|
|
105
|
+
)
|
|
106
|
+
}
|