Contextual menu for cards

This commit is contained in:
2024-04-22 19:23:28 +02:00
parent d52bfa37c8
commit cb3a470f53
4 changed files with 186 additions and 44 deletions
+50 -11
View File
@@ -8,32 +8,71 @@ const props = defineProps<Props>()
const cards = useState<{ [key: string]: any }>('cards') const cards = useState<{ [key: string]: any }>('cards')
const buttonsElement = ref<HTMLElement | null>(null)
const rightClicked = ref(false)
function cardClick() { function cardClick() {
if (!props.data) return if (!props.data) return
console.log(JSON.parse(JSON.stringify(cards.value[props.data].effects))) console.log(JSON.parse(JSON.stringify(cards.value[props.data].effects)))
} }
function contextmenu(e: MouseEvent) {
if (buttonsElement.value?.childElementCount === 0) { return }
buttonsElement.value?.setAttribute("style", `top:${e.clientY + 10}px;left:${e.clientX + 10}px`)
rightClicked.value = true
}
</script> </script>
<template> <template>
<span class="card">
<span v-if="props.data" @click="cardClick">
{{ cards[props.data]?.name }}
</span>
<div :class="`card ${Number(buttonsElement?.childElementCount) > 0 ? 'active' : ''}`" @contextmenu.prevent="false"
@click.left="cardClick" @click.right="contextmenu">
<img :class="`card_image ${rightClicked ? 'outlined' : ''}`" v-if="props.data"
:src="'/cards/' + cards[props.data].card_id.toString().padStart(3, '0') + '.jpg'">
<span v-if="props.data === null"> <span v-if="props.data === null">
HIDDEN HIDDEN
</span> </span>
</div>
<slot></slot> <div :class="rightClicked ? '' : 'hidden'" id="contextMenu" @click.self.prevent="rightClicked = false">
</span> <div id="contextMenuButtons" ref="buttonsElement">
<slot></slot>
</div>
</div>
</template> </template>
<style scoped> <style scoped>
.card { .card.active {
border: 1px solid black;
cursor: pointer cursor: pointer
} }
</style>
.card_image.outlined {
outline: 2px solid red;
outline-offset: -2px;
}
.card_image {
max-height: 150px;
}
.hidden {
display: none;
}
#contextMenu {
position: fixed;
height: 100%;
width: 100%;
top: 0;
left: 0;
/* background: rgba(0, 0, 0, .5); */
}
#contextMenuButtons {
position: absolute;
display: flex;
flex-direction: column;
}
</style>
+10 -1
View File
@@ -7,14 +7,23 @@ const props = withDefaults(defineProps<Props>(), {
stack: () => [], stack: () => [],
}) })
const wrapped = ref(false)
</script> </script>
<template> <template>
{{ props.stack?.length }} {{ props.stack?.length }}
<input type="checkbox" v-model="wrapped" />
<CardPreview :data="props.stack.at(-1)"> <CardPreview v-if="!wrapped" :data="props.stack.at(-1)">
<slot></slot> <slot></slot>
</CardPreview> </CardPreview>
<template v-if="wrapped" v-for="c in props.stack">
<CardPreview :data="c">
<slot></slot>
</CardPreview>
</template>
</template> </template>
+49 -9
View File
@@ -10,7 +10,23 @@ async function buy(cardId: string) {
socket.value.send(JSON.stringify({ socket.value.send(JSON.stringify({
type: "action", type: "action",
data_type: "buy", data_type: "buy",
data: [cardId] data: cardId
}))
}
async function buy_in_hand(cardId: string) {
socket.value.send(JSON.stringify({
type: "temp_action",
data_type: "buy_in_hand",
data: cardId
}))
}
async function buy_on_stack(cardId: string) {
socket.value.send(JSON.stringify({
type: "temp_action",
data_type: "buy_on_stack",
data: cardId
})) }))
} }
@@ -33,22 +49,46 @@ async function endTurn() {
market_amount = {{ props.game.market_stack?.length }} market_amount = {{ props.game.market_stack?.length }}
<br> <br>
market = market =
<template v-for="c in props.game.market"> <div class="cards_container">
<CardPreview :data="c"> <CardPreview :data="c" v-for="c in props.game.market">
<button v-if="isTurn && c" @click="buy(c)">BUY</button> <template v-if="isTurn && c">
</CardPreview> | <button @click="buy(c)">BUY</button>
</template> <button @click="buy_in_hand(c)">
BUY IN HAND
</button>
<button @click="buy_on_stack(c)">
BUY ON STACK
</button>
</template>
</CardPreview>
</div>
<br> <br>
gems = gems =
<CardSlot :stack="props.game.gem_stack"> <CardSlot :stack="props.game.gem_stack">
<button v-if="isTurn && props.game.gem_stack.length > 0" <template v-if="isTurn && props.game.gem_stack.length > 0">
@click="buy(props.game.gem_stack.at(-1))">BUY</button> <button @click="buy(props.game.gem_stack.at(-1))">
BUY
</button>
<button @click="buy_in_hand(props.game.gem_stack.at(-1))">
BUY IN HAND
</button>
<button @click="buy_on_stack(props.game.gem_stack.at(-1))">
BUY ON STACK
</button>
</template>
</CardSlot> </CardSlot>
</div> </div>
<div> <div>
<PlayerList :players="props.game?.players" :current_team="game.turn"></PlayerList> <PlayerList :players="props.game?.players" :current_team="game.turn"></PlayerList>
</div> </div>
</div> </div>
</template> </template>
<style>
.cards_container {
display: flex;
flex-direction: row;
}
</style>
+77 -23
View File
@@ -6,24 +6,25 @@ const socket = useState<WebSocket>('socket')
const isTurn = computed(() => props.player.team == props.current_team) const isTurn = computed(() => props.player.team == props.current_team)
const isSelf = computed(() => props.player.uuid == self.value) const isSelf = computed(() => props.player.uuid == self.value)
const discard_wrapped = ref(false)
async function playAllCards() {
function playAllCards() {
props.player.hand.forEach((c: any) => {
playCard(c)
});
}
function playCard(cardId: string) {
socket.value.send(JSON.stringify({ socket.value.send(JSON.stringify({
type: "action", type: "action",
data_type: "play_cards", data_type: "play_cards",
data: props.player.hand data: cardId
})) }))
} }
async function playCard(cardId: string) { function draw() {
socket.value.send(JSON.stringify({
type: "action",
data_type: "play_cards",
data: [cardId]
}))
}
async function draw() {
socket.value.send(JSON.stringify({ socket.value.send(JSON.stringify({
type: "action", type: "action",
data_type: "draw", data_type: "draw",
@@ -31,11 +32,42 @@ async function draw() {
})) }))
} }
async function discard(cardId: string) { function play_from_discard(cardId: string) {
socket.value.send(JSON.stringify({
type: "temp_action",
data_type: "play_from_discard",
data: cardId
}))
}
function discard(cardId: string) {
socket.value.send(JSON.stringify({ socket.value.send(JSON.stringify({
type: "action", type: "action",
data_type: "discard", data_type: "discard",
data: [cardId] data: cardId
}))
}
function sacrifice(cardId: any) {
socket.value.send(JSON.stringify({
type: "action",
data_type: "sacrifice",
data: cardId
}))
}
function put_on_stack_from_discard(cardId: any) {
socket.value.send(JSON.stringify({
type: "temp_action",
data_type: "put_on_stack_from_discard",
data: cardId
}))
}
function setHealth(event: Event) {
socket.value.send(JSON.stringify({
type: "temp_action",
data_type: "set_health",
data: (event.target as HTMLInputElement).value
})) }))
} }
</script> </script>
@@ -45,24 +77,27 @@ async function discard(cardId: string) {
<div v-if="isSelf"><b>YOU</b></div> <div v-if="isSelf"><b>YOU</b></div>
username = <b>{{ props.player.username }}</b> username = <b>{{ props.player.username }}</b>
<br> <br>
health = {{ teams[player.team].health }} health =
<template v-if="!isSelf">{{ teams[player.team].health }}</template>
<input type="number" :value="teams[player.team].health" v-if="isSelf" @change="setHealth" />
<br> <br>
hand = hand =
<template v-for="c in props.player.hand"> <div class="cards_container">
<CardPreview :data="c"> <CardPreview :data="c" v-for="c in props.player.hand">
<button v-if="isSelf && isTurn" @click="playCard(c)">PLAY</button> <button v-if="isSelf && isTurn" @click="playCard(c)">PLAY</button>
<button v-if="isSelf && isTurn" @click="discard(c)">DISCARD</button> <button v-if="isSelf && isTurn" @click="discard(c)">DISCARD</button>
</CardPreview> | </CardPreview>
</template> </div>
<button v-if="isSelf && isTurn && props.player.hand.length > 1" @click="playAllCards">PLAY <button v-if="isSelf && isTurn && props.player.hand.length > 1" @click="playAllCards">PLAY
ALL</button> ALL</button>
<br> <br>
board = board =
<template v-for="c in props.player.board"> <div class="cards_container">
<CardPreview :data="c"> <CardPreview :data="c" v-for="c in props.player.board">
<button v-if="isSelf && isTurn" @click="discard(c)">DISCARD</button> <button v-if="isSelf && isTurn" @click="discard(c)">DISCARD</button>
</CardPreview> | <button v-if="isSelf && isTurn" @click="sacrifice(c)">SACRIFICE</button>
</template> </CardPreview>
</div>
<br> <br>
stack = stack =
<CardSlot :stack="props.player.stack_pile"> <CardSlot :stack="props.player.stack_pile">
@@ -70,7 +105,26 @@ async function discard(cardId: string) {
</CardSlot> </CardSlot>
<br> <br>
discard = discard =
<CardSlot :stack="props.player.discard_pile"></CardSlot>
{{ props.player.discard_pile.length }}
<input type="checkbox" v-model="discard_wrapped" />
<CardPreview v-if="!discard_wrapped" :data="props.player.discard_pile.at(-1)">
<button v-if="isSelf && isTurn" @click="play_from_discard(props.player.discard_pile.at(-1))">DRAW</button>
<button v-if="isSelf && isTurn" @click="put_on_stack_from_discard(props.player.discard_pile.at(-1))">PUT ON
STACK</button>
<button v-if="isSelf && isTurn" @click="sacrifice(props.player.discard_pile.at(-1))">SACRIFICE</button>
</CardPreview>
<template v-if="discard_wrapped" v-for="c in props.player.discard_pile">
<CardPreview :data="c">
<button v-if="isSelf && isTurn" @click="play_from_discard(c)">DRAW</button>
<button v-if="isSelf && isTurn" @click="put_on_stack_from_discard(c)">PUT ON STACK</button>
<button v-if="isSelf && isTurn" @click="sacrifice(c)">SACRIFICE</button>
</CardPreview>
</template>
</div> </div>
</template> </template>