mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
feat(voice): render the pointer reticle beside the voice control
PointerReticle keeps the turn's timers and tool tracking and presents where the user pointed to the gev-pointer-reticle store, one entry per reticle; the command dock teleports each to the body with the same class, aria-hidden, hidden state, target and position. The voice QA reads the card and reticle after Vue's flush, and the application guide says leaving out the command dock leaves out the voice control and its reticle.
This commit is contained in:
1 parent
f9bf782b9c
commit
0926cbc105
11 files changed
+215
-78
No files matched your search
@@ -0,0 +1,32 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { markRaw, shallowRef } from 'vue';
|
||||
|
||||
/**
|
||||
* The voice pointer reticles as their view renders them. Each PointerReticle
|
||||
* (src/voice/pointerReticle.js) presents where the user pointed while its
|
||||
* voice turn is live.
|
||||
*/
|
||||
export const usePointerReticleStore = defineStore('gev-pointer-reticle', () => {
|
||||
/**
|
||||
* `[{owner, visible, left, top, target}]` in client pixels, one per
|
||||
* reticle that has shown, `target` being 'entity' or 'ground'.
|
||||
*/
|
||||
const reticles = shallowRef([]);
|
||||
|
||||
/**
|
||||
* @param {object} owner The reticle publishing.
|
||||
* @param {?object} view Its fresh presentation, or null to remove it.
|
||||
*/
|
||||
function publish(owner, view) {
|
||||
const index = reticles.value.findIndex((item) => item.owner === owner);
|
||||
const next = reticles.value.slice();
|
||||
if (!view) {
|
||||
if (index < 0) return;
|
||||
next.splice(index, 1);
|
||||
} else if (index < 0) next.push(markRaw({ ...view, owner }));
|
||||
else next[index] = markRaw({ ...view, owner });
|
||||
reticles.value = next;
|
||||
}
|
||||
|
||||
return { reticles, publish };
|
||||
});
|
||||
@@ -5,6 +5,7 @@ import { vClassToggle } from '../rail/classToggle.js';
|
||||
import { useDisplayStore } from '../stores/display.js';
|
||||
import { computed } from 'vue';
|
||||
import { useLocationStore } from '../stores/location.js';
|
||||
import { usePointerReticleStore } from '../stores/pointerReticle.js';
|
||||
import { useVoiceStore } from '../stores/voice.js';
|
||||
import PhoneTabBar from './panels/PhoneTabBar.vue';
|
||||
import VoiceControl from './panels/VoiceControl.vue';
|
||||
@@ -32,6 +33,9 @@ const dockOrder = computed(() => {
|
||||
: ['control', 'location'];
|
||||
});
|
||||
|
||||
// Where the user pointed while a voice turn is live (PointerReticle).
|
||||
const { reticles } = storeToRefs(usePointerReticleStore());
|
||||
|
||||
function selectMapSource(chip) {
|
||||
if (!chip.available) return;
|
||||
void mapSourceControls.value?.select(chip.id).catch(() => {});
|
||||
@@ -136,5 +140,8 @@ function selectMapSource(chip) {
|
||||
</div>
|
||||
</template>
|
||||
<PhoneTabBar />
|
||||
<Teleport to="body">
|
||||
<div v-for="reticle in reticles" :key="reticle.owner.key" class="gev-pointer-reticle" aria-hidden="true" :hidden="!reticle.visible" :data-target="reticle.target" :style="{ left: `${reticle.left}px`, top: `${reticle.top}px` }"></div>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
Reference in new issue
Block a user