xiaoyuan-assistant 0.5.56 → 0.5.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/XIAOYUAN-BUSINESS-FLOW.md +5 -0
- package/package.json +1 -1
- package/src/components/XiaoyuanAssistant.vue +100 -3
- package/src/styles/index.css +18 -1
package/CHANGELOG.md
CHANGED
|
@@ -455,3 +455,10 @@ ls -lh /mnt/data/xiaoyuan-assistant-siliconflow-v0.5.29.zip
|
|
|
455
455
|
- 去掉小园弹窗右上角除最小化之外的静音/停止播报入口,右上角仅保留收起按钮。
|
|
456
456
|
- 升级收起状态的小园悬浮图标:增加呼吸光晕、扩散聆听波纹、轨道光点和动态音波,默认有轻微动效。
|
|
457
457
|
- 当处于监听/处理状态时,收起图标自动加快波纹与音波动画,强化“正在聆听/工作中”的视觉反馈。
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
## v0.5.57
|
|
461
|
+
|
|
462
|
+
- 收起状态小园悬浮图标支持按住鼠标/触控拖拽到屏幕任意位置。
|
|
463
|
+
- 松开后自动吸附到距离最近的左侧或右侧屏幕边界,保持当前垂直位置。
|
|
464
|
+
- 拖拽过程禁用点击误触和过渡动画,提升大屏操作稳定性。
|
|
@@ -1275,3 +1275,8 @@ AI 分析开始提示音与数据获取/模型分析并行;多个数据源采
|
|
|
1275
1275
|
- 展开面板右上角仅保留“收起/最小化”按钮,不提供静音按钮。
|
|
1276
1276
|
- 小园收起状态采用高级悬浮球视觉:中心徽记 + 呼吸光晕 + 多层扩散聆听波纹 + 环绕光点 + 动态音波。
|
|
1277
1277
|
- 空闲状态使用轻量呼吸动画;监听/处理状态自动加速动画,提示用户小园正在聆听或处理。
|
|
1278
|
+
|
|
1279
|
+
|
|
1280
|
+
## v0.5.57|收起态悬浮图标拖拽
|
|
1281
|
+
|
|
1282
|
+
收起状态下,小园悬浮图标支持按住拖拽。用户可将图标移动到屏幕任意位置;松开鼠标或触控后,根据图标中心点距离自动吸附到最近的左侧或右侧边界,同时保持当前垂直位置。拖拽过程中不会触发打开小园的点击事件。
|
package/package.json
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
<button
|
|
4
4
|
v-if="!expanded"
|
|
5
5
|
class="xy-fab"
|
|
6
|
-
:class="stateClass"
|
|
6
|
+
:class="[stateClass, { 'xy-dragging': fabDragging }]"
|
|
7
7
|
type="button"
|
|
8
8
|
aria-label="打开小园"
|
|
9
|
-
|
|
9
|
+
:style="fabStyle"
|
|
10
|
+
@pointerdown="onFabPointerDown"
|
|
11
|
+
@click="onFabClick"
|
|
10
12
|
>
|
|
11
13
|
<span class="xy-fab-glow"></span>
|
|
12
14
|
<span class="xy-fab-ring ring-a"></span>
|
|
@@ -128,13 +130,22 @@ const runtime =
|
|
|
128
130
|
// 如果宿主项目因为 HMR / 重复依赖导致当前模块暂时拿不到注入值,
|
|
129
131
|
// 组件保持可挂载,并在 mounted 后再次尝试解析,避免整个页面崩溃。
|
|
130
132
|
const safeRuntime = runtime || { manager: null, speech: null, options: {} }
|
|
131
|
-
const XIAOYUAN_SDK_VERSION = '0.5.
|
|
133
|
+
const XIAOYUAN_SDK_VERSION = '0.5.57'
|
|
132
134
|
const { manager, speech, options } = safeRuntime
|
|
133
135
|
|
|
134
136
|
const wakeWord = options.wakeWord || '你好小园'
|
|
135
137
|
const autoCollapseMs = options.autoCollapseMs ?? 0
|
|
136
138
|
|
|
137
139
|
const expanded = ref(false)
|
|
140
|
+
const fabLeft = ref(null)
|
|
141
|
+
const fabTop = ref(null)
|
|
142
|
+
const fabDragging = ref(false)
|
|
143
|
+
let fabPointerId = null
|
|
144
|
+
let fabStartX = 0
|
|
145
|
+
let fabStartY = 0
|
|
146
|
+
let fabStartLeft = 0
|
|
147
|
+
let fabStartTop = 0
|
|
148
|
+
let fabMoved = false
|
|
138
149
|
const listening = ref(false)
|
|
139
150
|
const wakeListening = ref(false)
|
|
140
151
|
const processing = ref(false)
|
|
@@ -150,6 +161,89 @@ let speechQueue = Promise.resolve()
|
|
|
150
161
|
let speechQueueToken = 0
|
|
151
162
|
let commandSessionId = 0
|
|
152
163
|
|
|
164
|
+
const fabStyle = computed(() => {
|
|
165
|
+
if (fabLeft.value == null || fabTop.value == null) return undefined
|
|
166
|
+
return {
|
|
167
|
+
left: `${fabLeft.value}px`,
|
|
168
|
+
top: `${fabTop.value}px`,
|
|
169
|
+
right: 'auto'
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
function clampFab(left, top) {
|
|
174
|
+
const size = 66
|
|
175
|
+
const margin = 0
|
|
176
|
+
const maxLeft = Math.max(margin, window.innerWidth - size - margin)
|
|
177
|
+
const maxTop = Math.max(margin, window.innerHeight - size - margin)
|
|
178
|
+
return {
|
|
179
|
+
left: Math.min(Math.max(margin, left), maxLeft),
|
|
180
|
+
top: Math.min(Math.max(margin, top), maxTop)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function getFabRect() {
|
|
185
|
+
const el = document.querySelector('.xy-fab')
|
|
186
|
+
return el?.getBoundingClientRect?.() || null
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function onFabPointerDown(event) {
|
|
190
|
+
if (expanded.value) return
|
|
191
|
+
if (event.button != null && event.button !== 0) return
|
|
192
|
+
const rect = getFabRect()
|
|
193
|
+
if (!rect) return
|
|
194
|
+
fabPointerId = event.pointerId
|
|
195
|
+
fabStartX = event.clientX
|
|
196
|
+
fabStartY = event.clientY
|
|
197
|
+
fabStartLeft = rect.left
|
|
198
|
+
fabStartTop = rect.top
|
|
199
|
+
fabMoved = false
|
|
200
|
+
fabDragging.value = true
|
|
201
|
+
try { event.currentTarget.setPointerCapture?.(event.pointerId) } catch (_) {}
|
|
202
|
+
window.addEventListener('pointermove', onFabPointerMove, { passive: false })
|
|
203
|
+
window.addEventListener('pointerup', onFabPointerUp, { passive: true })
|
|
204
|
+
window.addEventListener('pointercancel', onFabPointerUp, { passive: true })
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function onFabPointerMove(event) {
|
|
208
|
+
if (!fabDragging.value || (fabPointerId != null && event.pointerId !== fabPointerId)) return
|
|
209
|
+
const dx = event.clientX - fabStartX
|
|
210
|
+
const dy = event.clientY - fabStartY
|
|
211
|
+
if (!fabMoved && Math.hypot(dx, dy) < 4) return
|
|
212
|
+
fabMoved = true
|
|
213
|
+
event.preventDefault?.()
|
|
214
|
+
const next = clampFab(fabStartLeft + dx, fabStartTop + dy)
|
|
215
|
+
fabLeft.value = next.left
|
|
216
|
+
fabTop.value = next.top
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function onFabPointerUp(event) {
|
|
220
|
+
if (!fabDragging.value || (fabPointerId != null && event.pointerId !== fabPointerId)) return
|
|
221
|
+
const rect = getFabRect()
|
|
222
|
+
const width = 66
|
|
223
|
+
if (rect) {
|
|
224
|
+
const viewportMid = window.innerWidth / 2
|
|
225
|
+
const snappedLeft = rect.left + rect.width / 2 <= viewportMid ? 0 : Math.max(0, window.innerWidth - width)
|
|
226
|
+
const next = clampFab(snappedLeft, rect.top)
|
|
227
|
+
fabLeft.value = next.left
|
|
228
|
+
fabTop.value = next.top
|
|
229
|
+
}
|
|
230
|
+
fabDragging.value = false
|
|
231
|
+
fabPointerId = null
|
|
232
|
+
window.removeEventListener('pointermove', onFabPointerMove)
|
|
233
|
+
window.removeEventListener('pointerup', onFabPointerUp)
|
|
234
|
+
window.removeEventListener('pointercancel', onFabPointerUp)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function onFabClick(event) {
|
|
238
|
+
if (fabMoved) {
|
|
239
|
+
event.preventDefault()
|
|
240
|
+
event.stopPropagation()
|
|
241
|
+
fabMoved = false
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
activate()
|
|
245
|
+
}
|
|
246
|
+
|
|
153
247
|
const state = computed(() => {
|
|
154
248
|
if (processing.value) return 'processing'
|
|
155
249
|
if (listening.value) return 'listening'
|
|
@@ -588,6 +682,9 @@ onMounted(() => {
|
|
|
588
682
|
})
|
|
589
683
|
|
|
590
684
|
onBeforeUnmount(() => {
|
|
685
|
+
window.removeEventListener('pointermove', onFabPointerMove)
|
|
686
|
+
window.removeEventListener('pointerup', onFabPointerUp)
|
|
687
|
+
window.removeEventListener('pointercancel', onFabPointerUp)
|
|
591
688
|
wakeController?.stop?.()
|
|
592
689
|
speech?.stopSpeaking?.()
|
|
593
690
|
window.clearTimeout(collapseTimer)
|
package/src/styles/index.css
CHANGED
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
.xy-root textarea { font: inherit; }
|
|
23
23
|
|
|
24
24
|
.xy-fab {
|
|
25
|
-
position:
|
|
25
|
+
position: fixed;
|
|
26
|
+
top: 22px;
|
|
27
|
+
right: 22px;
|
|
26
28
|
width: 66px;
|
|
27
29
|
height: 66px;
|
|
28
30
|
border: 1px solid rgba(255,255,255,.24);
|
|
@@ -48,6 +50,20 @@
|
|
|
48
50
|
filter: saturate(1.08);
|
|
49
51
|
}
|
|
50
52
|
.xy-fab:active { transform: translateY(-1px) scale(.985); }
|
|
53
|
+
.xy-fab.xy-dragging {
|
|
54
|
+
cursor: grabbing;
|
|
55
|
+
user-select: none;
|
|
56
|
+
transition: none;
|
|
57
|
+
transform: scale(1.02);
|
|
58
|
+
box-shadow:
|
|
59
|
+
0 20px 54px rgba(41,31,127,.56),
|
|
60
|
+
0 0 0 1px rgba(255,255,255,.12) inset,
|
|
61
|
+
0 0 44px rgba(109,93,252,.40);
|
|
62
|
+
}
|
|
63
|
+
.xy-fab {
|
|
64
|
+
touch-action: none;
|
|
65
|
+
user-select: none;
|
|
66
|
+
}
|
|
51
67
|
.xy-fab-glow {
|
|
52
68
|
position: absolute;
|
|
53
69
|
inset: -18px;
|
|
@@ -271,6 +287,7 @@
|
|
|
271
287
|
|
|
272
288
|
@media (max-width: 720px) {
|
|
273
289
|
.xy-root { top: 12px; right: 12px; }
|
|
290
|
+
.xy-fab { top: 12px; right: 12px; }
|
|
274
291
|
.xy-panel { width: calc(100vw - 24px); height: calc(100vh - 24px); min-height: 0; border-radius: 18px; }
|
|
275
292
|
}
|
|
276
293
|
|