From ed992e1c2d3aa9a04ec921947f361d8efc8affaf Mon Sep 17 00:00:00 2001 From: Dennis Postma <dennis@directonline.io> Date: Tue, 18 Feb 2025 18:27:35 +0100 Subject: [PATCH] Updated characters.vue --- src/components/screens/Characters.vue | 68 +++++++++++++++++---------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/src/components/screens/Characters.vue b/src/components/screens/Characters.vue index 68869c5..2994d1c 100644 --- a/src/components/screens/Characters.vue +++ b/src/components/screens/Characters.vue @@ -22,7 +22,7 @@ </div> <div class="character relative rounded default-border w-12 h-12 bg-[url('/assets/ui-texture.png')]" :class="{ active: characters.length == 0 }" v-if="characters.length < 4"> <button class="p-0 h-full w-full flex flex-col justify-between focus-visible:outline-offset-0 btn-sound" @click="isCreateNewCharacterModalOpen = true"> - <img class="w-6 h-6 object-contain center-element btn-sound" draggable="false" src="/assets/icons/plus-icon.svg" /> + <img class="w-6 h-6 object-contain center-element btn-sound" draggable="false" src="/assets/icons/plus-icon.svg" alt="Add character" /> </button> </div> </div> @@ -40,22 +40,27 @@ </button> </div> </div> - <!-- TODO: update gender on (selected) character --> - <!-- <div class="flex justify-between w-[190px]">--> - <!-- <button class="btn-empty flex gap-2" :class="{ selected: characters.find((c) => c.id == selectedCharacterId)?.characterType?.gender === 'MALE' }">--> - <!-- <img src="/assets/icons/male-icon.svg" class="w-4 h-4 m-auto" alt="Male symbol" />--> - <!-- <span class="text-white">Male</span>--> - <!-- </button>--> - <!-- <button class="btn-empty flex gap-2" :class="{ selected: characters.find((c) => c.id == selectedCharacterId)?.characterType?.gender === 'FEMALE' }">--> - <!-- <img src="/assets/icons/male-icon.svg" class="w-4 h-4 m-auto" alt="Male symbol" />--> - <!-- <span class="text-white">Female</span>--> - <!-- </button>--> - <!-- </div>--> + <div class="flex justify-between w-[190px]"> + <button class="btn-empty flex gap-2 selected"> + <img src="/assets/icons/male-icon.svg" class="w-4 h-4 m-auto" alt="Male symbol" /> + <span class="text-white">Male</span> + </button> + <button class="btn-empty flex gap-2"> + <img src="/assets/icons/male-icon.svg" class="w-4 h-4 m-auto" alt="Male symbol" /> + <span class="text-white">Female</span> + </button> + </div> </div> </div> </div> <div class="flex-1 lg:w-2/3 max-lg:min-h-[212px] h-full bg-[url('/assets/ui-texture.png')] bg-no-repeat bg-cover bg-center max-lg:rounded-bl-md rounded-r-md"> <div class="py-6 px-8 h-[calc(100%_-_48px)] flex flex-col items-center gap-10" v-if="selectedCharacterId"> + <div class="flex flex-col gap-3 w-full"> + <span class="text-sm">Hair color</span> + <div class="flex gap-2 flex-wrap"> + <input type="radio" name="hair-color" v-for="color in uniqueHairColors" class="w-6 h-6 m-0 rounded-sm hover:cursor-pointer checked:outline checked:outline-1 checked:outline-white" :style="getHairColorStyle(color)" @click="handleHairColorChange(color)" /> + </div> + </div> <div class="flex flex-col gap-3 w-full"> <span class="text-sm">Hairstyle</span> <div class="flex gap-2 flex-wrap max-h-20 overflow-y-auto scrollbar"> @@ -65,9 +70,8 @@ <img src="/assets/icons/x-button-gray.svg" class="w-4 h-4" alt="Empty button" /> <input type="radio" name="hair" :value="null" v-model="selectedHairId" class="h-full w-full absolute left-0 top-0 m-0 z-10 hover:cursor-pointer focus-visible:outline-offset-0 focus-visible:outline-white" /> </div> - <!-- TODO #255: make radio button so we can set a value, do the same with swatches --> <div - v-for="hair in characterHairs" + v-for="hair in filteredHairs" class="relative flex justify-center items-center bg-gray default-border w-[18px] h-[18px] p-2 rounded-sm hover:bg-gray-500 hover:border-gray-400 focus-visible:outline-none focus-visible:border-gray-300 focus-visible:bg-gray-500 has-[:checked]:bg-cyan has-[:checked]:border-transparent" > <img class="h-4 object-contain" :src="config.server_endpoint + '/textures/sprites/' + hair.sprite + '/front.png'" alt="Hair sprite" /> @@ -75,13 +79,6 @@ </div> </div> </div> - <div class="flex flex-col gap-3 w-full"> - <span class="text-sm">Hair color</span> - <div class="flex gap-2 flex-wrap"> - <!-- TODO: replace with hair colors --> - <input type="radio" name="hair-color" v-for="n in 10" class="bg-red w-6 h-6 m-0 rounded-sm hover:cursor-pointer checked:outline checked:outline-1 checked:outline-white" /> - </div> - </div> </div> </div> </div> @@ -89,7 +86,6 @@ <div v-else> <img class="w-20 invert-80" src="/assets/icons/loading-icon1.svg" alt="Loading" /> </div> - <div class="w-2/3 button-wrapper flex self-center justify-center lg:justify-end gap-4 max-w-[860px]" v-if="!isLoading"> <button class="btn-empty min-w-48" @click.stop="gameStore.disconnectSocket()">Back</button> <button class="btn-cyan min-w-48 disabled:bg-cyan-800 disabled:cursor-not-allowed" :disabled="!selectedCharacterId" @click="loginWithCharacter()">Play now</button> @@ -129,7 +125,7 @@ import { useSoundComposable } from '@/composables/useSoundComposable' import { socketManager } from '@/managers/SocketManager' import { CharacterHairStorage } from '@/storage/storages' import { useGameStore } from '@/stores/gameStore' -import { onBeforeUnmount, onMounted, ref, watch } from 'vue' +import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue' const { playSound } = useSoundComposable() const gameStore = useGameStore() @@ -141,6 +137,31 @@ const newCharacterName = ref<string>('') const characterHairs = ref<CharacterHair[]>([]) const selectedHairId = ref<string | null>(null) +const selectedHairColor = ref<string | null>(null) +const uniqueHairColors = computed(() => { + return [...new Set(characterHairs.value.map((hair) => hair.color))] +}) + +const filteredHairs = computed(() => { + if (!selectedHairColor.value) return characterHairs.value + return characterHairs.value.filter((hair) => hair.color === selectedHairColor.value) +}) + +function handleHairColorChange(color: string | null) { + selectedHairColor.value = color + // Reset hair selection if the current selection doesn't exist in filtered results + if (!filteredHairs.value.find((hair) => hair.id === selectedHairId.value)) { + selectedHairId.value = null + } +} + +function getHairColorStyle(color: string | null) { + return { + backgroundColor: color, + border: selectedHairColor.value === color ? '1px solid white' : '1px solid rgba(255, 255, 255, 0.2)' + } +} + // Fetch characters setTimeout(() => { socketManager.emit(SocketEvent.CHARACTER_LIST) @@ -151,7 +172,6 @@ socketManager.on(SocketEvent.CHARACTER_LIST, (data: any) => { isLoading.value = false }) -// Select character logics function loginWithCharacter() { if (!selectedCharacterId.value) return