From 5d8c7fd576995cb98f8cb9416bce0f8bea78fcb8 Mon Sep 17 00:00:00 2001 From: Jeremy Mees Date: Thu, 29 Jan 2026 13:00:45 +0100 Subject: [PATCH 01/18] feat: partial implementation 2024 rules --- .vscode/settings.json | 2 + app/components/atoms/ContentCardContent.vue | 241 --------- app/components/atoms/GameSystemFilter.vue | 136 +++++ app/components/form/Bestiary.vue | 56 +- .../ContentCard/ContentCardArmor.vue | 38 ++ .../ContentCard/ContentCardMagicItem.vue | 97 ++++ .../ContentCard/ContentCardSpell.vue | 196 +++++++ .../ContentCard/ContentCardWeapon.vue | 70 +++ .../index.vue} | 40 +- app/components/skeleton/ContentCard.vue | 6 +- app/components/templates/DnDContentSearch.vue | 48 +- app/types/open5e.ts | 244 ++++++--- app/utils/open5e.ts | 23 + app/utils/url-generators.ts | 17 +- i18n/locales/en.json | 4 + i18n/locales/nl.json | 4 + queries/open5e.ts | 52 +- .../atoms/ContentCardContent.spec.ts | 306 ----------- .../ContentCardContent.spec.ts.snap | 7 - .../__snapshots__/pinnedContent.spec.ts.snap | 22 +- .../initiative/Widgets/pinnedContent.spec.ts | 6 +- .../{ => ContentCard}/ContentCard.spec.ts | 8 +- .../ContentCard/ContentCardArmor.spec.ts | 30 ++ .../ContentCard/ContentCardMagicItem.spec.ts | 37 ++ .../ContentCard/ContentCardSpell.spec.ts | 39 ++ .../ContentCard/ContentCardWeapon.spec.ts | 36 ++ .../__snapshots__/ContentCard.spec.ts.snap | 13 +- .../ContentCardArmor.spec.ts.snap | 11 + .../ContentCardMagicItem.spec.ts.snap | 9 + .../ContentCardSpell.spec.ts.snap | 9 + .../ContentCardWeapon.spec.ts.snap | 11 + .../components/molecules/MonsterCard.spec.ts | 4 +- .../__snapshots__/MonsterCard.spec.ts.snap | 22 +- .../__snapshots__/ContentCard.spec.ts.snap | 12 +- .../templates/DnDContentSearch.spec.ts | 23 +- .../DnDContentSearch.spec.ts.snap | 281 +++++----- test/unit/fixtures/armor-listing.json | 362 ------------- test/unit/fixtures/open5e-item.json | 113 ---- test/unit/fixtures/open5e.ts | 498 ++++++++++++++++++ 39 files changed, 1791 insertions(+), 1342 deletions(-) delete mode 100644 app/components/atoms/ContentCardContent.vue create mode 100644 app/components/atoms/GameSystemFilter.vue create mode 100644 app/components/molecules/ContentCard/ContentCardArmor.vue create mode 100644 app/components/molecules/ContentCard/ContentCardMagicItem.vue create mode 100644 app/components/molecules/ContentCard/ContentCardSpell.vue create mode 100644 app/components/molecules/ContentCard/ContentCardWeapon.vue rename app/components/molecules/{ContentCard.vue => ContentCard/index.vue} (74%) create mode 100644 app/utils/open5e.ts delete mode 100644 test/unit/components/atoms/ContentCardContent.spec.ts delete mode 100644 test/unit/components/atoms/__snapshots__/ContentCardContent.spec.ts.snap rename test/unit/components/molecules/{ => ContentCard}/ContentCard.spec.ts (90%) create mode 100644 test/unit/components/molecules/ContentCard/ContentCardArmor.spec.ts create mode 100644 test/unit/components/molecules/ContentCard/ContentCardMagicItem.spec.ts create mode 100644 test/unit/components/molecules/ContentCard/ContentCardSpell.spec.ts create mode 100644 test/unit/components/molecules/ContentCard/ContentCardWeapon.spec.ts rename test/unit/components/molecules/{ => ContentCard}/__snapshots__/ContentCard.spec.ts.snap (60%) create mode 100644 test/unit/components/molecules/ContentCard/__snapshots__/ContentCardArmor.spec.ts.snap create mode 100644 test/unit/components/molecules/ContentCard/__snapshots__/ContentCardMagicItem.spec.ts.snap create mode 100644 test/unit/components/molecules/ContentCard/__snapshots__/ContentCardSpell.spec.ts.snap create mode 100644 test/unit/components/molecules/ContentCard/__snapshots__/ContentCardWeapon.spec.ts.snap delete mode 100644 test/unit/fixtures/armor-listing.json delete mode 100644 test/unit/fixtures/open5e-item.json create mode 100644 test/unit/fixtures/open5e.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 3783a8b9..c318556f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,7 +6,9 @@ "i18n-ally.keystyle": "nested", "cSpell.words": [ "dompurify", + "gamesystem", "imagekit", + "magicitems", "medior", "nuxtjs", "tabler", diff --git a/app/components/atoms/ContentCardContent.vue b/app/components/atoms/ContentCardContent.vue deleted file mode 100644 index df560c6a..00000000 --- a/app/components/atoms/ContentCardContent.vue +++ /dev/null @@ -1,241 +0,0 @@ - - - diff --git a/app/components/atoms/GameSystemFilter.vue b/app/components/atoms/GameSystemFilter.vue new file mode 100644 index 00000000..de5f2a58 --- /dev/null +++ b/app/components/atoms/GameSystemFilter.vue @@ -0,0 +1,136 @@ + + + diff --git a/app/components/form/Bestiary.vue b/app/components/form/Bestiary.vue index a92e284d..43278747 100644 --- a/app/components/form/Bestiary.vue +++ b/app/components/form/Bestiary.vue @@ -2,7 +2,15 @@ import { INITIATIVE_SHEET } from '~~/constants/provide-keys' import { useToast } from '~/components/ui/toast/use-toast' import { crOptions } from '~~/constants/dnd-rules' -import { useOpen5eListing } from '~~/queries/open5e' +import { useOpen5eDocuments, useOpen5eListing } from '~~/queries/open5e' + +const props = withDefaults(defineProps<{ + system?: Open5eGameSystem + preSelectedDocuments?: string[] +}>(), { + system: '5e-2024', + preSelectedDocuments: () => ['srd-2024'], +}) const { sheet, update } = validateInject(INITIATIVE_SHEET) @@ -14,12 +22,15 @@ const sortBy = ref('name') const cr = ref('all') const search = ref('') const debouncedSearch = refDebounced(search, 500, { maxWait: 1000 }) +const selectedSystem = ref(props.system) +const selectedDocuments = ref(props.preSelectedDocuments) const queryFilters = ref({ page: 0, search: debouncedSearch.value, cr: typeof cr.value === 'string' ? undefined : cr.value, ordering: sortBy.value, + document__key__in: selectedDocuments.value, }) watch([debouncedSearch, cr, sortBy], () => { @@ -28,14 +39,30 @@ watch([debouncedSearch, cr, sortBy], () => { search: debouncedSearch.value, cr: typeof cr.value === 'string' ? undefined : cr.value, ordering: sortBy.value, + document__key__in: selectedDocuments.value, } }) -const { data, status } = useOpen5eListing(computed(() => ({ +watch(selectedDocuments, () => { + queryFilters.value = { + page: 0, + search: '', + cr: typeof cr.value === 'string' ? undefined : cr.value, + ordering: sortBy.value, + document__key__in: selectedDocuments.value, + } +}) + +const { data, status: monstersStatus } = useOpen5eListing(computed(() => ({ type: 'monsters', filters: queryFilters.value, }))) +const { data: documents, status: documentsStatus } = useOpen5eDocuments() + +const isLoading = computed(() => monstersStatus.value === 'pending' || documentsStatus.value === 'pending') +const isError = computed(() => monstersStatus.value === 'error' || documentsStatus.value === 'error') + async function addMonster(monster: Open5eItem): Promise { if (!sheet.value) return @@ -69,7 +96,7 @@ async function addMonster(monster: Open5eItem): Promise { v-model="search" name="search" type="search" - :disabled="status === 'pending'" + :disabled="isLoading" /> { id="cr" v-model="cr" name="cr" + :disabled="isLoading" > @@ -113,7 +141,7 @@ async function addMonster(monster: Open5eItem): Promise { id="sortBy" v-model="sortBy" name="sortBy" - :disabled="status === 'pending'" + :disabled="isLoading" > @@ -139,11 +167,23 @@ async function addMonster(monster: Open5eItem): Promise { +
+ + {{ $t('components.inputs.gameSystemLabel') }} + + +
@@ -169,7 +209,7 @@ async function addMonster(monster: Open5eItem): Promise {
{ @paginate="scrollToId('el')" />

{{ $t('components.dndContentSearch.error') }}

{{ $t('components.dndContentSearch.notFound') }} diff --git a/app/components/molecules/ContentCard/ContentCardArmor.vue b/app/components/molecules/ContentCard/ContentCardArmor.vue new file mode 100644 index 00000000..2202656f --- /dev/null +++ b/app/components/molecules/ContentCard/ContentCardArmor.vue @@ -0,0 +1,38 @@ + + + diff --git a/app/components/molecules/ContentCard/ContentCardMagicItem.vue b/app/components/molecules/ContentCard/ContentCardMagicItem.vue new file mode 100644 index 00000000..78fafa79 --- /dev/null +++ b/app/components/molecules/ContentCard/ContentCardMagicItem.vue @@ -0,0 +1,97 @@ + + + diff --git a/app/components/molecules/ContentCard/ContentCardSpell.vue b/app/components/molecules/ContentCard/ContentCardSpell.vue new file mode 100644 index 00000000..428a4220 --- /dev/null +++ b/app/components/molecules/ContentCard/ContentCardSpell.vue @@ -0,0 +1,196 @@ + + + diff --git a/app/components/molecules/ContentCard/ContentCardWeapon.vue b/app/components/molecules/ContentCard/ContentCardWeapon.vue new file mode 100644 index 00000000..d178761b --- /dev/null +++ b/app/components/molecules/ContentCard/ContentCardWeapon.vue @@ -0,0 +1,70 @@ + + + diff --git a/app/components/molecules/ContentCard.vue b/app/components/molecules/ContentCard/index.vue similarity index 74% rename from app/components/molecules/ContentCard.vue rename to app/components/molecules/ContentCard/index.vue index e4ea505e..ef1cd018 100644 --- a/app/components/molecules/ContentCard.vue +++ b/app/components/molecules/ContentCard/index.vue @@ -16,10 +16,6 @@ const props = withDefaults( ) const isOpen = ref(false) - -function hideOpenButton(): boolean { - return props.type === 'weapons' || props.type === 'armor' -}