From d4d3d9390c45a59bdca98f2d6795559db9dd3fa0 Mon Sep 17 00:00:00 2001 From: Pantry Lead Agent Date: Tue, 24 Feb 2026 00:07:27 +0000 Subject: [PATCH] feat: add TagManager and tag filtering (#30 #31) Issue #30 - TagManager component: - Create/delete tags with name, category, icon, color - Color picker with hex input - Organized display by category - Integrated in settings page with tabs Issue #31 - Tag filter for inventory: - TagFilter component with multi-select - Filter button in inventory header - Active filter display with removable badges - Filters items by selected tags (OR logic) - Clean "Clear" button Updates: - Extended useTags composable with createTag, deleteTag - Enhanced settings page with tab navigation - Improved inventory filtering UX Closes #30, #31 --- app/components/inventory/InventoryList.vue | 18 +- app/components/tags/TagFilter.vue | 127 ++++++++++++ app/components/tags/TagManager.vue | 212 +++++++++++++++++++++ app/composables/useTags.ts | 44 ++++- app/pages/index.vue | 17 ++ app/pages/settings.vue | 110 +++++------ 6 files changed, 467 insertions(+), 61 deletions(-) create mode 100644 app/components/tags/TagFilter.vue create mode 100644 app/components/tags/TagManager.vue diff --git a/app/components/inventory/InventoryList.vue b/app/components/inventory/InventoryList.vue index 50bdf50..dc451b5 100644 --- a/app/components/inventory/InventoryList.vue +++ b/app/components/inventory/InventoryList.vue @@ -43,7 +43,7 @@
() const emit = defineEmits<{ @@ -86,6 +87,21 @@ const loadInventory = async () => { loading.value = false } +// Computed filtered items +const filteredItems = computed(() => { + if (!props.tagFilters || props.tagFilters.length === 0) { + return items.value + } + + // Filter items that have at least one of the selected tags + return items.value.filter(item => { + if (!item.tags || item.tags.length === 0) return false + + const itemTagIds = item.tags.map((t: any) => t.tag.id) + return props.tagFilters!.some(filterId => itemTagIds.includes(filterId)) + }) +}) + const handleDelete = async (id: string) => { if (!confirm('Are you sure you want to delete this item?')) { return diff --git a/app/components/tags/TagFilter.vue b/app/components/tags/TagFilter.vue new file mode 100644 index 0000000..200728d --- /dev/null +++ b/app/components/tags/TagFilter.vue @@ -0,0 +1,127 @@ + + + diff --git a/app/components/tags/TagManager.vue b/app/components/tags/TagManager.vue new file mode 100644 index 0000000..63b3f06 --- /dev/null +++ b/app/components/tags/TagManager.vue @@ -0,0 +1,212 @@ + + + diff --git a/app/composables/useTags.ts b/app/composables/useTags.ts index ed7bfa5..6de8b88 100644 --- a/app/composables/useTags.ts +++ b/app/composables/useTags.ts @@ -37,8 +37,50 @@ export const useTags = () => { return { data, error: null } } + /** + * Create a new tag + */ + const createTag = async (tag: { + name: string + category: string + icon?: string | null + color: string + }) => { + const { data, error } = await supabase + .from('tags') + .insert(tag) + .select() + .single() + + if (error) { + console.error('Error creating tag:', error) + return { data: null, error } + } + + return { data, error: null } + } + + /** + * Delete a tag + */ + const deleteTag = async (tagId: string) => { + const { error } = await supabase + .from('tags') + .delete() + .eq('id', tagId) + + if (error) { + console.error('Error deleting tag:', error) + return { error } + } + + return { error: null } + } + return { getTags, - getTagsByCategory + getTagsByCategory, + createTag, + deleteTag } } diff --git a/app/pages/index.vue b/app/pages/index.vue index 0ed0dc3..e7ffe58 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -21,9 +21,23 @@ > Add Manually + + + Filter +
+ + + + +
@@ -46,6 +60,7 @@ @@ -61,10 +76,12 @@ const route = useRoute() const router = useRouter() const showAddForm = ref(false) +const showFilters = ref(false) const editingItem = ref(null) const refreshKey = ref(0) const inventoryListRef = ref() const prefilledData = ref(null) +const selectedTagFilters = ref([]) // Handle scan-to-add flow (Issue #25) onMounted(() => { diff --git a/app/pages/settings.vue b/app/pages/settings.vue index a9f411a..054f95e 100644 --- a/app/pages/settings.vue +++ b/app/pages/settings.vue @@ -2,73 +2,65 @@

Settings

-
- - - -
-
- -

{{ user.email }}

+ + + + - - - -

- Manage your custom tags here (coming in Week 2). -

-
- - - - -

- Manage your custom units here (coming in Week 2). -

-
- - - - -
-

Pantry v0.1.0-alpha

-

Self-hosted inventory management

- - View on GitHub → - -
-
-
+ +