| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  | <template> | 
					
						
							|  |  |  |   <div> | 
					
						
							|  |  |  |     <slot v-bind="{ open, close }"> </slot> | 
					
						
							|  |  |  |     <v-dialog v-model="dialog" max-width="988px" content-class="top-dialog" :scrollable="false"> | 
					
						
							|  |  |  |       <v-app-bar sticky dark color="primary lighten-1" :rounded="!$vuetify.breakpoint.xs"> | 
					
						
							|  |  |  |         <v-text-field | 
					
						
							|  |  |  |           id="arrow-search" | 
					
						
							| 
									
										
										
										
											2023-03-12 12:59:28 -08:00
										 |  |  |           v-model="search.query.value" | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |           autofocus | 
					
						
							|  |  |  |           solo | 
					
						
							|  |  |  |           flat | 
					
						
							|  |  |  |           autocomplete="off" | 
					
						
							|  |  |  |           background-color="primary lighten-1" | 
					
						
							|  |  |  |           color="white" | 
					
						
							|  |  |  |           dense | 
					
						
							|  |  |  |           class="mx-2 arrow-search" | 
					
						
							|  |  |  |           hide-details | 
					
						
							|  |  |  |           single-line | 
					
						
							| 
									
										
										
										
											2022-08-10 07:12:45 +02:00
										 |  |  |           :placeholder="$t('search.search')" | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |           :prepend-inner-icon="$globals.icons.search" | 
					
						
							|  |  |  |         ></v-text-field> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         <v-btn v-if="$vuetify.breakpoint.xs" x-small fab light @click="dialog = false"> | 
					
						
							|  |  |  |           <v-icon> | 
					
						
							|  |  |  |             {{ $globals.icons.close }} | 
					
						
							|  |  |  |           </v-icon> | 
					
						
							|  |  |  |         </v-btn> | 
					
						
							|  |  |  |       </v-app-bar> | 
					
						
							|  |  |  |       <v-card class="mt-1 pa-1 scroll" max-height="700px" relative :loading="loading"> | 
					
						
							|  |  |  |         <v-card-actions> | 
					
						
							|  |  |  |           <div class="mr-auto"> | 
					
						
							|  |  |  |             {{ $t("search.results") }} | 
					
						
							|  |  |  |           </div> | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  |           <router-link :to="advancedSearchUrl"> {{ $t("search.advanced-search") }} </router-link> | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |         </v-card-actions> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         <RecipeCardMobile | 
					
						
							| 
									
										
										
										
											2023-03-12 12:59:28 -08:00
										 |  |  |           v-for="(recipe, index) in search.data.value" | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |           :key="index" | 
					
						
							|  |  |  |           :tabindex="index" | 
					
						
							|  |  |  |           class="ma-1 arrow-nav" | 
					
						
							|  |  |  |           :name="recipe.name" | 
					
						
							|  |  |  |           :description="recipe.description || ''" | 
					
						
							|  |  |  |           :slug="recipe.slug" | 
					
						
							|  |  |  |           :rating="recipe.rating" | 
					
						
							|  |  |  |           :image="recipe.image" | 
					
						
							|  |  |  |           :recipe-id="recipe.id" | 
					
						
							|  |  |  |           v-on="$listeners.selected ? { selected: () => handleSelect(recipe) } : {}" | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       </v-card> | 
					
						
							|  |  |  |     </v-dialog> | 
					
						
							|  |  |  |   </div> | 
					
						
							|  |  |  | </template> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <script lang="ts"> | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  | import { computed, defineComponent, toRefs, reactive, ref, watch, useContext, useRoute } from "@nuxtjs/composition-api"; | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  | import RecipeCardMobile from "./RecipeCardMobile.vue"; | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  | import { useLoggedInState } from "~/composables/use-logged-in-state"; | 
					
						
							| 
									
										
										
										
											2022-10-22 11:51:07 -08:00
										 |  |  | import { RecipeSummary } from "~/lib/api/types/recipe"; | 
					
						
							| 
									
										
										
										
											2023-02-11 21:26:10 -09:00
										 |  |  | import { useUserApi } from "~/composables/api"; | 
					
						
							| 
									
										
										
										
											2023-03-12 12:59:28 -08:00
										 |  |  | import { useRecipeSearch } from "~/composables/recipes/use-recipe-search"; | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  | import { usePublicExploreApi } from "~/composables/api/api-client"; | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  | const SELECTED_EVENT = "selected"; | 
					
						
							|  |  |  | export default defineComponent({ | 
					
						
							|  |  |  |   components: { | 
					
						
							|  |  |  |     RecipeCardMobile, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setup(_, context) { | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  |     const { $auth } = useContext(); | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |     const state = reactive({ | 
					
						
							|  |  |  |       loading: false, | 
					
						
							|  |  |  |       selectedIndex: -1, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // ===========================================================================
 | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     // Dialog State Management
 | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |     const dialog = ref(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Reset or Grab Recipes on Change
 | 
					
						
							| 
									
										
										
										
											2023-02-11 21:26:10 -09:00
										 |  |  |     watch(dialog, (val) => { | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |       if (!val) { | 
					
						
							| 
									
										
										
										
											2023-03-12 12:59:28 -08:00
										 |  |  |         search.query.value = ""; | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |         state.selectedIndex = -1; | 
					
						
							| 
									
										
										
										
											2023-03-12 12:59:28 -08:00
										 |  |  |         search.data.value = []; | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     // ===========================================================================
 | 
					
						
							|  |  |  |     // Event Handlers
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function selectRecipe() { | 
					
						
							|  |  |  |       const recipeCards = document.getElementsByClassName("arrow-nav"); | 
					
						
							|  |  |  |       if (recipeCards) { | 
					
						
							|  |  |  |         if (state.selectedIndex < 0) { | 
					
						
							|  |  |  |           state.selectedIndex = -1; | 
					
						
							|  |  |  |           document.getElementById("arrow-search")?.focus(); | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (state.selectedIndex >= recipeCards.length) { | 
					
						
							|  |  |  |           state.selectedIndex = recipeCards.length - 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         (recipeCards[state.selectedIndex] as HTMLElement).focus(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function onUpDown(e: KeyboardEvent) { | 
					
						
							|  |  |  |       if (e.key === "Enter") { | 
					
						
							|  |  |  |         console.log(document.activeElement); | 
					
						
							|  |  |  |         // (document.activeElement as HTMLElement).click();
 | 
					
						
							|  |  |  |       } else if (e.key === "ArrowUp") { | 
					
						
							|  |  |  |         e.preventDefault(); | 
					
						
							|  |  |  |         state.selectedIndex--; | 
					
						
							|  |  |  |       } else if (e.key === "ArrowDown") { | 
					
						
							|  |  |  |         e.preventDefault(); | 
					
						
							|  |  |  |         state.selectedIndex++; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       selectRecipe(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     watch(dialog, (val) => { | 
					
						
							|  |  |  |       if (!val) { | 
					
						
							|  |  |  |         document.removeEventListener("keyup", onUpDown); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         document.addEventListener("keyup", onUpDown); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  |     const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || ""); | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     const route = useRoute(); | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  |     const advancedSearchUrl = computed(() => `/g/${groupSlug.value}`) | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  |     watch(route, close); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |     function open() { | 
					
						
							|  |  |  |       dialog.value = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     function close() { | 
					
						
							|  |  |  |       dialog.value = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // ===========================================================================
 | 
					
						
							|  |  |  |     // Basic Search
 | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  |     const { isOwnGroup } = useLoggedInState(); | 
					
						
							|  |  |  |     const api = isOwnGroup.value ? useUserApi() : usePublicExploreApi(groupSlug.value).explore; | 
					
						
							| 
									
										
										
										
											2023-03-12 12:59:28 -08:00
										 |  |  |     const search = useRecipeSearch(api); | 
					
						
							| 
									
										
										
										
											2023-02-20 02:11:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |     // Select Handler
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function handleSelect(recipe: RecipeSummary) { | 
					
						
							|  |  |  |       close(); | 
					
						
							|  |  |  |       context.emit(SELECTED_EVENT, recipe); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-12 12:59:28 -08:00
										 |  |  |     return { | 
					
						
							|  |  |  |       ...toRefs(state), | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  |       advancedSearchUrl, | 
					
						
							| 
									
										
										
										
											2023-03-12 12:59:28 -08:00
										 |  |  |       dialog, | 
					
						
							|  |  |  |       open, | 
					
						
							|  |  |  |       close, | 
					
						
							|  |  |  |       handleSelect, | 
					
						
							|  |  |  |       search, | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  |   }, | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | </script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <style> | 
					
						
							|  |  |  | .scroll { | 
					
						
							| 
									
										
										
										
											2023-02-21 00:51:24 -06:00
										 |  |  |   overflow-y: auto; | 
					
						
							| 
									
										
										
										
											2021-11-08 21:12:13 -09:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-01-09 07:15:23 +01:00
										 |  |  | </style> |