From d84a9b87287d7ed24f08edd86aa37790701a59de Mon Sep 17 00:00:00 2001 From: TheAsel Date: Mon, 30 Oct 2023 19:32:19 +0100 Subject: [PATCH 1/4] multiple party implementation --- src/components/Encounter/CreatureList.vue | 2 +- .../CreaturesTable/EncounterBuilder.vue | 2 +- .../Encounter/CreaturesTable/PartyBuilder.vue | 199 +++++++++++++++--- src/pages/EncounterPage.vue | 41 +++- src/stores/store.ts | 43 +++- src/types/party.ts | 4 + 6 files changed, 246 insertions(+), 45 deletions(-) create mode 100644 src/types/party.ts diff --git a/src/components/Encounter/CreatureList.vue b/src/components/Encounter/CreatureList.vue index c1a85bc..a2b8239 100644 --- a/src/components/Encounter/CreatureList.vue +++ b/src/components/Encounter/CreatureList.vue @@ -27,7 +27,7 @@ const debouncedCall = debounce(async function () { } } } - const partyLevels = party.getParty; + const partyLevels = party.getActiveParty.members; const post = { enemy_levels: enemyLevels, party_levels: partyLevels diff --git a/src/components/Encounter/CreaturesTable/EncounterBuilder.vue b/src/components/Encounter/CreaturesTable/EncounterBuilder.vue index 511f533..4c1d70b 100644 --- a/src/components/Encounter/CreaturesTable/EncounterBuilder.vue +++ b/src/components/Encounter/CreaturesTable/EncounterBuilder.vue @@ -47,7 +47,7 @@ const restoreSettings = () => { const generateEncounter = async () => { saveChanges(); - const partyLevels = party.getParty; + const partyLevels = party.getActiveParty.members; const post = { traits: tmpFilters.value.traits, alignments: tmpFilters.value.alignment, diff --git a/src/components/Encounter/CreaturesTable/PartyBuilder.vue b/src/components/Encounter/CreaturesTable/PartyBuilder.vue index 665a71f..f8f4e2b 100644 --- a/src/components/Encounter/CreaturesTable/PartyBuilder.vue +++ b/src/components/Encounter/CreaturesTable/PartyBuilder.vue @@ -1,41 +1,97 @@ @@ -43,26 +99,109 @@ const saveChanges = () => { - -
Party Builder
- - + +
+
Party Builder
+ + +
+
+ + + + + + +
New party name
+
+ + + + + + + + + +
+
+ + + + + +
Remove this party?
+
+ + + + +
+
+
-
+
{ min="1" max="20" :label="'Player ' + (index + 1)" - v-model.number="tmpParty[index]" + v-model.number="tmpParty.members[index]" @update:model-value="validateLevel(index)" dense /> @@ -129,3 +268,11 @@ input[type='number'] { appearance: textfield; } + + diff --git a/src/pages/EncounterPage.vue b/src/pages/EncounterPage.vue index 90c0b37..85bb40f 100644 --- a/src/pages/EncounterPage.vue +++ b/src/pages/EncounterPage.vue @@ -2,6 +2,7 @@ import { shallowRef } from 'vue'; import { requestCreatures, requestFilters } from 'src/utils/api-calls'; import { partyStore, filtersStore, creaturesStore, encounterStore } from 'stores/store'; +import { party } from 'src/types/party'; import { creature } from 'src/types/creature'; import CreatureList from 'src/components/Encounter/CreatureList.vue'; @@ -11,19 +12,41 @@ const creatures = creaturesStore(); const encounter = encounterStore(); const currentComponent = shallowRef(); -const localParty = localStorage.getItem('party'); +const localParty = localStorage.getItem('parties'); if (localParty) { try { - const parsedParty: number[] = JSON.parse(localParty); - if (parsedParty && parsedParty.every((player) => player >= 1 && player <= 20)) { - party.updateParty(parsedParty); + const parsedParties = JSON.parse(localParty); + if (Array.isArray(parsedParties)) { + const isCompatible = parsedParties.every((p) => { + return ( + typeof p.name === 'string' && + Array.isArray(p.members) && + p.members.every((member: any) => typeof member === 'number') + ); + }); + if (isCompatible) { + const parties: party[] = parsedParties; + parties.forEach((p) => { + if (!p || !p.members.every((player) => player >= 1 && player <= 20)) { + throw 'Invalid saved party levels'; + } + }); + const partyNames = parties.map((p) => p.name); + if (new Set(partyNames).size !== partyNames.length) { + throw 'Duplicate saved party names'; + } + party.updateParties(parties); + } else { + throw 'Invalid saved party format'; + } } else { - throw 'Invalid saved party'; + throw 'Invalid saved party format'; } - } catch (_) { - console.error('Invalid saved party'); - localStorage.setItem('party', JSON.stringify([1, 1, 1, 1])); - party.updateParty([1, 1, 1, 1]); + } catch (error) { + console.error(error); + const defaultParty = { name: 'Default', members: [1, 1, 1, 1] }; + localStorage.setItem('parties', JSON.stringify([defaultParty])); + party.updateParties([defaultParty]); } } diff --git a/src/stores/store.ts b/src/stores/store.ts index 303aa73..a0148c0 100644 --- a/src/stores/store.ts +++ b/src/stores/store.ts @@ -1,21 +1,48 @@ +import { party } from 'src/types/party'; import { creature } from 'src/types/creature'; import { encounter } from 'src/types/encounter'; import { defineStore } from 'pinia'; export const partyStore = defineStore('party', { - state: () => ({ party: [1, 1, 1, 1] }), + state: () => ({ + parties: [{ name: 'Default', members: [1, 1, 1, 1] }] as party[], + activeParty: 0 + }), getters: { - getParty: (state) => state.party + getParties: (state) => state.parties, + getActive: (state) => state.activeParty, + getActiveParty: (state) => state.parties[state.activeParty] }, actions: { - updateParty(newParty: number[]) { - this.party = newParty; + getPartyIndex(partyName: string): number { + return this.parties.map((party) => party.name).indexOf(partyName); }, - addPlayer() { - this.party.push(1); + updateParty(partyName: string, newMembers: number[]) { + const partyIndex = this.getPartyIndex(partyName); + if (partyIndex >= 0) { + this.parties[partyIndex].members = newMembers; + } }, - removePlayer(index: number) { - this.party.splice(index, 1); + updateParties(newParties: party[]) { + this.parties = newParties; + }, + changeActiveParty(partyIndex: number) { + if (partyIndex >= this.parties.length || partyIndex < 0) { + this.activeParty = 0; + } else { + this.activeParty = partyIndex; + } + }, + addParty(partyName: string) { + this.parties.push({ name: partyName, members: [1, 1, 1, 1] }); + this.activeParty = this.parties.length - 1; + }, + removeParty() { + this.parties.splice(this.activeParty, 1); + this.activeParty = 0; + if (this.parties.length <= 0) { + this.parties = [{ name: 'Default', members: [1, 1, 1, 1] }]; + } } } }); diff --git a/src/types/party.ts b/src/types/party.ts new file mode 100644 index 0000000..46736d1 --- /dev/null +++ b/src/types/party.ts @@ -0,0 +1,4 @@ +export type party = { + name: string; + members: number[]; +}; From 9be3b259025c91c256cc1262d0c884f1f56b311b Mon Sep 17 00:00:00 2001 From: TheAsel Date: Mon, 30 Oct 2023 20:04:29 +0100 Subject: [PATCH 2/4] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d447a1e..73c2af5 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ - Browse and filter a list of all creatures - Balance encounters based on your party size and level - Generate random encounters based on your requirements -- Mobile friendly, light/dark theme, accessible +- Fast, mobile friendly, light/dark theme, accessible - More to come... ![Screenshot of the Encounter Builder page of BYBE](https://raw.githubusercontent.com/TheAsel/BYBE-frontend/HEAD/.github/encounter-builder.png) From edf343342fbc2e5f137a2b7e6ead2b94647d3246 Mon Sep 17 00:00:00 2001 From: TheAsel Date: Tue, 31 Oct 2023 15:03:37 +0100 Subject: [PATCH 3/4] ui tweaks, updated tour --- .../CreaturesTable/EncounterBuilder.vue | 11 +++--- .../Encounter/CreaturesTable/PartyBuilder.vue | 36 ++++++++++++++----- src/pages/EncounterPage.vue | 9 ++--- 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/components/Encounter/CreaturesTable/EncounterBuilder.vue b/src/components/Encounter/CreaturesTable/EncounterBuilder.vue index 4c1d70b..4ae1405 100644 --- a/src/components/Encounter/CreaturesTable/EncounterBuilder.vue +++ b/src/components/Encounter/CreaturesTable/EncounterBuilder.vue @@ -219,19 +219,20 @@ defineExpose({ generateEncounter }); - + + { -
-
Party Builder
+
+
Party Builder
{ - - + + - + {
Remove this party?
- - + + @@ -248,7 +268,7 @@ const saveChanges = () => { Date: Tue, 31 Oct 2023 15:17:00 +0100 Subject: [PATCH 4/4] fixed typo in tour --- src/pages/EncounterPage.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/EncounterPage.vue b/src/pages/EncounterPage.vue index 26d8925..05fe533 100644 --- a/src/pages/EncounterPage.vue +++ b/src/pages/EncounterPage.vue @@ -166,7 +166,7 @@ const steps = [ }, { target: '#v-step-4', - content: 'From this dropdown you can select which colums of the table to show and hide.', + content: 'From this dropdown you can select which columns of the table to show and hide.', params: { placement: 'bottom' }