fix(avatar): 移除并行工具轮播,头像固定显示当前工具,文字过渡与SVG切换同步

This commit is contained in:
JOJO 2026-08-12 23:41:34 +08:00
parent 56c067b710
commit 4f940e9a86
2 changed files with 21 additions and 28 deletions

View File

@ -101,7 +101,6 @@ const props = withDefaults(
}
);
const emit = defineEmits<{
(event: 'active-index', index: number): void;
(event: 'poke'): void;
}>();
@ -314,18 +313,12 @@ function trackEyes() {
trackRaf = requestAnimationFrame(trackEyes);
}
// ---- ----
let carouselTimer: number | null = null;
// ---- face ----
let faceSwitchTimer: number | null = null;
let blinkTimer: number | null = null;
let nervousTimer: number | null = null;
let isBlinking = false;
let carouselIdx = 0;
const internalMode = ref<string | null>(null);
function stopCarousel() {
if (carouselTimer) clearInterval(carouselTimer);
carouselTimer = null;
}
function stopFaceSwitchTimer() {
if (faceSwitchTimer) clearTimeout(faceSwitchTimer);
faceSwitchTimer = null;
@ -375,7 +368,6 @@ function triggerNervous() {
stopAutoBlink();
stopNervousTimer();
stopTracking();
stopCarousel();
stopFaceSwitchTimer();
activeFaceKey.value = null;
sharedVisible.value = true;
@ -424,20 +416,6 @@ function setIconFace(key: string, animated = true) {
faceSwitchTimer = null;
}, 160);
}
function startCarousel(keys: string[]) {
stopCarousel();
stopFaceSwitchTimer();
carouselIdx = 0;
setIconFace(keys[0]);
emit('active-index', carouselIdx);
if (keys.length < 2) return;
carouselTimer = window.setInterval(() => {
carouselIdx = (carouselIdx + 1) % keys.length;
setIconFace(keys[carouselIdx]);
emit('active-index', carouselIdx);
}, 1450);
}
// ---- ----
function applyState() {
if (props.mode !== 'idle' && internalMode.value) {
@ -449,10 +427,11 @@ function applyState() {
if (mode === 'tool') {
stopTracking();
const keys = (props.toolKeys || []).filter(Boolean);
startCarousel(keys.length ? keys : ['command']);
//
// toolKeys
setIconFace(keys.length ? keys[0] : 'command');
return;
}
stopCarousel();
stopFaceSwitchTimer();
if (mode === 'think') {
stopTracking();
@ -493,7 +472,13 @@ function applyState() {
}
}
watch(() => [props.mode, props.toolKeys, props.tracking, internalMode.value], () => applyState(), { deep: true });
// toolKeys join avatarStatus computed
// intent applyState
// face
watch(
() => [props.mode, (props.toolKeys || []).join('\u001f'), props.tracking, internalMode.value],
() => applyState()
);
onMounted(() => {
// SVG
@ -504,7 +489,6 @@ onMounted(() => {
onBeforeUnmount(() => {
document.removeEventListener('mousemove', onMouseMove);
stopTracking();
stopCarousel();
stopFaceSwitchTimer();
stopAutoBlink();
stopNervousTimer();

View File

@ -106,7 +106,7 @@
</span>
<span
v-else-if="composerAvatarText"
:key="`tool-${props.avatarStatus?.mode}`"
:key="composerAvatarTextKey"
class="composer-avatar__text"
:class="{
'composer-avatar__text--right': !floatingStatusVisible,
@ -975,6 +975,15 @@ const composerAvatarText = computed(() => {
return '';
});
// key running tool
// 12 out-in SVG
const composerAvatarTextKey = computed(() => {
const s = props.avatarStatus;
if (!s) return 'avatar-none';
if (s.mode === 'tool') return `avatar-tool-${s.toolKeys?.[0] || ''}`;
return `avatar-${s.mode}`;
});
const projectGitMenuOpen = ref<null | 'project' | 'branch'>(null);
const closeProjectGitMenu = () => {