xiaoyuan-assistant 0.5.57 → 0.5.58

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 CHANGED
@@ -462,3 +462,9 @@ ls -lh /mnt/data/xiaoyuan-assistant-siliconflow-v0.5.29.zip
462
462
  - 收起状态小园悬浮图标支持按住鼠标/触控拖拽到屏幕任意位置。
463
463
  - 松开后自动吸附到距离最近的左侧或右侧屏幕边界,保持当前垂直位置。
464
464
  - 拖拽过程禁用点击误触和过渡动画,提升大屏操作稳定性。
465
+
466
+ ## v0.5.58
467
+ - 收起状态拖拽后左右吸附固定保持 50px 边距。
468
+ - 取消拖拽结束后的焦点黑框/系统焦点外观。
469
+ - 展开面板跟随当前小园图标的位置与左右侧关系定位,不再固定在原始右上角。
470
+
@@ -1280,3 +1280,8 @@ AI 分析开始提示音与数据获取/模型分析并行;多个数据源采
1280
1280
  ## v0.5.57|收起态悬浮图标拖拽
1281
1281
 
1282
1282
  收起状态下,小园悬浮图标支持按住拖拽。用户可将图标移动到屏幕任意位置;松开鼠标或触控后,根据图标中心点距离自动吸附到最近的左侧或右侧边界,同时保持当前垂直位置。拖拽过程中不会触发打开小园的点击事件。
1283
+
1284
+ ## v0.5.58
1285
+ - 收起图标支持拖拽后吸附:无论左侧还是右侧,距离屏幕边界固定 50px。
1286
+ - 拖拽结束主动移除按钮焦点,避免出现黑色焦点框。
1287
+ - 打开小园时,面板根据当前图标的 left/top 与左右侧位置动态定位,保证弹窗与小园当前位置一致。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xiaoyuan-assistant",
3
- "version": "0.5.57",
3
+ "version": "0.5.58",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "module": "./src/index.js",
@@ -27,7 +27,7 @@
27
27
  </button>
28
28
 
29
29
  <transition name="xy-pop">
30
- <section v-if="expanded" class="xy-panel" aria-label="小园智能助手">
30
+ <section v-if="expanded" class="xy-panel" :style="panelStyle" aria-label="小园智能助手">
31
31
  <header class="xy-header">
32
32
  <div class="xy-title-wrap">
33
33
  <div class="xy-avatar small">园</div>
@@ -130,7 +130,7 @@ const runtime =
130
130
  // 如果宿主项目因为 HMR / 重复依赖导致当前模块暂时拿不到注入值,
131
131
  // 组件保持可挂载,并在 mounted 后再次尝试解析,避免整个页面崩溃。
132
132
  const safeRuntime = runtime || { manager: null, speech: null, options: {} }
133
- const XIAOYUAN_SDK_VERSION = '0.5.57'
133
+ const XIAOYUAN_SDK_VERSION = '0.5.58'
134
134
  const { manager, speech, options } = safeRuntime
135
135
 
136
136
  const wakeWord = options.wakeWord || '你好小园'
@@ -170,9 +170,29 @@ const fabStyle = computed(() => {
170
170
  }
171
171
  })
172
172
 
173
+ const panelStyle = computed(() => {
174
+ if (fabLeft.value == null || fabTop.value == null) return undefined
175
+ const fabSize = 66
176
+ const panelWidth = Math.min(430, Math.max(280, window.innerWidth - 28))
177
+ const distanceFromRight = Math.max(0, window.innerWidth - (fabLeft.value + fabSize))
178
+ const top = Math.max(8, Math.min(fabTop.value, Math.max(8, window.innerHeight - Math.min(680, window.innerHeight - 24))))
179
+ if (fabLeft.value + fabSize / 2 >= window.innerWidth / 2) {
180
+ return {
181
+ right: `${Math.max(14, distanceFromRight)}px`,
182
+ left: 'auto',
183
+ top: `${top}px`
184
+ }
185
+ }
186
+ return {
187
+ left: `${Math.max(14, fabLeft.value)}px`,
188
+ right: 'auto',
189
+ top: `${top}px`
190
+ }
191
+ })
192
+
173
193
  function clampFab(left, top) {
174
194
  const size = 66
175
- const margin = 0
195
+ const margin = 50
176
196
  const maxLeft = Math.max(margin, window.innerWidth - size - margin)
177
197
  const maxTop = Math.max(margin, window.innerHeight - size - margin)
178
198
  return {
@@ -222,13 +242,14 @@ function onFabPointerUp(event) {
222
242
  const width = 66
223
243
  if (rect) {
224
244
  const viewportMid = window.innerWidth / 2
225
- const snappedLeft = rect.left + rect.width / 2 <= viewportMid ? 0 : Math.max(0, window.innerWidth - width)
245
+ const snappedLeft = rect.left + rect.width / 2 <= viewportMid ? 50 : Math.max(50, window.innerWidth - width - 50)
226
246
  const next = clampFab(snappedLeft, rect.top)
227
247
  fabLeft.value = next.left
228
248
  fabTop.value = next.top
229
249
  }
230
250
  fabDragging.value = false
231
251
  fabPointerId = null
252
+ try { document.activeElement?.blur?.() } catch (_) {}
232
253
  window.removeEventListener('pointermove', onFabPointerMove)
233
254
  window.removeEventListener('pointerup', onFabPointerUp)
234
255
  window.removeEventListener('pointercancel', onFabPointerUp)
@@ -39,6 +39,8 @@
39
39
  0 0 0 1px rgba(255,255,255,.06) inset,
40
40
  0 0 32px rgba(109,93,252,.24);
41
41
  transition: transform .22s cubic-bezier(.2,.8,.2,1), box-shadow .22s ease, filter .22s ease;
42
+ outline: none;
43
+ -webkit-tap-highlight-color: transparent;
42
44
  isolation: isolate;
43
45
  }
44
46
  .xy-fab:hover {
@@ -50,6 +52,7 @@
50
52
  filter: saturate(1.08);
51
53
  }
52
54
  .xy-fab:active { transform: translateY(-1px) scale(.985); }
55
+ .xy-fab:focus, .xy-fab:focus-visible { outline: none; box-shadow: 0 18px 44px rgba(41,31,127,.44), 0 0 0 1px rgba(255,255,255,.06) inset, 0 0 32px rgba(109,93,252,.24); }
53
56
  .xy-fab.xy-dragging {
54
57
  cursor: grabbing;
55
58
  user-select: none;
@@ -168,10 +171,11 @@
168
171
  @keyframes xy-live-pulse { 0%,100% { transform: scale(.85); } 50% { transform: scale(1.15); } }
169
172
 
170
173
  .xy-panel {
171
- position: relative;
174
+ position: fixed;
172
175
  width: min(430px, calc(100vw - 28px));
173
176
  height: min(680px, calc(100vh - 44px));
174
177
  min-height: 500px;
178
+ z-index: 2;
175
179
  background: linear-gradient(180deg, rgba(17,24,47,.985), rgba(8,13,29,.99));
176
180
  border: 1px solid var(--xy-border-strong);
177
181
  border-radius: 22px;