mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-28 11:37:29 +08:00
feat(agent-assistant): add active prop to AgentAssistantEntry for visibility control
This commit is contained in:
@@ -27,9 +27,11 @@ interface AgentAssistantEntryBubbleInput {
|
|||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
active?: boolean
|
||||||
thinking?: boolean
|
thinking?: boolean
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
|
active: true,
|
||||||
thinking: false,
|
thinking: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -40,24 +42,50 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const FAB_DOCK_STORAGE_KEY = 'moviepilot-agent-assistant-entry-docked'
|
|
||||||
const FAB_IDLE_DOCK_DELAY = 4200
|
const FAB_IDLE_DOCK_DELAY = 4200
|
||||||
const FAB_DOCK_REVEAL_DISTANCE = 18
|
const FAB_RIGHT_EDGE_DOCK_DISTANCE = 88
|
||||||
const FAB_NOTIFICATION_BUBBLE_DURATION = 7000
|
const FAB_NOTIFICATION_BUBBLE_DURATION = 7000
|
||||||
const FAB_MAX_BUBBLES = 4
|
const FAB_MAX_BUBBLES = 4
|
||||||
|
const FAB_DEFAULT_RIGHT_OFFSET = 18
|
||||||
|
const FAB_DEFAULT_VERTICAL_RATIO = 2 / 3
|
||||||
|
|
||||||
|
// 入口位置只保存在当前页面生命周期内,刷新后回到默认位置。
|
||||||
|
interface FabPosition {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FabDragState {
|
||||||
|
pointerId: number
|
||||||
|
startClientX: number
|
||||||
|
startClientY: number
|
||||||
|
startX: number
|
||||||
|
startY: number
|
||||||
|
moved: boolean
|
||||||
|
}
|
||||||
|
|
||||||
const fabDocked = ref(false)
|
const fabDocked = ref(false)
|
||||||
|
const fabPosition = ref<FabPosition | null>(null)
|
||||||
const fabPointerStyle = ref({
|
const fabPointerStyle = ref({
|
||||||
'--agent-assistant-pointer-x': '0px',
|
'--agent-assistant-pointer-x': '0px',
|
||||||
'--agent-assistant-pointer-y': '0px',
|
'--agent-assistant-pointer-y': '0px',
|
||||||
'--agent-assistant-robot-tilt': '0deg',
|
'--agent-assistant-robot-tilt': '0deg',
|
||||||
})
|
})
|
||||||
|
const fabPositionStyle = computed(() => {
|
||||||
|
const position = fabPosition.value || getDefaultFabPosition()
|
||||||
|
|
||||||
|
return {
|
||||||
|
...fabPointerStyle.value,
|
||||||
|
'--agent-assistant-fab-x': `${position.x}px`,
|
||||||
|
'--agent-assistant-fab-y': `${position.y}px`,
|
||||||
|
}
|
||||||
|
})
|
||||||
const fabPressed = ref(false)
|
const fabPressed = ref(false)
|
||||||
const fabBubbles = ref<AgentAssistantEntryBubble[]>([])
|
const fabBubbles = ref<AgentAssistantEntryBubble[]>([])
|
||||||
const fabDragging = ref(false)
|
const fabDragging = ref(false)
|
||||||
|
|
||||||
let fabIdleTimer: number | null = null
|
let fabIdleTimer: number | null = null
|
||||||
let fabDragStart: { pointerId: number; x: number; y: number } | null = null
|
let fabDragState: FabDragState | null = null
|
||||||
let fabSuppressNextClick = false
|
let fabSuppressNextClick = false
|
||||||
let stopNotificationBubbleListener: (() => void) | null = null
|
let stopNotificationBubbleListener: (() => void) | null = null
|
||||||
|
|
||||||
@@ -70,6 +98,94 @@ function createBubbleId(prefix = 'bubble') {
|
|||||||
return `${prefix}-${Date.now()}-${Math.random().toString(16).slice(2)}`
|
return `${prefix}-${Date.now()}-${Math.random().toString(16).slice(2)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getViewportSize() {
|
||||||
|
return {
|
||||||
|
height: window.innerHeight || document.documentElement.clientHeight || 0,
|
||||||
|
width: window.innerWidth || document.documentElement.clientWidth || 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOpenFabSize() {
|
||||||
|
const viewport = getViewportSize()
|
||||||
|
const isMobile = viewport.width <= 600
|
||||||
|
|
||||||
|
return {
|
||||||
|
height: isMobile ? 106 : 115,
|
||||||
|
width: isMobile ? Math.min(198, Math.max(0, viewport.width - 16)) : 211,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDockedFabX() {
|
||||||
|
return Math.max(0, getViewportSize().width - 42)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFabSize() {
|
||||||
|
const root = document.querySelector('.agent-assistant-fab') as HTMLElement | null
|
||||||
|
const rect = root?.getBoundingClientRect()
|
||||||
|
|
||||||
|
return {
|
||||||
|
height: rect?.height || 115,
|
||||||
|
width: rect?.width || 211,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultFabPosition() {
|
||||||
|
if (typeof window === 'undefined') return { x: 0, y: 0 }
|
||||||
|
|
||||||
|
const viewport = getViewportSize()
|
||||||
|
const size = getOpenFabSize()
|
||||||
|
|
||||||
|
// 默认落点放在视窗约 2/3 高度,避开页面底部 FAB 和移动端底部导航。
|
||||||
|
return clampFabPosition({
|
||||||
|
x: viewport.width - size.width - FAB_DEFAULT_RIGHT_OFFSET,
|
||||||
|
y: Math.round(viewport.height * FAB_DEFAULT_VERTICAL_RATIO - size.height / 2),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function clampFabPosition(position: FabPosition) {
|
||||||
|
if (typeof window === 'undefined') return position
|
||||||
|
|
||||||
|
const viewport = getViewportSize()
|
||||||
|
const size = fabDocked.value ? getFabSize() : getOpenFabSize()
|
||||||
|
const maxX = Math.max(0, viewport.width - size.width)
|
||||||
|
const maxY = Math.max(0, viewport.height - size.height)
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: Math.min(maxX, Math.max(0, position.x)),
|
||||||
|
y: Math.min(maxY, Math.max(0, position.y)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentFabPosition() {
|
||||||
|
return fabPosition.value || getDefaultFabPosition()
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFabNearRightEdge(position = getCurrentFabPosition()) {
|
||||||
|
const viewport = getViewportSize()
|
||||||
|
const size = getFabSize()
|
||||||
|
|
||||||
|
return viewport.width - (position.x + size.width) <= FAB_RIGHT_EDGE_DOCK_DISTANCE
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFabPosition(position: FabPosition) {
|
||||||
|
fabPosition.value = clampFabPosition(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetFabPosition() {
|
||||||
|
fabPosition.value = getDefaultFabPosition()
|
||||||
|
if (isFabNearRightEdge()) scheduleFabAutoDock()
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWindowResize() {
|
||||||
|
updateFabPosition(getCurrentFabPosition())
|
||||||
|
if (fabDocked.value && isFabNearRightEdge()) {
|
||||||
|
fabPosition.value = {
|
||||||
|
...getCurrentFabPosition(),
|
||||||
|
x: getDockedFabX(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function stripMarkdownPreview(value: string) {
|
function stripMarkdownPreview(value: string) {
|
||||||
return value
|
return value
|
||||||
.replace(/```[\s\S]*?```/g, ' ')
|
.replace(/```[\s\S]*?```/g, ' ')
|
||||||
@@ -115,10 +231,10 @@ function clearFabIdleTimer() {
|
|||||||
|
|
||||||
function scheduleFabAutoDock() {
|
function scheduleFabAutoDock() {
|
||||||
clearFabIdleTimer()
|
clearFabIdleTimer()
|
||||||
if (fabDocked.value || hasKeepOpenFabBubbles.value) return
|
if (fabDocked.value || hasKeepOpenFabBubbles.value || !isFabNearRightEdge()) return
|
||||||
|
|
||||||
fabIdleTimer = window.setTimeout(() => {
|
fabIdleTimer = window.setTimeout(() => {
|
||||||
setFabDocked(true, { persist: false })
|
setFabDocked(true)
|
||||||
fabIdleTimer = null
|
fabIdleTimer = null
|
||||||
}, FAB_IDLE_DOCK_DELAY)
|
}, FAB_IDLE_DOCK_DELAY)
|
||||||
}
|
}
|
||||||
@@ -154,7 +270,7 @@ function scheduleFabBubbleRemoval(id: string, duration = FAB_NOTIFICATION_BUBBLE
|
|||||||
}
|
}
|
||||||
|
|
||||||
function upsertFabBubble(bubble: AgentAssistantEntryBubble, options: { autoClose?: boolean; duration?: number } = {}) {
|
function upsertFabBubble(bubble: AgentAssistantEntryBubble, options: { autoClose?: boolean; duration?: number } = {}) {
|
||||||
if (!bubble.text) return
|
if (!props.active || !bubble.text) return
|
||||||
|
|
||||||
const existingBubbles = fabBubbles.value.filter(item => item.id !== bubble.id)
|
const existingBubbles = fabBubbles.value.filter(item => item.id !== bubble.id)
|
||||||
fabBubbles.value = [bubble, ...existingBubbles].slice(0, FAB_MAX_BUBBLES)
|
fabBubbles.value = [bubble, ...existingBubbles].slice(0, FAB_MAX_BUBBLES)
|
||||||
@@ -166,7 +282,7 @@ function upsertFabBubble(bubble: AgentAssistantEntryBubble, options: { autoClose
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (options.autoClose) scheduleFabBubbleRemoval(bubble.id, options.duration)
|
if (options.autoClose) scheduleFabBubbleRemoval(bubble.id, options.duration)
|
||||||
setFabDocked(false, { persist: false })
|
setFabDocked(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function showBubble(input: AgentAssistantEntryBubbleInput) {
|
function showBubble(input: AgentAssistantEntryBubbleInput) {
|
||||||
@@ -231,62 +347,84 @@ function resetFabBubbles() {
|
|||||||
fabBubbles.value = []
|
fabBubbles.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFabDocked(docked: boolean, options: { persist?: boolean } = {}) {
|
function setFabDocked(docked: boolean) {
|
||||||
const { persist = true } = options
|
const currentPosition = getCurrentFabPosition()
|
||||||
|
|
||||||
fabDocked.value = docked
|
fabDocked.value = docked
|
||||||
resetFabPointer()
|
resetFabPointer()
|
||||||
if (docked) clearFabIdleTimer()
|
|
||||||
else scheduleFabAutoDock()
|
|
||||||
if (!persist) return
|
|
||||||
|
|
||||||
try {
|
if (docked) {
|
||||||
localStorage.setItem(FAB_DOCK_STORAGE_KEY, JSON.stringify(fabDocked.value))
|
clearFabIdleTimer()
|
||||||
} catch (error) {
|
fabPosition.value = {
|
||||||
// 停靠状态只是入口偏好,写入失败时保持当前内存状态即可。
|
...currentPosition,
|
||||||
|
x: getDockedFabX(),
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function restoreFabDockState() {
|
updateFabPosition({
|
||||||
try {
|
...currentPosition,
|
||||||
fabDocked.value = JSON.parse(localStorage.getItem(FAB_DOCK_STORAGE_KEY) || 'true') !== false
|
x: Math.min(currentPosition.x, Math.max(0, getViewportSize().width - getOpenFabSize().width - FAB_DEFAULT_RIGHT_OFFSET)),
|
||||||
} catch (error) {
|
})
|
||||||
fabDocked.value = true
|
scheduleFabAutoDock()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFabTriggerPointerDown(event: PointerEvent) {
|
function handleFabTriggerPointerDown(event: PointerEvent) {
|
||||||
fabPressed.value = true
|
fabPressed.value = true
|
||||||
pauseFabAutoDock()
|
pauseFabAutoDock()
|
||||||
|
|
||||||
if (!fabDocked.value) return
|
const currentPosition = getCurrentFabPosition()
|
||||||
|
fabDragState = {
|
||||||
fabDragStart = {
|
|
||||||
pointerId: event.pointerId,
|
pointerId: event.pointerId,
|
||||||
x: event.clientX,
|
startClientX: event.clientX,
|
||||||
y: event.clientY,
|
startClientY: event.clientY,
|
||||||
|
startX: currentPosition.x,
|
||||||
|
startY: currentPosition.y,
|
||||||
|
moved: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
;(event.currentTarget as HTMLElement).setPointerCapture?.(event.pointerId)
|
;(event.currentTarget as HTMLElement).setPointerCapture?.(event.pointerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFabTriggerPointerMove(event: PointerEvent) {
|
function handleFabTriggerPointerMove(event: PointerEvent) {
|
||||||
updateFabPointer(event)
|
updateFabPointer(event)
|
||||||
if (!fabDocked.value || !fabDragStart) return
|
if (!fabDragState || fabDragState.pointerId !== event.pointerId) return
|
||||||
|
|
||||||
const movedX = fabDragStart.x - event.clientX
|
const deltaX = event.clientX - fabDragState.startClientX
|
||||||
const movedY = Math.abs(fabDragStart.y - event.clientY)
|
const deltaY = event.clientY - fabDragState.startClientY
|
||||||
if (movedX > FAB_DOCK_REVEAL_DISTANCE && movedY < 48) {
|
const movedDistance = Math.hypot(deltaX, deltaY)
|
||||||
fabDragging.value = true
|
|
||||||
fabSuppressNextClick = true
|
if (movedDistance < 4 && !fabDragState.moved) return
|
||||||
setFabDocked(false, { persist: false })
|
|
||||||
}
|
fabDragState.moved = true
|
||||||
|
fabDragging.value = true
|
||||||
|
fabSuppressNextClick = true
|
||||||
|
fabDocked.value = false
|
||||||
|
updateFabPosition({
|
||||||
|
x: fabDragState.startX + deltaX,
|
||||||
|
y: fabDragState.startY + deltaY,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFabTriggerPointerUp(event: PointerEvent) {
|
function handleFabTriggerPointerUp(event: PointerEvent) {
|
||||||
fabPressed.value = false
|
fabPressed.value = false
|
||||||
|
const wasDragging = fabDragging.value
|
||||||
|
|
||||||
fabDragging.value = false
|
fabDragging.value = false
|
||||||
fabDragStart = null
|
fabDragState = null
|
||||||
;(event.currentTarget as HTMLElement).releasePointerCapture?.(event.pointerId)
|
;(event.currentTarget as HTMLElement).releasePointerCapture?.(event.pointerId)
|
||||||
if (!fabDocked.value) scheduleFabAutoDock()
|
|
||||||
|
if (!wasDragging) {
|
||||||
|
scheduleFabAutoDock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFabNearRightEdge()) {
|
||||||
|
scheduleFabAutoDock()
|
||||||
|
} else {
|
||||||
|
clearFabIdleTimer()
|
||||||
|
fabDocked.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFabTriggerClick() {
|
function handleFabTriggerClick() {
|
||||||
@@ -296,18 +434,17 @@ function handleFabTriggerClick() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fabDocked.value) {
|
if (fabDocked.value) {
|
||||||
setFabDocked(false, { persist: false })
|
setFabDocked(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clearBubbles()
|
clearBubbles()
|
||||||
setFabDocked(true, { persist: false })
|
|
||||||
emit('open')
|
emit('open')
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFabPointerLeave() {
|
function handleFabPointerLeave() {
|
||||||
resetFabPointer()
|
resetFabPointer()
|
||||||
if (!fabDocked.value) scheduleFabAutoDock()
|
if (!fabDocked.value && isFabNearRightEdge()) scheduleFabAutoDock()
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFabPointerEnter() {
|
function handleFabPointerEnter() {
|
||||||
@@ -315,15 +452,30 @@ function handleFabPointerEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
restoreFabDockState()
|
nextTick(resetFabPosition)
|
||||||
|
window.addEventListener('resize', handleWindowResize)
|
||||||
stopNotificationBubbleListener = onAgentAssistantNotificationBubble(showNotificationBubble)
|
stopNotificationBubbleListener = onAgentAssistantNotificationBubble(showNotificationBubble)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.active,
|
||||||
|
active => {
|
||||||
|
if (active) {
|
||||||
|
if (isFabNearRightEdge()) scheduleFabAutoDock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clearBubbles()
|
||||||
|
clearFabIdleTimer()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
onScopeDispose(clearFabIdleTimer)
|
onScopeDispose(clearFabIdleTimer)
|
||||||
onScopeDispose(resetFabBubbles)
|
onScopeDispose(resetFabBubbles)
|
||||||
onScopeDispose(() => {
|
onScopeDispose(() => {
|
||||||
stopNotificationBubbleListener?.()
|
stopNotificationBubbleListener?.()
|
||||||
stopNotificationBubbleListener = null
|
stopNotificationBubbleListener = null
|
||||||
|
window.removeEventListener('resize', handleWindowResize)
|
||||||
})
|
})
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
@@ -338,14 +490,16 @@ defineExpose({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
v-show="props.active"
|
||||||
class="agent-assistant-fab"
|
class="agent-assistant-fab"
|
||||||
:class="{
|
:class="{
|
||||||
'is-docked': fabDocked,
|
'is-docked': fabDocked,
|
||||||
|
'is-dragging': fabDragging,
|
||||||
'is-pressed': fabPressed,
|
'is-pressed': fabPressed,
|
||||||
'is-thinking': props.thinking,
|
'is-thinking': props.thinking,
|
||||||
'is-bubble-visible': hasFabBubbles,
|
'is-bubble-visible': hasFabBubbles,
|
||||||
}"
|
}"
|
||||||
:style="fabPointerStyle"
|
:style="fabPositionStyle"
|
||||||
@pointermove="updateFabPointer"
|
@pointermove="updateFabPointer"
|
||||||
@pointerenter="handleFabPointerEnter"
|
@pointerenter="handleFabPointerEnter"
|
||||||
@pointerleave="handleFabPointerLeave"
|
@pointerleave="handleFabPointerLeave"
|
||||||
@@ -408,7 +562,9 @@ defineExpose({
|
|||||||
|
|
||||||
.agent-assistant-fab {
|
.agent-assistant-fab {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 1000;
|
|
||||||
|
/* 保持高于菜单浮层,但低于 agent 会话面板(2101)。 */
|
||||||
|
z-index: 2100;
|
||||||
|
|
||||||
--agent-assistant-robot-outline: #5b00c5;
|
--agent-assistant-robot-outline: #5b00c5;
|
||||||
--agent-assistant-robot-outline-soft: #7432df;
|
--agent-assistant-robot-outline-soft: #7432df;
|
||||||
@@ -421,24 +577,27 @@ defineExpose({
|
|||||||
--agent-assistant-robot-play: #fff;
|
--agent-assistant-robot-play: #fff;
|
||||||
--agent-assistant-robot-shadow: rgba(54, 0, 126, 28%);
|
--agent-assistant-robot-shadow: rgba(54, 0, 126, 28%);
|
||||||
--agent-assistant-robot-shadow-strong: rgba(54, 0, 126, 34%);
|
--agent-assistant-robot-shadow-strong: rgba(54, 0, 126, 34%);
|
||||||
|
--agent-assistant-fab-x: calc(100vw - 14.3rem);
|
||||||
|
--agent-assistant-fab-y: calc(100vh - 13.2rem);
|
||||||
|
|
||||||
block-size: 7.2rem;
|
block-size: 7.2rem;
|
||||||
inline-size: 13.2rem;
|
inline-size: 13.2rem;
|
||||||
|
inset-block-start: 0;
|
||||||
/* 入口停在右下侧,但保留一点悬浮感,避免挡住底部导航和常用操作。 */
|
inset-inline-start: 0;
|
||||||
inset-block-start: clamp(12rem, 66vh, calc(100vh - 8.2rem));
|
|
||||||
inset-inline-end: max(1.1rem, env(safe-area-inset-right));
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transform: translateY(-50%);
|
transform: translate3d(var(--agent-assistant-fab-x), var(--agent-assistant-fab-y), 0);
|
||||||
transition:
|
transition:
|
||||||
inline-size 0.24s ease,
|
inline-size 0.24s ease,
|
||||||
inset-inline-end 0.24s ease,
|
|
||||||
transform 0.24s ease;
|
transform 0.24s ease;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-assistant-fab.is-docked {
|
.agent-assistant-fab.is-docked {
|
||||||
inline-size: 3.85rem;
|
inline-size: 3.85rem;
|
||||||
inset-inline-end: max(-1.55rem, calc(env(safe-area-inset-right) - 1.55rem));
|
}
|
||||||
|
|
||||||
|
.agent-assistant-fab.is-dragging {
|
||||||
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-assistant-fab__trigger {
|
.agent-assistant-fab__trigger {
|
||||||
@@ -447,14 +606,19 @@ defineExpose({
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
block-size: 100%;
|
block-size: 5.1rem;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
inline-size: 100%;
|
inline-size: 5.4rem;
|
||||||
inset: 0;
|
inset-block: auto 0;
|
||||||
|
inset-inline: auto 0;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
text-align: start;
|
text-align: start;
|
||||||
touch-action: manipulation;
|
touch-action: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-assistant-fab.is-dragging .agent-assistant-fab__trigger {
|
||||||
|
cursor: grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-assistant-fab__trigger::after {
|
.agent-assistant-fab__trigger::after {
|
||||||
@@ -940,14 +1104,10 @@ defineExpose({
|
|||||||
.agent-assistant-fab {
|
.agent-assistant-fab {
|
||||||
block-size: 6.65rem;
|
block-size: 6.65rem;
|
||||||
inline-size: min(12.4rem, calc(100vw - 1rem));
|
inline-size: min(12.4rem, calc(100vw - 1rem));
|
||||||
inset-block: auto calc(env(safe-area-inset-bottom, 0px) + 5.6rem);
|
|
||||||
inset-inline-end: 0.7rem;
|
|
||||||
transform: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-assistant-fab.is-docked {
|
.agent-assistant-fab.is-docked {
|
||||||
inline-size: 3.45rem;
|
inline-size: 3.45rem;
|
||||||
inset-inline-end: -1.28rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-assistant-fab__bubbles {
|
.agent-assistant-fab__bubbles {
|
||||||
@@ -970,6 +1130,11 @@ defineExpose({
|
|||||||
font-size: 0.68rem;
|
font-size: 0.68rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.agent-assistant-fab__trigger {
|
||||||
|
block-size: 4.8rem;
|
||||||
|
inline-size: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.agent-assistant-fab__bot {
|
.agent-assistant-fab__bot {
|
||||||
inset-inline-end: 1.02rem;
|
inset-inline-end: 1.02rem;
|
||||||
transform: scale(0.82) translate(var(--agent-assistant-pointer-x), var(--agent-assistant-pointer-y))
|
transform: scale(0.82) translate(var(--agent-assistant-pointer-x), var(--agent-assistant-pointer-y))
|
||||||
|
|||||||
@@ -21,6 +21,6 @@ function handleAssistantPreview(value: string) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AgentAssistantEntry ref="entryRef" :thinking="thinking" @open="openPanel" />
|
<AgentAssistantEntry ref="entryRef" :active="!panelOpen" :thinking="thinking" @open="openPanel" />
|
||||||
<AgentAssistantPanel v-model="panelOpen" @assistant-preview="handleAssistantPreview" @thinking-change="thinking = $event" />
|
<AgentAssistantPanel v-model="panelOpen" @assistant-preview="handleAssistantPreview" @thinking-change="thinking = $event" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user