feat(stage): group chat controls and track speech mute (#2139)
This commit is contained in:
@@ -44,7 +44,6 @@ const { activeCard, activeCardId } = storeToRefs(airiCardStore)
|
||||
const { t } = useI18n()
|
||||
const { openImagePreview } = journalPreviewStore
|
||||
const isComposing = ref(false)
|
||||
const sessionsDrawerOpen = defineModel<boolean>('sessionsDrawerOpen', { default: false })
|
||||
const DOUBLE_ENTER_INTERVAL_MS = 300
|
||||
const TRAILING_NEWLINES_REGEX = /[\r\n]+$/
|
||||
const SEND_MODES = ['enter', 'ctrl-enter', 'double-enter'] as const
|
||||
@@ -329,17 +328,6 @@ async function handleCleanupMessages() {
|
||||
</div>
|
||||
</div>
|
||||
<div :class="['flex items-center justify-end gap-2 py-1']">
|
||||
<button
|
||||
:class="[
|
||||
'max-h-[10lh] min-h-[1lh] flex items-center justify-center rounded-md p-2 outline-none',
|
||||
'bg-neutral-100 text-lg text-neutral-500 transition-colors transition-transform active:scale-95',
|
||||
'dark:bg-neutral-800 dark:text-neutral-400 hover:text-primary-500 dark:hover:text-primary-400',
|
||||
]"
|
||||
title="Conversations"
|
||||
@click="sessionsDrawerOpen = true"
|
||||
>
|
||||
<div class="i-solar:chat-line-bold-duotone" />
|
||||
</button>
|
||||
<DropdownMenuRoot>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<button
|
||||
|
||||
+9
-9
@@ -179,15 +179,6 @@ function resetMainWindowPosition() {
|
||||
</template>
|
||||
</ControlButtonTooltip>
|
||||
|
||||
<ControlButtonTooltip disable-hoverable-content>
|
||||
<ControlButton :button-style="adjustStyleClasses.button" @click="openChat">
|
||||
<div i-solar:chat-line-line-duotone :class="adjustStyleClasses.icon" text="neutral-800 dark:neutral-300" />
|
||||
</ControlButton>
|
||||
<template #tooltip>
|
||||
{{ t('tamagotchi.stage.controls-island.open-chat') }}
|
||||
</template>
|
||||
</ControlButtonTooltip>
|
||||
|
||||
<ControlButtonTooltip disable-hoverable-content>
|
||||
<ControlButton :button-style="adjustStyleClasses.button" @click="refreshWindow">
|
||||
<div i-solar:refresh-linear :class="adjustStyleClasses.icon" text="neutral-800 dark:neutral-300" />
|
||||
@@ -257,6 +248,15 @@ function resetMainWindowPosition() {
|
||||
</template>
|
||||
</ControlButtonTooltip>
|
||||
|
||||
<ControlButtonTooltip side="left">
|
||||
<ControlButton :button-style="adjustStyleClasses.button" @click="openChat">
|
||||
<div i-solar:chat-line-line-duotone :class="adjustStyleClasses.icon" text="neutral-800 dark:neutral-300" />
|
||||
</ControlButton>
|
||||
<template #tooltip>
|
||||
{{ t('tamagotchi.stage.controls-island.open-chat') }}
|
||||
</template>
|
||||
</ControlButtonTooltip>
|
||||
|
||||
<ControlButtonTooltip side="left">
|
||||
<ControlsIslandHearingConfig :show="blockingOverlays.has('hearing')" @update:show="setOverlay('hearing', $event)">
|
||||
<div class="relative">
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { defineInvoke } from '@moeru/eventa'
|
||||
import { useStopSpeakingButton } from '@proj-airi/stage-layouts/composables/useStopSpeakingButton'
|
||||
import { ChatSessionsDrawer } from '@proj-airi/stage-ui/components'
|
||||
import { getSpeechBusContext, speechOutputGetPlaybackState } from '@proj-airi/stage-ui/services/speech/bus'
|
||||
import { shallowRef } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
@@ -8,7 +10,17 @@ import InteractiveArea from '../components/InteractiveArea.vue'
|
||||
import WindowTitleBar from '../components/Window/TitleBar.vue'
|
||||
|
||||
const sessionsDrawerOpen = shallowRef(false)
|
||||
const { speechMuted, toggleSpeechMuted } = useStopSpeakingButton()
|
||||
const getOutputPlaybackState = defineInvoke(getSpeechBusContext(), speechOutputGetPlaybackState)
|
||||
const { speechMuted, toggleSpeechMuted } = useStopSpeakingButton({
|
||||
resolveSpeakingState: async () => {
|
||||
// A BroadcastChannel round trip is normally immediate. Bound the
|
||||
// analytics-only lookup so a reloading output renderer cannot stall mute.
|
||||
const state = await getOutputPlaybackState(undefined, {
|
||||
signal: AbortSignal.timeout(1000),
|
||||
})
|
||||
return state.speaking
|
||||
},
|
||||
})
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
@@ -20,6 +32,19 @@ const { t } = useI18n()
|
||||
@title-click="sessionsDrawerOpen = true"
|
||||
>
|
||||
<template #actions>
|
||||
<button
|
||||
data-testid="conversation-selector-button"
|
||||
:class="[
|
||||
'h-7 w-7 flex items-center justify-center rounded-md outline-none',
|
||||
'text-base text-neutral-400 transition-colors transition-transform active:scale-95',
|
||||
'hover:bg-neutral-200 hover:text-primary-500 dark:text-neutral-500 dark:hover:bg-neutral-800 dark:hover:text-primary-400',
|
||||
]"
|
||||
:title="t('stage.chat.sessions.title')"
|
||||
:aria-label="t('stage.chat.sessions.title')"
|
||||
@click="sessionsDrawerOpen = true"
|
||||
>
|
||||
<div class="i-solar:chat-line-bold-duotone" />
|
||||
</button>
|
||||
<button
|
||||
data-testid="speech-mute-button"
|
||||
:class="[
|
||||
@@ -40,7 +65,6 @@ const { t } = useI18n()
|
||||
</template>
|
||||
</WindowTitleBar>
|
||||
<InteractiveArea
|
||||
v-model:sessions-drawer-open="sessionsDrawerOpen"
|
||||
class="interaction-area block"
|
||||
h-full w-full p-4 transition="opacity duration-250"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user