mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-30 17:53:31 -04:00 
			
		
		
		
	Feature: Global Timeline (#2265)
* extended query filter to accept nested tables * decoupled timeline api from recipe slug * modified frontend to use simplified events api * fixed nested loop index ghosting * updated existing tests * gave mypy a snack * added tests for nested queries * fixed "last made" render error * decoupled recipe timeline from dialog * removed unused props * tweaked recipe get_all to accept ids * created group global timeline added new timeline page to sidebar reformatted the recipe timeline added vertical option to recipe card mobile * extracted timeline item into its own component * fixed apploader centering * added paginated scrolling to recipe timeline * added sort direction config fixed infinite scroll on dialog fixed hasMore var not resetting during instantiation * added sort direction to user preferences * updated API docs with new query filter feature * better error tracing * fix for recipe not found response * simplified recipe crud route for slug/id added test for fetching by slug/id * made query filter UUID validation clearer * moved timeline menu option below shopping lists --------- Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										162
									
								
								frontend/components/Domain/Recipe/RecipeTimelineItem.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								frontend/components/Domain/Recipe/RecipeTimelineItem.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| <template> | ||||
|   <v-timeline-item | ||||
|     :class="attrs.class" | ||||
|     fill-dot | ||||
|     :small="attrs.small" | ||||
|     :icon="icon" | ||||
|   > | ||||
|     <template v-if="!useMobileFormat" #opposite> | ||||
|         <v-chip v-if="event.timestamp" label large> | ||||
|         <v-icon class="mr-1"> {{ $globals.icons.calendar }} </v-icon> | ||||
|         {{ new Date(event.timestamp+"Z").toLocaleDateString($i18n.locale) }} | ||||
|         </v-chip> | ||||
|     </template> | ||||
|     <v-card> | ||||
|         <v-sheet> | ||||
|         <v-card-title> | ||||
|             <v-row> | ||||
|             <v-col align-self="center" :cols="useMobileFormat ? 'auto' : '2'" :class="attrs.avatar.class"> | ||||
|                 <UserAvatar :user-id="event.userId" :size="attrs.avatar.size" /> | ||||
|             </v-col> | ||||
|             <v-col v-if="useMobileFormat" align-self="center" class="pr-0"> | ||||
|                 <v-chip label> | ||||
|                 <v-icon> {{ $globals.icons.calendar }} </v-icon> | ||||
|                 {{ new Date(event.timestamp+"Z").toLocaleDateString($i18n.locale) }} | ||||
|                 </v-chip> | ||||
|             </v-col> | ||||
|             <v-col v-else cols="9" style="margin: auto; text-align: center;"> | ||||
|                 {{ event.subject }} | ||||
|             </v-col> | ||||
|             <v-spacer /> | ||||
|             <v-col :cols="useMobileFormat ? 'auto' : '1'" class="px-0"> | ||||
|                 <RecipeTimelineContextMenu | ||||
|                 v-if="$auth.user && $auth.user.id == event.userId && event.eventType != 'system'" | ||||
|                 :menu-top="false" | ||||
|                 :event="event" | ||||
|                 :menu-icon="$globals.icons.dotsVertical" | ||||
|                 fab | ||||
|                 color="transparent" | ||||
|                 :elevation="0" | ||||
|                 :card-menu="false" | ||||
|                 :use-items="{ | ||||
|                     edit: true, | ||||
|                     delete: true, | ||||
|                 }" | ||||
|                 @update="$emit('update')" | ||||
|                 @delete="$emit('delete')" | ||||
|                 /> | ||||
|             </v-col> | ||||
|             </v-row> | ||||
|         </v-card-title> | ||||
|         <v-sheet v-if="showRecipeCards && recipe"> | ||||
|             <v-row class="pt-3 pb-7 mx-3" style="max-width: 100%;"> | ||||
|             <v-col align-self="center" class="pa-0"> | ||||
|               <RecipeCardMobile | ||||
|                 :vertical="useMobileFormat" | ||||
|                 :name="recipe.name" | ||||
|                 :slug="recipe.slug" | ||||
|                 :description="recipe.description" | ||||
|                 :rating="recipe.rating" | ||||
|                 :image="recipe.image" | ||||
|                 :recipe-id="recipe.id" | ||||
|               /> | ||||
|             </v-col> | ||||
|             </v-row> | ||||
|         </v-sheet> | ||||
|         <v-divider v-if="showRecipeCards && recipe && (useMobileFormat || event.eventMessage)" /> | ||||
|         <v-card-text> | ||||
|             <v-row> | ||||
|             <v-col> | ||||
|                 <strong v-if="useMobileFormat">{{ event.subject }}</strong> | ||||
|                 <div v-if="event.eventMessage" :class="useMobileFormat ? 'text-caption' : ''"> | ||||
|                 {{ event.eventMessage }} | ||||
|                 </div> | ||||
|             </v-col> | ||||
|             </v-row> | ||||
|         </v-card-text> | ||||
|         </v-sheet> | ||||
|     </v-card> | ||||
|   </v-timeline-item> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import { computed, defineComponent, ref, useContext } from "@nuxtjs/composition-api"; | ||||
| import RecipeCardMobile from "./RecipeCardMobile.vue"; | ||||
| import RecipeTimelineContextMenu from "./RecipeTimelineContextMenu.vue"; | ||||
| import { Recipe, RecipeTimelineEventOut } from "~/lib/api/types/recipe" | ||||
| import UserAvatar from "~/components/Domain/User/UserAvatar.vue"; | ||||
|  | ||||
| export default defineComponent({ | ||||
|   components: { RecipeCardMobile, RecipeTimelineContextMenu, UserAvatar }, | ||||
|  | ||||
|   props: { | ||||
|     event: { | ||||
|       type: Object as () => RecipeTimelineEventOut, | ||||
|       required: true, | ||||
|     }, | ||||
|     recipe: { | ||||
|       type: Object as () => Recipe, | ||||
|       default: undefined, | ||||
|     }, | ||||
|     showRecipeCards: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   setup(props) { | ||||
|     const { $globals, $vuetify } = useContext(); | ||||
|     const timelineEvents = ref([] as RecipeTimelineEventOut[]); | ||||
|  | ||||
|     const useMobileFormat = computed(() => { | ||||
|       return $vuetify.breakpoint.smAndDown; | ||||
|     }); | ||||
|  | ||||
|     const attrs = computed(() => { | ||||
|       if (useMobileFormat.value) { | ||||
|         return { | ||||
|           class: "px-0", | ||||
|           small: false, | ||||
|           avatar: { | ||||
|             size: "30px", | ||||
|             class: "pr-0", | ||||
|           }, | ||||
|         } | ||||
|       } | ||||
|       else { | ||||
|         return { | ||||
|           class: "px-3", | ||||
|           small: false, | ||||
|           avatar: { | ||||
|             size: "42px", | ||||
|             class: "", | ||||
|           }, | ||||
|         } | ||||
|       } | ||||
|     }) | ||||
|  | ||||
|     const icon = computed( () => { | ||||
|       switch (props.event.eventType) { | ||||
|         case "comment": | ||||
|           return $globals.icons.commentTextMultiple; | ||||
|  | ||||
|         case "info": | ||||
|           return $globals.icons.informationVariant; | ||||
|  | ||||
|         case "system": | ||||
|           return $globals.icons.cog; | ||||
|  | ||||
|         default: | ||||
|           return $globals.icons.informationVariant; | ||||
|       }; | ||||
|     }) | ||||
|  | ||||
|     return { | ||||
|       attrs, | ||||
|       icon, | ||||
|       timelineEvents, | ||||
|       useMobileFormat, | ||||
|     }; | ||||
|   }, | ||||
| }); | ||||
| </script> | ||||
		Reference in New Issue
	
	Block a user