104 lines
3.2 KiB
Vue
104 lines
3.2 KiB
Vue
<template>
|
|
<div :class="[theme, 'min-h-screen flex flex-col no-select']"> <!-- min-h-screen and flex flex-col are good -->
|
|
<router-view class="flex-grow" /> <!-- Add flex-grow to router-view if its direct child needs to expand -->
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, onMounted, watch } from 'vue';
|
|
import { useStore } from 'vuex';
|
|
import { AudioService } from './services/AudioService';
|
|
|
|
const store = useStore();
|
|
const theme = computed(() => store.getters.theme);
|
|
|
|
onMounted(() => {
|
|
store.dispatch('loadState').then(() => {
|
|
console.log("App.vue: Store has finished loading state.");
|
|
applyTheme();
|
|
}).catch(error => {
|
|
console.error("App.vue: Error during store.dispatch('loadState'):", error);
|
|
});
|
|
|
|
document.addEventListener('keydown', handleGlobalKeyDown);
|
|
|
|
const resumeAudio = () => {
|
|
AudioService.resumeContext();
|
|
document.body.removeEventListener('click', resumeAudio);
|
|
document.body.removeEventListener('touchstart', resumeAudio);
|
|
};
|
|
document.body.addEventListener('click', resumeAudio, { once: true });
|
|
document.body.addEventListener('touchstart', resumeAudio, { once: true });
|
|
});
|
|
|
|
watch(theme, () => {
|
|
applyTheme();
|
|
});
|
|
|
|
watch(() => store.state.isMuted, (newMutedState) => {
|
|
AudioService.setMuted(newMutedState);
|
|
});
|
|
|
|
|
|
const applyTheme = () => {
|
|
if (store.getters.theme === 'dark') {
|
|
document.documentElement.classList.add('dark');
|
|
} else {
|
|
document.documentElement.classList.remove('dark');
|
|
}
|
|
};
|
|
|
|
const handleGlobalKeyDown = (event) => {
|
|
if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA' || event.target.isContentEditable) {
|
|
return;
|
|
}
|
|
|
|
const keyPressed = event.key.toLowerCase();
|
|
|
|
if (keyPressed === store.getters.globalHotkeyStopPause && store.getters.globalHotkeyStopPause) {
|
|
event.preventDefault();
|
|
store.dispatch('globalStopPauseAll');
|
|
return;
|
|
}
|
|
|
|
const currentPlayerInStore = store.getters.currentPlayer;
|
|
const gameModeInStore = store.getters.gameMode;
|
|
|
|
if (gameModeInStore === 'normal' && currentPlayerInStore && keyPressed === currentPlayerInStore.hotkey) {
|
|
event.preventDefault();
|
|
const wasRunning = currentPlayerInStore.isTimerRunning;
|
|
store.dispatch('passTurn').then(() => {
|
|
const newCurrentPlayer = store.getters.currentPlayer;
|
|
if (wasRunning && newCurrentPlayer && newCurrentPlayer.isTimerRunning) {
|
|
AudioService.playPassTurnAlert();
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (gameModeInStore === 'allTimers') {
|
|
const playerToToggle = store.state.players.find(p => p.hotkey === keyPressed && !p.isSkipped);
|
|
if (playerToToggle) {
|
|
event.preventDefault();
|
|
const playerIndex = store.state.players.indexOf(playerToToggle);
|
|
store.dispatch('togglePlayerTimerAllTimersMode', playerIndex);
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style>
|
|
html, body, #app { /* These styles are critical */
|
|
height: 100%;
|
|
margin: 0; /* Ensure no default margin */
|
|
padding: 0; /* Ensure no default padding */
|
|
overscroll-behavior: none;
|
|
}
|
|
/* Ensure #app's direct child (from router-view) can also flex expand if needed */
|
|
/* This might not be necessary if GameView itself handles its height with flex */
|
|
/* #app > div {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-grow: 1;
|
|
} */
|
|
</style> |