rewrite search for mobile

This commit is contained in:
hay-kot 2021-04-25 12:50:28 -08:00
commit 953dde4afc
6 changed files with 112 additions and 77 deletions

View file

@ -35,14 +35,6 @@ export default {
}, },
}, },
async created() {
window.addEventListener("keyup", e => {
if (e.key == "/" && !document.activeElement.id.startsWith("input")) {
this.search = !this.search;
}
});
},
async mounted() { async mounted() {
this.$store.dispatch("initTheme"); this.$store.dispatch("initTheme");
this.$store.dispatch("requestRecentRecipes"); this.$store.dispatch("requestRecentRecipes");

View file

@ -1,29 +1,49 @@
<template> <template>
<v-menu v-model="menuModel" offset-y readonly :width="maxWidth"> <v-menu
v-model="menuModel"
readonly
offset-y
offset-overflow
max-height="75vh"
>
<template #activator="{ attrs }"> <template #activator="{ attrs }">
<v-text-field <v-text-field
class="mt-6" ref="searchInput"
class="my-auto pt-1"
v-model="search" v-model="search"
v-bind="attrs" v-bind="attrs"
:dense="dense" :dense="dense"
light light
:label="$t('search.search-mealie')" dark
autofocus flat
:placeholder="$t('search.search-mealie')"
background-color="primary lighten-1"
color="white"
:solo="solo" :solo="solo"
:style="`max-width: ${maxWidth};`" :style="`max-width: ${maxWidth};`"
@focus="onFocus" @focus="onFocus"
@blur="isFocused = false"
autocomplete="off" autocomplete="off"
:autofocus="autofocus"
> >
<template #prepend-inner>
<v-icon color="grey lighten-3" size="29">
mdi-magnify
</v-icon>
</template>
</v-text-field> </v-text-field>
</template> </template>
<v-card v-if="showResults" max-height="500" :max-width="maxWidth"> <v-card
<v-card-text class="flex row mx-auto"> v-if="showResults"
max-height="75vh"
:max-width="maxWidth"
scrollable
>
<v-card-text class="flex row mx-auto ">
<div class="mr-auto"> <div class="mr-auto">
Results Results
</div> </div>
<router-link to="/search"> <router-link to="/search"> Advanced Search </router-link>
Advanced Search
</router-link>
</v-card-text> </v-card-text>
<v-divider></v-divider> <v-divider></v-divider>
<v-list scrollable v-if="autoResults"> <v-list scrollable v-if="autoResults">
@ -77,21 +97,21 @@ export default {
navOnClick: { navOnClick: {
default: true, default: true,
}, },
resetSearch: {
default: false,
},
solo: { solo: {
default: true, default: true,
}, },
autofocus: {
default: false,
},
}, },
data() { data() {
return { return {
isFocused: false,
searchSlug: "", searchSlug: "",
search: "", search: "",
menuModel: false, menuModel: false,
result: [], result: [],
fuseResults: [], fuseResults: [],
isDark: false,
options: { options: {
shouldSort: true, shouldSort: true,
threshold: 0.6, threshold: 0.6,
@ -105,8 +125,10 @@ export default {
}; };
}, },
mounted() { mounted() {
this.isDark = this.$store.getters.getIsDark; document.addEventListener("keydown", this.onDocumentKeydown);
this.$store.dispatch("requestAllRecipes"); },
beforeDestroy() {
document.removeEventListener("keydown", this.onDocumentKeydown);
}, },
computed: { computed: {
data() { data() {
@ -124,11 +146,7 @@ export default {
}, },
watch: { watch: {
isSearching(val) { isSearching(val) {
val ? (this.menuModel = true) : null; val ? (this.menuModel = true) : this.resetSearch();
},
resetSearch(val) {
val ? (this.search = "") : null;
}, },
search() { search() {
@ -167,9 +185,26 @@ export default {
this.$emit("selected", slug, name); this.$emit("selected", slug, name);
}, },
async onFocus() { async onFocus() {
clearTimeout(this.timeout); this.$store.dispatch("requestAllRecipes");
this.isFocused = true; this.isFocused = true;
}, },
resetSearch() {
this.$nextTick(() => {
this.search = "";
this.isFocused = false;
this.menuModel = false;
});
},
onDocumentKeydown(e) {
if (
e.key === "/" &&
e.target !== this.$refs.searchInput.$refs.input &&
!document.activeElement.id.startsWith("input")
) {
e.preventDefault();
this.$refs.searchInput.focus();
}
},
}, },
}; };
</script> </script>
@ -181,4 +216,9 @@ export default {
</style> </style>
<style lang="sass" scoped> <style lang="sass" scoped>
.v-menu__content
width: 100
&, & > *
display: flex
flex-direction: column
</style> </style>

View file

@ -1,34 +1,40 @@
<template> <template>
<div class="text-center "> <div class="text-center ">
<v-dialog v-model="dialog" width="600px" height="0" :fullscreen="isMobile"> <v-dialog
v-model="dialog"
width="600px"
height="0"
:fullscreen="isMobile"
content-class="top-dialog"
>
<v-card> <v-card>
<v-app-bar dark color="primary"> <v-app-bar dark color="primary lighten-1" rounded="0">
<v-toolbar-title class="headline">Search a Recipe</v-toolbar-title>
</v-app-bar>
<v-card-text>
<SearchBar <SearchBar
ref="mealSearchBar"
@results="updateResults" @results="updateResults"
@selected="emitSelect" @selected="emitSelect"
:show-results="!isMobile" :show-results="!isMobile"
max-width="550px" max-width="568"
:dense="false" :dense="false"
:nav-on-click="false" :nav-on-click="false"
:reset-search="dialog" :autofocus="true"
:solo="false"
/> />
<div v-if="isMobile"> <v-btn icon @click="dialog = false" class="mt-1">
<div v-for="recipe in searchResults.slice(0, 7)" :key="recipe.name"> <v-icon> mdi-close </v-icon>
<MobileRecipeCard </v-btn>
class="ma-1 px-0" </v-app-bar>
:name="recipe.item.name" <v-card-text v-if="isMobile">
:description="recipe.item.description" <div v-for="recipe in searchResults.slice(0, 7)" :key="recipe.name">
:slug="recipe.item.slug" <MobileRecipeCard
:rating="recipe.item.rating" class="ma-1 px-0"
:image="recipe.item.image" :name="recipe.item.name"
:route="true" :description="recipe.item.description"
@selected="dialog = false" :slug="recipe.item.slug"
/> :rating="recipe.item.rating"
</div> :image="recipe.item.image"
:route="true"
@selected="dialog = false"
/>
</div> </div>
</v-card-text> </v-card-text>
</v-card> </v-card>
@ -74,11 +80,12 @@ export default {
}, },
open() { open() {
this.dialog = true; this.dialog = true;
this.$router.push("#mobile-search"); this.$refs.mealSearchBar.resetSearch();
this.$router.push("#search");
}, },
toggleDialog(open) { toggleDialog(open) {
if (open) { if (open) {
this.$router.push("#mobile-search"); this.$router.push("#search");
} else { } else {
this.$router.back(); // 😎 back button click this.$router.back(); // 😎 back button click
} }
@ -92,4 +99,8 @@ export default {
align-items: flex-start; align-items: flex-start;
justify-content: flex-start; justify-content: flex-start;
} }
.top-dialog {
align-self: flex-start;
}
</style> </style>

View file

@ -13,7 +13,7 @@
<v-btn icon @click="openSidebar"> <v-btn icon @click="openSidebar">
<v-icon> mdi-menu </v-icon> <v-icon> mdi-menu </v-icon>
</v-btn> </v-btn>
<router-link v-if="!(isMobile && search)" to="/"> <router-link to="/">
<v-btn icon> <v-btn icon>
<v-icon size="40"> mdi-silverware-variant </v-icon> <v-icon size="40"> mdi-silverware-variant </v-icon>
</v-btn> </v-btn>
@ -26,18 +26,18 @@
</div> </div>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-expand-x-transition> <SearchBar
<SearchBar v-if="!isMobile"
ref="mainSearchBar" :show-results="true"
v-if="search" @selected="navigateFromSearch"
:show-results="true" :max-width="isMobile ? '100%' : '450px'"
@selected="navigateFromSearch" />
:max-width="isMobile ? '100%' : '450px'" <div v-else>
/> <v-btn icon @click="$refs.recipeSearch.open()">
</v-expand-x-transition> <v-icon> mdi-magnify </v-icon>
<v-btn icon @click="search = !search"> </v-btn>
<v-icon>mdi-magnify</v-icon> <SearchDialog ref="recipeSearch"/>
</v-btn> </div>
<TheSiteMenu /> <TheSiteMenu />
@ -54,6 +54,7 @@
<script> <script>
import TheSiteMenu from "@/components/UI/TheSiteMenu"; import TheSiteMenu from "@/components/UI/TheSiteMenu";
import SearchBar from "@/components/UI/Search/SearchBar"; import SearchBar from "@/components/UI/Search/SearchBar";
import SearchDialog from "@/components/UI/Search/SearchDialog";
import TheRecipeFab from "@/components/UI/TheRecipeFab"; import TheRecipeFab from "@/components/UI/TheRecipeFab";
import TheSidebar from "@/components/UI/TheSidebar"; import TheSidebar from "@/components/UI/TheSidebar";
import { user } from "@/mixins/user"; import { user } from "@/mixins/user";
@ -62,6 +63,7 @@ export default {
mixins: [user], mixins: [user],
components: { components: {
SearchDialog,
TheRecipeFab, TheRecipeFab,
TheSidebar, TheSidebar,
TheSiteMenu, TheSiteMenu,
@ -69,15 +71,9 @@ export default {
}, },
data() { data() {
return { return {
search: false,
showSidebar: false, showSidebar: false,
}; };
}, },
watch: {
$route() {
this.search = false;
},
},
computed: { computed: {
isMobile() { isMobile() {
return this.$vuetify.breakpoint.name === "xs"; return this.$vuetify.breakpoint.name === "xs";
@ -95,8 +91,4 @@ export default {
</script> </script>
<style scoped> <style scoped>
fab-position {
position: absolute;
bottom: 0;
}
</style> </style>

View file

@ -137,7 +137,7 @@ export default {
mainMenu() { mainMenu() {
return [...this.baseMainLinks, ...this.customPages]; return [...this.baseMainLinks, ...this.customPages];
}, },
settingsLink() { settingsLinks() {
return [ return [
{ {
icon: "mdi-account", icon: "mdi-account",

View file

@ -169,7 +169,7 @@
"image": "Image" "image": "Image"
}, },
"search": { "search": {
"search-mealie": "Search Mealie", "search-mealie": "Search Mealie (press /)",
"search-placeholder": "Search...", "search-placeholder": "Search...",
"max-results": "Max Results", "max-results": "Max Results",
"category-filter": "Category Filter", "category-filter": "Category Filter",