diff --git a/src/pirats/main.py b/src/pirats/main.py
index f08cb89..3eefc4e 100644
--- a/src/pirats/main.py
+++ b/src/pirats/main.py
@@ -541,17 +541,17 @@ def play_card_route(
if not ok:
return HTMLResponse(f"
{msg}
", status_code=400)
- # Return a success notification box that HTMX will show, or just return 204 to let polling pick it up.
- # Returning a message is nice! But returning 204 is clean. Let's return a brief HTML snippet.
+ # Return a success notification and HX-Trigger header to refresh the hand.
color_prefix = "🟩" if res["success"] else "🟥"
drew_text = f" (Drew card: {res['drew_card']})" if res["drew_card"] else ""
- return HTMLResponse(
- f""
+ drew_attr = "true" if res["drew_card"] else "false"
+ html = (
+ f"
"
f"
{color_prefix} {res['details']}{drew_text}
"
f"
Click to dismiss"
- f"
",
- headers={"HX-Trigger": "hand-updated"}
+ f"
"
)
+ return HTMLResponse(html, headers={"HX-Trigger": "hand-changed"})
# 12. Pi-Rat plays a Joker to replace an obstacle
@app.post("/game/{game_id}/player/{player_id}/play-joker")
@@ -566,13 +566,13 @@ def play_joker_route(
if not ok:
return HTMLResponse(f"{msg}
", status_code=400)
- return HTMLResponse(
- f""
+ html = (
+ f"
"
f"
🃏 Play Joker: Discarded obstacle and drew a new replacement!
"
f"
Click to dismiss"
- f"
",
- headers={"HX-Trigger": "hand-updated"}
+ f"
"
)
+ return HTMLResponse(html, headers={"HX-Trigger": "hand-changed"})
# 13. Toggle Objective Completion Checklist
@app.post("/game/{game_id}/player/{player_id}/objective/toggle")
diff --git a/src/pirats/templates/scene_partial.html b/src/pirats/templates/scene_partial.html
index 46ecbfe..6fe7854 100644
--- a/src/pirats/templates/scene_partial.html
+++ b/src/pirats/templates/scene_partial.html
@@ -341,9 +341,34 @@
? `/game/${gameId}/player/${playerId}/play-joker`
: `/game/${gameId}/player/${playerId}/play-card`;
+ // Find the dragged card element before the request
+ const draggedCard = document.querySelector(
+ `.card-large[data-card-code="${cardCode}"]`
+ );
+
htmx.ajax('POST', url, {
values: { obstacle_id: obstacleId, card_code: cardCode },
- swap: 'none'
+ target: 'body',
+ swap: 'beforeend'
+ }).then(function() {
+ // Remove the card from the hand on success
+ if (draggedCard && draggedCard.parentNode) {
+ draggedCard.remove();
+ }
+ // Check if hand is now empty (and no card was drawn)
+ const handFlex = document.querySelector('.hand-flex');
+ if (handFlex && handFlex.children.length === 0) {
+ handFlex.innerHTML = 'Your hand is empty! (You draw cards when playing cards that match the suit color of the obstacle.)
';
+ }
+ // Auto-dismiss the notification after 3 seconds
+ const notif = document.querySelector('.play-notification:last-of-type');
+ if (notif) {
+ setTimeout(function() { notif.remove(); }, 3000);
+ // If a card was drawn, refresh the full view to show it
+ if (notif.getAttribute('data-drew') === 'true') {
+ htmx.trigger(document.body, 'phase-changed');
+ }
+ }
});
}
}