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
+49 -10
View File
@@ -8,32 +8,71 @@ const props = defineProps<Props>()
const cards = useState<{ [key: string]: any }>('cards')
const buttonsElement = ref<HTMLElement | null>(null)
const rightClicked = ref(false)
function cardClick() {
if (!props.data) return
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>
<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">
HIDDEN
</span>
</div>
<slot></slot>
</span>
<div :class="rightClicked ? '' : 'hidden'" id="contextMenu" @click.self.prevent="rightClicked = false">
<div id="contextMenuButtons" ref="buttonsElement">
<slot></slot>
</div>
</div>
</template>
<style scoped>
.card {
border: 1px solid black;
.card.active {
cursor: pointer
}
.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: () => [],
})
const wrapped = ref(false)
</script>
<template>
{{ 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>
</CardPreview>
<template v-if="wrapped" v-for="c in props.stack">
<CardPreview :data="c">
<slot></slot>
</CardPreview>
</template>
</template>
+48 -8
View File
@@ -10,7 +10,23 @@ async function buy(cardId: string) {
socket.value.send(JSON.stringify({
type: "action",
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,18 +49,35 @@ async function endTurn() {
market_amount = {{ props.game.market_stack?.length }}
<br>
market =
<template v-for="c in props.game.market">
<div class="cards_container">
<CardPreview :data="c">
<button v-if="isTurn && c" @click="buy(c)">BUY</button>
</CardPreview> |
</template>
<CardPreview :data="c" v-for="c in props.game.market">
<template v-if="isTurn && c">
<button @click="buy(c)">BUY</button>
<button @click="buy_in_hand(c)">
BUY IN HAND
</button>
<button @click="buy_on_stack(c)">
BUY ON STACK
</button>
</template>
</CardPreview>
</div>
<br>
gems =
<CardSlot :stack="props.game.gem_stack">
<button v-if="isTurn && props.game.gem_stack.length > 0"
@click="buy(props.game.gem_stack.at(-1))">BUY</button>
<template v-if="isTurn && props.game.gem_stack.length > 0">
<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>
</div>
<div>
@@ -52,3 +85,10 @@ async function endTurn() {
</div>
</div>
</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 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({
type: "action",
data_type: "play_cards",
data: props.player.hand
data: cardId
}))
}
async function playCard(cardId: string) {
socket.value.send(JSON.stringify({
type: "action",
data_type: "play_cards",
data: [cardId]
}))
}
async function draw() {
function draw() {
socket.value.send(JSON.stringify({
type: "action",
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({
type: "action",
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>
@@ -45,24 +77,27 @@ async function discard(cardId: string) {
<div v-if="isSelf"><b>YOU</b></div>
username = <b>{{ props.player.username }}</b>
<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>
hand =
<template v-for="c in props.player.hand">
<CardPreview :data="c">
<div class="cards_container">
<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="discard(c)">DISCARD</button>
</CardPreview> |
</template>
</CardPreview>
</div>
<button v-if="isSelf && isTurn && props.player.hand.length > 1" @click="playAllCards">PLAY
ALL</button>
<br>
board =
<template v-for="c in props.player.board">
<CardPreview :data="c">
<div class="cards_container">
<CardPreview :data="c" v-for="c in props.player.board">
<button v-if="isSelf && isTurn" @click="discard(c)">DISCARD</button>
</CardPreview> |
</template>
<button v-if="isSelf && isTurn" @click="sacrifice(c)">SACRIFICE</button>
</CardPreview>
</div>
<br>
stack =
<CardSlot :stack="props.player.stack_pile">
@@ -70,7 +105,26 @@ async function discard(cardId: string) {
</CardSlot>
<br>
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>
</template>