Files
nexus-timer/src/App.vue
2025-05-08 03:04:42 +02:00

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>