mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-21 22:13:31 -07:00
rewrite search for mobile
This commit is contained in:
parent
5df1c906d0
commit
953dde4afc
6 changed files with 112 additions and 77 deletions
|
@ -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() {
|
||||
this.$store.dispatch("initTheme");
|
||||
this.$store.dispatch("requestRecentRecipes");
|
||||
|
|
|
@ -1,29 +1,49 @@
|
|||
<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 }">
|
||||
<v-text-field
|
||||
class="mt-6"
|
||||
ref="searchInput"
|
||||
class="my-auto pt-1"
|
||||
v-model="search"
|
||||
v-bind="attrs"
|
||||
:dense="dense"
|
||||
light
|
||||
:label="$t('search.search-mealie')"
|
||||
autofocus
|
||||
dark
|
||||
flat
|
||||
:placeholder="$t('search.search-mealie')"
|
||||
background-color="primary lighten-1"
|
||||
color="white"
|
||||
:solo="solo"
|
||||
:style="`max-width: ${maxWidth};`"
|
||||
@focus="onFocus"
|
||||
@blur="isFocused = false"
|
||||
autocomplete="off"
|
||||
:autofocus="autofocus"
|
||||
>
|
||||
<template #prepend-inner>
|
||||
<v-icon color="grey lighten-3" size="29">
|
||||
mdi-magnify
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</template>
|
||||
<v-card v-if="showResults" max-height="500" :max-width="maxWidth">
|
||||
<v-card-text class="flex row mx-auto">
|
||||
<v-card
|
||||
v-if="showResults"
|
||||
max-height="75vh"
|
||||
:max-width="maxWidth"
|
||||
scrollable
|
||||
>
|
||||
<v-card-text class="flex row mx-auto ">
|
||||
<div class="mr-auto">
|
||||
Results
|
||||
</div>
|
||||
<router-link to="/search">
|
||||
Advanced Search
|
||||
</router-link>
|
||||
<router-link to="/search"> Advanced Search </router-link>
|
||||
</v-card-text>
|
||||
<v-divider></v-divider>
|
||||
<v-list scrollable v-if="autoResults">
|
||||
|
@ -77,21 +97,21 @@ export default {
|
|||
navOnClick: {
|
||||
default: true,
|
||||
},
|
||||
resetSearch: {
|
||||
default: false,
|
||||
},
|
||||
solo: {
|
||||
default: true,
|
||||
},
|
||||
autofocus: {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isFocused: false,
|
||||
searchSlug: "",
|
||||
search: "",
|
||||
menuModel: false,
|
||||
result: [],
|
||||
fuseResults: [],
|
||||
isDark: false,
|
||||
options: {
|
||||
shouldSort: true,
|
||||
threshold: 0.6,
|
||||
|
@ -105,8 +125,10 @@ export default {
|
|||
};
|
||||
},
|
||||
mounted() {
|
||||
this.isDark = this.$store.getters.getIsDark;
|
||||
this.$store.dispatch("requestAllRecipes");
|
||||
document.addEventListener("keydown", this.onDocumentKeydown);
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("keydown", this.onDocumentKeydown);
|
||||
},
|
||||
computed: {
|
||||
data() {
|
||||
|
@ -124,11 +146,7 @@ export default {
|
|||
},
|
||||
watch: {
|
||||
isSearching(val) {
|
||||
val ? (this.menuModel = true) : null;
|
||||
},
|
||||
|
||||
resetSearch(val) {
|
||||
val ? (this.search = "") : null;
|
||||
val ? (this.menuModel = true) : this.resetSearch();
|
||||
},
|
||||
|
||||
search() {
|
||||
|
@ -167,9 +185,26 @@ export default {
|
|||
this.$emit("selected", slug, name);
|
||||
},
|
||||
async onFocus() {
|
||||
clearTimeout(this.timeout);
|
||||
this.$store.dispatch("requestAllRecipes");
|
||||
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>
|
||||
|
@ -181,4 +216,9 @@ export default {
|
|||
</style>
|
||||
|
||||
<style lang="sass" scoped>
|
||||
.v-menu__content
|
||||
width: 100
|
||||
&, & > *
|
||||
display: flex
|
||||
flex-direction: column
|
||||
</style>
|
|
@ -1,34 +1,40 @@
|
|||
<template>
|
||||
<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-app-bar dark color="primary">
|
||||
<v-toolbar-title class="headline">Search a Recipe</v-toolbar-title>
|
||||
</v-app-bar>
|
||||
<v-card-text>
|
||||
<v-app-bar dark color="primary lighten-1" rounded="0">
|
||||
<SearchBar
|
||||
ref="mealSearchBar"
|
||||
@results="updateResults"
|
||||
@selected="emitSelect"
|
||||
:show-results="!isMobile"
|
||||
max-width="550px"
|
||||
max-width="568"
|
||||
:dense="false"
|
||||
:nav-on-click="false"
|
||||
:reset-search="dialog"
|
||||
:solo="false"
|
||||
:autofocus="true"
|
||||
/>
|
||||
<div v-if="isMobile">
|
||||
<div v-for="recipe in searchResults.slice(0, 7)" :key="recipe.name">
|
||||
<MobileRecipeCard
|
||||
class="ma-1 px-0"
|
||||
:name="recipe.item.name"
|
||||
:description="recipe.item.description"
|
||||
:slug="recipe.item.slug"
|
||||
:rating="recipe.item.rating"
|
||||
:image="recipe.item.image"
|
||||
:route="true"
|
||||
@selected="dialog = false"
|
||||
/>
|
||||
</div>
|
||||
<v-btn icon @click="dialog = false" class="mt-1">
|
||||
<v-icon> mdi-close </v-icon>
|
||||
</v-btn>
|
||||
</v-app-bar>
|
||||
<v-card-text v-if="isMobile">
|
||||
<div v-for="recipe in searchResults.slice(0, 7)" :key="recipe.name">
|
||||
<MobileRecipeCard
|
||||
class="ma-1 px-0"
|
||||
:name="recipe.item.name"
|
||||
:description="recipe.item.description"
|
||||
:slug="recipe.item.slug"
|
||||
:rating="recipe.item.rating"
|
||||
:image="recipe.item.image"
|
||||
:route="true"
|
||||
@selected="dialog = false"
|
||||
/>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
@ -74,11 +80,12 @@ export default {
|
|||
},
|
||||
open() {
|
||||
this.dialog = true;
|
||||
this.$router.push("#mobile-search");
|
||||
this.$refs.mealSearchBar.resetSearch();
|
||||
this.$router.push("#search");
|
||||
},
|
||||
toggleDialog(open) {
|
||||
if (open) {
|
||||
this.$router.push("#mobile-search");
|
||||
this.$router.push("#search");
|
||||
} else {
|
||||
this.$router.back(); // 😎 back button click
|
||||
}
|
||||
|
@ -92,4 +99,8 @@ export default {
|
|||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.top-dialog {
|
||||
align-self: flex-start;
|
||||
}
|
||||
</style>
|
|
@ -13,7 +13,7 @@
|
|||
<v-btn icon @click="openSidebar">
|
||||
<v-icon> mdi-menu </v-icon>
|
||||
</v-btn>
|
||||
<router-link v-if="!(isMobile && search)" to="/">
|
||||
<router-link to="/">
|
||||
<v-btn icon>
|
||||
<v-icon size="40"> mdi-silverware-variant </v-icon>
|
||||
</v-btn>
|
||||
|
@ -26,18 +26,18 @@
|
|||
</div>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<v-expand-x-transition>
|
||||
<SearchBar
|
||||
ref="mainSearchBar"
|
||||
v-if="search"
|
||||
:show-results="true"
|
||||
@selected="navigateFromSearch"
|
||||
:max-width="isMobile ? '100%' : '450px'"
|
||||
/>
|
||||
</v-expand-x-transition>
|
||||
<v-btn icon @click="search = !search">
|
||||
<v-icon>mdi-magnify</v-icon>
|
||||
</v-btn>
|
||||
<SearchBar
|
||||
v-if="!isMobile"
|
||||
:show-results="true"
|
||||
@selected="navigateFromSearch"
|
||||
:max-width="isMobile ? '100%' : '450px'"
|
||||
/>
|
||||
<div v-else>
|
||||
<v-btn icon @click="$refs.recipeSearch.open()">
|
||||
<v-icon> mdi-magnify </v-icon>
|
||||
</v-btn>
|
||||
<SearchDialog ref="recipeSearch"/>
|
||||
</div>
|
||||
|
||||
<TheSiteMenu />
|
||||
|
||||
|
@ -54,6 +54,7 @@
|
|||
<script>
|
||||
import TheSiteMenu from "@/components/UI/TheSiteMenu";
|
||||
import SearchBar from "@/components/UI/Search/SearchBar";
|
||||
import SearchDialog from "@/components/UI/Search/SearchDialog";
|
||||
import TheRecipeFab from "@/components/UI/TheRecipeFab";
|
||||
import TheSidebar from "@/components/UI/TheSidebar";
|
||||
import { user } from "@/mixins/user";
|
||||
|
@ -62,6 +63,7 @@ export default {
|
|||
|
||||
mixins: [user],
|
||||
components: {
|
||||
SearchDialog,
|
||||
TheRecipeFab,
|
||||
TheSidebar,
|
||||
TheSiteMenu,
|
||||
|
@ -69,15 +71,9 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
search: false,
|
||||
showSidebar: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.search = false;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isMobile() {
|
||||
return this.$vuetify.breakpoint.name === "xs";
|
||||
|
@ -95,8 +91,4 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
fab-position {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
</style>
|
|
@ -137,7 +137,7 @@ export default {
|
|||
mainMenu() {
|
||||
return [...this.baseMainLinks, ...this.customPages];
|
||||
},
|
||||
settingsLink() {
|
||||
settingsLinks() {
|
||||
return [
|
||||
{
|
||||
icon: "mdi-account",
|
||||
|
|
|
@ -169,7 +169,7 @@
|
|||
"image": "Image"
|
||||
},
|
||||
"search": {
|
||||
"search-mealie": "Search Mealie",
|
||||
"search-mealie": "Search Mealie (press /)",
|
||||
"search-placeholder": "Search...",
|
||||
"max-results": "Max Results",
|
||||
"category-filter": "Category Filter",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue