mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-01-03 23:51:22 -05:00
Feature/image minify (#256)
* fix settings * app info cleanup * bottom-bar experiment * remove dup key * type hints * add dependency * updated image with query parameters * read image options * add image minification * add image minification step * alt image routes * add image minification * set mobile bar to top Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
@@ -28,8 +28,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import utils from "@/utils";
|
||||
import SearchDialog from "../UI/Search/SearchDialog";
|
||||
import { api } from "@/api";
|
||||
export default {
|
||||
components: {
|
||||
SearchDialog,
|
||||
@@ -47,7 +47,7 @@ export default {
|
||||
methods: {
|
||||
getImage(slug) {
|
||||
if (slug) {
|
||||
return utils.getImageURL(slug);
|
||||
return api.recipes.recipeSmallImage(slug);
|
||||
}
|
||||
},
|
||||
setSlug(name, slug) {
|
||||
|
||||
@@ -223,7 +223,7 @@ export default {
|
||||
},
|
||||
|
||||
getImage(image) {
|
||||
return utils.getImageURL(image);
|
||||
return api.recipes.recipeSmallImage(image);
|
||||
},
|
||||
|
||||
formatDate(date) {
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<v-card hover :to="`/recipe/${slug}`" max-height="125">
|
||||
<v-card
|
||||
hover
|
||||
:to="`/recipe/${slug}`"
|
||||
max-height="125"
|
||||
@click="$emit('selected')"
|
||||
>
|
||||
<v-list-item>
|
||||
<v-list-item-avatar rounded size="125" class="mt-0 ml-n4">
|
||||
<v-img :src="getImage(image)"> </v-img>
|
||||
@@ -20,7 +25,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import utils from "@/utils";
|
||||
import { api } from "@/api";
|
||||
export default {
|
||||
props: {
|
||||
name: String,
|
||||
@@ -35,7 +40,7 @@ export default {
|
||||
|
||||
methods: {
|
||||
getImage(image) {
|
||||
return utils.getImageURL(image);
|
||||
return api.recipes.recipeSmallImage(image);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import utils from "@/utils";
|
||||
import { api } from "@/api";
|
||||
export default {
|
||||
props: {
|
||||
name: String,
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
getImage(image) {
|
||||
return utils.getImageURL(image);
|
||||
return api.recipes.recipeSmallImage(image);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -162,6 +162,7 @@
|
||||
|
||||
<script>
|
||||
import utils from "@/utils";
|
||||
import { api } from "@/api";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
@@ -175,7 +176,7 @@ export default {
|
||||
methods: {
|
||||
getImage(image) {
|
||||
if (image) {
|
||||
return utils.getImageURL(image) + "?rnd=" + this.imageKey;
|
||||
return api.recipes.recipeImage(image) + "?rnd=" + this.imageKey;
|
||||
}
|
||||
},
|
||||
generateKey(item, index) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
>
|
||||
</v-text-field>
|
||||
</template>
|
||||
<v-card v-if="showResults" max-height="500" :max-width="maxWidth">
|
||||
<v-card v-if="showResults" max-height="500" :max-width="maxWidth">
|
||||
<v-card-text class="py-1">Results</v-card-text>
|
||||
<v-divider></v-divider>
|
||||
<v-list scrollable>
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
<script>
|
||||
import Fuse from "fuse.js";
|
||||
import utils from "@/utils";
|
||||
import { api } from "@/api";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
@@ -151,7 +151,7 @@ export default {
|
||||
);
|
||||
},
|
||||
getImage(image) {
|
||||
return utils.getImageURL(image);
|
||||
return api.recipes.recipeTinyImage(image);
|
||||
},
|
||||
selected(slug, name) {
|
||||
this.$emit("selected", slug, name);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="text-center ">
|
||||
<v-dialog v-model="dialog" class="search-dialog" width="600px" height="0">
|
||||
<v-dialog v-model="dialog" width="600px" height="0" :fullscreen="isMobile">
|
||||
<v-card>
|
||||
<v-app-bar dark color="primary">
|
||||
<v-toolbar-title class="headline">Search a Recipe</v-toolbar-title>
|
||||
@@ -9,13 +9,27 @@
|
||||
<SearchBar
|
||||
@results="updateResults"
|
||||
@selected="emitSelect"
|
||||
:show-results="true"
|
||||
:show-results="!isMobile"
|
||||
max-width="550px"
|
||||
:dense="false"
|
||||
:nav-on-click="false"
|
||||
:reset-search="dialog"
|
||||
:solo="false"
|
||||
/>
|
||||
<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>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
@@ -24,16 +38,32 @@
|
||||
|
||||
<script>
|
||||
import SearchBar from "./SearchBar";
|
||||
import MobileRecipeCard from "@/components/Recipe/MobileRecipeCard";
|
||||
export default {
|
||||
components: {
|
||||
SearchBar,
|
||||
MobileRecipeCard,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchResults: null,
|
||||
searchResults: [],
|
||||
dialog: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isMobile() {
|
||||
return this.$vuetify.breakpoint.name === "xs";
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
"$route.hash"(newHash, oldHash) {
|
||||
if (newHash === "#mobile-search") {
|
||||
this.dialog = true;
|
||||
} else if (oldHash === "#mobile-search") {
|
||||
this.dialog = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateResults(results) {
|
||||
this.searchResults = results;
|
||||
@@ -44,15 +74,22 @@ export default {
|
||||
},
|
||||
open() {
|
||||
this.dialog = true;
|
||||
this.$router.push("#mobile-search");
|
||||
},
|
||||
toggleDialog(open) {
|
||||
if (open) {
|
||||
this.$router.push("#mobile-search");
|
||||
} else {
|
||||
this.$router.back(); // 😎 back button click
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scope>
|
||||
.search-dialog {
|
||||
margin-top: 10%;
|
||||
.mobile-dialog {
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
</style>
|
||||
114
frontend/src/components/UI/TheAppBar.vue
Normal file
114
frontend/src/components/UI/TheAppBar.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-app-bar
|
||||
v-if="!isMobile"
|
||||
clipped-left
|
||||
dense
|
||||
app
|
||||
color="primary"
|
||||
dark
|
||||
class="d-print-none"
|
||||
>
|
||||
<router-link v-if="!(isMobile && search)" to="/">
|
||||
<v-btn icon>
|
||||
<v-icon size="40"> mdi-silverware-variant </v-icon>
|
||||
</v-btn>
|
||||
</router-link>
|
||||
|
||||
<div v-if="!isMobile" btn class="pl-2">
|
||||
<v-toolbar-title style="cursor: pointer" @click="$router.push('/')"
|
||||
>Mealie
|
||||
</v-toolbar-title>
|
||||
</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>
|
||||
|
||||
<SiteMenu />
|
||||
</v-app-bar>
|
||||
<v-app-bar
|
||||
v-else
|
||||
bottom
|
||||
clipped-left
|
||||
dense
|
||||
app
|
||||
color="primary"
|
||||
dark
|
||||
class="d-print-none"
|
||||
>
|
||||
<router-link to="/">
|
||||
<v-btn icon>
|
||||
<v-icon size="40"> mdi-silverware-variant </v-icon>
|
||||
</v-btn>
|
||||
</router-link>
|
||||
|
||||
<div v-if="!isMobile" btn class="pl-2">
|
||||
<v-toolbar-title style="cursor: pointer" @click="$router.push('/')"
|
||||
>Mealie
|
||||
</v-toolbar-title>
|
||||
</div>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<v-expand-x-transition>
|
||||
<SearchDialog ref="mainSearchDialog" />
|
||||
</v-expand-x-transition>
|
||||
<v-btn icon @click="$refs.mainSearchDialog.open()">
|
||||
<v-icon>mdi-magnify</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<SiteMenu />
|
||||
</v-app-bar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SiteMenu from "@/components/UI/SiteMenu";
|
||||
import SearchBar from "@/components/UI/Search/SearchBar";
|
||||
import SearchDialog from "@/components/UI/Search/SearchDialog";
|
||||
import { user } from "@/mixins/user";
|
||||
export default {
|
||||
name: "AppBar",
|
||||
|
||||
mixins: [user],
|
||||
components: {
|
||||
SiteMenu,
|
||||
SearchBar,
|
||||
SearchDialog,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: false,
|
||||
isMobile: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.search = false;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
// isMobile() {
|
||||
// return this.$vuetify.breakpoint.name === "xs";
|
||||
// },
|
||||
},
|
||||
methods: {
|
||||
navigateFromSearch(slug) {
|
||||
this.$router.push(`/recipe/${slug}`);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
Reference in New Issue
Block a user