From 64fb80235e312040e6d2793e862b042cb31982f8 Mon Sep 17 00:00:00 2001
From: Lightling <contact@lightling.xyz>
Date: Fri, 3 May 2024 18:09:36 -0400
Subject: [PATCH] create filter panel shared component

---
 .../src/components/shared/filter-panel.vue    | 66 +++++++++++++++++++
 .../src/views/gallery/gallery-list.vue        | 47 ++++---------
 2 files changed, 77 insertions(+), 36 deletions(-)
 create mode 100644 projects/frontend/src/components/shared/filter-panel.vue

diff --git a/projects/frontend/src/components/shared/filter-panel.vue b/projects/frontend/src/components/shared/filter-panel.vue
new file mode 100644
index 0000000..aedd9e4
--- /dev/null
+++ b/projects/frontend/src/components/shared/filter-panel.vue
@@ -0,0 +1,66 @@
+<script setup lang="ts">
+
+defineProps<{
+  tagsByCategory: { [category: string]: Record<string, string> }
+}>()
+
+const emits = defineEmits<{
+  (e: 'toggledTagsChanged', value: string[]): void
+}>()
+
+let tagsToggled: string[] = []
+
+/**
+ * Handler for a tag being selected;
+ * updates the visibility state of the current entries
+ * @param event the event context which invoked this handler
+ * @param tagId: the id of the tag
+ */
+const onToggleTag = (event: Event, tagId: string) => {
+  if ((event.target as HTMLInputElement).checked) {
+    tagsToggled.push(tagId)
+  } else {
+    const index = tagsToggled.indexOf(tagId)
+    if (index > -1) {
+      tagsToggled.splice(index, 1)
+    }
+  }
+  emits('toggledTagsChanged', tagsToggled)
+}
+
+/**
+ * Resets the `tagsToggled` array
+ */
+const resetTags = () => {
+  tagsToggled = []
+}
+</script>
+
+<template lang="pug">
+.filters
+  h2 Filters
+  .category(
+    v-for='(tags, category) in tagsByCategory'
+    :id='category'
+  )
+    h3(
+      v-if='category !== "NoCategory"'
+    ) {{ category }}
+    .input.labeled-checkbox(
+      v-for='(tagDisplayName, tagId) in tags'
+      :id='tagId'
+    )
+      label(
+        :for='`${tagId}-toggle`'
+      ) {{ tagDisplayName }}
+      input(
+        type='checkbox'
+        :name='`${tagId}-toggle`'
+        :id='`${tagId}-toggle`'
+        @input='onToggleTag($event, tagId)'
+      )
+</template>
+
+<style scoped lang="sass">
+
+</style>
diff --git a/projects/frontend/src/views/gallery/gallery-list.vue b/projects/frontend/src/views/gallery/gallery-list.vue
index 53f150b..729e4dd 100644
--- a/projects/frontend/src/views/gallery/gallery-list.vue
+++ b/projects/frontend/src/views/gallery/gallery-list.vue
@@ -12,6 +12,7 @@ import { fetchAndParseYaml, storage } from 'src/utilities/fetch'
 import { getCurrentRoute } from 'src/utilities/vuetils'
 import { useRouteStore } from 'src/routes'
 
+import FilterPanel from 'src/components/shared/filter-panel.vue'
 import GalleryTile from './gallery-tile.vue'
 
 /**
@@ -44,10 +45,10 @@ const globalConfig = routeStore._globals
 const storageId = `${globalConfig.id}`
 const router = useRouter()
 let config: GalleryList = null!
-let tagsToggled: string[] = []
 
 const ready = ref(false)
 const galleryReady = ref(false)
+const filterPanelRef = ref(null as typeof FilterPanel | null)
 const entries = ref({} as GalleryDisplayedEntries)
 const variants = ref(validateVariantPath(props.variants))
 const hasWarnings = ref(false)
@@ -148,19 +149,9 @@ const onHideWarningsToggled = (event: Event) => {
 /**
  * Handler for a tag being selected;
  * updates the visibility state of the current entries
- * @param event the event context which invoked this handler
- * @param tagId: the id of the tag
+ * @param tagsToggled: the tags currently toggled in the filter panel
  */
-const onToggleTag = (event: Event, tagId: string) => {
-  if ((event.target as HTMLInputElement).checked) {
-    tagsToggled.push(tagId)
-  } else {
-    const index = tagsToggled.indexOf(tagId)
-    if (index > -1) {
-      tagsToggled.splice(index, 1)
-    }
-  }
-
+ const onToggledTagsChanged = (tagsToggled: string[]) => {
   if (tagsToggled.length < 1) {
     Object.keys(entries.value).forEach(entryId => {
       entries.value[entryId].hidden = false
@@ -177,10 +168,12 @@ const onToggleTag = (event: Event, tagId: string) => {
  * and the `tagsToggled` array
  */
 const resetTags = () => {
+  if (!!filterPanelRef.value) {
+    filterPanelRef.value.resetTags()
+  }
   Object.keys(entries.value).forEach(entryId => {
     entries.value[entryId].hidden = false
   })
-  tagsToggled = []
 }
 
 onMounted(async () => {
@@ -218,30 +211,12 @@ onMounted(async () => {
         @input='onHideWarningsToggled($event)'
       )
   Transition
-    .filters(
+    FilterPanel(
       v-if='galleryReady && !!tagsByCategory'
+      :ref='filterPanelRef'
+      :tagsByCategory='tagsByCategory'
+      @toggledTagsChanged='onToggledTagsChanged($event)'
     )
-      h2 Filters
-      .category(
-        v-for='(tags, category) in tagsByCategory'
-        :id='category'
-      )
-        h3(
-          v-if='category !== "NoCategory"'
-        ) {{ category }}
-        .input.labeled-checkbox(
-          v-for='(tagDisplayName, tagId) in tags'
-          :id='tagId'
-        )
-          label(
-            :for='`${tagId}-toggle`'
-          ) {{ tagDisplayName }}
-          input(
-            type='checkbox'
-            :name='`${tagId}-toggle`'
-            :id='`${tagId}-toggle`'
-            @input='onToggleTag($event, tagId)'
-          )
   Transition
     .gallery(
       v-if='galleryReady'