From 8d874438fbcfb0e7fc86164e15db57bd4d8a3833 Mon Sep 17 00:00:00 2001 From: ilestis Date: Fri, 24 May 2024 12:29:19 -0600 Subject: [PATCH] New abilities subpage --- .../Entity/Abilities/ApiController.php | 2 +- app/Services/Abilities/AbilityService.php | 112 ++++++---- lang/en/entities/abilities.php | 9 + .../js/components/abilities/Abilities.vue | 79 ++----- resources/js/components/abilities/Ability.vue | 202 ++++++++++++------ resources/js/components/abilities/Parent.vue | 54 +++-- resources/sass/abilities.scss | 61 ------ resources/sass/colour.scss | 4 + resources/sass/theming.scss | 4 + .../views/campaigns/modules/box.blade.php | 4 +- 10 files changed, 285 insertions(+), 246 deletions(-) diff --git a/app/Http/Controllers/Entity/Abilities/ApiController.php b/app/Http/Controllers/Entity/Abilities/ApiController.php index 42785341f7..660a06bf37 100644 --- a/app/Http/Controllers/Entity/Abilities/ApiController.php +++ b/app/Http/Controllers/Entity/Abilities/ApiController.php @@ -22,7 +22,7 @@ public function index(Campaign $campaign, Entity $entity) 'data' => $this->service ->campaign($campaign) ->entity($entity) - ->abilities() + ->get() ]); } } diff --git a/app/Services/Abilities/AbilityService.php b/app/Services/Abilities/AbilityService.php index 82180fd3c3..32b9acb392 100644 --- a/app/Services/Abilities/AbilityService.php +++ b/app/Services/Abilities/AbilityService.php @@ -7,8 +7,11 @@ use App\Models\Attribute; use App\Models\Entity; use App\Models\EntityAbility; +use App\Models\Tag; use App\Traits\CampaignAware; use App\Traits\EntityAware; +use Illuminate\Support\Collection; +use Illuminate\Support\Str; class AbilityService extends BaseAbilityService { @@ -17,25 +20,27 @@ class AbilityService extends BaseAbilityService /** @var array All the abilities of this entity, nicely prepared */ protected array $abilities = [ - 'parents' => [], - 'abilities' => [], - 'meta' => [] + 'groups' => [], + 'meta' => [], ]; /** @var array A list of abilities that have already been loaded */ protected array $abilityIds = []; + protected array $groups = []; + /** + * Build a list of entities grouped by their parent */ - public function abilities(): array + public function get(): array { $abilities = $this->entity->abilities() ->select('entity_abilities.*') ->with(['ability', // entity - 'ability.entity', 'ability.entity.image', 'ability.entity.attributes', + 'ability.entity', 'ability.entity.image', 'ability.entity.attributes', 'ability.entity.attributes.entity', // parent - 'ability.ability', 'ability.ability.entity', 'ability.ability.entity.tags', 'ability.ability.entity.image' + 'ability.ability', 'ability.ability.entity', 'ability.ability.entity.tags', 'ability.ability.entity.image', ]) ->join('abilities as a', 'a.id', 'entity_abilities.ability_id') ->defaultOrder() @@ -51,7 +56,8 @@ public function abilities(): array } // Reorder parents - usort($this->abilities['parents'], function ($a, $b) { + $this->abilities['groups'] = $this->groups; + usort($this->abilities['groups'], function ($a, $b) { return strcmp(mb_strtoupper($a['name']), mb_strtoupper($b['name'])); }); @@ -73,41 +79,42 @@ protected function add(EntityAbility $entityAbility): void $ability = $entityAbility->ability; $parent = $ability->ability; - if (empty($parent)) { - if (in_array($ability->id, $this->abilityIds)) { - return; + $groupKey = $parent->id ?? 'unorganised'; + + if (empty($this->groups[$groupKey])) { + if (empty($parent)) { + $this->groups[$groupKey] = [ + 'id' => 0, + 'name' => __('entities/abilities.groups.unorganised'), + 'type' => __('entities/abilities.types.unorganised'), + 'abilities' => [], + ]; + } else { + $type = empty($parent->type) ? Str::limit(strip_tags($parent->entry), 200) : $parent->type; + $this->groups[$groupKey] = [ + 'id' => $parent->id, + 'name' => $parent->name, + 'type' => $type, + 'image' => Avatar::entity($parent->entity)->size(192)->thumbnail(), + 'has_image' => $parent->entity->hasImage(), + 'entry' => $parent->parsedEntry(), + 'url' => $parent->getLink(), + 'abilities' => [], + ]; } - // Abilities need to be added to the array in the order they get loaded, but we also want to avoid abilities - // appearing multiple times somehow. - $this->abilities['abilities'][] = $this->format($entityAbility); - $this->abilityIds[] = $ability->id; - return; - } - - if (!isset($this->abilities['parents'][$parent->id])) { - $this->abilities['parents'][$parent->id] = [ - 'id' => $parent->id, - 'name' => $parent->name, - 'type' => $parent->type, - 'image' => Avatar::entity($parent->entity)->size(192)->thumbnail(), - 'has_image' => !empty($parent->entity->image_path) || !empty($parent->entity->image), - 'entry' => $parent->parsedEntry(), - 'parent' => true, - 'abilities' => [], - 'url' => $parent->getLink(), - ]; } - // Add to their parent's abilities - $this->abilities['parents'][$parent->id]['abilities'][] = $this->format($entityAbility); + $this->groups[$groupKey]['abilities'][] = $this->formatAbility($entityAbility); } /** + * Prepare the entity ability into a json object that can be used on the frontend */ - protected function format(EntityAbility $entityAbility): array + protected function formatAbility(EntityAbility $entityAbility): array { $classes = []; - foreach ($entityAbility->ability->entity->tagsWithEntity() as $tag) { + $tags = $entityAbility->ability->entity->tagsWithEntity(); + foreach ($tags as $tag) { $classes[] = ' kanka-tag-' . $tag->id; $classes[] = ' kanka-tag-' . $tag->slug; @@ -117,7 +124,16 @@ protected function format(EntityAbility $entityAbility): array } //implode(' ', $classes); + $note = nl2br((string) $this->mapAttributes( + Mentions::mapAny($entityAbility, 'note'), + false + )); + if (!empty($note)) { + $note = '' . __('entities/abilities.fields.note') . ': ' . $note; + } + $data = [ + 'id' => $entityAbility->id, 'ability_id' => $entityAbility->ability_id, 'name' => $entityAbility->ability->name, 'entry' => $this->parseEntry($entityAbility->ability), @@ -125,11 +141,10 @@ protected function format(EntityAbility $entityAbility): array 'charges' => $this->parseCharges($entityAbility->ability), 'used_charges' => $entityAbility->charges, 'class' => $classes, - 'note' => nl2br((string) $this->mapAttributes( - Mentions::mapAny($entityAbility, 'note'), - false - )), + 'note' => $note, + 'tags' => $this->formatTags($tags), 'visibility_id' => $entityAbility->visibility_id, + 'visibility' => $entityAbility->visibilityName(), 'created_by' => $entityAbility->created_by, 'attributes' => $this->attributes($entityAbility->ability->entity), 'images' => [ @@ -143,10 +158,14 @@ protected function format(EntityAbility $entityAbility): array 'delete' => route('entities.entity_abilities.destroy', [$this->campaign, $this->entity, $entityAbility]), 'view' => route('entities.show', [$this->campaign, $entityAbility->ability->entity]), ], + 'i18n' => [ + 'edit' => __('crud.update'), + 'left' => __('entities/abilities.charges.left') + ], 'entity' => [ 'id' => $entityAbility->ability->entity->id, - 'tooltip' => route('entities.tooltip', [$this->campaign, $entityAbility->ability->entity->id]) - ] + 'tooltip' => route('entities.tooltip', [$this->campaign, $entityAbility->ability->entity->id]), + ], ]; if (!empty($entityAbility->ability->charges)) { @@ -172,4 +191,19 @@ protected function attributes(Entity $entity): array } return $attributes; } + + protected function formatTags(Collection $tags): array + { + $formatted = []; + /** @var Tag $tag */ + foreach ($tags as $tag) { + $formatted[] = [ + 'id' => $tag->id, + 'name' => $tag->name, + 'url' => $tag->getLink(), + ]; + } + + return $formatted; + } } diff --git a/lang/en/entities/abilities.php b/lang/en/entities/abilities.php index 26ce338d59..dd6fffa13a 100644 --- a/lang/en/entities/abilities.php +++ b/lang/en/entities/abilities.php @@ -15,6 +15,12 @@ 'note' => 'Note', 'position' => 'Position', ], + 'charges' => [ + 'left' => ':amount left', + ], + 'groups' => [ + 'unorganised' => 'Unorganised', + ], 'helpers' => [ 'note' => 'You can reference entities using advanced mentions (ex :code) and attributes of the entity (ex :attr) in this field.', 'recharge' => 'Reset all charges for abilities that have been used.', @@ -39,6 +45,9 @@ 'reorder' => 'Reorder', 'title' => ':name Abilities', ], + 'types' => [ + 'unorganised' => 'Abilities are grouped by their parent field, and fallback to being here.', + ], 'update' => [ 'success' => 'Entity ability :ability updated.', 'title' => 'Entity Ability for :name', diff --git a/resources/js/components/abilities/Abilities.vue b/resources/js/components/abilities/Abilities.vue index a2e0715a92..20d307d5aa 100644 --- a/resources/js/components/abilities/Abilities.vue +++ b/resources/js/components/abilities/Abilities.vue @@ -1,52 +1,18 @@ @@ -71,12 +37,9 @@ data() { return { - abilities: [], - parents: [], + groups: [], meta: [], loading: true, - show_parent: false, - parent: null, waiting: false, modal: false, json_trans: [], @@ -88,24 +51,12 @@ fetch(this.api) .then(response => response.json()) .then(response => { - this.abilities = response.data.abilities; - this.parents = response.data.parents; + this.groups = response.data.groups; this.meta = response.data.meta; this.loading = false; this.waiting = false; - - - if (this.parent) { - // We need to find our parent again to "reload" it properly - this.parent = this.parents[this.parent.id]; - this.showParent(this.parent); - } }); }, - // - showParent: function (parent) { - this.show_parent = !!parent; - }, /** * Add an ability @@ -138,11 +89,11 @@ mounted() { this.getAbilities(); - - this.emitter.on('click_parent', (parent) => { - this.parent = parent; - this.showParent(parent); - }); + // + // this.emitter.on('click_parent', (parent) => { + // this.parent = parent; + // this.showParent(parent); + // }); this.emitter.on('delete_ability', (ability) => { this.deleteAbility(ability); @@ -157,3 +108,5 @@ } } + diff --git a/resources/js/components/abilities/Ability.vue b/resources/js/components/abilities/Ability.vue index c4c5556f5f..b724bd6306 100644 --- a/resources/js/components/abilities/Ability.vue +++ b/resources/js/components/abilities/Ability.vue @@ -2,85 +2,147 @@ @@ -139,6 +201,12 @@ showAbility: function(ability) { window.open(ability.actions.view, "_blank"); }, + remainingNumber: function() { + return this.ability.charges - this.ability.used_charges; + }, + remainingText: function() { + return this.ability.i18n.left.replace(/:amount/, ''); + }, setVisibility: function(visibility_id) { let data = { visibility_id: visibility_id, diff --git a/resources/js/components/abilities/Parent.vue b/resources/js/components/abilities/Parent.vue index e3283e566c..82de10d631 100644 --- a/resources/js/components/abilities/Parent.vue +++ b/resources/js/components/abilities/Parent.vue @@ -1,36 +1,63 @@