diff --git a/.github/workflows/push_docker.yaml b/.github/workflows/push_docker.yaml index 9e0094a..4e91a69 100644 --- a/.github/workflows/push_docker.yaml +++ b/.github/workflows/push_docker.yaml @@ -3,6 +3,8 @@ on: branches: - main - development + tags: + - '**' jobs: push_to_registry: @@ -10,6 +12,10 @@ jobs: runs-on: ubuntu-latest if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: + - name: Dump job github var + env: + GITHUB_VAR: ${{ toJson(github) }} + run: echo "$GITHUB_VAR" - name: Checkout uses: actions/checkout@v3 @@ -28,6 +34,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push Docker dev image + if: startsWith(github.ref, 'refs/heads/development') uses: docker/build-push-action@v6 with: context: . diff --git a/client/sfx/select_slot.opus b/client/sfx/select_slot.opus new file mode 100644 index 0000000..e7b776d Binary files /dev/null and b/client/sfx/select_slot.opus differ diff --git a/client/sfx/slot_unavailable.opus b/client/sfx/slot_unavailable.opus new file mode 100644 index 0000000..75e0518 Binary files /dev/null and b/client/sfx/slot_unavailable.opus differ diff --git a/client/src/events.ts b/client/src/events.ts index be50eb5..0445800 100644 --- a/client/src/events.ts +++ b/client/src/events.ts @@ -1,4 +1,4 @@ -import { Game, GameMode, Hit, Player } from "./entities" +import { Game, GameMode, Hit, Player, Slot } from "./entities" export enum Sfx { joinGame, @@ -7,6 +7,8 @@ export enum Sfx { payToken, playHit, receiveToken, + selectSlot, + slotUnavailable, stopHit, youClaim, youFail, @@ -17,6 +19,7 @@ export enum Sfx { export interface SfxData { sfx: Sfx + pan?: number } export interface PlaySfxData extends SfxData {} @@ -77,6 +80,14 @@ export interface TokenReceivedData { game_mode: GameMode } +export interface SlotSelectedData { + slot: Slot | null + slot_count: number + from_year: number + to_year: number + unavailable: boolean +} + export enum Events { claimedHit = "Claimed hit", gameEnded = "Game ended", @@ -90,5 +101,6 @@ export enum Events { scored = "Scored", sfxEnded = "Sfx ended", skippedHit = "Skipped hit", + slotSelected = "Slot selected", tokenReceived = "Token received", } diff --git a/client/src/hooks.ts b/client/src/hooks.ts index 763338d..a11c35d 100644 --- a/client/src/hooks.ts +++ b/client/src/hooks.ts @@ -1,4 +1,4 @@ -import { useCallback, useEffect } from "react" +import { useCallback, useEffect, useState } from "react" import { useNavigate } from "react-router-dom" export const useRevalidate = () => { @@ -30,3 +30,19 @@ export const useRevalidateOnInterval = ({ [revalidate], ) } + +export const useModalShown = (): boolean => { + let [shown, setShown] = useState(false) + + useEffect(() => { + let id = setInterval(() => { + setShown(document.querySelector(".modal") !== null) + }, 50) + + return () => { + clearInterval(id) + } + }, []) + + return shown +} diff --git a/client/src/locale/de.json b/client/src/locale/de.json index 5546fe8..0aa6334 100644 --- a/client/src/locale/de.json +++ b/client/src/locale/de.json @@ -35,7 +35,9 @@ "confirmHeading": "Du musst nun bestätigen, ob <0>{{player}} den Titel und Interpreten korrekt erraten hat. Sei fair!", "confirmText": "Hat <0>{{player}} den Titel und Interpreten korrekt erraten?", "no": "Nein", + "noShortcut": "Alt+Umschalt+N", "yes": "Ja", + "yesShortcut": "Alt+Umschalt+Y", "guessText": "Wo, glaubst du, gehört dieser Hit hin?", "waitingText": "Dies sind die Möglichkeiten:", "dontIntercept": "Keine Vermutung äußern", @@ -43,14 +45,19 @@ "afterYear": "nach {{year}}", "betweenYears": "von {{year1}} bis {{year2}}", "submitGuess": "Vermutung abschicken", + "submitGuessShortcut": "Alt+Umschalt+Enter", "selectSlotFirst": "Wähle erst eine Möglichkeit", "cannotSubmitGuess": "Du kannst derzeit keine Vermutung abgeben", "game_one": "Spiel", "gameActions": "Spielaktionen:", "leaveGame": "Spiel verlassen", + "leaveGameShortcut": "Alt+Umschalt+Q", "joinGame": "Spiel beitreten", + "joinGameShortcut": "Alt+Umschalt+J", "stopGame": "Spiel stoppen", + "stopGameShortcut": "Alt+Umschalt+S", "startGame": "Spiel starten", + "startGameShortcut": "Alt+Umschalt+S", "name": "Name", "token_one": "Chip", "token_other": "Chips", @@ -110,8 +117,11 @@ "save": "Speichern", "sfxVolume": "Lautstärke der Sound Effekte", "publicGame": "Öffentliches Spiel", + "publicGameShortcut": "Alt+Umschalt+U", "privateGame": "Privates Spiel", + "privateGameShortcut": "Alt+Umschalt+R", "localGame": "Lokales Spiel", + "localGameShortcut": "Alt+Umschalt+L", "addPlayer": "Lokalen Spieler hinzufügen", "addPlayerNotLocalGame": "Du kannst lokale Spieler nur in einem lokalen Spiel hinzufügen", "addPlayerNotWaiting": "Du kannst lokale Spieler nur hinzufügen, während das Spiel gestoppt ist", @@ -144,6 +154,22 @@ "guessNothing": "{{player}} behauptet nichts Gegenteiliges", "guess": "{{player}} vermutet: {{guess}}", "youReceivedToken": "Du hast einen Token erhalten, da du Künstler und Titel dieses Hits wusstest", - "otherReceivedToken": "{{player}} hat einen Token erhalten, da der Künstler und Titel dieses Hits genannt wurde" + "otherReceivedToken": "{{player}} hat einen Token erhalten, da der Künstler und Titel dieses Hits genannt wurde", + "keyboardShortcut_one": "Tastenkombination", + "keyboardShortcut_other": "Tastenkombinationen", + "section": "Abschnitt", + "action": "Aktion", + "game": "Spiel", + "confirmYes": "Titel und Interpret des Hits wurde richtig erraten", + "confirmNo": "Titel und Interpret des Hits wurde nicht richtig erraten", + "selectPreviousSlot": "Vorherigen Slot auswählen", + "selectPreviousSlotShortcut": "Alt+Umschalt+Pfeil nach oben", + "selectNextSlot": "Nächsten Slot auswählen", + "selectNextSlotShortcut": "Alt+Umschalt+Pfeil nach unten", + "selectNoSlot": "Keinen Slot auswählen", + "selectNoSlotShortcut": "Alt+Umschalt+Rücktaste", + "playerStatsNotification": "{{player}}: {{hits}} Hits, {{tokens}} Chips", + "speakPlayerInfo": "Sprich wichtige Informationen zu Spieler {{player}}", + "speakPlayerInfoShortcut": "Alt+Umschalt+{{player}}" } } diff --git a/client/src/locale/en.json b/client/src/locale/en.json index 4a79e57..05109c9 100644 --- a/client/src/locale/en.json +++ b/client/src/locale/en.json @@ -35,7 +35,9 @@ "confirmHeading": "You now need to confirm if <0>{{player}} guessed title and artist of the song correctly. Be fair!", "confirmText": "Did <0>{{player}} guess artist and title correctly?", "no": "No", + "noShortcut": "Alt+Shift+N", "yes": "Yes", + "yesShortcut": "Alt+Shift+Y", "guessText": "Where do you think this hit belongs?", "waitingText": "These are the possible slots:", "dontIntercept": "Don't intercept", @@ -43,14 +45,19 @@ "afterYear": "after {{year}}", "betweenYears": "between {{year1}} and {{year2}}", "submitGuess": "Submit guess", + "submitGuessShortcut": "Alt+Shift+Return", "selectSlotFirst": "Select a slot first", "cannotSubmitGuess": "You cannot submit a guess right now", "game_one": "Game", "gameActions": "Game actions:", "leaveGame": "Leave game", + "leaveGameShortcut": "Alt+Shift+Q", "joinGame": "Join game", + "joinGameShortcut": "Alt+Shift+J", "stopGame": "Stop game", + "stopGameShortcut": "Alt+Shift+S", "startGame": "Start game", + "startGameShortcut": "Alt+Shift+S", "name": "Name", "token_one": "Token", "token_other": "Tokens", @@ -110,8 +117,11 @@ "save": "Save", "sfxVolume": "SFX Volume", "publicGame": "Public game", + "publicGameShortcut": "Alt+Shift+U", "privateGame": "Private game", + "privateGameShortcut": "Alt+Shift+R", "localGame": "Local game", + "localGameShortcut": "Alt+Shift+L", "addPlayer": "Add local player", "addPlayerNotLocalGame": "You can only add local players in a local game", "addPlayerNotWaiting": "You can only add local players while the game is stopped", @@ -144,6 +154,22 @@ "guessNothing": "{{player}} doesn't intercept", "guess": "{{player}} guesses: {{guess}}", "youReceivedToken": "You received a token for guessing artist and title of this hit correctly", - "otherReceivedToken": "{{player}} received a token for guessing artist and title of this hit correctly" + "otherReceivedToken": "{{player}} received a token for guessing artist and title of this hit correctly", + "keyboardShortcut_one": "Keyboard shortcut", + "keyboardShortcut_other": "Keyboard shortcuts", + "section": "Abschnitt", + "action": "Aktion", + "game": "Game", + "confirmYes": "title and artist of the hit was guessed correctly", + "confirmNo": "title and artist of the hit was guessed incorrectly", + "selectPreviousSlot": "Select previous slot", + "selectPreviousSlotShortcut": "Alt+Shift+Up arrow", + "selectNextSlot": "Select next slot", + "selectNextSlotShortcut": "Alt+Shift+Down arrow", + "selectNoSlot": "Select no slot", + "selectNoSlotShortcut": "Alt+Shift+Backspace", + "playerStatsNotification": "{{player}}: {{hits}} hits, {{tokens}} tokens", + "speakPlayerInfo": "Speak important information about player {{player}}", + "speakPlayerInfoShortcut": "Alt+Shift+{{player}}" } } diff --git a/client/src/navigation.tsx b/client/src/navigation.tsx index 2ae0a97..d55cd09 100644 --- a/client/src/navigation.tsx +++ b/client/src/navigation.tsx @@ -9,11 +9,13 @@ import { LinkContainer } from "react-router-bootstrap" import { useNavigate } from "react-router-dom" import { User } from "./entities" import Settings from "./settings" +import Shortcuts from "./shortcuts" export default function Navigation({ user }: { user: User | null }) { let navigate = useNavigate() const { t } = useTranslation() let [showSettings, setShowSettings] = useState(false) + let [showShortcuts, setShowShortcuts] = useState(false) let [_, setWelcome] = useLocalStorage("welcome") return ( @@ -48,6 +50,14 @@ export default function Navigation({ user }: { user: User | null }) { {t("welcome")} + + +