Skip to content

Commit

Permalink
Effort to improve tagging (#52)
Browse files Browse the repository at this point in the history
* Effort to improve tagging

* Automatically add tags when selecting in the tag box

* Unify tagging in bulk tagging modal

* Small test improvement
  • Loading branch information
GeniJaho authored Mar 13, 2024
1 parent 819a32e commit e7b0790
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 205 deletions.
2 changes: 1 addition & 1 deletion app/Http/Controllers/PhotoItemTagsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function store(PhotoItem $photoItem, StorePhotoItemTagRequest $request):
abort(404);
}

$photoItem->tags()->syncWithoutDetaching($request->input('tag_id'));
$photoItem->tags()->syncWithoutDetaching($request->input('tag_ids'));

return response()->json();
}
Expand Down
3 changes: 2 additions & 1 deletion app/Http/Requests/StorePhotoItemTagRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class StorePhotoItemTagRequest extends FormRequest
public function rules(): array
{
return [
'tag_id' => 'required|exists:tags,id',
'tag_ids' => 'required|array',
'tag_ids.*' => 'required|integer|exists:tags,id',
];
}
}
13 changes: 9 additions & 4 deletions resources/js/Components/TagBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ const props = defineProps({
type: Boolean,
default: false,
},
dropdownWidth: {
nullable: {
type: Boolean,
default: false,
},
placeholder: {
type: String,
default: 'w-full md:w-96 right-0',
default: '',
},
});
Expand Down Expand Up @@ -59,6 +63,7 @@ onMounted(() => {
:modelValue="modelValue"
@update:modelValue="value => $emit('update:modelValue', value)"
:multiple="multiple"
:nullable="nullable"
by="id"
>
<div class="relative">
Expand All @@ -67,6 +72,7 @@ onMounted(() => {
ref="input"
class="w-full rounded-md border-0 bg-white dark:bg-gray-900 py-1.5 pl-3 pr-12 text-gray-900 dark:text-gray-300 shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-gray-700 focus:ring-2 focus:ring-inset focus:ring-indigo-500 dark:focus:ring-indigo-600 sm:text-sm sm:leading-6"
:displayValue="(item) => item?.name"
:placeholder="placeholder"
@change="query = $event.target.value"
@focus="$event.target.select()"
autocomplete="off"
Expand Down Expand Up @@ -96,8 +102,7 @@ onMounted(() => {
@after-leave="query = ''"
>
<ComboboxOptions
class="absolute z-10 mt-1 max-h-96 overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm"
:class="dropdownWidth"
class="absolute z-10 mt-1 max-h-96 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm"
>
<div
v-if="filteredItems.length === 0 && query !== ''"
Expand Down
206 changes: 91 additions & 115 deletions resources/js/Pages/Photos/Partials/NewPhotoItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,23 @@ const props = defineProps({
const item = ref(props.propItem);
const selectedMaterialTag = ref(props.tags.material[0]);
const selectedBrandTag = ref(props.tags.brand[0]);
const selectedEventTag = ref(props.tags.event[0]);
const selectedStateTag = ref(props.tags.state[0]);
const selectedContentTag = ref(props.tags.content[0]);
const selectedSizeTag = ref(props.tags.size[0]);
const selectedMaterialTag = ref(null);
const selectedBrandTag = ref(null);
const selectedEventTag = ref(null);
const selectedStateTag = ref(null);
const selectedContentTag = ref(null);
const selectedSizeTag = ref(null);
const selectedTagIds = computed(() => {
return [
selectedMaterialTag.value?.id,
selectedBrandTag.value?.id,
selectedEventTag.value?.id,
selectedStateTag.value?.id,
selectedContentTag.value?.id,
selectedSizeTag.value?.id,
].filter(tag => tag);
});
const tagNames = computed(() => {
return item.value.tag_ids.map(function (tagId) {
Expand All @@ -32,13 +43,17 @@ const tagNames = computed(() => {
});
});
const addTagToItem = (tag) => {
if (item.value.tag_ids.find(itemTag => itemTag === tag.id)) {
return;
}
const addTagsToItem = () => {
item.value.tag_ids = [...new Set([...item.value.tag_ids, ...selectedTagIds.value])];
item.value.tag_ids.push(tag.id);
emit('change', item.value);
selectedMaterialTag.value = null;
selectedBrandTag.value = null;
selectedEventTag.value = null;
selectedStateTag.value = null;
selectedContentTag.value = null;
selectedSizeTag.value = null;
};
const removeTagFromItem = (tagId) => {
Expand Down Expand Up @@ -75,110 +90,63 @@ const copyItem = () => {
<i class="fas fa-fw fa-trash-alt text-xs"></i>
</IconDangerButton>
</div>
<div class="mt-6">
<div class="flex flex-row justify-between space-x-2">
<TagBox
class="w-full"
dropdownWidth="w-full"
:items="tags.material"
v-model="selectedMaterialTag"
></TagBox>
<PrimaryButton
class="whitespace-nowrap"
@click="addTagToItem(selectedMaterialTag)"
:disabled="!selectedMaterialTag"
>
Add Material
</PrimaryButton>
</div>
<div class="mt-2 flex flex-row justify-between space-x-2">
<TagBox
class="w-full"
dropdownWidth="w-full"
:items="tags.brand"
v-model="selectedBrandTag"
></TagBox>
<PrimaryButton
class="whitespace-nowrap"
@click="addTagToItem(selectedBrandTag)"
:disabled="!selectedBrandTag"
>
Add Brand
</PrimaryButton>
</div>
<div class="mt-2 flex flex-row justify-between space-x-2">
<TagBox
class="w-full"
dropdownWidth="w-full"
:items="tags.content"
v-model="selectedContentTag"
></TagBox>
<PrimaryButton
class="whitespace-nowrap"
@click="addTagToItem(selectedContentTag)"
:disabled="!selectedContentTag"
>
Add Content
</PrimaryButton>
</div>
<div class="mt-2 flex flex-row justify-between space-x-2">
<TagBox
class="w-full"
dropdownWidth="w-full"
:items="tags.size"
v-model="selectedSizeTag"
></TagBox>
<PrimaryButton
class="whitespace-nowrap"
@click="addTagToItem(selectedSizeTag)"
:disabled="!selectedSizeTag"
>
Add Size
</PrimaryButton>
</div>
<div class="mt-2 flex flex-row justify-between space-x-2">
<TagBox
class="w-full"
dropdownWidth="w-full"
:items="tags.state"
v-model="selectedStateTag"
></TagBox>
<PrimaryButton
class="whitespace-nowrap"
@click="addTagToItem(selectedStateTag)"
:disabled="!selectedStateTag"
>
Add State
</PrimaryButton>
</div>
<div class="mt-2 flex flex-row justify-between space-x-2">
<TagBox
class="w-full"
dropdownWidth="w-full"
:items="tags.event"
v-model="selectedEventTag"
></TagBox>
<PrimaryButton
class="whitespace-nowrap"
@click="addTagToItem(selectedEventTag)"
:disabled="!selectedEventTag"
>
Add Event
</PrimaryButton>
</div>
<div class="mt-6 space-y-2">
<TagBox
class="w-full"
:items="tags.material"
v-model="selectedMaterialTag"
:nullable="true"
placeholder="Material"
@change="addTagsToItem"
></TagBox>
<TagBox
class="w-full"
:items="tags.brand"
v-model="selectedBrandTag"
:nullable="true"
placeholder="Brand"
@change="addTagsToItem"
></TagBox>
<TagBox
class="w-full"
:items="tags.content"
v-model="selectedContentTag"
:nullable="true"
placeholder="Content"
@change="addTagsToItem"
></TagBox>
<TagBox
class="w-full"
:items="tags.size"
v-model="selectedSizeTag"
:nullable="true"
placeholder="Size"
@change="addTagsToItem"
></TagBox>
<TagBox
class="w-full"
:items="tags.state"
v-model="selectedStateTag"
:nullable="true"
placeholder="State"
@change="addTagsToItem"
></TagBox>
<TagBox
class="w-full"
:items="tags.event"
v-model="selectedEventTag"
:nullable="true"
placeholder="Event"
@change="addTagsToItem"
></TagBox>
</div>
<div class="mt-4 text-sm text-gray-500 flex flex-wrap gap-1">
<div class="mt-4 text-sm text-gray-500 flex flex-wrap gap-1">
<span
v-for="tag in tagNames"
:key="tag.id"
Expand All @@ -189,7 +157,15 @@ const copyItem = () => {
aria-hidden="true"><circle cx="3" cy="3" r="3"/></svg>
{{ tag.name }}
</span>
</div>
</div>
<div v-if="selectedTagIds.length" class="mt-4 flex justify-center">
<PrimaryButton
class="whitespace-nowrap"
@click="addTagsToItem"
>
Add Selected Tags
</PrimaryButton>
</div>
</div>
<div class="px-4 py-5 sm:p-6 flex flex-row justify-between">
Expand Down
Loading

0 comments on commit e7b0790

Please sign in to comment.