@lemoncat7/dsh-knowledge 2.2.1 → 2.2.8
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/docs/architecture.md +5 -5
- package/lib/api.d.ts.map +1 -1
- package/lib/api.js +55 -24
- package/lib/api.js.map +1 -1
- package/lib/async-pool.d.ts +7 -0
- package/lib/async-pool.d.ts.map +1 -0
- package/lib/async-pool.js +21 -0
- package/lib/async-pool.js.map +1 -0
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +53 -17
- package/lib/client.js.map +2 -2
- package/lib/domain.d.ts +16 -0
- package/lib/domain.d.ts.map +1 -1
- package/lib/domain.js.map +1 -1
- package/lib/extraction.d.ts +3 -0
- package/lib/extraction.d.ts.map +1 -1
- package/lib/extraction.js +65 -11
- package/lib/extraction.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +101 -29
- package/lib/index.js.map +1 -1
- package/lib/local-provider.d.ts +13 -2
- package/lib/local-provider.d.ts.map +1 -1
- package/lib/local-provider.js +307 -73
- package/lib/local-provider.js.map +1 -1
- package/lib/note-tools.js +4 -4
- package/lib/note-tools.js.map +1 -1
- package/lib/provider-router.d.ts +6 -2
- package/lib/provider-router.d.ts.map +1 -1
- package/lib/provider-router.js +10 -6
- package/lib/provider-router.js.map +1 -1
- package/lib/provider.d.ts +4 -2
- package/lib/provider.d.ts.map +1 -1
- package/lib/remote-provider.d.ts +4 -2
- package/lib/remote-provider.d.ts.map +1 -1
- package/lib/remote-provider.js +22 -2
- package/lib/remote-provider.js.map +1 -1
- package/lib/retrieval.d.ts.map +1 -1
- package/lib/retrieval.js +9 -7
- package/lib/retrieval.js.map +1 -1
- package/lib/tool-authorization.d.ts +3 -1
- package/lib/tool-authorization.d.ts.map +1 -1
- package/lib/tool-authorization.js +27 -14
- package/lib/tool-authorization.js.map +1 -1
- package/lib/tools.js +1 -1
- package/lib/tools.js.map +1 -1
- package/lib/tracking.d.ts.map +1 -1
- package/lib/tracking.js +8 -3
- package/lib/tracking.js.map +1 -1
- package/lib/web-workspace-effects.d.ts.map +1 -1
- package/lib/web-workspace-effects.js +10 -1
- package/lib/web-workspace-effects.js.map +1 -1
- package/lib/web.d.ts.map +1 -1
- package/lib/web.js +7 -4
- package/lib/web.js.map +1 -1
- package/package.json +2 -2
- package/web/app.js +215 -21
- package/web/styles.css +31 -17
- package/web/workspace-effects.js +2 -2
package/web/app.js
CHANGED
|
@@ -22,6 +22,7 @@ const WRITE_MODE_LABELS = { none: '仅召回', audit: '审核写入', direct: '
|
|
|
22
22
|
const EVIDENCE_LABELS = { explicit: '用户明确', verified: '结果已验证', inferred: '模型推断' }
|
|
23
23
|
const DOCUMENT_STATE_LABELS = { open: '进行中', resolved: '已解决', complete: '已收集完成' }
|
|
24
24
|
const DOCUMENT_LAYOUT_KEY = 'dsh-knowledge.document-layout'
|
|
25
|
+
const KNOWLEDGE_DOCUMENT_DRAG_TYPE = 'application/x-dsh-knowledge-document-id'
|
|
25
26
|
const NOTE_MAX_FILE_SIZE = 64 * 1024 * 1024
|
|
26
27
|
const pageParams = new URLSearchParams(location.search)
|
|
27
28
|
const mountContext = {
|
|
@@ -100,7 +101,10 @@ let navigationRequest = 0
|
|
|
100
101
|
let navigationSave = Promise.resolve(true)
|
|
101
102
|
let libraryDetailRequest = 0
|
|
102
103
|
let documentSearchTimer = 0
|
|
104
|
+
let documentSearchController = null
|
|
103
105
|
let noteSearchTimer = 0
|
|
106
|
+
let noteSearchController = null
|
|
107
|
+
let noteSearchRequest = 0
|
|
104
108
|
let markdownEditorHandle = null
|
|
105
109
|
let noteEditorLoader = null
|
|
106
110
|
let markdownEditorMountRequest = 0
|
|
@@ -109,6 +113,8 @@ let plainTextEditorMountRequest = 0
|
|
|
109
113
|
let noteTransferFrame = 0
|
|
110
114
|
let noteTransferSequence = 0
|
|
111
115
|
let noteSelectionRequest = 0
|
|
116
|
+
let knowledgeDocumentDrag = null
|
|
117
|
+
let movingDocumentId = ''
|
|
112
118
|
|
|
113
119
|
function installHostThemeBridge() {
|
|
114
120
|
if (window.parent === window) return Promise.resolve()
|
|
@@ -442,6 +448,7 @@ function renderLogin(message = '') {
|
|
|
442
448
|
}
|
|
443
449
|
|
|
444
450
|
function signOut() {
|
|
451
|
+
cancelPendingSearches()
|
|
445
452
|
releaseNoteEditors()
|
|
446
453
|
releaseNoteAsset()
|
|
447
454
|
sessionStorage.removeItem(TOKEN_KEY)
|
|
@@ -455,6 +462,7 @@ async function navigate(view) {
|
|
|
455
462
|
const request = ++navigationRequest
|
|
456
463
|
navigationSave = navigationSave.then(() => saveBeforeNavigation(), () => saveBeforeNavigation())
|
|
457
464
|
if (!await navigationSave || request !== navigationRequest) return
|
|
465
|
+
cancelPendingSearches()
|
|
458
466
|
navigationController?.abort()
|
|
459
467
|
const controller = new AbortController()
|
|
460
468
|
navigationController = controller
|
|
@@ -489,6 +497,20 @@ async function navigate(view) {
|
|
|
489
497
|
}
|
|
490
498
|
}
|
|
491
499
|
|
|
500
|
+
function cancelPendingSearches() {
|
|
501
|
+
state.documentView.searchRequest += 1
|
|
502
|
+
state.libraryDetail.view.searchRequest += 1
|
|
503
|
+
noteSearchRequest += 1
|
|
504
|
+
window.clearTimeout(documentSearchTimer)
|
|
505
|
+
window.clearTimeout(noteSearchTimer)
|
|
506
|
+
documentSearchController?.abort()
|
|
507
|
+
noteSearchController?.abort()
|
|
508
|
+
documentSearchController = null
|
|
509
|
+
noteSearchController = null
|
|
510
|
+
documentSearchTimer = 0
|
|
511
|
+
noteSearchTimer = 0
|
|
512
|
+
}
|
|
513
|
+
|
|
492
514
|
function loadingPhaseForView(view) {
|
|
493
515
|
return ({
|
|
494
516
|
overview: '正在汇总知识活动', bases: '正在读取知识库配置', entries: '正在读取知识目录',
|
|
@@ -739,7 +761,10 @@ function resetDocumentSearch(view) {
|
|
|
739
761
|
|
|
740
762
|
function scheduleDocumentSearch(workspace) {
|
|
741
763
|
window.clearTimeout(documentSearchTimer)
|
|
764
|
+
documentSearchController?.abort()
|
|
765
|
+
documentSearchController = null
|
|
742
766
|
const view = workspace.view
|
|
767
|
+
view.searchRequest += 1
|
|
743
768
|
if (!view.query.trim()) {
|
|
744
769
|
resetDocumentSearch(view)
|
|
745
770
|
renderShell()
|
|
@@ -747,7 +772,6 @@ function scheduleDocumentSearch(workspace) {
|
|
|
747
772
|
}
|
|
748
773
|
view.searchLoading = true
|
|
749
774
|
view.searchError = ''
|
|
750
|
-
renderShell()
|
|
751
775
|
documentSearchTimer = window.setTimeout(() => { void loadDocumentSearch(workspace, true) }, 220)
|
|
752
776
|
}
|
|
753
777
|
|
|
@@ -765,6 +789,9 @@ async function loadDocumentSearch(workspace, reset = false) {
|
|
|
765
789
|
const query = view.query.trim()
|
|
766
790
|
if (!query) return resetDocumentSearch(view)
|
|
767
791
|
const request = ++view.searchRequest
|
|
792
|
+
documentSearchController?.abort()
|
|
793
|
+
const controller = new AbortController()
|
|
794
|
+
documentSearchController = controller
|
|
768
795
|
view.searchLoading = true
|
|
769
796
|
view.searchError = ''
|
|
770
797
|
const params = new URLSearchParams({ q: query, limit: '80' })
|
|
@@ -783,7 +810,7 @@ async function loadDocumentSearch(workspace, reset = false) {
|
|
|
783
810
|
}
|
|
784
811
|
if (!reset && view.searchNextCursor) params.set('cursor', view.searchNextCursor)
|
|
785
812
|
try {
|
|
786
|
-
const result = await api(`document-index?${params}
|
|
813
|
+
const result = await api(`document-index?${params}`, { signal: controller.signal })
|
|
787
814
|
if (request !== view.searchRequest || query !== view.query.trim()) return
|
|
788
815
|
const merged = new Map((reset ? [] : view.searchResults).map(document => [document.id, document]))
|
|
789
816
|
for (const item of result.items) merged.set(item.id, item)
|
|
@@ -791,9 +818,11 @@ async function loadDocumentSearch(workspace, reset = false) {
|
|
|
791
818
|
view.searchNextCursor = result.nextCursor || ''
|
|
792
819
|
view.searchTotal = result.total
|
|
793
820
|
} catch (error) {
|
|
821
|
+
if (controller.signal.aborted) return
|
|
794
822
|
if (request !== view.searchRequest) return
|
|
795
823
|
view.searchError = friendlyError(error)
|
|
796
824
|
} finally {
|
|
825
|
+
if (documentSearchController === controller) documentSearchController = null
|
|
797
826
|
if (request === view.searchRequest) {
|
|
798
827
|
view.searchLoading = false
|
|
799
828
|
renderDocumentSearchState(workspace)
|
|
@@ -956,26 +985,119 @@ async function saveDocumentEditor(workspace = activeDocumentWorkspace()) {
|
|
|
956
985
|
}
|
|
957
986
|
}
|
|
958
987
|
|
|
988
|
+
function activateKnowledgeBaseDropTarget(event, workspace, baseId) {
|
|
989
|
+
const drag = knowledgeDocumentDrag
|
|
990
|
+
if (!drag || drag.workspaceKind !== workspace.kind || drag.sourceBaseId === baseId) return
|
|
991
|
+
if (!hasDragType(event, KNOWLEDGE_DOCUMENT_DRAG_TYPE)) return
|
|
992
|
+
event.preventDefault()
|
|
993
|
+
event.stopPropagation()
|
|
994
|
+
if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'
|
|
995
|
+
document.querySelectorAll('.note-tree-group[data-drop-target="true"]').forEach(target => {
|
|
996
|
+
if (target !== event.currentTarget) target.dataset.dropTarget = 'false'
|
|
997
|
+
})
|
|
998
|
+
event.currentTarget.dataset.dropTarget = 'true'
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
function clearKnowledgeDocumentDragState() {
|
|
1002
|
+
knowledgeDocumentDrag = null
|
|
1003
|
+
document.querySelectorAll('.note-tree-group[data-drop-target="true"]').forEach(node => { node.dataset.dropTarget = 'false' })
|
|
1004
|
+
document.querySelectorAll('.note-tree-document[data-dragging="true"]').forEach(node => { node.dataset.dragging = 'false' })
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
function dropKnowledgeDocument(event, workspace, targetBaseId) {
|
|
1008
|
+
const documentId = event.dataTransfer?.getData(KNOWLEDGE_DOCUMENT_DRAG_TYPE) || ''
|
|
1009
|
+
const source = documentWorkspaceDocuments(workspace).find(document => document.id === documentId)
|
|
1010
|
+
if (!documentId || !source || source.knowledgeBaseId === targetBaseId) return
|
|
1011
|
+
event.preventDefault()
|
|
1012
|
+
event.stopPropagation()
|
|
1013
|
+
clearKnowledgeDocumentDragState()
|
|
1014
|
+
void moveKnowledgeDocument(workspace, documentId, targetBaseId)
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
async function moveKnowledgeDocument(workspace, documentId, targetBaseId) {
|
|
1018
|
+
const bases = documentWorkspaceBases(workspace)
|
|
1019
|
+
const target = bases.find(base => base.id === targetBaseId && base.status === 'active')
|
|
1020
|
+
const summaries = documentWorkspaceDocuments(workspace)
|
|
1021
|
+
const current = summaries.find(document => document.id === documentId)
|
|
1022
|
+
const sourceBaseId = current?.knowledgeBaseId
|
|
1023
|
+
|| (workspace.view.editor?.id === documentId ? workspace.view.editor.knowledgeBaseId : '')
|
|
1024
|
+
if (!target || !sourceBaseId || sourceBaseId === targetBaseId || movingDocumentId) return false
|
|
1025
|
+
const editor = workspace.view.editor
|
|
1026
|
+
if (editor?.id === documentId && editor.dirty && !await saveDocumentEditor(workspace)) return false
|
|
1027
|
+
|
|
1028
|
+
movingDocumentId = documentId
|
|
1029
|
+
renderShell()
|
|
1030
|
+
try {
|
|
1031
|
+
const saved = await api(`documents/${encodeURIComponent(documentId)}/move`, {
|
|
1032
|
+
method: 'POST', body: { knowledgeBaseId: targetBaseId },
|
|
1033
|
+
})
|
|
1034
|
+
const latest = documentWorkspaceDocuments(workspace)
|
|
1035
|
+
const summary = latest.find(document => document.id === documentId) || current
|
|
1036
|
+
if (summary) {
|
|
1037
|
+
setDocumentWorkspaceDocuments(workspace, [
|
|
1038
|
+
{ ...summary, knowledgeBaseId: targetBaseId, updatedAt: saved.updatedAt },
|
|
1039
|
+
...latest.filter(document => document.id !== documentId),
|
|
1040
|
+
])
|
|
1041
|
+
}
|
|
1042
|
+
workspace.view.searchResults = workspace.view.searchResults.map(document => document.id === documentId
|
|
1043
|
+
? { ...document, knowledgeBaseId: targetBaseId, updatedAt: saved.updatedAt }
|
|
1044
|
+
: document)
|
|
1045
|
+
const sourcePage = documentPageState(workspace, sourceBaseId)
|
|
1046
|
+
const targetPage = documentPageState(workspace, targetBaseId)
|
|
1047
|
+
if (sourcePage.loaded) sourcePage.total = Math.max(0, sourcePage.total - 1)
|
|
1048
|
+
if (targetPage.loaded) targetPage.total += 1
|
|
1049
|
+
workspace.view.knowledgeBaseId = targetBaseId
|
|
1050
|
+
workspace.view.expandedBases.add(targetBaseId)
|
|
1051
|
+
if (workspace.view.documentId === documentId && workspace.view.editor?.id === documentId) {
|
|
1052
|
+
workspace.view.editor = {
|
|
1053
|
+
...workspace.view.editor,
|
|
1054
|
+
...saved,
|
|
1055
|
+
tagsText: saved.tags.join(', '),
|
|
1056
|
+
dirty: false,
|
|
1057
|
+
isNew: false,
|
|
1058
|
+
saveState: '已移动',
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
showToast(`已移动到“${target.name}”。`)
|
|
1062
|
+
return true
|
|
1063
|
+
} catch (error) {
|
|
1064
|
+
showToast(friendlyError(error), 'error')
|
|
1065
|
+
return false
|
|
1066
|
+
} finally {
|
|
1067
|
+
movingDocumentId = ''
|
|
1068
|
+
renderShell()
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
function openMoveKnowledgeDocument(workspace, editor) {
|
|
1073
|
+
const targets = documentWorkspaceBases(workspace).filter(base => base.status === 'active' && base.id !== editor.knowledgeBaseId)
|
|
1074
|
+
if (!targets.length) return showToast('当前没有其他可移动到的知识库。', 'error')
|
|
1075
|
+
const form = element('form', { class: 'form-grid' })
|
|
1076
|
+
const destination = selectField('目标知识库', targets.map(base => ({ value: base.id, label: base.name })), targets[0].id)
|
|
1077
|
+
destination.wrapper.classList.add('span-2')
|
|
1078
|
+
form.append(destination.wrapper)
|
|
1079
|
+
return openSheet({
|
|
1080
|
+
title: `移动“${editor.title}”`,
|
|
1081
|
+
description: '文档 ID、版本历史和关联笔记都会保留,Markdown 投影将同步移动。',
|
|
1082
|
+
body: form,
|
|
1083
|
+
primaryLabel: '移动文档',
|
|
1084
|
+
onPrimary: () => moveKnowledgeDocument(workspace, editor.id, destination.input.value),
|
|
1085
|
+
})
|
|
1086
|
+
}
|
|
1087
|
+
|
|
959
1088
|
function updateEditorSaveState(label) {
|
|
960
1089
|
const node = document.querySelector('.editor-save-status')
|
|
961
1090
|
if (node) node.textContent = label
|
|
962
1091
|
}
|
|
963
1092
|
|
|
964
1093
|
async function loadCandidates(signal) {
|
|
965
|
-
const [
|
|
966
|
-
api(`candidates?status=${state.candidateStatus}&limit=100`, { signal }),
|
|
1094
|
+
const [payload] = await Promise.all([
|
|
1095
|
+
api(`candidates?status=${state.candidateStatus}&limit=100&includeTargets=1`, { signal }),
|
|
967
1096
|
ensureKnowledgeBases(false, signal),
|
|
968
1097
|
])
|
|
1098
|
+
const candidates = payload.items
|
|
969
1099
|
state.candidates = candidates
|
|
970
|
-
|
|
971
|
-
const targets = await Promise.all(targetIds.map(async id => {
|
|
972
|
-
try { return [id, await api(`entries/${encodeURIComponent(id)}`, { signal })] }
|
|
973
|
-
catch (error) {
|
|
974
|
-
if (signal?.aborted) throw error
|
|
975
|
-
return [id, null]
|
|
976
|
-
}
|
|
977
|
-
}))
|
|
978
|
-
state.candidateTargets = new Map(targets)
|
|
1100
|
+
state.candidateTargets = new Map(payload.targets.map(target => [target.id, target]))
|
|
979
1101
|
if (!state.stats) await refreshStats(signal)
|
|
980
1102
|
}
|
|
981
1103
|
|
|
@@ -1616,6 +1738,7 @@ function renderDocumentWorkspace(workspace, options = {}) {
|
|
|
1616
1738
|
const activeBases = documentWorkspaceBases(workspace)
|
|
1617
1739
|
const workspaceDocuments = documentWorkspaceDocuments(workspace)
|
|
1618
1740
|
const readOnly = documentWorkspaceReadOnly(workspace)
|
|
1741
|
+
const canOrganize = !readOnly && activeBases.length > 1
|
|
1619
1742
|
const selectedBase = activeBases.find(base => base.id === view.knowledgeBaseId)
|
|
1620
1743
|
const search = element('input', {
|
|
1621
1744
|
class: 'note-tree-search', type: 'search', value: view.query, placeholder: '搜索文档', 'aria-label': '搜索知识库文档',
|
|
@@ -1639,6 +1762,11 @@ function renderDocumentWorkspace(workspace, options = {}) {
|
|
|
1639
1762
|
const documents = (query ? view.searchResults : workspaceDocuments).filter(document => document.knowledgeBaseId === base.id)
|
|
1640
1763
|
return element('section', {
|
|
1641
1764
|
class: 'note-tree-group', 'data-expanded': String(expanded),
|
|
1765
|
+
'data-base-id': base.id, 'data-drop-target': 'false',
|
|
1766
|
+
onDragEnter: event => activateKnowledgeBaseDropTarget(event, workspace, base.id),
|
|
1767
|
+
onDragOver: event => activateKnowledgeBaseDropTarget(event, workspace, base.id),
|
|
1768
|
+
onDragLeave: event => { if (!event.currentTarget.contains(event.relatedTarget)) event.currentTarget.dataset.dropTarget = 'false' },
|
|
1769
|
+
onDrop: event => dropKnowledgeDocument(event, workspace, base.id),
|
|
1642
1770
|
},
|
|
1643
1771
|
element('button', {
|
|
1644
1772
|
type: 'button', class: 'note-tree-base', 'aria-expanded': String(expanded),
|
|
@@ -1659,8 +1787,18 @@ function renderDocumentWorkspace(workspace, options = {}) {
|
|
|
1659
1787
|
actionButton('重试', () => { void loadDocumentPage(workspace, base.id, { reset: true }).then(renderShell) }, 'ghost small')) : null,
|
|
1660
1788
|
documents.map(document => element('button', {
|
|
1661
1789
|
type: 'button', class: 'note-tree-document', 'aria-current': document.id === view.documentId ? 'page' : undefined,
|
|
1790
|
+
draggable: canOrganize && movingDocumentId !== document.id ? 'true' : undefined,
|
|
1791
|
+
'aria-busy': movingDocumentId === document.id ? 'true' : undefined,
|
|
1792
|
+
title: canOrganize ? `${document.title} · 拖到其他知识库以移动` : document.title,
|
|
1662
1793
|
'data-document-id': document.id,
|
|
1663
1794
|
'data-knowledge-motion-key': `knowledge-document:${workspace.kind}:${document.id}`,
|
|
1795
|
+
onDragStart: event => {
|
|
1796
|
+
knowledgeDocumentDrag = { documentId: document.id, sourceBaseId: base.id, workspaceKind: workspace.kind }
|
|
1797
|
+
event.dataTransfer.effectAllowed = 'move'
|
|
1798
|
+
event.dataTransfer.setData(KNOWLEDGE_DOCUMENT_DRAG_TYPE, document.id)
|
|
1799
|
+
event.currentTarget.dataset.dragging = 'true'
|
|
1800
|
+
},
|
|
1801
|
+
onDragEnd: clearKnowledgeDocumentDragState,
|
|
1664
1802
|
onClick: () => { view.knowledgeBaseId = base.id; void selectDocument(workspace, document.id) },
|
|
1665
1803
|
}, element('span', { class: 'tree-document-icon', 'aria-hidden': 'true' }), element('span', { class: 'tree-document-copy' },
|
|
1666
1804
|
element('strong', {}, document.title), element('small', {}, document.relPath)),
|
|
@@ -1759,6 +1897,9 @@ function renderNoteEditor(workspace, editor, base) {
|
|
|
1759
1897
|
element('div', { class: 'note-editor-actions' },
|
|
1760
1898
|
finalized ? badge(DOCUMENT_STATE_LABELS[editor.documentState] || '已结束', 'success') : readOnly ? badge('只读') : null,
|
|
1761
1899
|
element('span', { class: 'editor-save-status', role: 'status' }, editor.saveState),
|
|
1900
|
+
!readOnly && !editor.isNew && documentWorkspaceBases(workspace).some(item => item.id !== editor.knowledgeBaseId)
|
|
1901
|
+
? actionButton('移动到…', () => openMoveKnowledgeDocument(workspace, editor), 'ghost small')
|
|
1902
|
+
: null,
|
|
1762
1903
|
finalized && !readOnly ? actionButton('重新打开', () => reopenDocument(workspace, editor), 'small') : null,
|
|
1763
1904
|
!readOnly && !editor.isNew && !finalized ? actionButton('标记结束', () => openFinalizeDocument(workspace, editor), 'small') : null,
|
|
1764
1905
|
!readOnly && !editor.isNew && !finalized ? actionButton('删除', () => confirmDeleteDocument(workspace, editor), 'ghost small') : null,
|
|
@@ -2024,6 +2165,7 @@ function renderNotes() {
|
|
|
2024
2165
|
actionButton('新建', () => openCreateNoteDocument(), 'primary small'),
|
|
2025
2166
|
actionButton('目录', () => openCreateNoteFolder(), 'small'),
|
|
2026
2167
|
actionButton('导入', () => fileInput.click(), 'ghost small'),
|
|
2168
|
+
actionButton('会话指令', openNoteAgentGuide, 'ghost small'),
|
|
2027
2169
|
fileInput,
|
|
2028
2170
|
),
|
|
2029
2171
|
),
|
|
@@ -2048,6 +2190,41 @@ function renderNotes() {
|
|
|
2048
2190
|
return element('section', { class: 'notes-page', 'aria-label': '笔记工作区' }, workspace)
|
|
2049
2191
|
}
|
|
2050
2192
|
|
|
2193
|
+
function openNoteAgentGuide() {
|
|
2194
|
+
const capabilityRows = [
|
|
2195
|
+
['笔记文档', '创建、追加或替换内容、重命名、移动、删除'],
|
|
2196
|
+
['笔记目录', '创建、重命名、移动、删除'],
|
|
2197
|
+
].map(([label, detail]) => element('div', { class: 'notes-agent-capability' },
|
|
2198
|
+
element('strong', {}, label), element('span', {}, detail)))
|
|
2199
|
+
const examples = [
|
|
2200
|
+
['创建', '在笔记工作区的「发布资料」目录里,新建笔记文档「上线检查.md」,内容是:……'],
|
|
2201
|
+
['更新', '把笔记文档「发布资料/上线检查.md」追加以下内容:……'],
|
|
2202
|
+
['目录', '把笔记目录「发布资料」重命名为「发布归档」。'],
|
|
2203
|
+
].map(([label, text]) => element('li', {}, element('span', {}, label), element('code', {}, text)))
|
|
2204
|
+
const body = element('div', { class: 'notes-agent-guide' },
|
|
2205
|
+
element('section', { class: 'notes-agent-guide-rule' },
|
|
2206
|
+
element('span', { class: 'notes-agent-guide-index', 'aria-hidden': 'true' }, '01'),
|
|
2207
|
+
element('div', {},
|
|
2208
|
+
element('h3', {}, '在当前消息里明确授权'),
|
|
2209
|
+
element('p', {}, '写清动作、对象和位置,并明确使用“笔记文档”“笔记目录”或“笔记工作区”。为了避免误写,不能只依赖上一轮说过的授权。'))),
|
|
2210
|
+
element('section', { class: 'notes-agent-guide-rule' },
|
|
2211
|
+
element('span', { class: 'notes-agent-guide-index', 'aria-hidden': 'true' }, '02'),
|
|
2212
|
+
element('div', {},
|
|
2213
|
+
element('h3', {}, '名称足够,重名时补全路径'),
|
|
2214
|
+
element('p', {}, '不需要填写内部编号。会话会先浏览笔记目录定位目标;如果有重名,请写成“目录/子目录/文档名”。'))),
|
|
2215
|
+
element('div', { class: 'notes-agent-capabilities', 'aria-label': '会话可执行的笔记操作' }, capabilityRows),
|
|
2216
|
+
element('section', { class: 'notes-agent-examples' },
|
|
2217
|
+
element('h3', {}, '可以直接这样说'),
|
|
2218
|
+
element('ul', {}, examples)),
|
|
2219
|
+
element('p', { class: 'notes-agent-guide-note' }, '只说“新建 Markdown”或“创建本地目录”不会获得笔记写入权限;请明确指出这是笔记工作区中的文档或目录。'))
|
|
2220
|
+
return openSheet({
|
|
2221
|
+
title: '让会话整理笔记',
|
|
2222
|
+
description: '会话可以操作笔记工作区,但每次写入都需要当前用户消息明确授权。',
|
|
2223
|
+
body,
|
|
2224
|
+
cancelLabel: '知道了',
|
|
2225
|
+
})
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2051
2228
|
function renderNoteTransfer() {
|
|
2052
2229
|
const transfer = state.notes.transfer
|
|
2053
2230
|
if (!transfer) return null
|
|
@@ -2563,11 +2740,24 @@ function releaseNoteAsset() {
|
|
|
2563
2740
|
function scheduleNoteSearch(value) {
|
|
2564
2741
|
state.notes.query = value
|
|
2565
2742
|
window.clearTimeout(noteSearchTimer)
|
|
2743
|
+
noteSearchController?.abort()
|
|
2744
|
+
noteSearchController = null
|
|
2745
|
+
const request = ++noteSearchRequest
|
|
2566
2746
|
noteSearchTimer = window.setTimeout(async () => {
|
|
2747
|
+
const controller = new AbortController()
|
|
2748
|
+
noteSearchController = controller
|
|
2567
2749
|
try {
|
|
2568
|
-
|
|
2750
|
+
const results = value.trim()
|
|
2751
|
+
? await api(`notes?q=${encodeURIComponent(value.trim())}&limit=200`, { signal: controller.signal })
|
|
2752
|
+
: []
|
|
2753
|
+
if (request !== noteSearchRequest || value !== state.notes.query) return
|
|
2754
|
+
state.notes.searchResults = results
|
|
2569
2755
|
renderShell()
|
|
2570
|
-
} catch (error) {
|
|
2756
|
+
} catch (error) {
|
|
2757
|
+
if (!controller.signal.aborted && request === noteSearchRequest) showToast(friendlyError(error), 'error')
|
|
2758
|
+
} finally {
|
|
2759
|
+
if (noteSearchController === controller) noteSearchController = null
|
|
2760
|
+
}
|
|
2571
2761
|
}, 180)
|
|
2572
2762
|
}
|
|
2573
2763
|
|
|
@@ -3024,12 +3214,16 @@ function clearNoteDragState() {
|
|
|
3024
3214
|
document.querySelectorAll('.notes-tree-item[data-dragging="true"]').forEach(node => { node.dataset.dragging = 'false' })
|
|
3025
3215
|
}
|
|
3026
3216
|
|
|
3027
|
-
function
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3217
|
+
function installDragRecovery() {
|
|
3218
|
+
const clear = () => {
|
|
3219
|
+
clearNoteDragState()
|
|
3220
|
+
clearKnowledgeDocumentDragState()
|
|
3221
|
+
}
|
|
3222
|
+
window.addEventListener('drop', clear, true)
|
|
3223
|
+
window.addEventListener('dragend', clear, true)
|
|
3224
|
+
window.addEventListener('blur', clear)
|
|
3031
3225
|
document.addEventListener('dragleave', event => {
|
|
3032
|
-
if (event.relatedTarget === null)
|
|
3226
|
+
if (event.relatedTarget === null) clear()
|
|
3033
3227
|
}, true)
|
|
3034
3228
|
}
|
|
3035
3229
|
|
|
@@ -3924,5 +4118,5 @@ window.addEventListener('beforeunload', event => {
|
|
|
3924
4118
|
event.returnValue = ''
|
|
3925
4119
|
})
|
|
3926
4120
|
|
|
3927
|
-
|
|
4121
|
+
installDragRecovery()
|
|
3928
4122
|
void installHostThemeBridge().then(() => boot())
|
package/web/styles.css
CHANGED
|
@@ -433,7 +433,7 @@ html,
|
|
|
433
433
|
border-radius: 20px;
|
|
434
434
|
overflow: hidden;
|
|
435
435
|
background: var(--material-sidebar);
|
|
436
|
-
box-shadow:
|
|
436
|
+
box-shadow: 10px 0 36px rgb(0 0 0 / 3%);
|
|
437
437
|
-webkit-backdrop-filter: var(--glass-filter);
|
|
438
438
|
backdrop-filter: var(--glass-filter);
|
|
439
439
|
transform-origin: left center;
|
|
@@ -562,7 +562,7 @@ html,
|
|
|
562
562
|
padding: 14px clamp(18px, 3vw, 38px);
|
|
563
563
|
overflow: hidden;
|
|
564
564
|
background: var(--material-toolbar);
|
|
565
|
-
box-shadow:
|
|
565
|
+
box-shadow: 0 8px 24px rgb(0 0 0 / 3%);
|
|
566
566
|
-webkit-backdrop-filter: var(--glass-filter);
|
|
567
567
|
backdrop-filter: var(--glass-filter);
|
|
568
568
|
}
|
|
@@ -840,7 +840,7 @@ html,
|
|
|
840
840
|
overflow: hidden;
|
|
841
841
|
border-right: 1px solid var(--glass-separator);
|
|
842
842
|
background: var(--surface-pane);
|
|
843
|
-
box-shadow:
|
|
843
|
+
box-shadow: none;
|
|
844
844
|
-webkit-backdrop-filter: var(--glass-filter);
|
|
845
845
|
backdrop-filter: var(--glass-filter);
|
|
846
846
|
}
|
|
@@ -862,8 +862,11 @@ html,
|
|
|
862
862
|
}
|
|
863
863
|
.note-tree-group + .note-tree-group { margin-top: 3px; }
|
|
864
864
|
.note-tree-base, .note-tree-document, .note-tree-new { width: 100%; display: flex; align-items: center; border: 0; background: transparent; color: var(--text-secondary); text-align: left; }
|
|
865
|
-
.note-tree-base { min-height: 36px; gap: 7px; border-radius: 9px; padding: 5px 7px; font-weight: 620; transition: background var(--motion-fast) ease, color var(--motion-fast) ease, transform var(--motion-base) var(--ease-out); }
|
|
865
|
+
.note-tree-base { position: relative; min-height: 36px; gap: 7px; border-radius: 9px; padding: 5px 7px; font-weight: 620; transition: background var(--motion-fast) ease, color var(--motion-fast) ease, transform var(--motion-base) var(--ease-out), box-shadow var(--motion-fast) ease; }
|
|
866
866
|
.note-tree-base:hover, .note-tree-document:hover, .note-tree-new:hover { background: var(--surface-hover); color: var(--text); transform: translateX(2px); }
|
|
867
|
+
.note-tree-group[data-drop-target="true"] > .note-tree-base { background: color-mix(in srgb, var(--accent) 13%, var(--surface)); color: var(--text); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 44%, transparent), var(--shadow-control); transform: translateX(2px); }
|
|
868
|
+
.note-tree-group[data-drop-target="true"] > .note-tree-base .tree-count { visibility: hidden; }
|
|
869
|
+
.note-tree-group[data-drop-target="true"] > .note-tree-base::after { content: "移动到这里"; position: absolute; right: 7px; border-radius: 5px; padding: 2px 6px; background: var(--surface-raised); color: var(--accent); font-size: 9px; font-weight: 650; pointer-events: none; }
|
|
867
870
|
.tree-disclosure { width: 7px; height: 7px; flex: none; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(-45deg); transition: transform .16s ease; }
|
|
868
871
|
.note-tree-group[data-expanded="true"] .tree-disclosure { transform: rotate(45deg) translate(-1px, -1px); }
|
|
869
872
|
.tree-folder-icon {
|
|
@@ -882,6 +885,10 @@ html,
|
|
|
882
885
|
.tree-count { min-width: 20px; color: var(--text-tertiary); font-size: 10px; font-variant-numeric: tabular-nums; text-align: right; }
|
|
883
886
|
.note-tree-documents { display: grid; gap: 1px; margin: 1px 0 5px 18px; padding-left: 10px; border-left: 1px solid color-mix(in srgb, var(--border-strong) 55%, transparent); }
|
|
884
887
|
.note-tree-document { position: relative; min-height: 40px; gap: 8px; border-radius: 9px; padding: 5px 8px; transition: background var(--motion-fast) ease, color var(--motion-fast) ease, transform var(--motion-base) var(--ease-out), box-shadow var(--motion-base) ease; }
|
|
888
|
+
.note-tree-document[draggable="true"] { cursor: grab; }
|
|
889
|
+
.note-tree-document[draggable="true"]:active { cursor: grabbing; }
|
|
890
|
+
.note-tree-document[data-dragging="true"] { opacity: .42; transform: translateX(5px) scale(.985); }
|
|
891
|
+
.note-tree-document[aria-busy="true"] { opacity: .58; pointer-events: none; }
|
|
885
892
|
.note-tree-document[aria-current="page"] { background: var(--material-control); color: var(--text); box-shadow: inset 2px 0 0 color-mix(in srgb, var(--text-secondary) 74%, transparent), var(--shadow-control); transform: translateX(2px); }
|
|
886
893
|
.tree-document-icon {
|
|
887
894
|
width: 14px;
|
|
@@ -920,12 +927,27 @@ html,
|
|
|
920
927
|
overflow: hidden;
|
|
921
928
|
background: var(--surface-editor);
|
|
922
929
|
}
|
|
923
|
-
.notes-browser { min-width: 0; min-height: 0; display: grid; grid-template-rows: auto auto minmax(0, 1fr); overflow: hidden; border-right: 1px solid var(--glass-separator); background: var(--surface-pane); box-shadow:
|
|
930
|
+
.notes-browser { min-width: 0; min-height: 0; display: grid; grid-template-rows: auto auto minmax(0, 1fr); overflow: hidden; border-right: 1px solid var(--glass-separator); background: var(--surface-pane); box-shadow: none; -webkit-backdrop-filter: var(--glass-filter); backdrop-filter: var(--glass-filter); }
|
|
924
931
|
.notes-browser-header { min-height: 68px; display: grid; gap: 8px; padding: 10px 10px 7px; }
|
|
925
932
|
.notes-browser-header > div:first-child { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
|
|
926
933
|
.notes-browser-header h2 { margin: 0; font-size: 13px; font-weight: 650; }
|
|
927
934
|
.notes-browser-header span { color: var(--text-tertiary); font-size: 10px; }
|
|
928
935
|
.notes-browser-actions { display: flex; align-items: center; gap: 4px; }
|
|
936
|
+
.notes-agent-guide { display: grid; gap: 18px; color: var(--text-secondary); }
|
|
937
|
+
.notes-agent-guide-rule { display: grid; grid-template-columns: 30px minmax(0, 1fr); gap: 12px; align-items: start; }
|
|
938
|
+
.notes-agent-guide-index { display: grid; place-items: center; width: 30px; height: 30px; border: 1px solid var(--glass-border); border-radius: 9px; background: var(--material-control); color: var(--text-tertiary); font: 650 9px/1 var(--font-mono); box-shadow: var(--shadow-control); }
|
|
939
|
+
.notes-agent-guide h3 { margin: 0 0 5px; color: var(--text); font-size: 13px; }
|
|
940
|
+
.notes-agent-guide p { margin: 0; font-size: 12px; line-height: 1.65; }
|
|
941
|
+
.notes-agent-capabilities { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
|
|
942
|
+
.notes-agent-capability { min-width: 0; display: grid; gap: 4px; border: 1px solid var(--glass-border); border-radius: 11px; padding: 12px; background: var(--material-panel); box-shadow: var(--shadow-soft); }
|
|
943
|
+
.notes-agent-capability strong { color: var(--text); font-size: 12px; }
|
|
944
|
+
.notes-agent-capability span { color: var(--text-tertiary); font-size: 10px; line-height: 1.55; }
|
|
945
|
+
.notes-agent-examples { display: grid; gap: 8px; }
|
|
946
|
+
.notes-agent-examples ul { display: grid; gap: 7px; margin: 0; padding: 0; list-style: none; }
|
|
947
|
+
.notes-agent-examples li { min-width: 0; display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: 9px; align-items: start; }
|
|
948
|
+
.notes-agent-examples li > span { border-radius: 6px; padding: 4px 5px; background: var(--surface-soft); color: var(--text-tertiary); font-size: 9px; font-weight: 650; text-align: center; }
|
|
949
|
+
.notes-agent-examples code { min-width: 0; border: 1px solid var(--glass-border); border-radius: 8px; padding: 8px 10px; background: var(--surface-editor); color: var(--text-secondary); font: 11px/1.6 var(--font-mono); white-space: normal; overflow-wrap: anywhere; }
|
|
950
|
+
.notes-agent-guide-note { border-left: 2px solid var(--border-strong); padding: 7px 0 7px 11px; color: var(--text-tertiary); }
|
|
929
951
|
.notes-search { padding: 1px 10px 7px; }
|
|
930
952
|
.notes-search .input { width: 100%; height: 34px; }
|
|
931
953
|
.notes-tree { min-width: 0; max-width: 100%; min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; padding: 2px 5px 16px; }
|
|
@@ -1533,10 +1555,7 @@ html,
|
|
|
1533
1555
|
|
|
1534
1556
|
.sidebar.knowledge-glass-surface {
|
|
1535
1557
|
background: var(--liquid-glass-large);
|
|
1536
|
-
box-shadow:
|
|
1537
|
-
inset 1px 0 0 var(--glass-rim-light),
|
|
1538
|
-
inset -1px 0 0 var(--glass-rim-shadow),
|
|
1539
|
-
10px 0 36px rgb(0 0 0 / 4%);
|
|
1558
|
+
box-shadow: 10px 0 36px rgb(0 0 0 / 4%);
|
|
1540
1559
|
}
|
|
1541
1560
|
|
|
1542
1561
|
.topbar.knowledge-glass-surface,
|
|
@@ -1544,19 +1563,13 @@ html,
|
|
|
1544
1563
|
.notes-document-toolbar.knowledge-glass-surface,
|
|
1545
1564
|
.notes-content-header.knowledge-glass-surface {
|
|
1546
1565
|
background: var(--liquid-glass-regular);
|
|
1547
|
-
box-shadow:
|
|
1548
|
-
inset 0 1px 0 var(--glass-rim-light),
|
|
1549
|
-
inset 0 -1px 0 var(--glass-rim-shadow),
|
|
1550
|
-
0 8px 24px rgb(0 0 0 / 3%);
|
|
1566
|
+
box-shadow: 0 8px 24px rgb(0 0 0 / 3%);
|
|
1551
1567
|
}
|
|
1552
1568
|
|
|
1553
1569
|
.note-tree-panel.knowledge-glass-surface,
|
|
1554
1570
|
.notes-browser.knowledge-glass-surface {
|
|
1555
1571
|
background: var(--liquid-glass-clear);
|
|
1556
|
-
box-shadow:
|
|
1557
|
-
inset 1px 0 0 var(--glass-rim-light),
|
|
1558
|
-
inset -1px 0 0 var(--glass-rim-shadow),
|
|
1559
|
-
10px 0 28px rgb(0 0 0 / 3.5%);
|
|
1572
|
+
box-shadow: none;
|
|
1560
1573
|
}
|
|
1561
1574
|
|
|
1562
1575
|
.dialog.knowledge-glass-surface {
|
|
@@ -1933,6 +1946,7 @@ html,
|
|
|
1933
1946
|
.candidate-actions .button { flex: 1 1 auto; }
|
|
1934
1947
|
.notes-heading { align-items: flex-start; }
|
|
1935
1948
|
.notes-browser-actions { flex-wrap: wrap; }
|
|
1949
|
+
.notes-agent-capabilities { grid-template-columns: 1fr; }
|
|
1936
1950
|
.notes-content-title { align-items: stretch; flex-direction: column; }
|
|
1937
1951
|
.notes-content-actions .button { flex: 1 1 auto; }
|
|
1938
1952
|
.notes-document-toolbar { align-items: center; flex-direction: row; overflow-x: auto; }
|
package/web/workspace-effects.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";(()=>{var M="http://www.w3.org/2000/svg",x=[".sidebar",".topbar",".note-tree-panel",".notes-browser",".notes-content-header",".notes-document-toolbar",".note-editor-toolbar",".dialog"].join(","),L=[".login-card",".metric",".panel",".library-detail-header",".mount-manager",".knowledge-card",".candidate",".api-access-card"].join(","),
|
|
1
|
+
"use strict";(()=>{var M="http://www.w3.org/2000/svg",x=[".sidebar",".topbar",".note-tree-panel",".notes-browser",".notes-content-header",".notes-document-toolbar",".note-editor-toolbar",".dialog"].join(","),A=[".sidebar",".topbar",".note-tree-panel",".notes-browser"].join(","),L=[".login-card",".metric",".panel",".library-detail-header",".mount-manager",".knowledge-card",".candidate",".api-access-card"].join(","),R=[".mount-table",".note-workspace",".notes-workspace",".dialog",L].join(","),T=[".button",".nav-button",".tab",".pane-toggle-button",".note-tree-base",".note-tree-document",".note-tree-new",".notes-tree-row",".notes-search-row",".notes-file-main"].join(","),C=[".note-tree",".notes-tree",".base-grid",".mount-table"].join(","),G="[data-knowledge-motion-key]",F=700,P=38,m=new Map,b=new Map,u=new Map,g=new Map,$=0,d,O=window.matchMedia("(prefers-reduced-motion: reduce)"),_=window.matchMedia("(prefers-reduced-transparency: reduce)");function v(e,t){let n=Array.from(e.querySelectorAll(t));return e instanceof HTMLElement&&e.matches(t)&&n.unshift(e),n}function H(){return d?.isConnected||(d=document.createElementNS(M,"svg"),d.classList.add("knowledge-glass-filter-bank"),d.setAttribute("aria-hidden","true"),d.setAttribute("focusable","false"),document.body.append(d)),d}function h(e,t){let n=document.createElementNS(M,e);for(let[o,s]of Object.entries(t))n.setAttribute(o,s);return n}function N(e){let t=h("filter",{id:e,x:"0%",y:"0%",width:"100%",height:"100%","color-interpolation-filters":"sRGB"}),n=h("feImage",{x:"0",y:"0",width:"100%",height:"100%",preserveAspectRatio:"none",result:"map"});return t.append(n,h("feGaussianBlur",{in:"SourceGraphic",stdDeviation:"6",result:"frosted"})),t.append(h("feDisplacementMap",{in:"frosted",in2:"map",scale:"-16",xChannelSelector:"R",yChannelSelector:"G",result:"refracted"}),h("feGaussianBlur",{in:"refracted",stdDeviation:".12"})),{filter:t,image:n}}function I(){if(_.matches)return!1;let e=navigator.userAgent;return/Firefox/i.test(e)||/Safari/i.test(e)&&!/(Chrome|Chromium|CriOS)/i.test(e)?!1:CSS.supports?.("backdrop-filter","url(#knowledge-glass-support)")||CSS.supports?.("-webkit-backdrop-filter","url(#knowledge-glass-support)")||!1}function D(e,t,n){let o=Number.parseFloat(getComputedStyle(e).borderTopLeftRadius);return Number.isFinite(o)?Math.max(0,Math.min(o,Math.min(t,n)/2)):Math.min(t,n)*.16}function B(e,t,n){let o=Math.min(12,Math.max(4,Math.min(e,t)*.08)),s=`<svg viewBox="0 0 ${e} ${t}" xmlns="${M}">
|
|
2
2
|
<defs>
|
|
3
3
|
<clipPath id="shape"><rect width="${e}" height="${t}" rx="${n}"/></clipPath>
|
|
4
4
|
<linearGradient id="left" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stop-color="rgb(92 128 128)"/><stop offset="100%" stop-color="rgb(128 128 128)"/></linearGradient>
|
|
@@ -13,4 +13,4 @@
|
|
|
13
13
|
<rect width="${e}" height="${o}" fill="url(#top)"/>
|
|
14
14
|
<rect y="${t-o}" width="${e}" height="${o}" fill="url(#bottom)"/>
|
|
15
15
|
</g>
|
|
16
|
-
</svg>`;return`data:image/svg+xml,${encodeURIComponent(s)}`}function
|
|
16
|
+
</svg>`;return`data:image/svg+xml,${encodeURIComponent(s)}`}function V(e){if(m.has(e))return;if(e.classList.add("knowledge-glass-surface"),e.matches(A)||!I()){e.dataset.knowledgeGlass="fallback",m.set(e,{filter:void 0,observer:void 0,frame:0});return}let t=`knowledge-glass-filter-${++$}`,{filter:n,image:o}=N(t);H().append(n),e.dataset.knowledgeGlass="svg",e.style.setProperty("--knowledge-glass-filter",`url(#${t})`);let s={filter:n,observer:void 0,frame:0},c=()=>{if(s.frame=0,!e.isConnected)return;let a=e.getBoundingClientRect(),l=Math.max(1,Math.round(a.width)),i=Math.max(1,Math.round(a.height));o.setAttribute("href",B(l,i,D(e,l,i)))},r=()=>{s.frame===0&&(s.frame=requestAnimationFrame(c))};s.observer=typeof ResizeObserver>"u"?void 0:new ResizeObserver(r),s.observer?.observe(e),s.frame=requestAnimationFrame(c),m.set(e,s)}function q(e){if(b.has(e))return;e.classList.add("knowledge-border-surface"),e.style.setProperty("--knowledge-pointer-x","50%"),e.style.setProperty("--knowledge-pointer-y","50%");let t=0,n,o=()=>{if(t=0,n===void 0||!e.isConnected)return;let r=e.getBoundingClientRect(),a=Math.min(r.width,Math.max(0,n.x-r.left)),l=Math.min(r.height,Math.max(0,n.y-r.top)),i=Math.min(a,r.width-a,l,r.height-l),y=Math.min(1,Math.max(0,1-i/P)),w=Math.atan2(l-r.height/2,a-r.width/2)*(180/Math.PI)+90;e.style.setProperty("--knowledge-pointer-x",`${(a/Math.max(1,r.width)*100).toFixed(2)}%`),e.style.setProperty("--knowledge-pointer-y",`${(l/Math.max(1,r.height)*100).toFixed(2)}%`),e.style.setProperty("--knowledge-border-proximity",y.toFixed(3)),e.style.setProperty("--knowledge-border-angle",`${w.toFixed(2)}deg`)},s=r=>{n={x:r.clientX,y:r.clientY},t===0&&(t=requestAnimationFrame(o))},c=()=>{n=void 0,e.style.setProperty("--knowledge-border-proximity","0")};e.addEventListener("pointermove",s,{passive:!0}),e.addEventListener("pointerleave",c,{passive:!0}),b.set(e,()=>{t!==0&&cancelAnimationFrame(t),e.removeEventListener("pointermove",s),e.removeEventListener("pointerleave",c)})}function K(e,t){let n=e.dataset.knowledgeMotionKey;if(n===void 0)return!1;let o=g.get(n);return o!==void 0&&t-o<F}function U(e,t){let n=e.dataset.knowledgeMotionKey;if(n===void 0||(g.set(n,t),g.size<=4e3))return;let o=g.keys().next().value;o!==void 0&&g.delete(o)}function S(e){let t=e.scrollHeight-e.clientHeight-e.scrollTop;e.dataset.scrollTop=String(e.scrollTop<=2),e.dataset.scrollBottom=String(t<=2)}function j(e){if(u.has(e))return;let t=e.matches(".base-grid");e.classList.add("knowledge-animated-list"),e.dataset.knowledgeListLayout=t?"grid":"scroll",S(e);let n=()=>S(e);e.addEventListener("scroll",n,{passive:!0});let o=Array.from(e.querySelectorAll(G));if(O.matches||typeof IntersectionObserver>"u"){for(let i of o)i.classList.add("knowledge-list-reveal","is-visible");u.set(e,()=>e.removeEventListener("scroll",n));return}let s=e.scrollHeight-e.clientHeight>2?e:null,c=new IntersectionObserver(i=>{let y=i.filter(f=>f.isIntersecting).sort((f,p)=>f.boundingClientRect.top-p.boundingClientRect.top),w=performance.now();y.forEach((f,p)=>{let E=f.target,k=t?52:38;E.style.setProperty("--knowledge-list-delay",`${Math.min(p,7)*k}ms`),E.classList.add("is-visible"),U(E,w)});for(let f of i){if(f.isIntersecting)continue;let p=f.target;p.classList.remove("is-visible"),p.style.setProperty("--knowledge-list-delay","0ms")}},{root:s,threshold:.12,rootMargin:"-4px 0px"}),r=performance.now();for(let i of o)i.classList.add("knowledge-list-reveal"),!t&&K(i,r)&&i.classList.add("is-visible");let a=0,l=0;a=requestAnimationFrame(()=>{a=0,l=requestAnimationFrame(()=>{l=0;for(let i of o)c.observe(i)})}),u.set(e,()=>{a!==0&&cancelAnimationFrame(a),l!==0&&cancelAnimationFrame(l),c.disconnect(),e.removeEventListener("scroll",n)})}function W(){for(let[e,t]of m)e.isConnected||(t.frame!==0&&cancelAnimationFrame(t.frame),t.observer?.disconnect(),t.filter?.remove(),m.delete(e));for(let[e,t]of b)e.isConnected||(t(),b.delete(e));for(let[e,t]of u)e.isConnected||(t(),u.delete(e))}function z(e=document){W();for(let t of v(e,x))V(t);for(let t of v(e,L))t.classList.add("knowledge-card-surface");for(let t of v(e,R))q(t);for(let t of v(e,T))t.classList.add("knowledge-glare-surface");for(let t of v(e,C))j(t)}function Y(){for(let[e,t]of m)t.frame!==0&&cancelAnimationFrame(t.frame),t.observer?.disconnect(),t.filter?.remove(),e.classList.remove("knowledge-glass-surface"),e.removeAttribute("data-knowledge-glass"),e.style.removeProperty("--knowledge-glass-filter");for(let[e,t]of b)t(),e.classList.remove("knowledge-border-surface"),e.classList.remove("knowledge-card-surface"),e.style.removeProperty("--knowledge-pointer-x"),e.style.removeProperty("--knowledge-pointer-y");for(let[e,t]of u)t(),e.classList.remove("knowledge-animated-list");m.clear(),b.clear(),u.clear(),g.clear(),d?.remove(),d=void 0}window.DshKnowledgeEffects?.destroy();window.DshKnowledgeEffects={refresh:z,destroy:Y};})();
|