GameState
+@inject IDispatcher Dispatcher
+@inject GameDefinitionRegistry GameRegistry
+
+@if (_availableActions.Count > 0)
+{
+
+ @foreach (var action in _availableActions.OrderBy(a => a.Order))
+ {
+
+ @action.Label
+
+ }
+
+}
+
+
+
+@code {
+ private IReadOnlyList _availableActions = [];
+
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+ GameState.StateChanged += OnGameStateChanged;
+ UpdateAvailableActions();
+ }
+
+ private void OnGameStateChanged(object? sender, EventArgs e)
+ {
+ UpdateAvailableActions();
+ InvokeAsync(StateHasChanged);
+ }
+
+ private void UpdateAvailableActions()
+ {
+ _availableActions = [];
+ var state = GameState.Value;
+
+ if (!state.IsGameActive || state.GameModel == null ||
+ string.IsNullOrEmpty(state.GameTypeName) ||
+ !state.Participants.CurrentPlayerId.HasValue)
+ return;
+
+ try
+ {
+ var logicService = GameRegistry.GetLogicService(state.GameTypeName);
+ _availableActions = logicService.GetAvailableActions(
+ state.GameModel,
+ state.Participants.CurrentPlayerId.Value);
+ }
+ catch
+ {
+ // Silently ignore - game type might not support actions
+ }
+ }
+
+ private void ExecuteAction(string actionId)
+ {
+ Dispatcher.Dispatch(new ExecuteGameActionAction(actionId));
+ }
+
+ private static Color GetColor(string colorName) => colorName switch
+ {
+ "Primary" => Color.Primary,
+ "Secondary" => Color.Secondary,
+ "Warning" => Color.Warning,
+ "Error" => Color.Error,
+ "Success" => Color.Success,
+ "Info" => Color.Info,
+ _ => Color.Primary
+ };
+
+ private static string? GetIcon(string? iconName) => iconName switch
+ {
+ "SkipNext" => Icons.Material.Filled.SkipNext,
+ "Stop" => Icons.Material.Filled.Stop,
+ "PlayArrow" => Icons.Material.Filled.PlayArrow,
+ "Pause" => Icons.Material.Filled.Pause,
+ "Check" => Icons.Material.Filled.Check,
+ "Close" => Icons.Material.Filled.Close,
+ "Add" => Icons.Material.Filled.Add,
+ "Remove" => Icons.Material.Filled.Remove,
+ "Refresh" => Icons.Material.Filled.Refresh,
+ _ => iconName // Allow passing full icon path
+ };
+
+ public void Dispose()
+ {
+ GameState.StateChanged -= OnGameStateChanged;
+ }
+}
diff --git a/src/Koogle.Web/Components/Game/GameInputPanel.razor b/src/Koogle.Web/Components/Game/GameInputPanel.razor
index 4b43f87..9483c08 100644
--- a/src/Koogle.Web/Components/Game/GameInputPanel.razor
+++ b/src/Koogle.Web/Components/Game/GameInputPanel.razor
@@ -68,6 +68,9 @@
+ @* Game-specific actions *@
+
+
@* Error display *@
@if (!string.IsNullOrEmpty(GameState.Value.Error))
{
diff --git a/src/Koogle.Web/Components/Game/Shit/ShitSetup.razor b/src/Koogle.Web/Components/Game/Shit/ShitSetup.razor
index bbbb3c6..a43a6c1 100644
--- a/src/Koogle.Web/Components/Game/Shit/ShitSetup.razor
+++ b/src/Koogle.Web/Components/Game/Shit/ShitSetup.razor
@@ -55,8 +55,8 @@
- Jeder Spieler startet mit der Start-Punktzahl
- Geworfene Kegel werden von deinen Punkten abgezogen
- - Du kannst weiterwürfeln oder zum nächsten Spieler übergeben
- - Wirfst du die Scheiss-Zahl oder in die Rinne, bekommst du alle gesammelten Punkte dazu
+ - Du kannst weiterspielen oder zum nächsten Spieler übergeben
+ - Wirfst du die Scheiss-Zahl oder in die Gosse, bekommst du alle gesammelten Punkte dazu
- Wer zuerst 0 erreicht, gewinnt!
- Die Verlierer zahlen Strafe basierend auf ihren Restpunkten
diff --git a/src/Koogle.Web/Store/GameState/GameActions.cs b/src/Koogle.Web/Store/GameState/GameActions.cs
index 4b1a837..5b4e2dc 100644
--- a/src/Koogle.Web/Store/GameState/GameActions.cs
+++ b/src/Koogle.Web/Store/GameState/GameActions.cs
@@ -265,3 +265,33 @@ public record ClearGameErrorAction;
/// Action to update the game-specific model.
///