mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 14:33:33 -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() {
|
async mounted() {
|
||||||
this.$store.dispatch("initTheme");
|
this.$store.dispatch("initTheme");
|
||||||
this.$store.dispatch("requestRecentRecipes");
|
this.$store.dispatch("requestRecentRecipes");
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue