mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
feat(voice): render the voice control from a presenter
createVoiceControl now returns a presenter instead of building the control with innerHTML: the session, cost, input, card and panel owners write its state by part and listen for interactions, and VoiceControl.vue renders it in the command dock, between the location bar and the visual presets as before. Focus moves wait for the render; the waveform's bars publish apart from the control and only when they change; the minutes field keeps a draft until its owner writes it. Owner tests use a real presenter on their own store, and view tests render the control.
This commit is contained in:
1 parent
2ffd7a4afd
commit
1de4f635ca
47 files changed
+1691
-1645
No files matched your search
@@ -3,8 +3,11 @@ import { storeToRefs } from 'pinia';
|
||||
import { t } from '../../i18n/index.js';
|
||||
import { vClassToggle } from '../rail/classToggle.js';
|
||||
import { useDisplayStore } from '../stores/display.js';
|
||||
import { computed } from 'vue';
|
||||
import { useLocationStore } from '../stores/location.js';
|
||||
import { useVoiceStore } from '../stores/voice.js';
|
||||
import PhoneTabBar from './panels/PhoneTabBar.vue';
|
||||
import VoiceControl from './panels/VoiceControl.vue';
|
||||
|
||||
// VisualSettings publishes the active style and the map source controls
|
||||
// their chip row; until they do, the dock shows its initial markup. The
|
||||
@@ -14,6 +17,21 @@ const { style, mapSource, mapSourceControls } = storeToRefs(useDisplayStore());
|
||||
// and the search field keeps their listeners.
|
||||
const { view: loc, controls: locationControls } = storeToRefs(useLocationStore());
|
||||
|
||||
// The voice control, while a voice session presents one. It sits between the
|
||||
// location bar and the visual presets; the trays keep their elements when the
|
||||
// order changes.
|
||||
const { view: voice } = storeToRefs(useVoiceStore());
|
||||
// Once voice has taken its place, the location bar stays first.
|
||||
let voiceShown = false;
|
||||
const dockOrder = computed(() => {
|
||||
if (voice.value) voiceShown = true;
|
||||
return voice.value
|
||||
? ['location', 'voice', 'control']
|
||||
: voiceShown
|
||||
? ['location', 'control']
|
||||
: ['control', 'location'];
|
||||
});
|
||||
|
||||
function selectMapSource(chip) {
|
||||
if (!chip.available) return;
|
||||
void mapSourceControls.value?.select(chip.id).catch(() => {});
|
||||
@@ -21,10 +39,11 @@ function selectMapSource(chip) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Unified bottom command dock: locations, voice (injected at runtime), visual presets -->
|
||||
<!-- Unified bottom command dock: locations, voice, visual presets -->
|
||||
<div id="command-dock" class="ui-scroll" aria-label="Navigation, voice, and visual preset controls" data-i18n-aria-label>
|
||||
<template v-for="slot in dockOrder" :key="slot">
|
||||
<!-- Control panel -->
|
||||
<div id="control-panel" class="panel-collapsible collapsed">
|
||||
<div v-if="slot === 'control'" id="control-panel" class="panel-collapsible collapsed">
|
||||
<div class="panel-glow"></div>
|
||||
<div class="panel-inner">
|
||||
<button id="control-panel-toggle" class="panel-header dock-tray-toggle" type="button"
|
||||
@@ -82,8 +101,10 @@ function selectMapSource(chip) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VoiceControl v-else-if="slot === 'voice'" :key="voice.id" :view="voice" />
|
||||
|
||||
<!-- Location bar -->
|
||||
<div id="location-bar" class="panel-collapsible collapsed">
|
||||
<div v-else-if="slot === 'location'" id="location-bar" class="panel-collapsible collapsed">
|
||||
<div class="panel-glow"></div>
|
||||
<div class="location-inner">
|
||||
<div class="location-toolbar">
|
||||
@@ -113,6 +134,7 @@ function selectMapSource(chip) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<PhoneTabBar />
|
||||
</div>
|
||||
</template>
|
||||
Reference in new issue
Block a user