|
53 | 53 | </div> |
54 | 54 | <div v-if="showBottomSpacer" class="w-full" :style="{ height: spacerHeight + 'px' }"></div> |
55 | 55 | </CustomAutoScrollContainer> |
56 | | - <button @click="scrollContainer.scrollToBottom();"> |
57 | | - <IconArrowDownOutline |
58 | | - class="absolute z-10 bottom-8 left-1/2 -translate-x-1/2 bg-lightPrimary/20 dark:bg-darkPrimary/10 |
59 | | - border border-lightPrimary dark:border-darkPrimary text-lightPrimary dark:text-darkPrimary p-2 w-10 h-10 |
60 | | - rounded-full transition-opacity duration-100 ease-in backdrop-blur-sm" |
61 | | - :class="showScrollToBottomButton ? 'opacity-100' : 'opacity-0 pointer-events-none'" |
62 | | - :disabled="!showScrollToBottomButton" |
63 | | - /> |
64 | | - </button> |
| 56 | + <Transition |
| 57 | + enter-active-class="transition-all duration-250 ease-out" |
| 58 | + enter-from-class="opacity-0 translate-y-3 scale-90" |
| 59 | + enter-to-class="opacity-100 translate-y-0 scale-100" |
| 60 | + leave-active-class="transition-all duration-200 ease-in" |
| 61 | + leave-from-class="opacity-100 translate-y-0 scale-100" |
| 62 | + leave-to-class="opacity-0 translate-y-3 scale-90" |
| 63 | + > |
| 64 | + <button |
| 65 | + v-if="showScrollToBottomButton" |
| 66 | + @click="scrollContainer.scrollToBottom();" |
| 67 | + class="absolute z-10 bottom-8 left-1/2 -translate-x-1/2 |
| 68 | + bg-lightPrimary/20 dark:bg-darkPrimary/10 |
| 69 | + border border-lightPrimary dark:border-darkPrimary |
| 70 | + text-lightPrimary dark:text-darkPrimary |
| 71 | + backdrop-blur-sm rounded-full |
| 72 | + w-10 h-10 flex items-center justify-center gap-0.5" |
| 73 | + :class="{ 'w-12 h-8': showAnimationInScrollToBottomButton }" |
| 74 | + > |
| 75 | + <IconArrowDownOutline |
| 76 | + v-if="!showAnimationInScrollToBottomButton" |
| 77 | + class="p-2 w-10 h-10 transition-opacity duration-100 ease-in " |
| 78 | + :disabled="!showScrollToBottomButton" |
| 79 | + /> |
| 80 | + <ThreeDotsAnimation |
| 81 | + v-else |
| 82 | + :disabled="!showScrollToBottomButton" |
| 83 | + /> |
| 84 | + </button> |
| 85 | + </Transition> |
65 | 86 | </div> |
66 | 87 | </template> |
67 | 88 |
|
68 | 89 |
|
69 | 90 | <script setup lang="ts"> |
70 | 91 | import type { IMessage } from '../types'; |
71 | | -import { useTemplateRef, ref, onMounted, onUnmounted, watch, nextTick, defineAsyncComponent } from 'vue'; |
| 92 | +import { useTemplateRef, ref, onMounted, onUnmounted, watch, nextTick, defineAsyncComponent, computed } from 'vue'; |
72 | 93 | import { IconArrowDownOutline } from '@iconify-prerendered/vue-flowbite'; |
73 | 94 | import SessionsHistory from '../SessionsHistory.vue'; |
74 | 95 | import { useAgentStore } from '../composables/useAgentStore'; |
75 | 96 | import { useAgentTransitions } from '../composables/useAgentTransitions'; |
76 | 97 | import MessageRenderer from './MessageRenderer.vue'; |
| 98 | +import ThreeDotsAnimation from './ThreeDotsAnimation.vue'; |
77 | 99 |
|
78 | 100 | const CustomAutoScrollContainer = defineAsyncComponent(() => import('../CustomAutoScrollContainer.vue')); |
79 | 101 |
|
@@ -114,6 +136,10 @@ let updateSpacerFrameId: number | null = null; |
114 | 136 | let pendingSpacerUpdate: Promise<void> | null = null; |
115 | 137 | let spacerUpdateQueued = false; |
116 | 138 |
|
| 139 | +const showAnimationInScrollToBottomButton = computed(() => { |
| 140 | + return agentStore.isResponseInProgress && showScrollToBottomButton.value; |
| 141 | +}); |
| 142 | +
|
117 | 143 | onMounted(async () => { |
118 | 144 | messageResizeObserver = new ResizeObserver(() => { |
119 | 145 | scheduleSpacerHeightUpdate(); |
|
0 commit comments