dsh-notes-plugin 0.1.0 → 0.1.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 +17 -9
- package/index.mjs +77 -6
- package/lib/client.js +170 -17
- package/lib/styles.css +104 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
# 📝 dsh-notes-plugin
|
|
4
|
+
|
|
5
|
+
**把 Agent 会话里「聊完就丢」的决策与约定,沉淀成本地 Markdown 笔记**
|
|
6
|
+
|
|
7
|
+
自动注入系统提示 · 可派发待办给活跃会话 · 选区一键摘录 · 纯本地 Markdown 不上传
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/dsh-notes-plugin)
|
|
10
|
+
[](https://www.npmjs.com/package/dsh-notes-plugin)
|
|
11
|
+
[](https://www.npmjs.com/package/dsh-notes-plugin)
|
|
12
|
+
[](https://github.com/PPawnsir/dsh-notes-plugin/blob/main/LICENSE)
|
|
7
13
|

|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
<img src="./docs/screenshot-panel.png" alt="dsh-notes-plugin 笔记面板" width="820">
|
|
16
|
+
|
|
17
|
+
</div>
|
|
10
18
|
|
|
11
19
|
## 解决什么问题
|
|
12
20
|
|
|
@@ -27,7 +35,7 @@ dsh-notes 把这件事变成可积累的本地资产:
|
|
|
27
35
|
> 宿主要求:Node ≥ 22;DSH ≥ `0.1.5-rc.1`(已通过 `peerDependencies` 声明,含预发布分支的版本范围见 package.json)
|
|
28
36
|
|
|
29
37
|
```sh
|
|
30
|
-
dsh plugin --profile web add dsh-notes
|
|
38
|
+
dsh plugin --profile web add dsh-notes-plugin
|
|
31
39
|
```
|
|
32
40
|
|
|
33
41
|
重启 DSH 后生效:会话头部出现「**智能笔记**」按钮(✎,带计数徽标),点击打开/关闭面板;桌面角落另有可拖拽的悬浮气泡入口。
|
|
@@ -35,8 +43,8 @@ dsh plugin --profile web add dsh-notes
|
|
|
35
43
|
## 升级 / 卸载
|
|
36
44
|
|
|
37
45
|
```sh
|
|
38
|
-
dsh plugin --profile web add dsh-notes@latest # 升级(重启 DSH)
|
|
39
|
-
dsh plugin --profile web remove dsh-notes # 卸载(不删数据)
|
|
46
|
+
dsh plugin --profile web add dsh-notes-plugin@latest # 升级(重启 DSH)
|
|
47
|
+
dsh plugin --profile web remove dsh-notes-plugin # 卸载(不删数据)
|
|
40
48
|
```
|
|
41
49
|
|
|
42
50
|
## 功能清单
|
package/index.mjs
CHANGED
|
@@ -21,9 +21,12 @@ import fsNode from 'node:fs'
|
|
|
21
21
|
import { fileURLToPath } from 'node:url'
|
|
22
22
|
|
|
23
23
|
export const name = 'dsh-notes-plugin'
|
|
24
|
-
// 硬依赖:fs(笔记读写)+ sandboxPolicy(写策略)+ webServer(静态包 RPC 路由)+ tools
|
|
25
|
-
//
|
|
26
|
-
|
|
24
|
+
// 硬依赖:fs(笔记读写)+ sandboxPolicy(写策略)+ webServer(静态包 RPC 路由)+ tools(静态包工具注册)
|
|
25
|
+
// + agents/workspaceRegistry/sessionPersistence/sessionQuery/sessionTitle(派发与注入的会话列表数据源——
|
|
26
|
+
// 这些服务注册时机晚于基础服务,不声明 inject 时 apply 先于它们执行,ctx.get 拿到 undefined,会话列表永远为空)。
|
|
27
|
+
// harness 是动态插件的全局 Builtin,静态包里不存在(PACKAGING.md)——静态包必须 inject webServer/tools 走 ctx 服务通道。
|
|
28
|
+
// llm / agentDefaultModel / systemPrompt 为可选增强(自动分类/约定注入),保持 ctx.get + 守卫降级,不进 inject。
|
|
29
|
+
export const inject = ['fs', 'sandboxPolicy', 'webServer', 'tools', 'agents', 'workspaceRegistry', 'sessionPersistence', 'sessionQuery', 'sessionTitle']
|
|
27
30
|
|
|
28
31
|
// ---- 路径锚点(模块级常量,import 时求值,无副作用)----
|
|
29
32
|
const PKG_DIR = path.dirname(fileURLToPath(import.meta.url)) // packages/dsh-notes
|
|
@@ -290,6 +293,37 @@ export function apply(ctx) {
|
|
|
290
293
|
}
|
|
291
294
|
}
|
|
292
295
|
|
|
296
|
+
// 由 sessionId 推导工作区名:live 走 agents 的 header.cwd,非 live 走 persistence/sessionQuery 快照。
|
|
297
|
+
// 旧笔记(agents 未就绪期创建)workspace 为空时用于兜底补全——否则“本工作区”注入范围因严格匹配永不命中。
|
|
298
|
+
async function _wsOfSession(sid) {
|
|
299
|
+
if (!sid) return ''
|
|
300
|
+
try {
|
|
301
|
+
const a = agents && agents.get ? agents.get(sid) : undefined
|
|
302
|
+
let cwd = (a && a.session && a.session.header && a.session.header.cwd) || ''
|
|
303
|
+
if (!cwd && sessionPersistence && typeof sessionPersistence.list === 'function') {
|
|
304
|
+
let snaps = []
|
|
305
|
+
try { snaps = sessionPersistence.list() || [] } catch (e) { snaps = [] }
|
|
306
|
+
if (snaps && typeof snaps.then === 'function') { try { snaps = await snaps } catch (e2) { snaps = [] } }
|
|
307
|
+
for (const s of (snaps || [])) {
|
|
308
|
+
const h = s && s.header ? s.header : s
|
|
309
|
+
if (h && h.id === sid) { cwd = h.cwd || ''; break }
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// 兜底二:sessionQuery.readTitleSnapshots(_activeSessions 同款,已验证在当前 DSH 可用)
|
|
313
|
+
if (!cwd && sessionQuery && typeof sessionQuery.readTitleSnapshots === 'function') {
|
|
314
|
+
try {
|
|
315
|
+
const rs = await sessionQuery.readTitleSnapshots([sid])
|
|
316
|
+
for (const r of (rs || [])) {
|
|
317
|
+
const v = r && r.status === 'fulfilled' ? r.value : (r && r.value)
|
|
318
|
+
const hd = v && v.session ? v.session : null
|
|
319
|
+
if (hd && hd.cwd) { cwd = hd.cwd; break }
|
|
320
|
+
}
|
|
321
|
+
} catch (e) {}
|
|
322
|
+
}
|
|
323
|
+
return cwd ? basename(cwd) : ''
|
|
324
|
+
} catch (e) { return '' }
|
|
325
|
+
}
|
|
326
|
+
|
|
293
327
|
async function _create(title, body, tags, topic, extra) {
|
|
294
328
|
const id = genId()
|
|
295
329
|
const now = new Date().toISOString()
|
|
@@ -368,6 +402,11 @@ export function apply(ctx) {
|
|
|
368
402
|
if (injectTo !== undefined) note.injectTo = injectTo
|
|
369
403
|
if (body !== undefined) note.body = body
|
|
370
404
|
note.updatedAt = new Date().toISOString()
|
|
405
|
+
// 兜底补全:约定笔记 workspace 为空(agents 未就绪期创建的存量)时按来源会话推导填入,
|
|
406
|
+
// 否则“本工作区”注入范围在严格匹配下永不命中
|
|
407
|
+
if (!note.workspace && note.sessionId) {
|
|
408
|
+
try { note.workspace = await _wsOfSession(note.sessionId) } catch (e) {}
|
|
409
|
+
}
|
|
371
410
|
await persistNote(note)
|
|
372
411
|
return { id, kind: note.kind, status: note.status }
|
|
373
412
|
}
|
|
@@ -742,12 +781,13 @@ export function apply(ctx) {
|
|
|
742
781
|
const targets = n.injectTo || []
|
|
743
782
|
let hit = false
|
|
744
783
|
if (targets.length === 0) {
|
|
745
|
-
//
|
|
746
|
-
|
|
784
|
+
// 默认:当前工作区。严格匹配:ws 有值时要求笔记 workspace 一致(旧笔记无 workspace 视为记录时未知,
|
|
785
|
+
// 仅在 cwd 不可得的会话兜底注入——修掉"选定工作区注入后切到别的会话仍注入")
|
|
786
|
+
hit = ws ? n.workspace === ws : !n.workspace
|
|
747
787
|
} else {
|
|
748
788
|
for (const t of targets) {
|
|
749
789
|
if (t === 'global') { hit = true; break }
|
|
750
|
-
if (t === 'workspace') { if (
|
|
790
|
+
if (t === 'workspace') { if (ws ? n.workspace === ws : !n.workspace) { hit = true; break } }
|
|
751
791
|
else if (t === curSid) { hit = true; break }
|
|
752
792
|
}
|
|
753
793
|
}
|
|
@@ -1141,6 +1181,37 @@ export function apply(ctx) {
|
|
|
1141
1181
|
}
|
|
1142
1182
|
let migrationDone = migrateLegacyNotes()
|
|
1143
1183
|
|
|
1184
|
+
// 存量一次性修补:agents 未就绪期创建的笔记 workspace 为空,导致“本工作区”注入范围严格匹配后永不命中。
|
|
1185
|
+
// 启动时按来源会话推导补填一次(只补空值)。注意:不用 _list()(它 await migrationDone,会与本补全死锁),
|
|
1186
|
+
// 直接走底层遍历;也不挂进 migrationDone 链——_list 只需等 legacy 迁移,补全异步自跑即可。
|
|
1187
|
+
const legacyDone = migrationDone
|
|
1188
|
+
async function fixLegacyWorkspaces() {
|
|
1189
|
+
try { await legacyDone } catch (e) {}
|
|
1190
|
+
try {
|
|
1191
|
+
const dirTarget = await fs.resolve(NOTES_DIR)
|
|
1192
|
+
const info = await fs.stat(dirTarget)
|
|
1193
|
+
if (!info) return { fixed: 0 }
|
|
1194
|
+
const entries = await fs.listDir(dirTarget)
|
|
1195
|
+
let fixed = 0
|
|
1196
|
+
let skipped = 0
|
|
1197
|
+
for (const entry of entries) {
|
|
1198
|
+
if (!entry.name || !entry.name.endsWith('.md')) continue
|
|
1199
|
+
const id = entry.name.replace(/\.md$/, '')
|
|
1200
|
+
try {
|
|
1201
|
+
const n = await loadNote(id)
|
|
1202
|
+
if (n.deleted || n.workspace) continue
|
|
1203
|
+
const ws = await _wsOfSession(n.sessionId)
|
|
1204
|
+
if (!ws) { skipped++; console.log('notes: workspace backfill skip ' + id + ' (sid=' + (n.sessionId || 'none') + ', 推导不到 cwd)') ; continue }
|
|
1205
|
+
await persistNote(Object.assign({}, n, { workspace: ws }))
|
|
1206
|
+
fixed++
|
|
1207
|
+
} catch (e) { skipped++; console.error('notes: workspace backfill item failed', id, e) }
|
|
1208
|
+
}
|
|
1209
|
+
console.log('notes: workspace backfill done, fixed=' + fixed + ' skipped=' + skipped)
|
|
1210
|
+
return { fixed: fixed }
|
|
1211
|
+
} catch (e) { console.error('notes: workspace backfill error', e); return { fixed: 0, error: String(e && e.message || e) } }
|
|
1212
|
+
}
|
|
1213
|
+
fixLegacyWorkspaces()
|
|
1214
|
+
|
|
1144
1215
|
ctx.effect(() => () => {
|
|
1145
1216
|
for (const d of disposers) { try { d() } catch (e) {} }
|
|
1146
1217
|
})
|
package/lib/client.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// · 样式 :fetch notes-css + document.createElement('style') 注入(doc 级,进程单例)
|
|
10
10
|
// (动态插件的 styles 服务在静态包中不存在)
|
|
11
11
|
// · 定时器 :动态插件的 ctx.interval 快捷方式不存在,用 ctx.get('timer') + ctx.effect
|
|
12
|
-
// · inject
|
|
12
|
+
// · inject :声明全部服务(slots/timer/sessions/workspaces),保证就绪后才 apply
|
|
13
13
|
//
|
|
14
14
|
// 要改 client 行为:改开发版 client-impl.js,然后 `node scripts/build-dist.cjs` 重新生成。
|
|
15
15
|
window.__ModuleLoader__.load({
|
|
@@ -60,6 +60,86 @@ window.__ModuleLoader__.load({
|
|
|
60
60
|
const notify = () => listeners.forEach(fn => fn({ panelOpen }))
|
|
61
61
|
const notifyNotesChanged = () => noteRefreshListeners.forEach(fn => fn())
|
|
62
62
|
const e = React.createElement
|
|
63
|
+
// ===== Markdown 预览渲染器(内联手写,零外部依赖;所有插值先 HTML 转义)=====
|
|
64
|
+
// 安全红线:esc() 先把 & < > " ' 转为实体,绝不用 innerHTML 直插原文;代码块内容同样转义
|
|
65
|
+
function esc(s) {
|
|
66
|
+
return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\x22/g, '"').replace(/\x27/g, ''')
|
|
67
|
+
}
|
|
68
|
+
function renderMarkdown(md) {
|
|
69
|
+
var src = String(md || '')
|
|
70
|
+
if (!src.trim()) return ''
|
|
71
|
+
var lines = src.replace(/\r\n/g, '\n').split('\n')
|
|
72
|
+
var out = []
|
|
73
|
+
var i = 0
|
|
74
|
+
var inUl = false, inOl = false
|
|
75
|
+
function closeLists() { if (inUl) { out.push('</ul>'); inUl = false } if (inOl) { out.push('</ol>'); inOl = false } }
|
|
76
|
+
// 行内格式:行内代码 → 粗体 → 斜体 → 链接(仅 http/https)。esc 已在入口执行
|
|
77
|
+
function inline(s) {
|
|
78
|
+
var t = esc(s)
|
|
79
|
+
t = t.replace(/\x60([^\x60]+)\x60/g, function (m, c) { return '<code>' + c + '</code>' })
|
|
80
|
+
t = t.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
|
|
81
|
+
t = t.replace(/\*([^*]+)\*/g, '<em>$1</em>')
|
|
82
|
+
t = t.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>')
|
|
83
|
+
return t
|
|
84
|
+
}
|
|
85
|
+
while (i < lines.length) {
|
|
86
|
+
var line = lines[i]
|
|
87
|
+
// 围栏代码块
|
|
88
|
+
if (/^\x60\x60\x60/.test(line)) {
|
|
89
|
+
closeLists()
|
|
90
|
+
var lang = line.replace(/^\x60\x60\x60/, '').trim()
|
|
91
|
+
var codeLines = []
|
|
92
|
+
i++
|
|
93
|
+
while (i < lines.length && !/^\x60\x60\x60/.test(lines[i])) { codeLines.push(lines[i]); i++ }
|
|
94
|
+
i++
|
|
95
|
+
out.push('<pre class="dsh-notes-preview-code"' + (lang ? ' data-lang="' + esc(lang) + '"' : '') + '><code>' + esc(codeLines.join('\n')) + '</code></pre>')
|
|
96
|
+
continue
|
|
97
|
+
}
|
|
98
|
+
// 标题 # ~ ###
|
|
99
|
+
var hm = line.match(/^(#{1,3})\s+(.*)$/)
|
|
100
|
+
if (hm) {
|
|
101
|
+
closeLists()
|
|
102
|
+
var lvl = hm[1].length
|
|
103
|
+
out.push('<h' + lvl + ' class="dsh-notes-preview-h' + lvl + '">' + inline(hm[2]) + '</h' + lvl + '>')
|
|
104
|
+
i++
|
|
105
|
+
continue
|
|
106
|
+
}
|
|
107
|
+
// 引用块
|
|
108
|
+
if (/^>\s?/.test(line)) {
|
|
109
|
+
closeLists()
|
|
110
|
+
var quoteLines = []
|
|
111
|
+
while (i < lines.length && /^>\s?/.test(lines[i])) { quoteLines.push(lines[i].replace(/^>\s?/, '')); i++ }
|
|
112
|
+
out.push('<blockquote class="dsh-notes-preview-quote">' + inline(quoteLines.join(' ')) + '</blockquote>')
|
|
113
|
+
continue
|
|
114
|
+
}
|
|
115
|
+
// 无序列表
|
|
116
|
+
if (/^[-*+]\s+/.test(line)) {
|
|
117
|
+
if (inOl) { out.push('</ol>'); inOl = false }
|
|
118
|
+
if (!inUl) { out.push('<ul class="dsh-notes-preview-ul">'); inUl = true }
|
|
119
|
+
out.push('<li>' + inline(line.replace(/^[-*+]\s+/, '')) + '</li>')
|
|
120
|
+
i++
|
|
121
|
+
continue
|
|
122
|
+
}
|
|
123
|
+
// 有序列表
|
|
124
|
+
if (/^\d+\.\s+/.test(line)) {
|
|
125
|
+
if (inUl) { out.push('</ul>'); inUl = false }
|
|
126
|
+
if (!inOl) { out.push('<ol class="dsh-notes-preview-ol">'); inOl = true }
|
|
127
|
+
out.push('<li>' + inline(line.replace(/^\d+\.\s+/, '')) + '</li>')
|
|
128
|
+
i++
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
// 空行
|
|
132
|
+
if (line.trim() === '') { closeLists(); i++; continue }
|
|
133
|
+
// 段落(连续非空非特殊行合并)
|
|
134
|
+
closeLists()
|
|
135
|
+
var paraLines = []
|
|
136
|
+
while (i < lines.length && lines[i].trim() !== '' && !/^(#{1,3}\s|\x60\x60\x60|>\s?|[-*+]\s|\d+\.\s)/.test(lines[i])) { paraLines.push(lines[i]); i++ }
|
|
137
|
+
out.push('<p class="dsh-notes-preview-p">' + inline(paraLines.join(' ')) + '</p>')
|
|
138
|
+
}
|
|
139
|
+
closeLists()
|
|
140
|
+
return out.join('\n')
|
|
141
|
+
}
|
|
142
|
+
// ===== end Markdown 预览渲染器 =====
|
|
63
143
|
// 性能自检计数器:浏览器控制台执行 JSON.stringify(window.__dshNotesPerf) 可取数诊断
|
|
64
144
|
const now = (typeof performance !== 'undefined' && performance.now) ? () => performance.now() : () => Date.now()
|
|
65
145
|
const perf = { selChange: 0, selCollapsedSkip: 0, selChangeMs: 0, selShowEval: 0, selShowMs: 0, mousemoveTracked: 0, hostCall: 0, hostCallMs: 0, panelRender: 0, selRender: 0, hdrRender: 0, longTasks: 0, longTaskMs: 0, worstTaskMs: 0 }
|
|
@@ -224,10 +304,13 @@ window.__ModuleLoader__.load({
|
|
|
224
304
|
const [dispatching, setDispatching] = React.useState(false)
|
|
225
305
|
const [dispatchMode, setDispatchMode] = React.useState('existing') // existing=派发到活跃会话 / new=新建会话派发
|
|
226
306
|
const [dispatchInstr, setDispatchInstr] = React.useState('')
|
|
307
|
+
const [previewMode, setPreviewMode] = React.useState(false) // 编辑/预览双态:默认编辑(textarea 行为不变)
|
|
308
|
+
const [ctxMenu, setCtxMenu] = React.useState(null) // 列表项右键菜单:{ x, y, note }(面板内坐标)或 null
|
|
227
309
|
const [dispatchWsId, setDispatchWsId] = React.useState('') // new 模式:选中的工作区 id
|
|
228
310
|
const [dispatchSessWs, setDispatchSessWs] = React.useState('') // existing 模式:选中的工作区名
|
|
229
311
|
const [dispatchSessId, setDispatchSessId] = React.useState('') // existing 模式:选中的会话 id
|
|
230
312
|
const [wsList, setWsList] = React.useState([])
|
|
313
|
+
const [dispatchHistoryOpen, setDispatchHistoryOpen] = React.useState(false) // 派发历史折叠态:默认折叠,点标题行展开
|
|
231
314
|
const keepQuickRef = React.useRef(false)
|
|
232
315
|
const capRef = React.useRef(null)
|
|
233
316
|
const timersRef = React.useRef([])
|
|
@@ -246,6 +329,7 @@ window.__ModuleLoader__.load({
|
|
|
246
329
|
// T2 顶栏压缩:展开态镜像到 ref(keydown 闭包挂一次,需读最新值避免过期)
|
|
247
330
|
const searchOpenRef = React.useRef(false)
|
|
248
331
|
const capOpenRef = React.useRef(false)
|
|
332
|
+
const ctxMenuRef = React.useRef(null) // 右键菜单镜像(keydown 闭包读最新值)
|
|
249
333
|
// 自动保存:编辑字段的最新值 ref(debounce 回调读 ref 而非闭包 state,避免过期)
|
|
250
334
|
const edTitleRef = React.useRef('')
|
|
251
335
|
const edTopicRef = React.useRef('')
|
|
@@ -297,6 +381,7 @@ window.__ModuleLoader__.load({
|
|
|
297
381
|
// T2 顶栏压缩:展开态同步到 ref(keydown 闭包读 ref 避免过期)
|
|
298
382
|
React.useEffect(() => { searchOpenRef.current = searchOpen }, [searchOpen])
|
|
299
383
|
React.useEffect(() => { capOpenRef.current = capOpen }, [capOpen])
|
|
384
|
+
React.useEffect(() => { ctxMenuRef.current = ctxMenu }, [ctxMenu])
|
|
300
385
|
// T2 顶栏压缩:展开时自动聚焦(Ctrl+K/Ctrl+N 改为 setSearchOpen(true)/setCapOpen(true),由此 effect 完成聚焦)
|
|
301
386
|
React.useEffect(() => { if (searchOpen && searchInputRef.current) searchInputRef.current.focus() }, [searchOpen])
|
|
302
387
|
React.useEffect(() => {
|
|
@@ -316,8 +401,9 @@ window.__ModuleLoader__.load({
|
|
|
316
401
|
const mod = ev.ctrlKey || ev.metaKey
|
|
317
402
|
if (mod && (ev.key === 'k' || ev.key === 'K')) { ev.preventDefault(); setSearchOpen(true); return }
|
|
318
403
|
if (mod && (ev.key === 'n' || ev.key === 'N')) { ev.preventDefault(); setCapOpen(true); return }
|
|
319
|
-
if (ev.key === 'Escape') { ev.preventDefault(); if (capOpenRef.current) { setCapOpen(false); return } if (searchOpenRef.current) { setSearchOpen(false); return } closeRef.current(); return }
|
|
404
|
+
if (ev.key === 'Escape') { ev.preventDefault(); if (ctxMenuRef.current) { setCtxMenu(null); return } if (capOpenRef.current) { setCapOpen(false); return } if (searchOpenRef.current) { setSearchOpen(false); return } closeRef.current(); return }
|
|
320
405
|
if (inField) return
|
|
406
|
+
if (ctxMenuRef.current) return // 右键菜单打开时暂停列表导航/打开
|
|
321
407
|
const ids = pagedIdsRef.current
|
|
322
408
|
if (!ids.length) return
|
|
323
409
|
if (ev.key === 'j' || ev.key === 'ArrowDown') { ev.preventDefault(); moveFocusRef.current(ids, 1) }
|
|
@@ -416,6 +502,33 @@ window.__ModuleLoader__.load({
|
|
|
416
502
|
await loadNotes(true); notifyNotesChanged()
|
|
417
503
|
} catch (err) { setError(String(err.message || err)) }
|
|
418
504
|
}
|
|
505
|
+
// 列表项右键菜单:替代悬浮 × 按钮(打开即选中目标笔记,操作上下文明确)
|
|
506
|
+
function openCtxMenu(ev, n) {
|
|
507
|
+
ev.preventDefault(); ev.stopPropagation()
|
|
508
|
+
const floatEl = ev.currentTarget.closest('.dsh-notes-floating')
|
|
509
|
+
const rect = floatEl ? floatEl.getBoundingClientRect() : { left: 0, top: 0, width: 600, height: 500 }
|
|
510
|
+
const mw = 160, mh = 116
|
|
511
|
+
let x = ev.clientX - rect.left, y = ev.clientY - rect.top
|
|
512
|
+
x = Math.max(4, Math.min(x, rect.width - mw - 4))
|
|
513
|
+
y = Math.max(4, Math.min(y, rect.height - mh - 4))
|
|
514
|
+
setCtxMenu({ x: x, y: y, note: n })
|
|
515
|
+
selectNote(n)
|
|
516
|
+
}
|
|
517
|
+
async function ctxSetStatus(n, status) {
|
|
518
|
+
setCtxMenu(null); setError('')
|
|
519
|
+
try {
|
|
520
|
+
const res = await rpc('notes-update', { id: n.id, status: status })
|
|
521
|
+
if (res && res.error) { setError(res.error); return }
|
|
522
|
+
await loadNotes(true); notifyNotesChanged()
|
|
523
|
+
} catch (err) { setError(String(err.message || err)) }
|
|
524
|
+
}
|
|
525
|
+
// 点击菜单外部关闭(Esc 在全局 keydown 里处理)
|
|
526
|
+
React.useEffect(() => {
|
|
527
|
+
if (!ctxMenu) return
|
|
528
|
+
const onDown = (ev) => { if (!(ev.target && ev.target.closest && ev.target.closest('.dsh-notes-ctxmenu'))) setCtxMenu(null) }
|
|
529
|
+
document.addEventListener('mousedown', onDown)
|
|
530
|
+
return () => document.removeEventListener('mousedown', onDown)
|
|
531
|
+
}, [ctxMenu])
|
|
419
532
|
async function pickTopic(id, topic) {
|
|
420
533
|
setTopicPickFor(null); setError('')
|
|
421
534
|
try {
|
|
@@ -563,13 +676,12 @@ window.__ModuleLoader__.load({
|
|
|
563
676
|
if (n.topic && n.topic !== '分类中') metaEls.push(e('span', { className: 'dsh-note-meta-topic' }, n.topic))
|
|
564
677
|
if (n.sessionId) metaEls.push(e('span', { className: 'dsh-note-meta-sess' }, '会话 ' + shortSid(n.sessionId)))
|
|
565
678
|
if (visTags.length) metaEls.push(e('span', { className: 'dsh-note-meta-tags' }, visTags.join(' · ')))
|
|
566
|
-
return e('div', { key: n.id, className: 'dsh-note-item' + (selected === n.id ? ' selected' : '') + (flashId === n.id ? ' flash' : '') + (focusId === n.id ? ' focused' : '') + statusCls, onClick: () => selectNote(n), 'data-tooltip': n.title },
|
|
679
|
+
return e('div', { key: n.id, className: 'dsh-note-item' + (selected === n.id ? ' selected' : '') + (flashId === n.id ? ' flash' : '') + (focusId === n.id ? ' focused' : '') + statusCls, onClick: () => selectNote(n), onContextMenu: (ev) => openCtxMenu(ev, n), 'data-tooltip': n.title },
|
|
567
680
|
e('div', { className: 'dsh-note-row' },
|
|
568
681
|
e('span', { className: 'dsh-note-kind-ic dsh-note-kind-' + (n.kind || 'note') }, kindIc),
|
|
569
682
|
e('span', { className: 'dsh-note-title' }, e('span', { className: 'dsh-note-title-text' }, highlight(n.title, q))),
|
|
570
683
|
e('span', { className: 'dsh-note-date' }, n.updatedAt ? n.updatedAt.slice(0, 10) : '')),
|
|
571
|
-
metaEls.length ? e('div', { className: 'dsh-note-meta' }, metaEls) : null
|
|
572
|
-
e('button', { className: 'dsh-note-delete dsh-nt', onClick: (ev) => { ev.stopPropagation(); doDelete(n.id) }, 'data-tooltip': '删除' }, '×'))
|
|
684
|
+
metaEls.length ? e('div', { className: 'dsh-note-meta' }, metaEls) : null)
|
|
573
685
|
}
|
|
574
686
|
let listContent
|
|
575
687
|
if (loading && notes.length === 0) listContent = e('div', { className: 'dsh-notes-loading' }, '加载中...')
|
|
@@ -649,7 +761,7 @@ window.__ModuleLoader__.load({
|
|
|
649
761
|
e('div', { className: 'dsh-notes-ed-head' },
|
|
650
762
|
e('input', { className: 'dsh-notes-editor-title', placeholder: '标题', value: edTitle, onChange: (ev) => { setEdTitle(ev.target.value); triggerAutoSave() } }),
|
|
651
763
|
e('div', { className: 'dsh-notes-ed-meta' },
|
|
652
|
-
e('select', { className: 'dsh-notes-ed-select', value: edKind, onChange: (ev) => { setEdKind(ev.target.value); triggerAutoSave() }, 'data-tooltip': '笔记类型' },
|
|
764
|
+
e('select', { className: 'dsh-notes-ed-select dsh-notes-ed-kind-chip dsh-notes-ed-kind-' + edKind, value: edKind, onChange: (ev) => { setEdKind(ev.target.value); triggerAutoSave() }, 'data-tooltip': '笔记类型' },
|
|
653
765
|
e('option', { value: 'note' }, '笔记'),
|
|
654
766
|
e('option', { value: 'decision' }, '决策'),
|
|
655
767
|
e('option', { value: 'todo' }, '待办'),
|
|
@@ -661,9 +773,14 @@ window.__ModuleLoader__.load({
|
|
|
661
773
|
e('option', { value: 'resolved' }, '已解决'),
|
|
662
774
|
e('option', { value: 'superseded' }, '已取代')),
|
|
663
775
|
e('input', { className: 'dsh-notes-ed-topic', placeholder: '主题', value: edTopic, onChange: (ev) => { setEdTopic(ev.target.value); triggerAutoSave() }, 'data-tooltip': '主题' }),
|
|
664
|
-
e('input', { className: 'dsh-notes-ed-
|
|
776
|
+
e('input', { className: 'dsh-notes-ed-tags-input', placeholder: '标签,逗号分隔', value: edTags, onChange: (ev) => { setEdTags(ev.target.value); triggerAutoSave() }, 'data-tooltip': '标签(convention 表示工作区约定)' }),
|
|
777
|
+
(edTags || '').split(/[,,;;]/).map(function (s) { return s.trim() }).filter(Boolean).length
|
|
778
|
+
? e('div', { className: 'dsh-notes-ed-tags-chips' },
|
|
779
|
+
(edTags || '').split(/[,,;;]/).map(function (s) { return s.trim() }).filter(Boolean)
|
|
780
|
+
.map(function (tag, i) { return e('span', { key: 'tag-' + i, className: 'dsh-notes-ed-tag-chip' }, tag) }))
|
|
781
|
+
: null,
|
|
665
782
|
e('div', { className: 'dsh-notes-ed-meta-right' },
|
|
666
|
-
e('button', { className: 'dsh-notes-ed-action dsh-nt', onClick: (ev) => { ev.stopPropagation(); openDispatch() }, 'data-tooltip': '派发待办到会话(可补充具体要求)' }, dispatching ? '…' : '▶ 派发'),
|
|
783
|
+
e('button', { className: 'dsh-notes-ed-action dsh-notes-dispatch-btn dsh-nt', onClick: (ev) => { ev.stopPropagation(); openDispatch() }, 'data-tooltip': '派发待办到会话(可补充具体要求)' }, dispatching ? '…' : '▶ 派发'),
|
|
667
784
|
notes.find(n => n.id === selected) && notes.find(n => n.id === selected).sessionId ? e('button', { className: 'dsh-notes-ed-action dsh-nt', onClick: () => jumpToSession(notes.find(n => n.id === selected).sessionId), 'data-tooltip': '跳转到来源会话' }, '↗ 会话') : null,
|
|
668
785
|
e('button', { className: 'dsh-notes-ed-action' + (edStatus === 'pinned' ? ' on' : ''), onClick: () => { setEdStatus(edStatus === 'pinned' ? 'active' : 'pinned'); triggerAutoSave() }, 'data-tooltip': edStatus === 'pinned' ? '取消置顶' : '置顶' }, '📌'),
|
|
669
786
|
e('button', { className: 'dsh-notes-ed-action danger', onClick: () => doDelete(selected), 'data-tooltip': '删除(软删除,可恢复)' }, '🗑'))),
|
|
@@ -683,17 +800,21 @@ window.__ModuleLoader__.load({
|
|
|
683
800
|
' ' + s.name)))))
|
|
684
801
|
: null)
|
|
685
802
|
: null)),
|
|
686
|
-
curDispatches.length ? e('div', { className: 'dsh-notes-dispatch-history' },
|
|
687
|
-
e('div', { className: 'dsh-notes-dispatch-history-t'
|
|
688
|
-
|
|
803
|
+
curDispatches.length ? e('div', { className: 'dsh-notes-dispatch-history' + (dispatchHistoryOpen ? ' open' : ' collapsed') },
|
|
804
|
+
e('div', { className: 'dsh-notes-dispatch-history-t', onClick: () => setDispatchHistoryOpen(!dispatchHistoryOpen), role: 'button', 'aria-expanded': dispatchHistoryOpen ? 'true' : 'false' },
|
|
805
|
+
(dispatchHistoryOpen ? '▼ ' : '▶ ') + '派发历史(' + curDispatches.length + ')'),
|
|
806
|
+
dispatchHistoryOpen ? curDispatches.map((d, origIdx) => ({ d: d, origIdx: origIdx })).reverse().map(({ d, origIdx }) => e('div', { key: origIdx, className: 'dsh-notes-dispatch-rec' + (d.done ? ' done' : '') },
|
|
689
807
|
e('div', { className: 'dsh-notes-dispatch-rec-top' },
|
|
690
|
-
e('span', { className: 'dsh-notes-dispatch-rec-t' },
|
|
808
|
+
e('span', { className: 'dsh-notes-dispatch-rec-t' }, d.done ? '✓ ' + (d.sessionName || d.sessionId) : [e('span', { key: 'dot', className: 'dsh-notes-dispatch-dot' }), ' ' + (d.sessionName || d.sessionId)]),
|
|
691
809
|
e('span', { className: 'dsh-notes-dispatch-rec-m' }, (d.done ? '已完成 · ' : '待处理 · ') + (d.mode === 'new' ? '新会话' : (d.workspace || '已有会话')) + (d.at ? ' · ' + String(d.at).slice(5, 16).replace('T', ' ') : ''))),
|
|
692
810
|
d.instruction ? e('div', { className: 'dsh-notes-dispatch-rec-i' }, '要求:' + d.instruction) : null,
|
|
693
|
-
!d.done ? e('button', { className: 'dsh-notes-dispatch-done-btn', onClick: () => doDispatchDone(origIdx) }, '标记完成') : null)))
|
|
811
|
+
!d.done ? e('button', { className: 'dsh-notes-dispatch-done-btn', onClick: () => doDispatchDone(origIdx) }, '标记完成') : null)) : null)
|
|
694
812
|
: null,
|
|
695
|
-
|
|
813
|
+
previewMode
|
|
814
|
+
? e('div', { className: 'dsh-notes-preview-container', dangerouslySetInnerHTML: { __html: renderMarkdown(edBody) } })
|
|
815
|
+
: e('textarea', { className: 'dsh-notes-editor-body', placeholder: '开始记录…(支持 Markdown)', value: edBody, onChange: (ev) => { setEdBody(ev.target.value); triggerAutoSave() } }),
|
|
696
816
|
e('div', { className: 'dsh-notes-ed-foot' },
|
|
817
|
+
e('button', { className: 'dsh-notes-preview-toggle dsh-nt' + (previewMode ? ' on' : ''), onClick: () => setPreviewMode(!previewMode), 'data-tooltip': previewMode ? '切换到编辑模式' : '预览 Markdown 渲染' }, previewMode ? '✎ 编辑' : '👁 预览'),
|
|
697
818
|
e('span', { className: 'dsh-notes-ed-saved' + (savedAt ? ' show' : '') }, savedAt ? '已自动保存 ' + new Date(savedAt).toTimeString().slice(0, 5) : ''),
|
|
698
819
|
e('span', null, (edBody || '').length + ' 字')))
|
|
699
820
|
: e('div', { className: 'dsh-notes-editor-empty' },
|
|
@@ -727,6 +848,12 @@ window.__ModuleLoader__.load({
|
|
|
727
848
|
e('div', { className: 'dsh-notes-dispatch-actions' },
|
|
728
849
|
e('button', { className: 'dsh-notes-dispatch-cancel', onClick: () => setDispatchOpen(false) }, '取消'),
|
|
729
850
|
e('button', { className: 'dsh-notes-dispatch-ok', onClick: doDispatchConfirm, disabled: dispatching }, dispatching ? '派发中…' : '派发'))))
|
|
851
|
+
: null,
|
|
852
|
+
// 列表项右键菜单(替代悬浮 ×):置顶/已解决/删除
|
|
853
|
+
ctxMenu ? e('div', { className: 'dsh-notes-ctxmenu', style: { left: ctxMenu.x + 'px', top: ctxMenu.y + 'px' } },
|
|
854
|
+
e('button', { className: 'dsh-notes-ctxmenu-item', onClick: () => ctxSetStatus(ctxMenu.note, ctxMenu.note.status === 'pinned' ? 'active' : 'pinned') }, '📌 ' + (ctxMenu.note.status === 'pinned' ? '取消置顶' : '置顶')),
|
|
855
|
+
e('button', { className: 'dsh-notes-ctxmenu-item', onClick: () => ctxSetStatus(ctxMenu.note, ctxMenu.note.status === 'resolved' ? 'active' : 'resolved') }, '✓ ' + (ctxMenu.note.status === 'resolved' ? '重开' : '标记已解决')),
|
|
856
|
+
e('button', { className: 'dsh-notes-ctxmenu-item danger', onClick: () => { setCtxMenu(null); doDelete(ctxMenu.note.id) } }, '🗑 删除'))
|
|
730
857
|
: null)
|
|
731
858
|
}
|
|
732
859
|
slots.register({ name: 'shell.overlay', id: 'dsh-notes-panel', order: 200 }, (props) => e(FloatingPanel, props))
|
|
@@ -857,10 +984,37 @@ window.__ModuleLoader__.load({
|
|
|
857
984
|
} catch (err) { setToast('记录失败:' + String(err.message || err)) }
|
|
858
985
|
}
|
|
859
986
|
function cancel() { visibleRef.current = false; setBtn(null); setInstrText(''); if (window.getSelection()) window.getSelection().removeAllRanges() }
|
|
987
|
+
// 复制选区文本到剪贴板:优先 navigator.clipboard,不可用/失败时降级 execCommand;不关浮层不清选区
|
|
988
|
+
function fallbackCopy(text) {
|
|
989
|
+
try {
|
|
990
|
+
var ta = document.createElement('textarea')
|
|
991
|
+
ta.value = text
|
|
992
|
+
ta.style.position = 'fixed'
|
|
993
|
+
ta.style.opacity = '0'
|
|
994
|
+
ta.style.pointerEvents = 'none'
|
|
995
|
+
document.body.appendChild(ta)
|
|
996
|
+
ta.select()
|
|
997
|
+
document.execCommand('copy')
|
|
998
|
+
document.body.removeChild(ta)
|
|
999
|
+
setToast('已复制选区')
|
|
1000
|
+
} catch (err) { setToast('复制失败') }
|
|
1001
|
+
}
|
|
1002
|
+
function copySelection() {
|
|
1003
|
+
var text = selTextRef.current
|
|
1004
|
+
if (!text) { setToast('无选区可复制'); return }
|
|
1005
|
+
try {
|
|
1006
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
1007
|
+
navigator.clipboard.writeText(text).then(function () { setToast('已复制选区') }, function () { fallbackCopy(text) })
|
|
1008
|
+
return
|
|
1009
|
+
}
|
|
1010
|
+
} catch (err) {}
|
|
1011
|
+
fallbackCopy(text)
|
|
1012
|
+
}
|
|
860
1013
|
return e('div', null, btn ? e('div', { className: 'dsh-notes-instruct-box', style: { left: btn.x + 'px', top: btn.y + 'px' } },
|
|
861
1014
|
e('div', { className: 'dsh-notes-instruct-preview' }, previewText(selTextRef.current)),
|
|
862
1015
|
e('input', { ref: instrRef, className: 'dsh-notes-instruct-input', type: 'text', placeholder: '可补充:打标签/引导标题/定类型/设为约定…直接回车则仅记录', value: instrText, onChange: function (ev) { setInstrText(ev.target.value) }, onKeyDown: function (ev) { if (ev.key === 'Enter') { ev.preventDefault(); submit() } else if (ev.key === 'Escape') { ev.preventDefault(); cancel() } } }),
|
|
863
1016
|
e('div', { className: 'dsh-notes-instruct-actions' },
|
|
1017
|
+
e('button', { className: 'dsh-notes-instruct-btn', onClick: copySelection }, '复制'),
|
|
864
1018
|
e('button', { className: 'dsh-notes-instruct-btn primary', onClick: submit }, '记录'),
|
|
865
1019
|
e('button', { className: 'dsh-notes-instruct-btn', onClick: cancel }, '取消')
|
|
866
1020
|
)
|
|
@@ -873,9 +1027,8 @@ window.__ModuleLoader__.load({
|
|
|
873
1027
|
console.log('notes plugin: client ready')
|
|
874
1028
|
}
|
|
875
1029
|
|
|
876
|
-
//
|
|
877
|
-
//
|
|
878
|
-
// 避免服务未就绪时插件永远不启动。
|
|
1030
|
+
// inject 声明 apply 用到的全部服务(slots/timer/sessions/workspaces),
|
|
1031
|
+
// 保证 Cordis 在服务就绪后才激活 apply;apply 内仍保留 ctx.get + 存在性守卫做双保险。
|
|
879
1032
|
module.exports = { name: 'dsh-notes-plugin', inject: ['slots', 'timer', 'sessions', 'workspaces'], apply: apply }
|
|
880
1033
|
return module.exports
|
|
881
1034
|
}
|
package/lib/styles.css
CHANGED
|
@@ -6,18 +6,20 @@
|
|
|
6
6
|
.dsh-notes-floating,.dsh-notes-fab{
|
|
7
7
|
/* 背景 */
|
|
8
8
|
--nbg:var(--dsw-alias-bg-overlay, #ffffff); /* 面板主背景 */
|
|
9
|
-
--nsf:
|
|
10
|
-
--nbg-hover:
|
|
11
|
-
--nbg-sel:
|
|
9
|
+
--nsf:rgba(128,128,128,.05); /* 列表区背景(次级面)——color-mix 兜底(明暗面板均可见) */
|
|
10
|
+
--nbg-hover:rgba(128,128,128,.08); /* 列表项 hover(比底色深一档)——color-mix 兜底 */
|
|
11
|
+
--nbg-sel:rgba(128,128,128,.12); /* 列表项选中(macOS 选中灰)——color-mix 兜底 */
|
|
12
12
|
--nbd:var(--dsw-alias-border-l1, #e5e5ea); /* 边框/分隔线 */
|
|
13
13
|
--nbd-soft:var(--dsw-alias-border-l1, #ececf0); /* 更柔和的分隔 */
|
|
14
14
|
/* 文字 */
|
|
15
15
|
--ntx:var(--dsw-alias-label-primary, #1c1c1e); /* 主文字 */
|
|
16
|
+
--ntx-soft:var(--ntx); /* 正文柔化版(88% 主色,color-mix 覆盖;兜底保持主色) */
|
|
16
17
|
--nt2:var(--dsw-alias-label-secondary, #6c6c70); /* 次要文字(时间/来源) */
|
|
17
18
|
--nt3:var(--dsw-alias-label-secondary, #aeaeb2); /* 弱化(placeholder/图标) */
|
|
18
19
|
/* 强调 */
|
|
19
20
|
--nacc:var(--dsw-alias-brand-primary, #0a84ff); /* 蓝(交互/选中) */
|
|
20
21
|
--nacc-soft:rgba(10,132,255,.12);
|
|
22
|
+
--nwarn:#ff9500; /* 待处理/警告(橙) */
|
|
21
23
|
/* kind 强调色(灰阶为主,kind 用低调色;深浅通用,保留原值) */
|
|
22
24
|
--nkind-note:#8e8e93;
|
|
23
25
|
--nkind-decision:#0a84ff;
|
|
@@ -27,12 +29,27 @@
|
|
|
27
29
|
/* 尺寸 */
|
|
28
30
|
--nr-sm:6px; --nr-md:8px; --nr-lg:10px;
|
|
29
31
|
/* 字体 */
|
|
30
|
-
--nfont:-apple-system,BlinkMacSystemFont,"
|
|
31
|
-
--nmono:"SF Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
|
|
32
|
+
--nfont:-apple-system,BlinkMacSystemFont,"Segoe UI Variable Text","Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei UI","Microsoft YaHei","Noto Sans SC","Source Han Sans SC",system-ui,sans-serif; /* YaHei UI 优先于 YaHei(UI 优化版字距松/笔画清爽);Win11 可变字体优先 */
|
|
33
|
+
--nmono:"SF Mono",ui-monospace,"Cascadia Code","Cascadia Mono",SFMono-Regular,Menlo,Consolas,monospace; /* Win11 Cascadia 优先于 Consolas */
|
|
32
34
|
/* 阴影(极淡,仅面板) */
|
|
33
35
|
--nshadow:0 18px 50px rgba(0,0,0,.12),0 2px 8px rgba(0,0,0,.06);
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
/* color-mix 增强:从主文字色(--ntx)派生半透明灰,亮色呈浅灰、暗色呈浅白,随 DSH 主题自动切换。
|
|
39
|
+
修复 --dsw-alias-bg-layer-2/3 在亮色主题解析为 #fff 导致列表分栏/胶囊/选中态与面板底色撞色。
|
|
40
|
+
color-mix 不可用时回退到上方中性 rgba 灰(不依赖 layer token,明暗面板均可见)。 */
|
|
41
|
+
@supports (color: color-mix(in srgb, #fff, transparent)){
|
|
42
|
+
.dsh-notes-floating,.dsh-notes-fab{
|
|
43
|
+
--nsf:color-mix(in srgb, var(--ntx) 5%, transparent);
|
|
44
|
+
--nbg-hover:color-mix(in srgb, var(--ntx) 8%, transparent);
|
|
45
|
+
--nbg-sel:color-mix(in srgb, var(--ntx) 12%, transparent);
|
|
46
|
+
--ntx-soft:color-mix(in srgb, var(--ntx) 88%, transparent);
|
|
47
|
+
}
|
|
48
|
+
.dsh-notes-instruct-box{
|
|
49
|
+
--nbg-hover:color-mix(in srgb, var(--ntx) 8%, transparent);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
36
53
|
/* ===== tooltip(作用域隔离) ===== */
|
|
37
54
|
.dsh-nt{position:relative}
|
|
38
55
|
.dsh-nt[data-tooltip]::after{content:attr(data-tooltip);position:fixed;background:rgba(28,28,30,.95);color:#fff;padding:5px 9px;border-radius:6px;font-size:11px;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .12s;z-index:2147483646;font-family:var(--nfont)}
|
|
@@ -88,14 +105,14 @@
|
|
|
88
105
|
.dsh-notes-kinds{flex:1;display:flex;align-items:center;gap:6px;overflow-x:auto;padding:0;border-bottom:none}
|
|
89
106
|
.dsh-notes-kind-chip{background:transparent;border:1px solid var(--nbd);border-radius:13px;color:var(--nt2);font-size:11px;padding:3px 11px;cursor:pointer;transition:all .15s;white-space:nowrap;font-weight:500}
|
|
90
107
|
.dsh-notes-kind-chip:hover{border-color:var(--nt3);color:var(--ntx)}
|
|
91
|
-
.dsh-notes-kind-chip.on{background:var(--
|
|
108
|
+
.dsh-notes-kind-chip.on{background:var(--nbg-sel);border-color:transparent;color:var(--ntx);font-weight:600} /* 柔和灰底深字(贴 DSH 侧边栏选中风),不再黑底白字 */
|
|
92
109
|
.dsh-notes-pin-toggle{margin-left:auto;background:transparent;border:1px solid var(--nbd);border-radius:13px;color:var(--nt2);font-size:11px;padding:3px 11px;cursor:pointer;transition:all .15s;white-space:nowrap;font-weight:500;flex-shrink:0}
|
|
93
110
|
.dsh-notes-pin-toggle:hover{border-color:var(--nt3);color:var(--ntx)}
|
|
94
|
-
.dsh-notes-pin-toggle.on{background:var(--
|
|
111
|
+
.dsh-notes-pin-toggle.on{background:var(--nbg-sel);border-color:transparent;color:var(--ntx);font-weight:600} /* 与 kind-chip.on 同款柔和灰底 */
|
|
95
112
|
|
|
96
113
|
/* ===== 列表区(两列布局) ===== */
|
|
97
114
|
.dsh-notes-content{display:flex;flex:1;overflow:hidden;min-height:0;position:relative}
|
|
98
|
-
.dsh-notes-divider{width:5px;cursor:col-resize;flex-shrink:0;background:
|
|
115
|
+
.dsh-notes-divider{width:5px;cursor:col-resize;flex-shrink:0;background:var(--nbd);transition:background .15s;position:relative;z-index:5}
|
|
99
116
|
.dsh-notes-list{overflow:hidden;flex-shrink:0;display:flex;flex-direction:column;background:var(--nsf);min-width:180px;max-width:400px;border-right:1px solid var(--nbd-soft)}
|
|
100
117
|
.dsh-notes-list-items{flex:1;overflow-y:auto;padding:2px 5px}
|
|
101
118
|
.dsh-notes-list-items::-webkit-scrollbar{width:8px}
|
|
@@ -109,7 +126,6 @@
|
|
|
109
126
|
/* ===== 笔记列表项(Apple Notes:0 圆角、无阴影、纯背景选中) ===== */
|
|
110
127
|
.dsh-note-item{padding:5px 9px;margin:0;border-radius:var(--nr-md);cursor:pointer;transition:background .12s;position:relative;background:transparent;box-shadow:none;user-select:none}
|
|
111
128
|
.dsh-note-item:hover{background:var(--nbg-hover)}
|
|
112
|
-
.dsh-note-item:hover .dsh-note-delete{opacity:1}
|
|
113
129
|
.dsh-note-item.selected{background:var(--nbg-sel)}
|
|
114
130
|
.dsh-note-item.focused{background:var(--nbg-hover)}
|
|
115
131
|
.dsh-note-item.pinned{}
|
|
@@ -133,15 +149,14 @@
|
|
|
133
149
|
.dsh-note-meta-sess{font-size:10px;color:var(--nt3);white-space:nowrap;flex-shrink:0}
|
|
134
150
|
.dsh-note-meta-tags{font-size:10px;color:var(--nt3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}
|
|
135
151
|
.dsh-note-preview{display:none} /* Apple Notes 默认不显示预览,保持列表极简 */
|
|
136
|
-
|
|
137
|
-
.dsh-note-delete:hover{color:#ff3b30;border-color:rgba(255,59,48,.4)}
|
|
152
|
+
/* 列表项删除已迁入右键菜单(dsh-notes-ctxmenu),不再用悬浮 × 按钮 */
|
|
138
153
|
.dsh-note-jump{display:none} /* 跳转并入 meta 里的会话,不再单独按钮 */
|
|
139
154
|
.dsh-note-topic-picker{display:none} /* 主题改到详情区编辑,列表不再内联选择器 */
|
|
140
155
|
|
|
141
156
|
/* ===== 详情区(阅读 + 编辑) ===== */
|
|
142
157
|
.dsh-notes-editor{flex:1;min-width:0;display:flex;flex-direction:column;overflow:hidden;background:var(--nbg)}
|
|
143
158
|
.dsh-notes-editor-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--nt3);gap:12px;padding:30px;text-align:center;font-size:13px;background:var(--nbg)}
|
|
144
|
-
.dsh-notes-editor-empty-ic{font-size:
|
|
159
|
+
.dsh-notes-editor-empty-ic{font-size:30px;opacity:.55;line-height:1;display:inline-flex;align-items:center;justify-content:center;width:60px;height:60px;border-radius:50%;background:var(--nbg-hover);margin-bottom:4px}
|
|
145
160
|
.dsh-notes-editor-empty-t{font-size:15px;font-weight:600;color:var(--nt2)}
|
|
146
161
|
.dsh-notes-editor-empty-s{font-size:12px;color:var(--nt3)}
|
|
147
162
|
|
|
@@ -157,6 +172,20 @@
|
|
|
157
172
|
.dsh-notes-ed-topic{background:transparent;border:1px solid transparent;border-radius:6px;color:var(--nacc);font-size:12px;padding:4px 8px;font-family:var(--nfont);outline:none;max-width:140px;transition:border-color .15s,background .15s}
|
|
158
173
|
.dsh-notes-ed-topic:hover{background:var(--nbg-hover)}
|
|
159
174
|
.dsh-notes-ed-topic:focus{border-color:var(--nacc);background:var(--nbg)}
|
|
175
|
+
/* 详情区 kind tint chip(低饱和 tint 底 + 同系深色字,明暗均可读) */
|
|
176
|
+
.dsh-notes-ed-kind-chip{border-radius:13px;font-weight:600;border:1px solid transparent;padding:4px 10px}
|
|
177
|
+
.dsh-notes-ed-kind-chip.dsh-notes-ed-kind-note{background:rgba(10,132,255,.13);color:#0a84ff}
|
|
178
|
+
.dsh-notes-ed-kind-chip.dsh-notes-ed-kind-decision{background:rgba(191,90,242,.13);color:#bf5af2}
|
|
179
|
+
.dsh-notes-ed-kind-chip.dsh-notes-ed-kind-todo{background:rgba(255,149,0,.15);color:#ff9500}
|
|
180
|
+
.dsh-notes-ed-kind-chip.dsh-notes-ed-kind-link{background:rgba(90,200,250,.16);color:#0a9fc4}
|
|
181
|
+
.dsh-notes-ed-kind-chip.dsh-notes-ed-kind-quote{background:rgba(255,55,95,.13);color:#ff375f}
|
|
182
|
+
/* 详情区标签输入(灰色小胶囊形态) */
|
|
183
|
+
.dsh-notes-ed-tags-input{background:var(--nbg-hover);border:1px solid transparent;border-radius:11px;color:var(--nt2);font-size:11px;padding:3px 10px;font-family:var(--nfont);outline:none;max-width:160px;transition:border-color .15s,background .15s}
|
|
184
|
+
.dsh-notes-ed-tags-input:hover{background:var(--nbg-sel)}
|
|
185
|
+
.dsh-notes-ed-tags-input:focus{border-color:var(--nacc);background:var(--nbg);color:var(--ntx)}
|
|
186
|
+
/* 详情区标签 chip 行(灰色小胶囊,与列表项同款) */
|
|
187
|
+
.dsh-notes-ed-tags-chips{display:flex;flex-wrap:wrap;gap:5px;align-items:center}
|
|
188
|
+
.dsh-notes-ed-tag-chip{background:var(--nbg-hover);border-radius:10px;color:var(--nt2);font-size:10px;padding:2px 9px;font-weight:500;white-space:nowrap;line-height:1.5}
|
|
160
189
|
.dsh-notes-ed-inject{background:transparent;border:1px solid var(--nbd);border-radius:6px;color:var(--nt2);font-size:11px;padding:4px 8px;font-family:var(--nmono);outline:none;width:120px}
|
|
161
190
|
.dsh-notes-ed-inject:focus{border-color:var(--nacc);color:var(--ntx)}
|
|
162
191
|
.dsh-notes-ed-meta-right{margin-left:auto;display:flex;gap:4px;align-items:center}
|
|
@@ -174,7 +203,7 @@
|
|
|
174
203
|
/* 范围浮层触发按钮 */
|
|
175
204
|
.dsh-notes-ed-scope-wrap{position:relative;flex:1;min-width:0}
|
|
176
205
|
.dsh-notes-scope-trigger{background:transparent;border:1px solid var(--nbd);border-radius:6px;color:var(--ntx);font-size:12px;padding:4px 10px;cursor:pointer;transition:border-color .15s;font-family:var(--nfont);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}
|
|
177
|
-
.dsh-notes-scope-trigger:hover{border-color:var(--
|
|
206
|
+
.dsh-notes-scope-trigger:hover{border-color:var(--nt3)}
|
|
178
207
|
.dsh-notes-scope-caret{color:var(--nt3);font-size:10px}
|
|
179
208
|
/* 逐级浮层面板 */
|
|
180
209
|
.dsh-notes-scope-panel{position:absolute;top:calc(100% + 4px);left:0;min-width:230px;max-width:300px;max-height:280px;overflow-y:auto;background:var(--nbg);border:1px solid var(--nbd);border-radius:10px;box-shadow:var(--nshadow);padding:6px;z-index:30;font-family:var(--nfont)}
|
|
@@ -189,7 +218,7 @@
|
|
|
189
218
|
.dsh-notes-dispatch-mask{position:fixed;inset:0;background:rgba(0,0,0,.28);z-index:60;display:flex;align-items:center;justify-content:center}
|
|
190
219
|
.dsh-notes-dispatch-modal{width:340px;max-width:90%;background:var(--nbg);border:1px solid var(--nbd);border-radius:14px;box-shadow:0 20px 60px rgba(0,0,0,.3);padding:16px;font-family:var(--nfont);max-height:80vh;overflow-y:auto}
|
|
191
220
|
.dsh-notes-dispatch-modal-t{font-size:14px;font-weight:700;color:var(--ntx);margin-bottom:10px}
|
|
192
|
-
.dsh-notes-dispatch-todo{background:var(--
|
|
221
|
+
.dsh-notes-dispatch-todo{background:var(--nsf);border:1px solid var(--nbd-soft);border-radius:8px;padding:9px 11px;margin-bottom:10px}
|
|
193
222
|
.dsh-notes-dispatch-todo-t{font-size:12px;font-weight:600;color:var(--ntx);margin-bottom:3px}
|
|
194
223
|
.dsh-notes-dispatch-todo-b{font-size:11px;color:var(--nt3);line-height:1.5;max-height:60px;overflow:hidden;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical}
|
|
195
224
|
.dsh-notes-dispatch-instr{width:100%;box-sizing:border-box;background:var(--nbg);border:1px solid var(--nbd);border-radius:8px;color:var(--ntx);font-size:12px;padding:8px 10px;resize:vertical;font-family:var(--nfont);margin-bottom:10px;outline:none}
|
|
@@ -205,36 +234,74 @@
|
|
|
205
234
|
.dsh-notes-dispatch-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:4px}
|
|
206
235
|
.dsh-notes-dispatch-cancel{background:transparent;border:1px solid var(--nbd);border-radius:7px;color:var(--nt2);font-size:12px;padding:6px 16px;cursor:pointer;font-family:var(--nfont)}
|
|
207
236
|
.dsh-notes-dispatch-cancel:hover{border-color:var(--nt3);color:var(--ntx)}
|
|
208
|
-
.dsh-notes-dispatch-ok{background:var(--nacc);border:none;border-radius:7px;color
|
|
237
|
+
.dsh-notes-dispatch-ok{background:var(--nacc);border:none;border-radius:7px;color:var(--dsw-alias-label-primary-foreground,#fff);font-size:12px;font-weight:600;padding:6px 16px;cursor:pointer;font-family:var(--nfont)}
|
|
209
238
|
.dsh-notes-dispatch-ok:hover{filter:brightness(1.08)}
|
|
210
239
|
.dsh-notes-dispatch-ok:disabled{opacity:.5;cursor:not-allowed}
|
|
211
240
|
/* ===== 派发历史(详情区) ===== */
|
|
212
|
-
|
|
213
|
-
.dsh-notes-dispatch-history
|
|
214
|
-
.dsh-notes-dispatch-
|
|
241
|
+
/* 派发历史(可折叠:默认 collapsed 只占一行标题;点击标题行切换 open/collapsed,不挤压正文) */
|
|
242
|
+
.dsh-notes-dispatch-history{margin:10px 20px 10px;padding-top:10px;border-top:1px dashed var(--nbd-soft)} /* 左右 20px 与正文(ed-body/preview padding)对齐 */
|
|
243
|
+
.dsh-notes-dispatch-history-t{font-size:11px;font-weight:600;color:var(--nt2);margin-bottom:6px;cursor:pointer;user-select:none;display:flex;align-items:center;gap:5px;transition:color .15s}
|
|
244
|
+
.dsh-notes-dispatch-history-t:hover{color:var(--ntx)}
|
|
245
|
+
.dsh-notes-dispatch-history.collapsed{margin-bottom:6px}
|
|
246
|
+
.dsh-notes-dispatch-history.collapsed .dsh-notes-dispatch-history-t{margin-bottom:0}
|
|
247
|
+
.dsh-notes-dispatch-rec{padding:5px 8px;border-radius:6px;background:var(--nsf);border:1px solid var(--nbd-soft);margin-bottom:4px}
|
|
215
248
|
.dsh-notes-dispatch-rec-top{display:flex;justify-content:space-between;align-items:baseline;gap:8px}
|
|
216
249
|
.dsh-notes-dispatch-rec-t{font-size:11px;font-weight:600;color:var(--nacc)}
|
|
217
250
|
.dsh-notes-dispatch-rec-m{font-size:10px;color:var(--nt3);flex-shrink:0}
|
|
218
251
|
.dsh-notes-dispatch-rec-i{font-size:10px;color:var(--nt2);margin-top:2px;line-height:1.4}
|
|
219
252
|
.dsh-notes-dispatch-rec.done{opacity:.55}
|
|
220
253
|
.dsh-notes-dispatch-rec.done .dsh-notes-dispatch-rec-t{color:var(--nt3)}
|
|
221
|
-
.dsh-notes-dispatch-done-btn{margin-top:4px;background:transparent;border:
|
|
222
|
-
.dsh-notes-dispatch-done-btn:hover{
|
|
254
|
+
.dsh-notes-dispatch-done-btn{margin-top:4px;background:transparent;border:none;border-radius:0;color:var(--nacc);font-size:10px;padding:1px 4px;cursor:pointer;font-family:var(--nfont);transition:color .15s;text-decoration:none}
|
|
255
|
+
.dsh-notes-dispatch-done-btn:hover{text-decoration:underline}
|
|
256
|
+
/* 派发待处理状态点(橙色圆点) */
|
|
257
|
+
.dsh-notes-dispatch-dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--nwarn,#ff9500);margin-right:5px;vertical-align:middle;flex-shrink:0}
|
|
223
258
|
|
|
224
259
|
/* 详情操作按钮(右上角 icon) */
|
|
225
260
|
.dsh-notes-ed-action{background:transparent;border:1px solid var(--nbd);border-radius:6px;color:var(--nt2);font-size:12px;cursor:pointer;padding:4px 10px;line-height:1;transition:all .15s;font-family:var(--nfont)}
|
|
226
261
|
.dsh-notes-ed-action:hover{background:var(--nbg-hover);color:var(--ntx)}
|
|
227
262
|
.dsh-notes-ed-action.on{background:var(--nacc-soft);border-color:var(--nacc);color:var(--nacc)}
|
|
228
263
|
.dsh-notes-ed-action.danger:hover{color:#ff3b30;border-color:rgba(255,59,48,.4);background:rgba(255,59,48,.06)}
|
|
264
|
+
/* 派发主按钮:主题色描边 + 浅色底(hover 加深)。
|
|
265
|
+
须置于 .dsh-notes-ed-action 基础规则之后——派发按钮同时带 ed-action 与 dispatch-btn 两个类,
|
|
266
|
+
同优先级(0-1-0)下后定义者胜,否则 ed-action 的透明底/灰字会覆盖派发按钮主样式。 */
|
|
267
|
+
.dsh-notes-dispatch-btn{background:var(--nacc-soft);border:1px solid var(--nacc);color:var(--nacc);font-weight:600}
|
|
268
|
+
.dsh-notes-dispatch-btn:hover{background:var(--nacc);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--nacc)}
|
|
229
269
|
|
|
230
270
|
/* 正文(无边框、宽行高、自动保存) */
|
|
231
|
-
.dsh-notes-editor-body{flex:1;min-height:0;background:transparent;border:none;outline:none;color:var(--ntx);padding:
|
|
271
|
+
.dsh-notes-editor-body{flex:1;min-height:0;background:transparent;border:none;outline:none;color:var(--ntx-soft);caret-color:var(--nacc);padding:18px 24px 24px;font-size:14px;font-family:var(--nfont);line-height:1.78;resize:none;margin:0;box-sizing:border-box;letter-spacing:.2px;text-rendering:optimizeLegibility;font-synthesis-weight:none}
|
|
232
272
|
.dsh-notes-editor-body::placeholder{color:var(--nt3)}
|
|
233
273
|
.dsh-notes-editor-body.mono{font-family:var(--nmono);font-size:13px;line-height:1.6}
|
|
234
274
|
|
|
275
|
+
/* ===== Markdown 预览态(dsh-notes-preview-* 前缀,走既有 token 体系)===== */
|
|
276
|
+
.dsh-notes-preview-container{flex:1;min-height:0;overflow-y:auto;padding:18px 24px 24px;font-size:14px;font-family:var(--nfont);line-height:1.78;color:var(--ntx-soft);letter-spacing:.2px;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;font-synthesis-weight:none}
|
|
277
|
+
.dsh-notes-preview-container::-webkit-scrollbar{width:8px}
|
|
278
|
+
.dsh-notes-preview-container::-webkit-scrollbar-thumb{background:var(--nbd);border-radius:4px}
|
|
279
|
+
.dsh-notes-preview-container::-webkit-scrollbar-thumb:hover{background:var(--nt3)}
|
|
280
|
+
.dsh-notes-preview-container>:first-child{margin-top:0}
|
|
281
|
+
.dsh-notes-preview-container>:last-child{margin-bottom:0}
|
|
282
|
+
.dsh-notes-preview-p{margin:0 0 14px;word-break:break-word}
|
|
283
|
+
.dsh-notes-preview-h1{font-size:19px;font-weight:700;margin:24px 0 12px;color:var(--ntx);letter-spacing:.3px}
|
|
284
|
+
.dsh-notes-preview-h2{font-size:16.5px;font-weight:600;margin:20px 0 10px;color:var(--ntx);letter-spacing:.2px}
|
|
285
|
+
.dsh-notes-preview-h3{font-size:14.5px;font-weight:600;margin:16px 0 8px;color:var(--ntx)}
|
|
286
|
+
.dsh-notes-preview-code{background:var(--nbg-hover,var(--nsf));border:1px solid var(--nbd-soft);border-radius:var(--nr-md);padding:14px 16px;margin:0 0 14px;overflow-x:auto;font-family:var(--nmono);font-size:13px;line-height:1.65}
|
|
287
|
+
.dsh-notes-preview-code code{background:none;border:none;padding:0;font-family:inherit;font-size:inherit;color:var(--ntx)}
|
|
288
|
+
.dsh-notes-preview-container code{background:var(--nbg-hover,var(--nsf));border:1px solid var(--nbd-soft);border-radius:4px;padding:1px 6px;font-family:var(--nmono);font-size:12.5px;color:var(--ntx)}
|
|
289
|
+
.dsh-notes-preview-container pre code{background:none;border:none;padding:0;font-size:inherit}
|
|
290
|
+
.dsh-notes-preview-ul,.dsh-notes-preview-ol{margin:0 0 14px;padding-left:24px}
|
|
291
|
+
.dsh-notes-preview-ul li,.dsh-notes-preview-ol li{margin-bottom:5px;word-break:break-word}
|
|
292
|
+
.dsh-notes-preview-quote{margin:0 0 14px;padding:10px 16px;border-left:3px solid var(--nbd);background:var(--nbg-hover,var(--nsf));border-radius:0 var(--nr-sm) var(--nr-sm) 0;color:var(--nt2)} /* 中文排版忌斜体:去 italic,左边框用中性色 */
|
|
293
|
+
.dsh-notes-preview-container a{color:var(--nacc);text-decoration:none;border-bottom:1px solid transparent;transition:border-color .15s}
|
|
294
|
+
.dsh-notes-preview-container a:hover{border-bottom-color:var(--nacc)}
|
|
295
|
+
.dsh-notes-preview-container strong{font-weight:600;color:var(--ntx)}
|
|
296
|
+
.dsh-notes-preview-container em{font-style:italic}
|
|
297
|
+
/* 预览/编辑切换按钮(详情底部状态条左侧) */
|
|
298
|
+
.dsh-notes-preview-toggle{background:transparent;border:1px solid var(--nbd);border-radius:var(--nr-sm);color:var(--nt2);font-size:11px;padding:3px 10px;cursor:pointer;transition:all .15s;font-family:var(--nfont);line-height:1.5;white-space:nowrap;flex-shrink:0}
|
|
299
|
+
.dsh-notes-preview-toggle:hover{border-color:var(--nacc);color:var(--nacc);background:var(--nacc-soft)}
|
|
300
|
+
.dsh-notes-preview-toggle.on{background:var(--nacc-soft);border-color:var(--nacc);color:var(--nacc);font-weight:600}
|
|
301
|
+
|
|
235
302
|
/* 详情底部:轻量状态条(保存提示 + 字数) */
|
|
236
|
-
.dsh-notes-ed-foot{display:flex;align-items:center;justify-content:space-between;padding:
|
|
237
|
-
.dsh-notes-ed-saved{opacity:0;transition:opacity .2s;color:var(--
|
|
303
|
+
.dsh-notes-ed-foot{display:flex;align-items:center;justify-content:space-between;padding:8px 24px 12px;font-size:11px;color:var(--nt3);flex-shrink:0;border-top:1px solid var(--nbd-soft)}
|
|
304
|
+
.dsh-notes-ed-saved{opacity:0;transition:opacity .2s;color:var(--nt3)} /* 保存提示收敛为三级灰,不再绿色跳眼 */
|
|
238
305
|
.dsh-notes-ed-saved.show{opacity:1}
|
|
239
306
|
|
|
240
307
|
/* ===== 状态与反馈 ===== */
|
|
@@ -244,7 +311,7 @@
|
|
|
244
311
|
.dsh-notes-empty-ic{font-size:34px;opacity:.4;line-height:1;margin-bottom:4px}
|
|
245
312
|
.dsh-notes-empty-t{font-size:14px;font-weight:600;color:var(--nt2)}
|
|
246
313
|
.dsh-notes-empty-s{font-size:12px;color:var(--nt3);line-height:1.6;max-width:220px}
|
|
247
|
-
.dsh-notes-empty-btn{margin-top:10px;background:var(--nacc);color
|
|
314
|
+
.dsh-notes-empty-btn{margin-top:10px;background:var(--nacc);color:var(--dsw-alias-label-primary-foreground,#fff);border:none;border-radius:var(--nr-md);padding:7px 18px;font-size:12px;font-weight:500;cursor:pointer;transition:filter .15s;font-family:var(--nfont)}
|
|
248
315
|
.dsh-notes-empty-btn:hover{filter:brightness(1.06)}
|
|
249
316
|
/* 搜索高亮(琥珀色,深浅通用;明暗随 DSH 主题,不再用系统级 prefers-color-scheme) */
|
|
250
317
|
.dsh-notes-mark{background:rgba(255,213,79,.35);color:inherit;border-radius:2px;padding:0 1px}
|
|
@@ -264,7 +331,7 @@
|
|
|
264
331
|
|
|
265
332
|
/* ===== 选区快速记录浮动按钮 ===== */
|
|
266
333
|
/* 注意:此按钮 position:fixed 且不在 .dsh-notes-floating 内,拿不到面板的设计令牌变量,必须用具体颜色值 */
|
|
267
|
-
.dsh-notes-sel-btn{position:fixed;z-index:2147483646;background:#0a84ff;color
|
|
334
|
+
.dsh-notes-sel-btn{position:fixed;z-index:2147483646;background:#0a84ff;color:var(--dsw-alias-label-primary-foreground,#fff);border:none;border-radius:8px;padding:7px 14px;font-size:12px;font-weight:600;cursor:pointer;box-shadow:0 4px 16px rgba(10,132,255,.5),0 1px 3px rgba(0,0,0,.2);line-height:1;white-space:nowrap;transition:filter .15s,transform .1s;font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",system-ui,sans-serif}
|
|
268
335
|
.dsh-notes-sel-btn:hover{filter:brightness(1.08);transform:translateY(-1px)}
|
|
269
336
|
|
|
270
337
|
/* ===== T3 选区指令框(划选后弹出:预览 + 备注输入 + 记录/取消) ===== */
|
|
@@ -276,7 +343,7 @@
|
|
|
276
343
|
--nt2:var(--dsw-alias-label-secondary,#6c6c70);
|
|
277
344
|
--nt3:var(--dsw-alias-label-secondary,#aeaeb2);
|
|
278
345
|
--nacc:var(--dsw-alias-brand-primary,#0a84ff);
|
|
279
|
-
--nbg-hover:
|
|
346
|
+
--nbg-hover:rgba(128,128,128,.08); /* color-mix 兜底(避免亮色下与面板底色撞色) */
|
|
280
347
|
--nr-md:8px;
|
|
281
348
|
--nfont:-apple-system,BlinkMacSystemFont,"SF Pro Text","PingFang SC","Microsoft YaHei",system-ui,sans-serif;
|
|
282
349
|
position:fixed;z-index:2147483646;width:320px;background:var(--nbg);border:1px solid var(--nbd);border-radius:12px;
|
|
@@ -289,14 +356,14 @@
|
|
|
289
356
|
.dsh-notes-instruct-actions{display:flex;gap:8px;padding:8px 11px;justify-content:flex-end}
|
|
290
357
|
.dsh-notes-instruct-btn{background:transparent;border:1px solid var(--nbd);border-radius:var(--nr-md);color:var(--nt2);padding:6px 14px;cursor:pointer;font-size:12px;font-weight:500;font-family:var(--nfont);line-height:1;transition:all .15s}
|
|
291
358
|
.dsh-notes-instruct-btn:hover{border-color:var(--nt3);color:var(--ntx)}
|
|
292
|
-
.dsh-notes-instruct-btn.primary{background:var(--nacc);color
|
|
293
|
-
.dsh-notes-instruct-btn.primary:hover{filter:brightness(
|
|
359
|
+
.dsh-notes-instruct-btn.primary{background:var(--nacc);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--nacc)}
|
|
360
|
+
.dsh-notes-instruct-btn.primary:hover{filter:brightness(0.9);color:var(--dsw-alias-label-primary-foreground,#fff)}
|
|
294
361
|
|
|
295
362
|
/* ===== 旧类名兼容(已废弃,保留避免渲染期报错;后续清理 client 引用) ===== */
|
|
296
363
|
.dsh-notes-capture{padding:10px 14px;border-bottom:1px solid var(--nbd-soft);display:flex;gap:8px;background:var(--nbg);flex-shrink:0;align-items:flex-end}
|
|
297
364
|
.dsh-notes-capture-input{flex:1;min-width:0;background:var(--nbg-hover);border:1px solid transparent;border-radius:var(--nr-md);color:var(--ntx);padding:8px 11px;font-size:13px;resize:none;height:36px;min-height:36px;max-height:110px;font-family:var(--nfont);box-sizing:border-box;transition:border-color .15s,background .15s;line-height:1.5;outline:none}
|
|
298
365
|
.dsh-notes-capture-input:focus{border-color:var(--nacc);background:var(--nbg)}
|
|
299
|
-
.dsh-notes-capture-btn{background:var(--nacc);color
|
|
366
|
+
.dsh-notes-capture-btn{background:var(--nacc);color:var(--dsw-alias-label-primary-foreground,#fff);border:none;border-radius:var(--nr-md);padding:0 15px;height:36px;cursor:pointer;font-size:13px;font-weight:500;white-space:nowrap;flex-shrink:0;transition:filter .15s}
|
|
300
367
|
.dsh-notes-capture-btn:hover:not(:disabled){filter:brightness(1.06)}
|
|
301
368
|
.dsh-notes-capture-btn:disabled{opacity:.4;cursor:default}
|
|
302
369
|
.dsh-notes-capture-btn.saved{background:#34c759}
|
|
@@ -306,7 +373,14 @@
|
|
|
306
373
|
.dsh-notes-editor-topic{flex:1;min-width:0}
|
|
307
374
|
.dsh-notes-editor-tags{flex:1.5;min-width:0}
|
|
308
375
|
.dsh-notes-editor-actions{padding:0 14px 14px;display:flex;gap:8px;flex-shrink:0}
|
|
309
|
-
.dsh-notes-save-btn{background:var(--nacc);color
|
|
376
|
+
.dsh-notes-save-btn{background:var(--nacc);color:var(--dsw-alias-label-primary-foreground,#fff);border:none;border-radius:var(--nr-md);padding:8px 16px;cursor:pointer;font-size:13px;font-weight:500;transition:filter .15s}
|
|
310
377
|
.dsh-notes-save-btn:hover{filter:brightness(1.06)}
|
|
311
378
|
.dsh-notes-delete-btn{background:transparent;color:var(--nt3);border:1px solid var(--nbd);border-radius:var(--nr-md);padding:8px 16px;cursor:pointer;font-size:13px;font-weight:500;transition:all .15s}
|
|
312
379
|
.dsh-notes-delete-btn:hover{color:#ff3b30;border-color:rgba(255,59,48,.4)}
|
|
380
|
+
|
|
381
|
+
/* 列表项右键菜单(替代悬浮 ×):面板风格、点击外部/Esc 关闭 */
|
|
382
|
+
.dsh-notes-ctxmenu{position:absolute;z-index:60;min-width:150px;background:var(--nbg);border:1px solid var(--nbd);border-radius:var(--nr-md);box-shadow:0 6px 24px rgba(0,0,0,.14);padding:4px;display:flex;flex-direction:column;gap:1px}
|
|
383
|
+
.dsh-notes-ctxmenu-item{display:flex;align-items:center;gap:7px;background:transparent;border:none;color:var(--ntx);font-size:12px;text-align:left;padding:6px 10px;border-radius:6px;cursor:pointer;transition:background .1s;font-family:var(--nfont)}
|
|
384
|
+
.dsh-notes-ctxmenu-item:hover{background:var(--nbg-hover)}
|
|
385
|
+
.dsh-notes-ctxmenu-item.danger{color:var(--ntx)}
|
|
386
|
+
.dsh-notes-ctxmenu-item.danger:hover{color:#ff3b30;background:rgba(255,59,48,.08)}
|
package/package.json
CHANGED